mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-10 18:25:17 +00:00
83 lines
3.8 KiB
Go
83 lines
3.8 KiB
Go
|
// Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use
|
||
|
// of this source code is governed by a BSD-style license that can be found in
|
||
|
// the LICENSE file.
|
||
|
|
||
|
package record
|
||
|
|
||
|
// RotationHelper is a type used to inform the decision of rotating a record log
|
||
|
// file.
|
||
|
//
|
||
|
// The assumption is that multiple records can be coalesced into a single record
|
||
|
// (called a snapshot). Starting a new file, where the first record is a
|
||
|
// snapshot of the current state is referred to as "rotating" the log.
|
||
|
//
|
||
|
// Normally we rotate files when a certain file size is reached. But in certain
|
||
|
// cases (e.g. contents become very large), this can result in too frequent
|
||
|
// rotation. This helper contains logic to impose extra conditions on the
|
||
|
// rotation.
|
||
|
//
|
||
|
// The rotation helper uses "size" as a unit-less estimation that is correlated
|
||
|
// with the on-disk size of a record or snapshot.
|
||
|
type RotationHelper struct {
|
||
|
// lastSnapshotSize is the size of the last snapshot.
|
||
|
lastSnapshotSize int64
|
||
|
// sizeSinceLastSnapshot is the sum of sizes of records applied since the last
|
||
|
// snapshot.
|
||
|
sizeSinceLastSnapshot int64
|
||
|
lastRecordSize int64
|
||
|
}
|
||
|
|
||
|
// AddRecord makes the rotation helper aware of a new record.
|
||
|
func (rh *RotationHelper) AddRecord(recordSize int64) {
|
||
|
rh.sizeSinceLastSnapshot += recordSize
|
||
|
rh.lastRecordSize = recordSize
|
||
|
}
|
||
|
|
||
|
// ShouldRotate returns whether we should start a new log file (with a snapshot).
|
||
|
// Does not need to be called if other rotation factors (log file size) are not
|
||
|
// satisfied.
|
||
|
func (rh *RotationHelper) ShouldRotate(nextSnapshotSize int64) bool {
|
||
|
// The primary goal is to ensure that when reopening a log file, the number of
|
||
|
// edits that need to be replayed on top of the snapshot is "sane" while
|
||
|
// keeping the rotation frequency as low as possible.
|
||
|
//
|
||
|
// For the purposes of this description, we assume that the log is mainly
|
||
|
// storing a collection of "entries", with edits adding or removing entries.
|
||
|
// Consider the following cases:
|
||
|
//
|
||
|
// - The number of live entries is roughly stable: after writing the snapshot
|
||
|
// (with S entries), we require that there be enough edits such that the
|
||
|
// cumulative number of entries in those edits, E, be greater than S. This
|
||
|
// will ensure that at most 50% of data written out is due to rotation.
|
||
|
//
|
||
|
// - The number of live entries K in the DB is shrinking drastically, say from
|
||
|
// S to S/10: After this shrinking, E = 0.9S, and so if we used the previous
|
||
|
// snapshot entry count, S, as the threshold that needs to be exceeded, we
|
||
|
// will further delay the snapshot writing. Which means on reopen we will
|
||
|
// need to replay 0.9S edits to get to a version with 0.1S entries. It would
|
||
|
// be better to create a new snapshot when E exceeds the number of entries in
|
||
|
// the current version.
|
||
|
//
|
||
|
// - The number of live entries L in the DB is growing; say the last snapshot
|
||
|
// had S entries, and now we have 10S entries, so E = 9S. If we required
|
||
|
// that E is at least the current number of entries, we would further delay
|
||
|
// writing a new snapshot (which is not desirable).
|
||
|
//
|
||
|
// The logic below uses the min of the last snapshot size count and the size
|
||
|
// count in the current version.
|
||
|
return rh.sizeSinceLastSnapshot > rh.lastSnapshotSize || rh.sizeSinceLastSnapshot > nextSnapshotSize
|
||
|
}
|
||
|
|
||
|
// Rotate makes the rotation helper aware that we are rotating to a new snapshot
|
||
|
// (to which we will apply the latest edit).
|
||
|
func (rh *RotationHelper) Rotate(snapshotSize int64) {
|
||
|
rh.lastSnapshotSize = snapshotSize
|
||
|
rh.sizeSinceLastSnapshot = rh.lastRecordSize
|
||
|
}
|
||
|
|
||
|
// DebugInfo returns the last snapshot size and size of the edits since the last
|
||
|
// snapshot; used for testing and debugging.
|
||
|
func (rh *RotationHelper) DebugInfo() (lastSnapshotSize int64, sizeSinceLastSnapshot int64) {
|
||
|
return rh.lastSnapshotSize, rh.sizeSinceLastSnapshot
|
||
|
}
|