LCOV - code coverage report
Current view: top level - pebble/record - rotation.go (source / functions) Hit Total Coverage
Test: 2024-03-13 08:16Z d938cdc6 - tests + meta.lcov Lines: 42 42 100.0 %
Date: 2024-03-13 08:16:56 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2023 The LevelDB-Go and Pebble Authors. All rights reserved. Use
       2             : // of this source code is governed by a BSD-style license that can be found in
       3             : // the LICENSE file.
       4             : 
       5             : package record
       6             : 
       7             : // RotationHelper is a type used to inform the decision of rotating a record log
       8             : // file.
       9             : //
      10             : // The assumption is that multiple records can be coalesced into a single record
      11             : // (called a snapshot). Starting a new file, where the first record is a
      12             : // snapshot of the current state is referred to as "rotating" the log.
      13             : //
      14             : // Normally we rotate files when a certain file size is reached. But in certain
      15             : // cases (e.g. contents become very large), this can result in too frequent
      16             : // rotation. This helper contains logic to impose extra conditions on the
      17             : // rotation.
      18             : //
      19             : // The rotation helper uses "size" as a unit-less estimation that is correlated
      20             : // with the on-disk size of a record or snapshot.
      21             : type RotationHelper struct {
      22             :         // lastSnapshotSize is the size of the last snapshot.
      23             :         lastSnapshotSize int64
      24             :         // sizeSinceLastSnapshot is the sum of sizes of records applied since the last
      25             :         // snapshot.
      26             :         sizeSinceLastSnapshot int64
      27             :         lastRecordSize        int64
      28             : }
      29             : 
      30             : // AddRecord makes the rotation helper aware of a new record.
      31           2 : func (rh *RotationHelper) AddRecord(recordSize int64) {
      32           2 :         rh.sizeSinceLastSnapshot += recordSize
      33           2 :         rh.lastRecordSize = recordSize
      34           2 : }
      35             : 
      36             : // ShouldRotate returns whether we should start a new log file (with a snapshot).
      37             : // Does not need to be called if other rotation factors (log file size) are not
      38             : // satisfied.
      39           2 : func (rh *RotationHelper) ShouldRotate(nextSnapshotSize int64) bool {
      40           2 :         // The primary goal is to ensure that when reopening a log file, the number of
      41           2 :         // edits that need to be replayed on top of the snapshot is "sane" while
      42           2 :         // keeping the rotation frequency as low as possible.
      43           2 :         //
      44           2 :         // For the purposes of this description, we assume that the log is mainly
      45           2 :         // storing a collection of "entries", with edits adding or removing entries.
      46           2 :         // Consider the following cases:
      47           2 :         //
      48           2 :         // - The number of live entries is roughly stable: after writing the snapshot
      49           2 :         //   (with S entries), we require that there be enough edits such that the
      50           2 :         //   cumulative number of entries in those edits, E, be greater than S. This
      51           2 :         //   will ensure that at most 50% of data written out is due to rotation.
      52           2 :         //
      53           2 :         // - The number of live entries K in the DB is shrinking drastically, say from
      54           2 :         //   S to S/10: After this shrinking, E = 0.9S, and so if we used the previous
      55           2 :         //   snapshot entry count, S, as the threshold that needs to be exceeded, we
      56           2 :         //   will further delay the snapshot writing. Which means on reopen we will
      57           2 :         //   need to replay 0.9S edits to get to a version with 0.1S entries. It would
      58           2 :         //   be better to create a new snapshot when E exceeds the number of entries in
      59           2 :         //   the current version.
      60           2 :         //
      61           2 :         // - The number of live entries L in the DB is growing; say the last snapshot
      62           2 :         //   had S entries, and now we have 10S entries, so E = 9S. If we required
      63           2 :         //   that E is at least the current number of entries, we would further delay
      64           2 :         //   writing a new snapshot (which is not desirable).
      65           2 :         //
      66           2 :         // The logic below uses the min of the last snapshot size count and the size
      67           2 :         // count in the current version.
      68           2 :         return rh.sizeSinceLastSnapshot > rh.lastSnapshotSize || rh.sizeSinceLastSnapshot > nextSnapshotSize
      69           2 : }
      70             : 
      71             : // Rotate makes the rotation helper aware that we are rotating to a new snapshot
      72             : // (to which we will apply the latest edit).
      73           2 : func (rh *RotationHelper) Rotate(snapshotSize int64) {
      74           2 :         rh.lastSnapshotSize = snapshotSize
      75           2 :         rh.sizeSinceLastSnapshot = rh.lastRecordSize
      76           2 : }
      77             : 
      78             : // DebugInfo returns the last snapshot size and size of the edits since the last
      79             : // snapshot; used for testing and debugging.
      80           1 : func (rh *RotationHelper) DebugInfo() (lastSnapshotSize int64, sizeSinceLastSnapshot int64) {
      81           1 :         return rh.lastSnapshotSize, rh.sizeSinceLastSnapshot
      82           1 : }

Generated by: LCOV version 1.14