lsm-tree-0.1.0.0: Log-structured merge-trees
Safe HaskellSafe-Inferred
LanguageGHC2021

Database.LSMTree.Internal.MergeSchedule

Synopsis

Traces

data AtLevel a Source #

Constructors

AtLevel LevelNo a 

Instances

Instances details
Show a => Show (AtLevel a) Source # 
Instance details

Defined in Database.LSMTree.Internal.MergeSchedule

Methods

showsPrec :: Int -> AtLevel a -> ShowS #

show :: AtLevel a -> String #

showList :: [AtLevel a] -> ShowS #

data MergeTrace Source #

Constructors

TraceFlushWriteBuffer 

Fields

TraceAddLevel 
TraceAddRun 

Fields

TraceNewMerge 
TraceNewMergeSingleRun 

Fields

TraceCompletedMerge 

Fields

TraceExpectCompletedMerge RunNumber

This is traced at the latest point the merge could complete.

Instances

Instances details
Show MergeTrace Source # 
Instance details

Defined in Database.LSMTree.Internal.MergeSchedule

Table content

data TableContent m h Source #

The levels of the table, from most to least recently inserted.

Concurrency: read-only operations are allowed to be concurrent with each other, but update operations must not be concurrent with each other or read operations. For example, inspecting the levels cache can be done concurrently, but updatesWithInterleavedFlushes must be serialised.

Constructors

TableContent 

Fields

Levels cache

data LevelsCache m h Source #

Flattend cache of the runs that referenced by a table.

This cache includes a vector of runs, but also vectors of the runs broken down into components, like bloom filters, fence pointer indexes and file handles. This allows for quick access in the lookup code. Recomputing this cache should be relatively rare.

Caches keep references to its runs on construction, and they release each reference when the cache is invalidated. This is done so that incremental merges can remove references for their input runs when a merge completes, without closing runs that might be in use for other operations such as lookups. This does mean that a cache can keep runs open for longer than necessary, so caches should be rebuilt using, e.g., rebuildCache, in a timely manner.

mkLevelsCache :: forall m h. (PrimMonad m, MonadMVar m, MonadMask m) => ActionRegistry m -> Levels m h -> m (LevelsCache m h) Source #

Flatten the argument Levels into a single vector of runs, including all runs that are inputs to an ongoing merge. Use that to populate the LevelsCache. The cache will take a reference for each of its runs.

Levels, runs and ongoing merges

type Levels m h = Vector (Level m h) Source #

data Level m h Source #

A level is a sequence of resident runs at this level, prefixed by an incoming run, which is usually multiple runs that are being merged. Once completed, the resulting run will become a resident run at this level.

Constructors

Level 

Fields

Union level

data UnionLevel m h Source #

An additional optional last level, created as a result of union. It can not only contain an ongoing merge of multiple runs, but a nested tree of merges.

TODO: So far, this is * not considered when creating cursors (also used for range lookups) * never merged into the regular levels

Constructors

NoUnion 
Union !(Ref (MergingTree m h)) 

Flushes and scheduled merges

updatesWithInterleavedFlushes :: forall m h. (MonadMask m, MonadMVar m, MonadSTM m, MonadST m) => Tracer m (AtLevel MergeTrace) -> TableConfig -> ResolveSerialisedValue -> HasFS m h -> HasBlockIO m h -> SessionRoot -> UniqCounter m -> Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob) -> ActionRegistry m -> TableContent m h -> m (TableContent m h) Source #

A single batch of updates can fill up the write buffer multiple times. We flush the write buffer each time it fills up before trying to fill it up again.

TODO: in practice the size of a batch will be much smaller than the maximum size of the write buffer, so we should optimise for the case that small batches are inserted. Ideas:

  • we can allow a range of sizes to flush to disk rather than just the max size
  • could do a map bulk merge rather than sequential insert, on the prefix of the batch that's guaranteed to fit
  • or flush the existing buffer if we would expect the next batch to cause the buffer to become too large

TODO: we could also optimise for the case where the write buffer is small compared to the size of the batch, but it is less critical. In particular, in case the write buffer is empty, or if it fills up multiple times for a single batch of updates, we might be able to skip adding entries to the write buffer for a large part. When the write buffer is empty, we can sort and deduplicate the vector of updates directly, slice it up into properly sized sub-vectors, and write those to disk. Of course, any remainder that did not fit into a whole run should then end up in a fresh write buffer.

flushWriteBuffer :: (MonadMask m, MonadMVar m, MonadST m, MonadSTM m) => Tracer m (AtLevel MergeTrace) -> TableConfig -> ResolveSerialisedValue -> HasFS m h -> HasBlockIO m h -> SessionRoot -> UniqCounter m -> ActionRegistry m -> TableContent m h -> m (TableContent m h) Source #

Flush the write buffer to disk, regardless of whether it is full or not.

The returned table content contains an updated set of levels, where the write buffer is inserted into level 1.

Exported for cabal-docspec

maxRunSize :: SizeRatio -> WriteBufferAlloc -> MergePolicyForLevel -> LevelNo -> NumEntries Source #

Compute the maximum size of a run for a given level.

The size of a tiering run at each level is allowed to be bufferSize*sizeRatio^(level-1) < size <= bufferSize*sizeRatio^level.

>>> unNumEntries . maxRunSize Four (AllocNumEntries (NumEntries 2)) LevelTiering . LevelNo <$> [0, 1, 2, 3, 4]
[0,2,8,32,128]

The size of a levelling run at each level is allowed to be bufferSize*sizeRatio^(level-1) < size <= bufferSize*sizeRatio^(level+1). A levelling run can take take up a whole level, so the maximum size of a run is sizeRatio* larger than the maximum size of a tiering run on the same level.

>>> unNumEntries . maxRunSize Four (AllocNumEntries (NumEntries 2)) LevelLevelling . LevelNo <$> [0, 1, 2, 3, 4]
[0,8,32,128,512]

Credits

newtype MergeCredits Source #

Constructors

MergeCredits Int 

Instances

Instances details
Enum MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Num MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Integral MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Real MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Show MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

NFData MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Methods

rnf :: MergeCredits -> () #

Eq MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

Ord MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.MergingRun

DecodeVersioned MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.Snapshot.Codec

Encode MergeCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.Snapshot.Codec

supplyCredits :: (MonadSTM m, MonadST m, MonadMVar m, MonadMask m) => TableConfig -> NominalCredits -> Levels m h -> m () Source #

Supply the given amount of credits to each merge in the levels structure. This may cause some merges to progress.

newtype NominalDebt Source #

Total merge debt to complete the merge in an incoming run.

This corresponds to the number (worst case, minimum number) of update operations inserted into the table, before we will expect the merge to complete.

Constructors

NominalDebt Int 

newtype NominalCredits Source #

Merge credits that get supplied to a table's levels.

This corresponds to the number of update operations inserted into the table.

Constructors

NominalCredits Int 

Instances

Instances details
NFData NominalCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.IncomingRun

Methods

rnf :: NominalCredits -> () #

Eq NominalCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.IncomingRun

DecodeVersioned NominalCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.Snapshot.Codec

Encode NominalCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.Snapshot.Codec

Prim NominalCredits Source # 
Instance details

Defined in Database.LSMTree.Internal.IncomingRun

nominalDebtForLevel :: TableConfig -> LevelNo -> NominalDebt Source #

The nominal debt equals the minimum of credits we will supply before we expect the merge to complete. This is the same as the number of updates in a run that gets moved to this level.

Exported for testing

addWriteBufferEntries :: (MonadSTM m, MonadThrow m, PrimMonad m) => HasFS m h -> ResolveSerialisedValue -> Ref (WriteBufferBlobs m h) -> NumEntries -> WriteBuffer -> Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob) -> m (WriteBuffer, Vector (SerialisedKey, Entry SerialisedValue SerialisedBlob)) Source #

Add entries to the write buffer up until a certain write buffer size n.

NOTE: if the write buffer is larger n already, this is a no-op.