LCOV - code coverage report
Current view: top level - pebble - format_major_version.go (source / functions) Hit Total Coverage
Test: 2024-10-08 08:17Z 3f7527ff - tests + meta.lcov Lines: 94 189 49.7 %
Date: 2024-10-08 08:18:11 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2021 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 pebble
       6             : 
       7             : import (
       8             :         "fmt"
       9             :         "strconv"
      10             : 
      11             :         "github.com/cockroachdb/errors"
      12             :         "github.com/cockroachdb/pebble/internal/manifest"
      13             :         "github.com/cockroachdb/pebble/sstable"
      14             :         "github.com/cockroachdb/pebble/vfs"
      15             :         "github.com/cockroachdb/pebble/vfs/atomicfs"
      16             : )
      17             : 
      18             : // FormatMajorVersion is a constant controlling the format of persisted
      19             : // data. Backwards incompatible changes to durable formats are gated
      20             : // behind new format major versions.
      21             : //
      22             : // At any point, a database's format major version may be bumped.
      23             : // However, once a database's format major version is increased,
      24             : // previous versions of Pebble will refuse to open the database.
      25             : //
      26             : // The zero value format is the FormatDefault constant. The exact
      27             : // FormatVersion that the default corresponds to may change with time.
      28             : type FormatMajorVersion uint64
      29             : 
      30             : // SafeValue implements redact.SafeValue.
      31           0 : func (v FormatMajorVersion) SafeValue() {}
      32             : 
      33             : // String implements fmt.Stringer.
      34           2 : func (v FormatMajorVersion) String() string {
      35           2 :         // NB: This must not change. It's used as the value for the on-disk
      36           2 :         // version marker file.
      37           2 :         //
      38           2 :         // Specifically, this value must always parse as a base 10 integer
      39           2 :         // that fits in a uint64. We format it as zero-padded, 3-digit
      40           2 :         // number today, but the padding may change.
      41           2 :         return fmt.Sprintf("%03d", v)
      42           2 : }
      43             : 
      44             : const (
      45             :         // FormatDefault leaves the format version unspecified. When used to create a
      46             :         // new store, Pebble will choose the earliest format version it supports.
      47             :         FormatDefault FormatMajorVersion = iota
      48             : 
      49             :         // 21.2 versions.
      50             : 
      51             :         // FormatMostCompatible maintains the most backwards compatibility,
      52             :         // maintaining bi-directional compatibility with RocksDB 6.2.1 in
      53             :         // the particular configuration described in the Pebble README.
      54             :         // Deprecated.
      55             :         _ // FormatMostCompatible
      56             : 
      57             :         // formatVersionedManifestMarker is the first
      58             :         // backwards-incompatible change made to Pebble, introducing the
      59             :         // format-version marker file for handling backwards-incompatible
      60             :         // changes more broadly, and replacing the `CURRENT` file with a
      61             :         // marker file.
      62             :         //
      63             :         // This format version is intended as an intermediary version state.
      64             :         // It is deliberately unexported to discourage direct use of this
      65             :         // format major version.  Clients should use FormatVersioned which
      66             :         // also ensures earlier versions of Pebble fail to open a database
      67             :         // written in a future format major version.
      68             :         // Deprecated.
      69             :         _ // formatVersionedManifestMarker
      70             : 
      71             :         // FormatVersioned is a new format major version that replaces the
      72             :         // old `CURRENT` file with a new 'marker' file scheme.  Previous
      73             :         // Pebble versions will be unable to open the database unless
      74             :         // they're aware of format versions.
      75             :         // Deprecated.
      76             :         _ // FormatVersioned
      77             : 
      78             :         // FormatSetWithDelete is a format major version that introduces a new key
      79             :         // kind, base.InternalKeyKindSetWithDelete. Previous Pebble versions will be
      80             :         // unable to open this database.
      81             :         // Deprecated.
      82             :         _ // FormatSetWithDelete
      83             : 
      84             :         // 22.1 versions.
      85             : 
      86             :         // FormatBlockPropertyCollector is a format major version that introduces
      87             :         // BlockPropertyCollectors.
      88             :         // Deprecated.
      89             :         _ // FormatBlockPropertyCollector
      90             : 
      91             :         // FormatSplitUserKeysMarked is a format major version that guarantees that
      92             :         // all files that share user keys with neighbors are marked for compaction
      93             :         // in the manifest. Ratcheting to FormatSplitUserKeysMarked will block
      94             :         // (without holding mutexes) until the scan of the LSM is complete and the
      95             :         // manifest has been rotated.
      96             :         // Deprecated.
      97             :         _ // FormatSplitUserKeysMarked
      98             : 
      99             :         // 22.2 versions.
     100             : 
     101             :         // FormatSplitUserKeysMarkedCompacted is a format major version that
     102             :         // guarantees that all files explicitly marked for compaction in the manifest
     103             :         // have been compacted. Combined with the FormatSplitUserKeysMarked format
     104             :         // major version, this version guarantees that there are no user keys split
     105             :         // across multiple files within a level L1+. Ratcheting to this format version
     106             :         // will block (without holding mutexes) until all necessary compactions for
     107             :         // files marked for compaction are complete.
     108             :         // Deprecated.
     109             :         _ // FormatSplitUserKeysMarkedCompacted
     110             : 
     111             :         // FormatRangeKeys is a format major version that introduces range keys.
     112             :         // Deprecated.
     113             :         _ // FormatRangeKeys
     114             : 
     115             :         // FormatMinTableFormatPebblev1 is a format major version that guarantees that
     116             :         // tables created by or ingested into the DB at or above this format major
     117             :         // version will have a table format version of at least Pebblev1 (Block
     118             :         // Properties).
     119             :         // Deprecated.
     120             :         _ // FormatMinTableFormatPebblev1
     121             : 
     122             :         // FormatPrePebblev1Marked is a format major version that guarantees that all
     123             :         // sstables with a table format version pre-Pebblev1 (i.e. those that are
     124             :         // guaranteed to not contain block properties) are marked for compaction in
     125             :         // the manifest. Ratcheting to FormatPrePebblev1Marked will block (without
     126             :         // holding mutexes) until the scan of the LSM is complete and the manifest has
     127             :         // been rotated.
     128             :         // Deprecated.
     129             :         _ // FormatPrePebblev1Marked
     130             : 
     131             :         // 23.1 versions.
     132             : 
     133             :         // formatUnusedPrePebblev1MarkedCompacted is an unused format major version.
     134             :         // This format major version was originally intended to ship in the 23.1
     135             :         // release. It was later decided that this should be deferred until a
     136             :         // subsequent release. The original ordering is preserved so as not to
     137             :         // introduce breaking changes in Cockroach.
     138             :         _ // formatUnusedPrePebblev1MarkedCompacted
     139             : 
     140             :         // FormatSSTableValueBlocks is a format major version that adds support for
     141             :         // storing values in value blocks in the sstable. Value block support is not
     142             :         // necessarily enabled when writing sstables, when running with this format
     143             :         // major version.
     144             :         _ // FormatSSTableValueBlocks
     145             : 
     146             :         // FormatFlushableIngest is a format major version that enables lazy
     147             :         // addition of ingested sstables into the LSM structure. When an ingest
     148             :         // overlaps with a memtable, a record of the ingest is written to the WAL
     149             :         // without waiting for a flush. Subsequent reads treat the ingested files as
     150             :         // a level above the overlapping memtable. Once the memtable is flushed, the
     151             :         // ingested files are moved into the lowest possible levels.
     152             :         //
     153             :         // This feature is behind a format major version because it required
     154             :         // breaking changes to the WAL format.
     155             :         FormatFlushableIngest
     156             : 
     157             :         // 23.2 versions.
     158             : 
     159             :         // FormatPrePebblev1MarkedCompacted is a format major version that guarantees
     160             :         // that all sstables explicitly marked for compaction in the manifest (see
     161             :         // FormatPrePebblev1Marked) have been compacted. Ratcheting to this format
     162             :         // version will block (without holding mutexes) until all necessary
     163             :         // compactions for files marked for compaction are complete.
     164             :         FormatPrePebblev1MarkedCompacted
     165             : 
     166             :         // FormatDeleteSizedAndObsolete is a format major version that adds support
     167             :         // for deletion tombstones that encode the size of the value they're
     168             :         // expected to delete. This format major version is required before the
     169             :         // associated key kind may be committed through batch applications or
     170             :         // ingests. It also adds support for keys that are marked obsolete (see
     171             :         // sstable/format.go for details).
     172             :         FormatDeleteSizedAndObsolete
     173             : 
     174             :         // FormatVirtualSSTables is a format major version that adds support for
     175             :         // virtual sstables that can reference a sub-range of keys in an underlying
     176             :         // physical sstable. This information is persisted through new,
     177             :         // backward-incompatible fields in the Manifest, and therefore requires
     178             :         // a format major version.
     179             :         FormatVirtualSSTables
     180             : 
     181             :         // FormatSyntheticPrefixSuffix is a format major version that adds support for
     182             :         // sstables to have their content exposed in a different prefix or suffix of
     183             :         // keyspace than the actual prefix/suffix persisted in the keys in such
     184             :         // sstables. The prefix and suffix replacement information is stored in new
     185             :         // fields in the Manifest and thus requires a format major version.
     186             :         FormatSyntheticPrefixSuffix
     187             : 
     188             :         // FormatFlushableIngestExcises is a format major version that adds support for
     189             :         // having excises unconditionally being written as flushable ingestions. This
     190             :         // is implemented through adding a new key kind that can go in the same batches
     191             :         // as flushable ingested sstables.
     192             :         FormatFlushableIngestExcises
     193             : 
     194             :         // TODO(msbutler): add major version for synthetic suffixes
     195             : 
     196             :         // -- Add new versions here --
     197             : 
     198             :         // FormatNewest is the most recent format major version.
     199             :         FormatNewest FormatMajorVersion = iota - 1
     200             : 
     201             :         // Experimental versions, which are excluded by FormatNewest (but can be used
     202             :         // in tests) can be defined here.
     203             : 
     204             :         // -- Add experimental versions here --
     205             : 
     206             :         // internalFormatNewest is the most recent, possibly experimental format major
     207             :         // version.
     208             :         internalFormatNewest FormatMajorVersion = iota - 2
     209             : )
     210             : 
     211             : // FormatMinSupported is the minimum format version that is supported by this
     212             : // Pebble version.
     213             : const FormatMinSupported = FormatFlushableIngest
     214             : 
     215             : // FormatMinForSharedObjects it the minimum format version that supports shared
     216             : // objects (see CreateOnShared option).
     217             : const FormatMinForSharedObjects = FormatVirtualSSTables
     218             : 
     219             : // IsSupported returns true if the version is supported by the current Pebble
     220             : // version.
     221           0 : func (v FormatMajorVersion) IsSupported() bool {
     222           0 :         return v == FormatDefault && v >= FormatMinSupported && v <= internalFormatNewest
     223           0 : }
     224             : 
     225             : // MaxTableFormat returns the maximum sstable.TableFormat that can be used at
     226             : // this FormatMajorVersion.
     227           2 : func (v FormatMajorVersion) MaxTableFormat() sstable.TableFormat {
     228           2 :         switch v {
     229           2 :         case FormatDefault, FormatFlushableIngest, FormatPrePebblev1MarkedCompacted:
     230           2 :                 return sstable.TableFormatPebblev3
     231             :         case FormatDeleteSizedAndObsolete, FormatVirtualSSTables, FormatSyntheticPrefixSuffix,
     232           2 :                 FormatFlushableIngestExcises:
     233           2 :                 return sstable.TableFormatPebblev4
     234           1 :         default:
     235           1 :                 panic(fmt.Sprintf("pebble: unsupported format major version: %s", v))
     236             :         }
     237             : }
     238             : 
     239             : // MinTableFormat returns the minimum sstable.TableFormat that can be used at
     240             : // this FormatMajorVersion.
     241           2 : func (v FormatMajorVersion) MinTableFormat() sstable.TableFormat {
     242           2 :         switch v {
     243             :         case FormatDefault, FormatFlushableIngest, FormatPrePebblev1MarkedCompacted,
     244             :                 FormatDeleteSizedAndObsolete, FormatVirtualSSTables, FormatSyntheticPrefixSuffix,
     245           2 :                 FormatFlushableIngestExcises:
     246           2 :                 return sstable.TableFormatPebblev1
     247           1 :         default:
     248           1 :                 panic(fmt.Sprintf("pebble: unsupported format major version: %s", v))
     249             :         }
     250             : }
     251             : 
     252             : // formatMajorVersionMigrations defines the migrations from one format
     253             : // major version to the next. Each migration is defined as a closure
     254             : // which will be invoked on the database before the new format major
     255             : // version is committed. Migrations must be idempotent. Migrations are
     256             : // invoked with d.mu locked.
     257             : //
     258             : // Each migration is responsible for invoking finalizeFormatVersUpgrade
     259             : // to set the new format major version.  RatchetFormatMajorVersion will
     260             : // panic if a migration returns a nil error but fails to finalize the
     261             : // new format major version.
     262             : var formatMajorVersionMigrations = map[FormatMajorVersion]func(*DB) error{
     263           0 :         FormatFlushableIngest: func(d *DB) error { return nil },
     264           2 :         FormatPrePebblev1MarkedCompacted: func(d *DB) error {
     265           2 :                 // Before finalizing the format major version, rewrite any sstables
     266           2 :                 // still marked for compaction. Note all format major versions
     267           2 :                 // migrations are invoked with DB.mu locked.
     268           2 :                 if err := d.compactMarkedFilesLocked(); err != nil {
     269           0 :                         return err
     270           0 :                 }
     271           2 :                 return d.finalizeFormatVersUpgrade(FormatPrePebblev1MarkedCompacted)
     272             :         },
     273           2 :         FormatDeleteSizedAndObsolete: func(d *DB) error {
     274           2 :                 return d.finalizeFormatVersUpgrade(FormatDeleteSizedAndObsolete)
     275           2 :         },
     276           2 :         FormatVirtualSSTables: func(d *DB) error {
     277           2 :                 return d.finalizeFormatVersUpgrade(FormatVirtualSSTables)
     278           2 :         },
     279           2 :         FormatSyntheticPrefixSuffix: func(d *DB) error {
     280           2 :                 return d.finalizeFormatVersUpgrade(FormatSyntheticPrefixSuffix)
     281           2 :         },
     282           2 :         FormatFlushableIngestExcises: func(d *DB) error {
     283           2 :                 return d.finalizeFormatVersUpgrade(FormatFlushableIngestExcises)
     284           2 :         },
     285             : }
     286             : 
     287             : const formatVersionMarkerName = `format-version`
     288             : 
     289             : // lookupFormatMajorVersion retrieves the format version from the format version
     290             : // marker file.
     291             : //
     292             : // If such a file does not exist, returns FormatDefault. Note that this case is
     293             : // only acceptable if we are creating a new store (we no longer support
     294             : // FormatMostCompatible which is the only one with no version marker file).
     295             : func lookupFormatMajorVersion(
     296             :         fs vfs.FS, dirname string, ls []string,
     297           2 : ) (FormatMajorVersion, *atomicfs.Marker, error) {
     298           2 :         m, versString, err := atomicfs.LocateMarkerInListing(fs, dirname, formatVersionMarkerName, ls)
     299           2 :         if err != nil {
     300           1 :                 return 0, nil, err
     301           1 :         }
     302           2 :         if versString == "" {
     303           2 :                 return FormatDefault, m, nil
     304           2 :         }
     305           2 :         v, err := strconv.ParseUint(versString, 10, 64)
     306           2 :         if err != nil {
     307           0 :                 return 0, nil, errors.Wrap(err, "parsing format major version")
     308           0 :         }
     309           2 :         vers := FormatMajorVersion(v)
     310           2 :         if vers == FormatDefault {
     311           0 :                 return 0, nil, errors.Newf("pebble: default format major version should not persisted", vers)
     312           0 :         }
     313           2 :         if vers > internalFormatNewest {
     314           1 :                 return 0, nil, errors.Newf("pebble: database %q written in unknown format major version %d", dirname, vers)
     315           1 :         }
     316           2 :         if vers < FormatMinSupported {
     317           0 :                 return 0, nil, errors.Newf("pebble: database %q written in format major version %d which is no longer supported", dirname, vers)
     318           0 :         }
     319           2 :         return vers, m, nil
     320             : }
     321             : 
     322             : // FormatMajorVersion returns the database's active format major
     323             : // version. The format major version may be higher than the one
     324             : // provided in Options when the database was opened if the existing
     325             : // database was written with a higher format version.
     326           2 : func (d *DB) FormatMajorVersion() FormatMajorVersion {
     327           2 :         return FormatMajorVersion(d.mu.formatVers.vers.Load())
     328           2 : }
     329             : 
     330             : // RatchetFormatMajorVersion ratchets the opened database's format major
     331             : // version to the provided version. It errors if the provided format
     332             : // major version is below the database's current version. Once a
     333             : // database's format major version is upgraded, previous Pebble versions
     334             : // that do not know of the format version will be unable to open the
     335             : // database.
     336           2 : func (d *DB) RatchetFormatMajorVersion(fmv FormatMajorVersion) error {
     337           2 :         if err := d.closed.Load(); err != nil {
     338           1 :                 panic(err)
     339             :         }
     340             : 
     341           2 :         d.mu.Lock()
     342           2 :         defer d.mu.Unlock()
     343           2 :         return d.ratchetFormatMajorVersionLocked(fmv)
     344             : }
     345             : 
     346           2 : func (d *DB) ratchetFormatMajorVersionLocked(formatVers FormatMajorVersion) error {
     347           2 :         if d.opts.ReadOnly {
     348           0 :                 return ErrReadOnly
     349           0 :         }
     350           2 :         if formatVers > internalFormatNewest {
     351           0 :                 // Guard against accidentally forgetting to update internalFormatNewest.
     352           0 :                 return errors.Errorf("pebble: unknown format version %d", formatVers)
     353           0 :         }
     354           2 :         if currentVers := d.FormatMajorVersion(); currentVers > formatVers {
     355           0 :                 return errors.Newf("pebble: database already at format major version %d; cannot reduce to %d",
     356           0 :                         currentVers, formatVers)
     357           0 :         }
     358           2 :         if d.mu.formatVers.ratcheting {
     359           0 :                 return errors.Newf("pebble: database format major version upgrade is in-progress")
     360           0 :         }
     361           2 :         d.mu.formatVers.ratcheting = true
     362           2 :         defer func() { d.mu.formatVers.ratcheting = false }()
     363             : 
     364           2 :         for nextVers := d.FormatMajorVersion() + 1; nextVers <= formatVers; nextVers++ {
     365           2 :                 if err := formatMajorVersionMigrations[nextVers](d); err != nil {
     366           0 :                         return errors.Wrapf(err, "migrating to version %d", nextVers)
     367           0 :                 }
     368             : 
     369             :                 // NB: The migration is responsible for calling
     370             :                 // finalizeFormatVersUpgrade to finalize the upgrade. This
     371             :                 // structure is necessary because some migrations may need to
     372             :                 // update in-memory state (without ever dropping locks) after
     373             :                 // the upgrade is finalized. Here we assert that the upgrade
     374             :                 // did occur.
     375           2 :                 if d.FormatMajorVersion() != nextVers {
     376           0 :                         d.opts.Logger.Fatalf("pebble: successful migration to format version %d never finalized the upgrade", nextVers)
     377           0 :                 }
     378             :         }
     379           2 :         return nil
     380             : }
     381             : 
     382             : // finalizeFormatVersUpgrade is typically only be called from within a
     383             : // format major version migration.
     384             : //
     385             : // See formatMajorVersionMigrations.
     386           2 : func (d *DB) finalizeFormatVersUpgrade(formatVers FormatMajorVersion) error {
     387           2 :         if err := d.writeFormatVersionMarker(formatVers); err != nil {
     388           0 :                 return err
     389           0 :         }
     390           2 :         d.mu.formatVers.vers.Store(uint64(formatVers))
     391           2 :         d.opts.EventListener.FormatUpgrade(formatVers)
     392           2 :         return nil
     393             : }
     394             : 
     395           2 : func (d *DB) writeFormatVersionMarker(formatVers FormatMajorVersion) error {
     396           2 :         // We use the marker to encode the active format version in the
     397           2 :         // marker filename. Unlike other uses of the atomic marker, there is
     398           2 :         // no file with the filename `formatVers.String()` on the
     399           2 :         // filesystem.
     400           2 :         return d.mu.formatVers.marker.Move(formatVers.String())
     401           2 : }
     402             : 
     403             : // compactMarkedFilesLocked performs a migration that schedules rewrite
     404             : // compactions to compact away any sstables marked for compaction.
     405             : // compactMarkedFilesLocked is run while ratcheting the database's format major
     406             : // version to FormatSplitUserKeysMarkedCompacted.
     407             : //
     408             : // Note that while this method is called with the DB.mu held, and will not
     409             : // return until all marked files have been compacted, the mutex is dropped while
     410             : // waiting for compactions to complete (or for slots to free up).
     411           2 : func (d *DB) compactMarkedFilesLocked() error {
     412           2 :         curr := d.mu.versions.currentVersion()
     413           2 :         for curr.Stats.MarkedForCompaction > 0 {
     414           0 :                 // Attempt to schedule a compaction to rewrite a file marked for
     415           0 :                 // compaction.
     416           0 :                 d.maybeScheduleCompactionPicker(func(picker compactionPicker, env compactionEnv) *pickedCompaction {
     417           0 :                         return picker.pickRewriteCompaction(env)
     418           0 :                 })
     419             : 
     420             :                 // The above attempt might succeed and schedule a rewrite compaction. Or
     421             :                 // there might not be available compaction concurrency to schedule the
     422             :                 // compaction.  Or compaction of the file might have already been in
     423             :                 // progress. In any scenario, wait until there's some change in the
     424             :                 // state of active compactions.
     425             : 
     426             :                 // Before waiting, check that the database hasn't been closed. Trying to
     427             :                 // schedule the compaction may have dropped d.mu while waiting for a
     428             :                 // manifest write to complete. In that dropped interim, the database may
     429             :                 // have been closed.
     430           0 :                 if err := d.closed.Load(); err != nil {
     431           0 :                         return err.(error)
     432           0 :                 }
     433             : 
     434             :                 // Some flush or compaction may have scheduled or completed while we waited
     435             :                 // for the manifest lock in maybeScheduleCompactionPicker. Get the latest
     436             :                 // Version before waiting on a compaction.
     437           0 :                 curr = d.mu.versions.currentVersion()
     438           0 : 
     439           0 :                 // Only wait on compactions if there are files still marked for compaction.
     440           0 :                 // NB: Waiting on this condition variable drops d.mu while blocked.
     441           0 :                 if curr.Stats.MarkedForCompaction > 0 {
     442           0 :                         if d.mu.compact.compactingCount == 0 {
     443           0 :                                 panic("expected a compaction of marked files in progress")
     444             :                         }
     445           0 :                         d.mu.compact.cond.Wait()
     446           0 :                         // Refresh the current version again.
     447           0 :                         curr = d.mu.versions.currentVersion()
     448             :                 }
     449             :         }
     450           2 :         return nil
     451             : }
     452             : 
     453             : // findFilesFunc scans the LSM for files, returning true if at least one
     454             : // file was found. The returned array contains the matched files, if any, per
     455             : // level.
     456             : type findFilesFunc func(v *version) (found bool, files [numLevels][]*fileMetadata, _ error)
     457             : 
     458             : // This method is not used currently, but it will be useful the next time we need
     459             : // to mark files for compaction.
     460             : var _ = (*DB)(nil).markFilesLocked
     461             : 
     462             : // markFilesLocked durably marks the files that match the given findFilesFunc for
     463             : // compaction.
     464           0 : func (d *DB) markFilesLocked(findFn findFilesFunc) error {
     465           0 :         jobID := d.newJobIDLocked()
     466           0 : 
     467           0 :         // Acquire a read state to have a view of the LSM and a guarantee that none
     468           0 :         // of the referenced files will be deleted until we've unreferenced the read
     469           0 :         // state. Some findFilesFuncs may read the files, requiring they not be
     470           0 :         // deleted.
     471           0 :         rs := d.loadReadState()
     472           0 :         var (
     473           0 :                 found bool
     474           0 :                 files [numLevels][]*fileMetadata
     475           0 :                 err   error
     476           0 :         )
     477           0 :         func() {
     478           0 :                 defer rs.unrefLocked()
     479           0 :                 // Note the unusual locking: unlock, defer Lock(). The scan of the files in
     480           0 :                 // the version does not need to block other operations that require the
     481           0 :                 // DB.mu. Drop it for the scan, before re-acquiring it.
     482           0 :                 d.mu.Unlock()
     483           0 :                 defer d.mu.Lock()
     484           0 :                 found, files, err = findFn(rs.current)
     485           0 :         }()
     486           0 :         if err != nil {
     487           0 :                 return err
     488           0 :         }
     489             : 
     490             :         // The database lock has been acquired again by the defer within the above
     491             :         // anonymous function.
     492           0 :         if !found {
     493           0 :                 // Nothing to do.
     494           0 :                 return nil
     495           0 :         }
     496             : 
     497             :         // After scanning, if we found files to mark, we fetch the current state of
     498             :         // the LSM (which may have changed) and set MarkedForCompaction on the files,
     499             :         // and update the version's Stats.MarkedForCompaction count, which are both
     500             :         // protected by d.mu.
     501             : 
     502             :         // Lock the manifest for a coherent view of the LSM. The database lock has
     503             :         // been re-acquired by the defer within the above anonymous function.
     504           0 :         d.mu.versions.logLock()
     505           0 :         vers := d.mu.versions.currentVersion()
     506           0 :         for l, filesToMark := range files {
     507           0 :                 if len(filesToMark) == 0 {
     508           0 :                         continue
     509             :                 }
     510           0 :                 for _, f := range filesToMark {
     511           0 :                         // Ignore files to be marked that have already been compacted or marked.
     512           0 :                         if f.CompactionState == manifest.CompactionStateCompacted ||
     513           0 :                                 f.MarkedForCompaction {
     514           0 :                                 continue
     515             :                         }
     516             :                         // Else, mark the file for compaction in this version.
     517           0 :                         vers.Stats.MarkedForCompaction++
     518           0 :                         f.MarkedForCompaction = true
     519             :                 }
     520             :                 // The compaction picker uses the markedForCompactionAnnotator to
     521             :                 // quickly find files marked for compaction, or to quickly determine
     522             :                 // that there are no such files marked for compaction within a level.
     523             :                 // A b-tree node may be annotated with an annotation recording that
     524             :                 // there are no files marked for compaction within the node's subtree,
     525             :                 // based on the assumption that it's static.
     526             :                 //
     527             :                 // Since we're marking files for compaction, these b-tree nodes'
     528             :                 // annotations will be out of date. Clear the compaction-picking
     529             :                 // annotation, so that it's recomputed the next time the compaction
     530             :                 // picker looks for a file marked for compaction.
     531           0 :                 markedForCompactionAnnotator.InvalidateLevelAnnotation(vers.Levels[l])
     532             :         }
     533             : 
     534             :         // The 'marked-for-compaction' bit is persisted in the MANIFEST file
     535             :         // metadata. We've already modified the in-memory file metadata, but the
     536             :         // manifest hasn't been updated. Force rotation to a new MANIFEST file,
     537             :         // which will write every file metadata to the new manifest file and ensure
     538             :         // that the now marked-for-compaction file metadata are persisted as marked.
     539             :         // NB: This call to logAndApply will unlockthe MANIFEST, which we locked up
     540             :         // above before obtaining `vers`.
     541           0 :         return d.mu.versions.logAndApply(
     542           0 :                 jobID,
     543           0 :                 &manifest.VersionEdit{},
     544           0 :                 map[int]*LevelMetrics{},
     545           0 :                 true, /* forceRotation */
     546           0 :                 func() []compactionInfo { return d.getInProgressCompactionInfoLocked(nil) })
     547             : }

Generated by: LCOV version 1.14