diff --git a/bench/macro/lsm-tree-bench-lookups.hs b/bench/macro/lsm-tree-bench-lookups.hs index af6ee7589..a55d2a898 100644 --- a/bench/macro/lsm-tree-bench-lookups.hs +++ b/bench/macro/lsm-tree-bench-lookups.hs @@ -32,6 +32,7 @@ import Database.LSMTree.Internal.Paths (RunFsPaths (RunFsPaths)) import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) +import Database.LSMTree.Internal.RunBuilder (RunParams (..)) import qualified Database.LSMTree.Internal.RunBuilder as RunBuilder import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise (SerialisedKey, @@ -349,10 +350,13 @@ lookupsEnv runSizes keyRng0 hfs hbio caching = do -- create the runs rbs <- sequence [ RunBuilder.new hfs hbio + RunParams { + runParamCaching = caching, + runParamAlloc = RunAllocFixed benchmarkNumBitsPerEntry, + runParamIndex = Index.Compact + } (RunFsPaths (FS.mkFsPath []) (RunNumber i)) (NumEntries numEntries) - (RunAllocFixed benchmarkNumBitsPerEntry) - Index.Compact | ((numEntries, _), i) <- zip runSizes [0..] ] -- fill the runs @@ -373,7 +377,7 @@ lookupsEnv runSizes keyRng0 hfs hbio caching = do putStr "DONE" -- return runs - runs <- V.fromList <$> mapM (Run.fromMutable caching) rbs + runs <- V.fromList <$> mapM Run.fromMutable rbs let blooms = V.map (\(DeRef r) -> Run.runFilter r) runs indexes = V.map (\(DeRef r) -> Run.runIndex r) runs handles = V.map (\(DeRef r) -> Run.runKOpsFile r) runs diff --git a/bench/micro/Bench/Database/LSMTree/Internal/Lookup.hs b/bench/micro/Bench/Database/LSMTree/Internal/Lookup.hs index bd88c2476..74fd2f8d1 100644 --- a/bench/micro/Bench/Database/LSMTree/Internal/Lookup.hs +++ b/bench/micro/Bench/Database/LSMTree/Internal/Lookup.hs @@ -19,16 +19,15 @@ import qualified Data.Vector as V import Database.LSMTree.Extras.Orphans () import Database.LSMTree.Extras.Random (frequency, randomByteStringR, sampleUniformWithReplacement, uniformWithoutReplacement) +import Database.LSMTree.Extras.RunData (defaultRunParams) import Database.LSMTree.Extras.UTxO import Database.LSMTree.Internal.Entry (Entry (..), NumEntries (..)) -import qualified Database.LSMTree.Internal.Index as Index (IndexType (Compact)) import Database.LSMTree.Internal.Lookup (bloomQueries, indexSearches, intraPageLookups, lookupsIO, prepLookups) import Database.LSMTree.Internal.Page (getNumPages) import Database.LSMTree.Internal.Paths (RunFsPaths (..)) import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise import qualified Database.LSMTree.Internal.WriteBuffer as WB @@ -192,7 +191,7 @@ lookupsInBatchesEnv Config {..} = do wbblobs <- WBB.new hasFS (FS.mkFsPath ["0.wbblobs"]) wb <- WB.fromMap <$> traverse (traverse (WBB.addBlob hasFS wbblobs)) storedKeys let fsps = RunFsPaths (FS.mkFsPath []) (RunNumber 0) - r <- Run.fromWriteBuffer hasFS hasBlockIO caching (RunAllocFixed 10) Index.Compact fsps wb wbblobs + r <- Run.fromWriteBuffer hasFS hasBlockIO defaultRunParams fsps wb wbblobs let NumEntries nentriesReal = Run.size r assertEqual nentriesReal nentries $ pure () -- 42 to 43 entries per page diff --git a/bench/micro/Bench/Database/LSMTree/Internal/Merge.hs b/bench/micro/Bench/Database/LSMTree/Internal/Merge.hs index 9f7976f8a..731184609 100644 --- a/bench/micro/Bench/Database/LSMTree/Internal/Merge.hs +++ b/bench/micro/Bench/Database/LSMTree/Internal/Merge.hs @@ -23,7 +23,6 @@ import qualified Database.LSMTree.Internal.Merge as Merge import Database.LSMTree.Internal.Paths (RunFsPaths (..)) import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise import Database.LSMTree.Internal.UniqCounter @@ -264,8 +263,7 @@ merge :: merge fs hbio Config {..} targetPaths runs = do let f = fromMaybe const mergeMappend m <- fromMaybe (error "empty inputs, no merge created") <$> - Merge.new fs hbio Run.CacheRunData (RunAllocFixed 10) Index.Compact - mergeType f targetPaths runs + Merge.new fs hbio defaultRunParams mergeType f targetPaths runs Merge.stepsToCompletion m stepSize fsPath :: FS.FsPath diff --git a/lsm-tree.cabal b/lsm-tree.cabal index f0c0c7cd0..b9b41c841 100644 --- a/lsm-tree.cabal +++ b/lsm-tree.cabal @@ -131,6 +131,7 @@ library Database.LSMTree.Internal.CRC32C Database.LSMTree.Internal.Cursor Database.LSMTree.Internal.Entry + Database.LSMTree.Internal.IncomingRun Database.LSMTree.Internal.Index Database.LSMTree.Internal.Index.Compact Database.LSMTree.Internal.Index.CompactAcc diff --git a/src-extras/Database/LSMTree/Extras/MergingRunData.hs b/src-extras/Database/LSMTree/Extras/MergingRunData.hs index 854f273b1..426b5934a 100644 --- a/src-extras/Database/LSMTree/Extras/MergingRunData.hs +++ b/src-extras/Database/LSMTree/Extras/MergingRunData.hs @@ -28,9 +28,7 @@ import Database.LSMTree.Internal.Lookup (ResolveSerialisedValue) import Database.LSMTree.Internal.MergingRun (MergingRun) import qualified Database.LSMTree.Internal.MergingRun as MR import Database.LSMTree.Internal.Paths -import Database.LSMTree.Internal.Run (RunDataCaching (..)) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise import Database.LSMTree.Internal.UniqCounter @@ -88,8 +86,8 @@ unsafeCreateMergingRun hfs hbio resolve indexType path counter = \case $ \runs -> do n <- incrUniqCounter counter let fsPaths = RunFsPaths path (RunNumber (uniqueToInt n)) - MR.new hfs hbio resolve CacheRunData (RunAllocFixed 10) indexType - mergeType fsPaths (V.fromList runs) + MR.new hfs hbio resolve defaultRunParams mergeType + fsPaths (V.fromList runs) {------------------------------------------------------------------------------- MergingRunData diff --git a/src-extras/Database/LSMTree/Extras/MergingTreeData.hs b/src-extras/Database/LSMTree/Extras/MergingTreeData.hs index 7d4b7915b..013bccc8e 100644 --- a/src-extras/Database/LSMTree/Extras/MergingTreeData.hs +++ b/src-extras/Database/LSMTree/Extras/MergingTreeData.hs @@ -74,17 +74,17 @@ unsafeCreateMergingTree :: unsafeCreateMergingTree hfs hbio resolve indexType path counter = go where go = \case - CompletedTreeMergeData rd -> do + CompletedTreeMergeData rd -> withRun hfs hbio indexType path counter rd $ \run -> - MT.mkMergingTree . MT.CompletedTreeMerge =<< dupRef run - OngoingTreeMergeData mrd -> do + MT.newCompletedMerge run + OngoingTreeMergeData mrd -> withMergingRun hfs hbio resolve indexType path counter mrd $ \mr -> - MT.mkMergingTree . MT.OngoingTreeMerge =<< dupRef mr - PendingLevelMergeData prds mtd -> do + MT.newOngoingMerge mr + PendingLevelMergeData prds mtd -> withPreExistingRuns prds $ \prs -> withMaybeTree mtd $ \mt -> MT.newPendingLevelMerge prs mt - PendingUnionMergeData mtds -> do + PendingUnionMergeData mtds -> withTrees mtds $ \mts -> MT.newPendingUnionMerge mts diff --git a/src-extras/Database/LSMTree/Extras/NoThunks.hs b/src-extras/Database/LSMTree/Extras/NoThunks.hs index 510a758d3..e8cf06bac 100644 --- a/src-extras/Database/LSMTree/Extras/NoThunks.hs +++ b/src-extras/Database/LSMTree/Extras/NoThunks.hs @@ -214,9 +214,18 @@ deriving stock instance Generic (Run m h) deriving anyclass instance (Typeable m, Typeable (PrimState m), Typeable h) => NoThunks (Run m h) +deriving stock instance Generic RunParams +deriving anyclass instance NoThunks RunParams + +deriving stock instance Generic RunBloomFilterAlloc +deriving anyclass instance NoThunks RunBloomFilterAlloc + deriving stock instance Generic RunDataCaching deriving anyclass instance NoThunks RunDataCaching +deriving stock instance Generic IndexType +deriving anyclass instance NoThunks IndexType + {------------------------------------------------------------------------------- Paths -------------------------------------------------------------------------------} diff --git a/src-extras/Database/LSMTree/Extras/RunData.hs b/src-extras/Database/LSMTree/Extras/RunData.hs index cdac062b0..431bc2a30 100644 --- a/src-extras/Database/LSMTree/Extras/RunData.hs +++ b/src-extras/Database/LSMTree/Extras/RunData.hs @@ -2,8 +2,10 @@ -- from them. Tests and benchmarks should preferably use these utilities instead -- of (re-)defining their own. module Database.LSMTree.Extras.RunData ( + -- * RunParams + defaultRunParams -- * Create runs - withRun + , withRun , withRunAt , withRuns , unsafeCreateRun @@ -48,12 +50,13 @@ import qualified Data.Vector as V import Database.LSMTree.Extras (showPowersOf10) import Database.LSMTree.Extras.Generators () import Database.LSMTree.Internal.Entry -import Database.LSMTree.Internal.Index (IndexType) +import Database.LSMTree.Internal.Index (IndexType (..)) import Database.LSMTree.Internal.Lookup (ResolveSerialisedValue) import Database.LSMTree.Internal.MergeSchedule (addWriteBufferEntries) import Database.LSMTree.Internal.Paths import qualified Database.LSMTree.Internal.Paths as Paths -import Database.LSMTree.Internal.Run (Run, RunDataCaching (..)) +import Database.LSMTree.Internal.Run (Run, RunDataCaching (..), + RunParams (..)) import qualified Database.LSMTree.Internal.Run as Run import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..), entryWouldFitInPage) @@ -69,6 +72,15 @@ import qualified System.FS.BlockIO.API as FS import System.FS.BlockIO.API (HasBlockIO) import Test.QuickCheck + +defaultRunParams :: RunParams +defaultRunParams = + RunParams { + runParamCaching = CacheRunData, + runParamAlloc = RunAllocFixed 10, + runParamIndex = Compact + } + {------------------------------------------------------------------------------- Create runs -------------------------------------------------------------------------------} @@ -153,7 +165,8 @@ unsafeCreateRunAt fs hbio indexType fsPaths (RunData m) = do let blobpath = FS.addExtension (runBlobPath fsPaths) ".wb" bracket (WBB.new fs blobpath) releaseRef $ \wbblobs -> do wb <- WB.fromMap <$> traverse (traverse (WBB.addBlob fs wbblobs)) m - Run.fromWriteBuffer fs hbio CacheRunData (RunAllocFixed 10) indexType + Run.fromWriteBuffer fs hbio + defaultRunParams { runParamIndex = indexType } fsPaths wb wbblobs -- | Create a 'RunFsPaths' using an empty 'FsPath'. The empty path corresponds diff --git a/src/Database/LSMTree/Internal.hs b/src/Database/LSMTree/Internal.hs index 9f76f0d44..3e4ce6e12 100644 --- a/src/Database/LSMTree/Internal.hs +++ b/src/Database/LSMTree/Internal.hs @@ -64,7 +64,7 @@ module Database.LSMTree.Internal ( , openSnapshot , deleteSnapshot , listSnapshots - -- * Mutiple writable tables + -- * Multiple writable tables , duplicate -- * Table union , unions @@ -323,7 +323,7 @@ data SessionState m h = | SessionClosed data SessionEnv m h = SessionEnv { - -- | The path to the directory in which this sesion is live. This is a path + -- | The path to the directory in which this session is live. This is a path -- relative to root of the 'HasFS' instance. -- -- INVARIANT: the session root is never changed during the lifetime of a @@ -1234,18 +1234,30 @@ createSnapshot snap label tableType t = do let wb = tableWriteBuffer content let wbb = tableWriteBufferBlobs content snapWriteBufferNumber <- Paths.writeBufferNumber <$> - snapshotWriteBuffer reg hfs hbio activeUc snapUc activeDir snapDir wb wbb + snapshotWriteBuffer hfs hbio activeUc snapUc reg activeDir snapDir wb wbb -- Convert to snapshot format snapLevels <- toSnapLevels (tableLevels content) -- Hard link runs into the named snapshot directory - snapLevels' <- snapshotRuns reg snapUc snapDir snapLevels + snapLevels' <- traverse (snapshotRun hfs hbio snapUc reg snapDir) snapLevels + + -- If a merging tree exists, do the same hard-linking for the runs within + mTreeOpt <- case tableUnionLevel content of + NoUnion -> pure Nothing + Union mTreeRef -> do + mTree <- toSnapMergingTree mTreeRef + Just <$> traverse (snapshotRun hfs hbio snapUc reg snapDir) mTree - -- Release the table content releaseTableContent reg content - let snapMetaData = SnapshotMetaData label tableType (tableConfig t) snapWriteBufferNumber snapLevels' + let snapMetaData = SnapshotMetaData + label + tableType + (tableConfig t) + snapWriteBufferNumber + snapLevels' + mTreeOpt SnapshotMetaDataFile contentPath = Paths.snapshotMetaDataFile snapDir SnapshotMetaDataChecksumFile checksumPath = Paths.snapshotMetaDataChecksumFile snapDir writeFileSnapshotMetaData hfs contentPath checksumPath snapMetaData @@ -1290,7 +1302,7 @@ openSnapshot sesh label tableType override snap resolve = do Left e -> throwIO (ErrSnapshotDeserialiseFailure e snap) Right x -> pure x - let SnapshotMetaData label' tableType' conf snapWriteBuffer snapLevels = snapMetaData + let SnapshotMetaData label' tableType' conf snapWriteBuffer snapLevels mTreeOpt = snapMetaData unless (tableType == tableType') $ throwIO (ErrSnapshotWrongTableType snap tableType tableType') @@ -1308,11 +1320,18 @@ openSnapshot sesh label tableType override snap resolve = do (tableWriteBuffer, tableWriteBufferBlobs) <- openWriteBuffer reg resolve hfs hbio uc activeDir snapWriteBufferPaths -- Hard link runs into the active directory, - snapLevels' <- openRuns reg hfs hbio conf (sessionUniqCounter seshEnv) snapDir activeDir snapLevels + snapLevels' <- traverse (openRun hfs hbio uc reg snapDir activeDir) snapLevels + unionLevel <- case mTreeOpt of + Nothing -> pure NoUnion + Just mTree -> do + snapTree <- traverse (openRun hfs hbio uc reg snapDir activeDir) mTree + mt <- fromSnapMergingTree hfs hbio uc resolve activeDir reg snapTree + traverse_ (delayedCommit reg . releaseRef) snapTree + pure (Union mt) -- Convert from the snapshot format, restoring merge progress in the process - tableLevels <- fromSnapLevels reg hfs hbio conf (sessionUniqCounter seshEnv) resolve activeDir snapLevels' - releaseRuns reg snapLevels' + tableLevels <- fromSnapLevels hfs hbio uc conf resolve reg activeDir snapLevels' + traverse_ (delayedCommit reg . releaseRef) snapLevels' tableCache <- mkLevelsCache reg tableLevels newWith reg sesh seshEnv conf' am $! TableContent { @@ -1320,7 +1339,7 @@ openSnapshot sesh label tableType override snap resolve = do , tableWriteBufferBlobs , tableLevels , tableCache - , tableUnionLevel = NoUnion -- TODO: at some point also load union level from snapshot + , tableUnionLevel = unionLevel } {-# SPECIALISE deleteSnapshot :: @@ -1370,7 +1389,7 @@ listSnapshots sesh = do else pure $ Nothing {------------------------------------------------------------------------------- - Mutiple writable tables + Multiple writable tables -------------------------------------------------------------------------------} {-# SPECIALISE duplicate :: Table IO h -> IO (Table IO h) #-} @@ -1534,28 +1553,19 @@ writeBufferToNewRun SessionEnv { sessionHasBlockIO = hbio, sessionUniqCounter = uc } - conf@TableConfig { - confDiskCachePolicy, - confFencePointerIndex - } + conf TableContent{ tableWriteBuffer, tableWriteBufferBlobs } | WB.null tableWriteBuffer = pure Nothing | otherwise = Just <$> do - !n <- incrUniqCounter uc - let !ln = LevelNo 1 - !cache = diskCachePolicyForLevel confDiskCachePolicy ln - !alloc = bloomFilterAllocForLevel conf ln - !indexType = indexTypeForRun confFencePointerIndex - !path = Paths.runPath (Paths.activeDir root) - (uniqueToRunNumber n) - Run.fromWriteBuffer hfs hbio - cache - alloc - indexType - path + !uniq <- incrUniqCounter uc + let (!runParams, !runPaths) = mergingRunParamsForLevel + (Paths.activeDir root) conf uniq (LevelNo 1) + Run.fromWriteBuffer + hfs hbio + runParams runPaths tableWriteBuffer tableWriteBufferBlobs diff --git a/src/Database/LSMTree/Internal/Config.hs b/src/Database/LSMTree/Internal/Config.hs index 3c61f90c1..ccf30c826 100644 --- a/src/Database/LSMTree/Internal/Config.hs +++ b/src/Database/LSMTree/Internal/Config.hs @@ -46,7 +46,7 @@ import qualified Monkey newtype LevelNo = LevelNo Int deriving stock (Show, Eq) - deriving newtype Enum + deriving newtype (Enum, NFData) {------------------------------------------------------------------------------- Table configuration diff --git a/src/Database/LSMTree/Internal/IncomingRun.hs b/src/Database/LSMTree/Internal/IncomingRun.hs new file mode 100644 index 000000000..a21357592 --- /dev/null +++ b/src/Database/LSMTree/Internal/IncomingRun.hs @@ -0,0 +1,378 @@ +{-# LANGUAGE CPP #-} +{-# LANGUAGE MagicHash #-} +{-# LANGUAGE UnboxedTuples #-} + +#if !(MIN_VERSION_GLASGOW_HASKELL(9,0,0,0)) +-- Fix for ghc 8.10.x with deriving newtype Prim +{-# LANGUAGE DataKinds #-} +#endif + +module Database.LSMTree.Internal.IncomingRun ( + IncomingRun (..) + , MergePolicyForLevel (..) + , duplicateIncomingRun + , releaseIncomingRun + , newIncomingSingleRun + , newIncomingMergingRun + , snapshotIncomingRun + + -- * Credits and credit tracking + -- $credittracking + , NominalDebt (..) + , NominalCredits (..) + , nominalDebtAsCredits + , supplyCreditsIncomingRun + , immediatelyCompleteIncomingRun + ) where + +import Control.ActionRegistry +import Control.Concurrent.Class.MonadMVar.Strict +import Control.DeepSeq (NFData (..)) +import Control.Monad.Class.MonadST (MonadST) +import Control.Monad.Class.MonadSTM (MonadSTM (..)) +import Control.Monad.Class.MonadThrow (MonadMask, MonadThrow (..)) +import Control.Monad.Primitive +import Control.RefCount +import Data.Primitive (Prim) +import Data.Primitive.PrimVar +import Database.LSMTree.Internal.Assertions (assert) +import Database.LSMTree.Internal.Config +import Database.LSMTree.Internal.Entry (NumEntries (..)) +import Database.LSMTree.Internal.MergingRun (MergeCredits (..), + MergeDebt (..), MergingRun) +import qualified Database.LSMTree.Internal.MergingRun as MR +import Database.LSMTree.Internal.Run (Run) + +import GHC.Exts (Word (W#), quotRemWord2#, timesWord2#) + +{------------------------------------------------------------------------------- + Incoming runs +-------------------------------------------------------------------------------} + +-- | An incoming run is either a single run, or a merge. +data IncomingRun m h = + Single !(Ref (Run m h)) + | Merging !MergePolicyForLevel + !NominalDebt + !(PrimVar (PrimState m) NominalCredits) + !(Ref (MergingRun MR.LevelMergeType m h)) + +data MergePolicyForLevel = LevelTiering | LevelLevelling + deriving stock (Show, Eq) + +instance NFData MergePolicyForLevel where + rnf LevelTiering = () + rnf LevelLevelling = () + +{-# SPECIALISE duplicateIncomingRun :: ActionRegistry IO -> IncomingRun IO h -> IO (IncomingRun IO h) #-} +duplicateIncomingRun :: + (PrimMonad m, MonadMask m) + => ActionRegistry m + -> IncomingRun m h + -> m (IncomingRun m h) +duplicateIncomingRun reg (Single r) = + Single <$> withRollback reg (dupRef r) releaseRef + +duplicateIncomingRun reg (Merging mp md mcv mr) = + Merging mp md <$> (newPrimVar =<< readPrimVar mcv) + <*> withRollback reg (dupRef mr) releaseRef + +{-# SPECIALISE releaseIncomingRun :: IncomingRun IO h -> IO () #-} +releaseIncomingRun :: + (PrimMonad m, MonadMask m) + => IncomingRun m h -> m () +releaseIncomingRun (Single r) = releaseRef r +releaseIncomingRun (Merging _ _ _ mr) = releaseRef mr + +{-# INLINE newIncomingSingleRun #-} +newIncomingSingleRun :: + (PrimMonad m, MonadThrow m) + => Ref (Run m h) + -> m (IncomingRun m h) +newIncomingSingleRun r = Single <$> dupRef r + +{-# INLINE newIncomingMergingRun #-} +newIncomingMergingRun :: + (PrimMonad m, MonadThrow m) + => MergePolicyForLevel + -> NominalDebt + -> Ref (MergingRun MR.LevelMergeType m h) + -> m (IncomingRun m h) +newIncomingMergingRun mergePolicy nominalDebt mr = do + nominalCreditsVar <- newPrimVar (NominalCredits 0) + Merging mergePolicy nominalDebt nominalCreditsVar <$> dupRef mr + +{-# SPECIALISE snapshotIncomingRun :: + IncomingRun IO h + -> IO (Either (Ref (Run IO h)) + (MergePolicyForLevel, + NominalDebt, + NominalCredits, + Ref (MergingRun MR.LevelMergeType IO h))) #-} +snapshotIncomingRun :: + PrimMonad m + => IncomingRun m h + -> m (Either (Ref (Run m h)) + (MergePolicyForLevel, + NominalDebt, + NominalCredits, + Ref (MergingRun MR.LevelMergeType m h))) +snapshotIncomingRun (Single r) = pure (Left r) +snapshotIncomingRun (Merging mergePolicy nominalDebt nominalCreditsVar mr) = do + nominalCredits <- readPrimVar nominalCreditsVar + pure (Right (mergePolicy, nominalDebt, nominalCredits, mr)) + +{------------------------------------------------------------------------------- + Credits +-------------------------------------------------------------------------------} + +{- $credittracking + +With scheduled merges, each update (e.g., insert) on a table contributes to the +progression of ongoing merges in the levels structure. This ensures that merges +are finished in time before a new merge has to be started. The points in the +evolution of the levels structure where new merges are started are known: a +flush of a full write buffer will create a new run on the first level, and +after sufficient flushes (e.g., 4) we will start at least one new merge on the +second level. This may cascade down to lower levels depending on how full the +levels are. As such, we have a well-defined measure to determine when merges +should be finished: it only depends on the maximum size of the write buffer! + +The simplest solution to making sure merges are done in time is to step them to +completion immediately when started. This does not, however, spread out work +over time nicely. Instead, we schedule merge work based on how many updates are +made on the table, taking care to ensure that the merge is finished /just/ in +time before the next flush comes around, and not too early. + +The progression is tracked using nominal credits. Each individual update +contributes a single credit to each level, since each level contains precisely +one ongoing merge. Contributing a credit does not, however, translate directly +to performing one /unit/ of merging work: + +* The amount of work to do for one credit is adjusted depending on the actual + size of the merge we are doing. Last-level merges, for example, can have + larger inputs, and therefore we have to do a little more work for each + credit. Or input runs involved in a merge can be less than maximal size for + the level, and so there may be less merging work to do. As such, we /scale/ + 'NominalCredits' to 'MergeCredits', and then supply the 'MergeCredits' to + the 'MergingRun'. + +* Supplying 'MergeCredits' to a 'MergingRun' does not necessarily directly + translate into performing merging work. Merge credits are accumulated until + they go over a threshold, after which a batch of merge work will be performed. + Configuring this threshold should allow a good balance between spreading out + I\/O and achieving good (concurrent) performance. + +Merging runs can be shared across tables, which means that multiple threads +can contribute to the same merge concurrently. Incoming runs however are /not/ +shared between tables. As such the tracking of 'NominalCredits' does not need +to use any concurrency precautions. +-} + +-- | 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. +newtype NominalDebt = NominalDebt Int + deriving stock Eq + deriving newtype (NFData) + +-- | Merge credits that get supplied to a table's levels. +-- +-- This corresponds to the number of update operations inserted into the table. +newtype NominalCredits = NominalCredits Int + deriving stock Eq + deriving newtype (Prim, NFData) + +nominalDebtAsCredits :: NominalDebt -> NominalCredits +nominalDebtAsCredits (NominalDebt c) = NominalCredits c + +{-# SPECIALISE supplyCreditsIncomingRun :: + TableConfig + -> LevelNo + -> IncomingRun IO h + -> NominalCredits + -> IO () #-} +-- | Supply a given number of nominal credits to the merge in an incoming run. +-- This is a relative addition of credits, not a new absolute total value. +supplyCreditsIncomingRun :: + (MonadSTM m, MonadST m, MonadMVar m, MonadMask m) + => TableConfig + -> LevelNo + -> IncomingRun m h + -> NominalCredits + -> m () +supplyCreditsIncomingRun _ _ (Single _r) _ = return () +supplyCreditsIncomingRun conf ln (Merging _ nominalDebt nominalCreditsVar mr) + deposit = do + (_nominalCredits, + nominalCredits') <- depositNominalCredits nominalDebt nominalCreditsVar + deposit + let !mergeDebt = MR.totalMergeDebt mr + !mergeCredits' = scaleNominalToMergeCredit nominalDebt mergeDebt + nominalCredits' + !thresh = creditThresholdForLevel conf ln + (_suppliedCredits, + _suppliedCredits') <- MR.supplyCreditsAbsolute mr thresh mergeCredits' + return () + --TODO: currently each supplying credits action results in contributing + -- credits to the underlying merge, but this need not be the case. We + -- _could_ do threshold based batching at the level of the IncomingRun. + -- The IncomingRun does not need to worry about concurrency, so does not + -- pay the cost of atomic operations on the counters. Then when we + -- accumulate a batch we could supply that to the MergingRun (which must + -- use atomic operations for its counters). We could potentially simplify + -- MergingRun by dispensing with batching for the MergeCredits counters. + +-- TODO: the thresholds for doing merge work should be different for each level, +-- maybe co-prime? +creditThresholdForLevel :: TableConfig -> LevelNo -> MR.CreditThreshold +creditThresholdForLevel conf (LevelNo _i) = + let AllocNumEntries (NumEntries x) = confWriteBufferAlloc conf + in MR.CreditThreshold (MR.UnspentCredits (MergeCredits x)) + +-- | Deposit nominal credits in the local credits var, ensuring the total +-- credits does not exceed the total debt. +-- +-- Depositing /could/ leave the credit higher than the total debt. It is not +-- avoided by construction. The scenario is this: when a completed merge is +-- underfull, we combine it with the incoming run, so it means we have one run +-- fewer on the level then we'd normally have. This means that the level +-- becomes full at a later time, so more time passes before we call +-- 'MR.expectCompleted' on any levels further down the tree. This means we keep +-- supplying nominal credits to levels further down past the point their +-- nominal debt is paid off. So the solution here is just to drop any nominal +-- credits that are in excess of the nominal debt. +-- +-- This is /not/ itself thread safe. All 'TableContent' update operations are +-- expected to be serialised by the caller. See concurrency comments for +-- 'TableContent' for detail. +depositNominalCredits :: + PrimMonad m + => NominalDebt + -> PrimVar (PrimState m) NominalCredits + -> NominalCredits + -> m (NominalCredits, NominalCredits) +depositNominalCredits (NominalDebt nominalDebt) + nominalCreditsVar + (NominalCredits deposit) = do + NominalCredits before <- readPrimVar nominalCreditsVar + let !after = NominalCredits (min (before + deposit) nominalDebt) + writePrimVar nominalCreditsVar after + return (NominalCredits before, after) + +-- | Linearly scale a nominal credit (between 0 and the nominal debt) into an +-- equivalent merge credit (between 0 and the total merge debt). +-- +-- Crucially, @100% nominal credit ~~ 100% merge credit@, so when we pay off +-- the nominal debt, we also exactly pay off the merge debt. That is: +-- +-- > scaleNominalToMergeCredit nominalDebt mergeDebt nominalDebt == mergeDebt +-- +-- (modulo some newtype conversions) +-- +scaleNominalToMergeCredit :: + NominalDebt + -> MergeDebt + -> NominalCredits + -> MergeCredits +scaleNominalToMergeCredit (NominalDebt nominalDebt) + (MergeDebt (MergeCredits mergeDebt)) + (NominalCredits nominalCredits) = + -- The scaling involves an operation: (a * b) `div` c + -- but where potentially the variables a,b,c may be bigger than a 32bit + -- integer can hold. This would be the case for runs that have more than + -- 4 billion entries. + -- + -- (This is assuming 64bit Int, the problem would be even worse for 32bit + -- systems. The solution here would also work for 32bit systems, allowing + -- up to, 2^31, 2 billion entries per run.) + -- + -- To work correctly in this case we need higher range for the intermediate + -- result a*b which could be bigger than 64bits can hold. A correct + -- implementation can use Rational, but a fast implementation should use + -- only integer operations. This is relevant because this is on the fast + -- path for small insertions into the table that often do no merging work + -- and just update credit counters. + + -- The fast implementation uses integer operations that produce a 128bit + -- intermediate result for the a*b result, and use a 128bit numerator in + -- the division operation (but 64bit denominator). These are known as + -- "widening multiplication" and "narrowing division". GHC has direct + -- support for these operations as primops: timesWord2# and quotRemWord2#, + -- but they are not exposed through any high level API shipped with GHC. + + -- The specification using Rational is: + let mergeCredits_spec = floor $ toRational nominalCredits + * toRational mergeDebt + / toRational nominalDebt + -- Note that it doesn't matter if we use floor or ceiling here. + -- Rounding errors will not compound because we sum nominal debt and + -- convert absolute nominal to absolute merging credit. We don't + -- convert each deposit and sum all the rounding errors. + -- When nominalCredits == nominalDebt then the result is exact anyway + -- (being mergeDebt) so the rounding mode makes no difference when we + -- get to the end of the merge. Using floor makes things simpler for + -- the fast integer implementation below, so we take that as the spec. + + -- If the nominalCredits is between 0 and nominalDebt then it's + -- guaranteed that the mergeCredit is between 0 and mergeDebt. + -- The mergeDebt fits in an Int, therefore the result does too. + -- Therefore the undefined behaviour case of timesDivABC_fast is + -- avoided and the w2i cannot overflow. + mergeCredits_fast = w2i $ timesDivABC_fast (i2w nominalCredits) + (i2w mergeDebt) + (i2w nominalDebt) + in assert (0 < nominalDebt) $ + assert (0 <= nominalCredits && nominalCredits <= nominalDebt) $ + assert (mergeCredits_spec == mergeCredits_fast) $ + MergeCredits mergeCredits_fast + where + {-# INLINE i2w #-} + {-# INLINE w2i #-} + i2w :: Int -> Word + w2i :: Word -> Int + i2w = fromIntegral + w2i = fromIntegral + +-- | Compute @(a * b) `div` c@ for unsigned integers for the full range of +-- 64bit unsigned integers, provided that @a <= c@ and thus the result will +-- fit in 64bits. +-- +-- The @a * b@ intermediate result is computed using 128bit precision. +-- +-- Note: the behaviour is undefined if the result will not fit in 64bits. +-- It will probably result in immediate termination with SIGFPE. +-- +timesDivABC_fast :: Word -> Word -> Word -> Word +timesDivABC_fast (W# a) (W# b) (W# c) = + case timesWord2# a b of + (# ph, pl #) -> + case quotRemWord2# ph pl c of + (# q, _r #) -> W# q + +{-# SPECIALISE immediatelyCompleteIncomingRun :: + TableConfig + -> LevelNo + -> IncomingRun IO h + -> IO (Ref (Run IO h)) #-} +-- | Supply enough credits to complete the merge now. +immediatelyCompleteIncomingRun :: + (MonadSTM m, MonadST m, MonadMVar m, MonadMask m) + => TableConfig + -> LevelNo + -> IncomingRun m h + -> m (Ref (Run m h)) +immediatelyCompleteIncomingRun conf ln ir = + case ir of + Single r -> dupRef r + Merging _ (NominalDebt nominalDebt) nominalCreditsVar mr -> do + + NominalCredits nominalCredits <- readPrimVar nominalCreditsVar + let !deposit = NominalCredits (nominalDebt - nominalCredits) + supplyCreditsIncomingRun conf ln ir deposit + + -- This ensures the merge is really completed. However, we don't + -- release the merge yet, but we do return a new reference to the run. + MR.expectCompleted mr diff --git a/src/Database/LSMTree/Internal/Index.hs b/src/Database/LSMTree/Internal/Index.hs index 7a9552797..9fc68a5e7 100644 --- a/src/Database/LSMTree/Internal/Index.hs +++ b/src/Database/LSMTree/Internal/Index.hs @@ -25,6 +25,7 @@ module Database.LSMTree.Internal.Index ( -- * Index types IndexType (Compact, Ordinary), + indexToIndexType, -- * Indexes Index (CompactIndex, OrdinaryIndex), @@ -70,6 +71,11 @@ import Database.LSMTree.Internal.Serialise (SerialisedKey) -- | The type of supported index types. data IndexType = Compact | Ordinary + deriving stock (Eq, Show) + +instance NFData IndexType where + rnf Compact = () + rnf Ordinary = () -- * Indexes @@ -80,10 +86,13 @@ data Index deriving stock (Eq, Show) instance NFData Index where - rnf (CompactIndex index) = rnf index rnf (OrdinaryIndex index) = rnf index +indexToIndexType :: Index -> IndexType +indexToIndexType CompactIndex{} = Compact +indexToIndexType OrdinaryIndex{} = Ordinary + {-| Searches for a page span that contains a key–value pair with the given key. If there is indeed such a pair, the result is the corresponding page span; diff --git a/src/Database/LSMTree/Internal/Merge.hs b/src/Database/LSMTree/Internal/Merge.hs index 782f4fbe7..21352b9b0 100644 --- a/src/Database/LSMTree/Internal/Merge.hs +++ b/src/Database/LSMTree/Internal/Merge.hs @@ -9,6 +9,7 @@ module Database.LSMTree.Internal.Merge ( , TreeMergeType (..) , Mappend , MergeState (..) + , RunParams (..) , new , abort , complete @@ -16,6 +17,7 @@ module Database.LSMTree.Internal.Merge ( , stepsToCompletionCounted , StepResult (..) , steps + , mergeRunParams ) where import Control.DeepSeq (NFData (..)) @@ -31,11 +33,9 @@ import Data.Traversable (for) import qualified Data.Vector as V import Database.LSMTree.Internal.BlobRef (RawBlobRef) import Database.LSMTree.Internal.Entry -import Database.LSMTree.Internal.Index (IndexType) -import Database.LSMTree.Internal.Run (Run, RunDataCaching) +import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) -import Database.LSMTree.Internal.RunBuilder (RunBuilder) +import Database.LSMTree.Internal.RunBuilder (RunBuilder, RunParams) import qualified Database.LSMTree.Internal.RunBuilder as Builder import qualified Database.LSMTree.Internal.RunReader as Reader import Database.LSMTree.Internal.RunReaders (Readers) @@ -60,8 +60,6 @@ data Merge t m h = Merge { , mergeMappend :: !Mappend , mergeReaders :: {-# UNPACK #-} !(Readers m h) , mergeBuilder :: !(RunBuilder m h) - -- | The caching policy to use for the output Run. - , mergeCaching :: !RunDataCaching -- | The result of the latest call to 'steps'. This is used to determine -- whether a merge can be 'complete'd. , mergeState :: !(MutVar (PrimState m) MergeState) @@ -69,6 +67,9 @@ data Merge t m h = Merge { , mergeHasBlockIO :: !(HasBlockIO m h) } +mergeRunParams :: Merge t m h -> RunParams +mergeRunParams = Builder.runBuilderParams . mergeBuilder + -- | The current state of the merge. data MergeState = -- | There is still merging work to be done @@ -152,9 +153,7 @@ type Mappend = SerialisedValue -> SerialisedValue -> SerialisedValue IsMergeType t => HasFS IO h -> HasBlockIO IO h - -> RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> t -> Mappend -> Run.RunFsPaths @@ -166,21 +165,19 @@ new :: (IsMergeType t, MonadMask m, MonadSTM m, MonadST m) => HasFS m h -> HasBlockIO m h - -> RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> t -> Mappend -> Run.RunFsPaths -> V.Vector (Ref (Run m h)) -> m (Maybe (Merge t m h)) -new hfs hbio mergeCaching alloc indexType mergeType mergeMappend targetPaths runs = do +new hfs hbio runParams mergeType mergeMappend targetPaths runs = do -- no offset, no write buffer mreaders <- Readers.new Readers.NoOffsetKey Nothing runs for mreaders $ \mergeReaders -> do -- calculate upper bounds based on input runs let numEntries = V.foldMap' Run.size runs - mergeBuilder <- Builder.new hfs hbio targetPaths numEntries alloc indexType + mergeBuilder <- Builder.new hfs hbio runParams targetPaths numEntries mergeState <- newMutVar $! Merging return Merge { mergeIsLastLevel = isLastLevel mergeType @@ -239,7 +236,7 @@ complete Merge{..} = do Merging -> error "complete: Merge is not done" MergingDone -> do -- the readers are already drained, therefore closed - r <- Run.fromMutable mergeCaching mergeBuilder + r <- Run.fromMutable mergeBuilder writeMutVar mergeState $! Completed pure r Completed -> error "complete: Merge is already completed" diff --git a/src/Database/LSMTree/Internal/MergeSchedule.hs b/src/Database/LSMTree/Internal/MergeSchedule.hs index ebe143c7c..b69f03cd2 100644 --- a/src/Database/LSMTree/Internal/MergeSchedule.hs +++ b/src/Database/LSMTree/Internal/MergeSchedule.hs @@ -26,11 +26,11 @@ module Database.LSMTree.Internal.MergeSchedule ( , IncomingRun (..) , MergePolicyForLevel (..) , newIncomingSingleRun - , newIncomingCompletedMergingRun , newIncomingMergingRun , releaseIncomingRun , supplyCreditsIncomingRun , snapshotIncomingRun + , mergingRunParamsForLevel -- * Union level , UnionLevel (..) -- * Flushes and scheduled merges @@ -45,13 +45,14 @@ module Database.LSMTree.Internal.MergeSchedule ( , creditThresholdForLevel , NominalDebt (..) , NominalCredits (..) + , nominalDebtAsCredits + , nominalDebtForLevel -- * Exported for testing , addWriteBufferEntries ) where import Control.ActionRegistry import Control.Concurrent.Class.MonadMVar.Strict -import Control.DeepSeq (NFData (..)) import Control.Monad.Class.MonadST (MonadST) import Control.Monad.Class.MonadSTM (MonadSTM (..)) import Control.Monad.Class.MonadThrow (MonadMask, MonadThrow (..)) @@ -60,25 +61,23 @@ import Control.RefCount import Control.Tracer import Data.BloomFilter (Bloom) import Data.Foldable (fold) -import Data.Primitive (Prim) -import Data.Primitive.PrimVar import qualified Data.Vector as V import Database.LSMTree.Internal.Assertions (assert) import Database.LSMTree.Internal.Config import Database.LSMTree.Internal.Entry (Entry, NumEntries (..), unNumEntries) +import Database.LSMTree.Internal.IncomingRun import Database.LSMTree.Internal.Index (Index) import Database.LSMTree.Internal.Lookup (ResolveSerialisedValue) import Database.LSMTree.Internal.MergingRun (MergeCredits (..), - MergeDebt (..), MergingRun, NumRuns (..)) + MergeDebt (..), MergingRun, RunParams (..)) import qualified Database.LSMTree.Internal.MergingRun as MR import Database.LSMTree.Internal.MergingTree (MergingTree) import Database.LSMTree.Internal.Paths (ActiveDir, RunFsPaths (..), - SessionRoot (..)) + SessionRoot) import qualified Database.LSMTree.Internal.Paths as Paths -import Database.LSMTree.Internal.Run (Run, RunDataCaching (..)) +import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise (SerialisedBlob, SerialisedKey, SerialisedValue) @@ -92,8 +91,6 @@ import qualified System.FS.API as FS import System.FS.API (HasFS) import System.FS.BlockIO.API (HasBlockIO) -import GHC.Exts (Word (W#), quotRemWord2#, timesWord2#) - {------------------------------------------------------------------------------- Traces -------------------------------------------------------------------------------} @@ -105,8 +102,7 @@ data MergeTrace = TraceFlushWriteBuffer NumEntries -- ^ Size of the write buffer RunNumber - RunDataCaching - RunBloomFilterAlloc + RunParams | TraceAddLevel | TraceAddRun RunNumber -- ^ newly added run @@ -114,16 +110,12 @@ data MergeTrace = | TraceNewMerge (V.Vector NumEntries) -- ^ Sizes of input runs RunNumber - RunDataCaching - RunBloomFilterAlloc + RunParams MergePolicyForLevel MR.LevelMergeType | TraceNewMergeSingleRun NumEntries -- ^ Size of run RunNumber - | TraceNewMergeCompletedRun - NumEntries -- ^ Size of run - RunNumber | TraceCompletedMerge -- TODO: currently not traced for Incremental merges NumEntries -- ^ Size of output run RunNumber @@ -357,367 +349,6 @@ releaseLevels reg levels = iforLevelM_ :: Monad m => Levels m h -> (LevelNo -> Level m h -> m ()) -> m () iforLevelM_ lvls k = V.iforM_ lvls $ \i lvl -> k (LevelNo (i + 1)) lvl -{------------------------------------------------------------------------------- - Incoming runs --------------------------------------------------------------------------------} - --- | An incoming run is either a single run, or a merge. -data IncomingRun m h = - Single !(Ref (Run m h)) - | Merging !MergePolicyForLevel - !NominalDebt - !(PrimVar (PrimState m) NominalCredits) - !(Ref (MergingRun MR.LevelMergeType m h)) - -data MergePolicyForLevel = LevelTiering | LevelLevelling - deriving stock (Show, Eq) - -instance NFData MergePolicyForLevel where - rnf LevelTiering = () - rnf LevelLevelling = () - --- | Total merge debt to complete the merge in an incoming run. --- --- This corresponds to the number (worst case, minimum number) of update --- operatons inserted into the table, before we will expect the merge to --- complete. -newtype NominalDebt = NominalDebt Int - deriving stock Eq - --- | Merge credits that get supplied to a table's levels. --- --- This corresponds to the number of update operatons inserted into the table. -newtype NominalCredits = NominalCredits Int - deriving stock Eq - deriving newtype (Prim, NFData) - -nominalDebtAsCredits :: NominalDebt -> NominalCredits -nominalDebtAsCredits (NominalDebt c) = NominalCredits c - -{-# SPECIALISE duplicateIncomingRun :: ActionRegistry IO -> IncomingRun IO h -> IO (IncomingRun IO h) #-} -duplicateIncomingRun :: - (PrimMonad m, MonadMask m) - => ActionRegistry m - -> IncomingRun m h - -> m (IncomingRun m h) -duplicateIncomingRun reg (Single r) = - Single <$> withRollback reg (dupRef r) releaseRef - -duplicateIncomingRun reg (Merging mp md mcv mr) = - Merging mp md <$> (newPrimVar =<< readPrimVar mcv) - <*> withRollback reg (dupRef mr) releaseRef - -{-# SPECIALISE releaseIncomingRun :: IncomingRun IO h -> IO () #-} -releaseIncomingRun :: - (PrimMonad m, MonadMask m) - => IncomingRun m h -> m () -releaseIncomingRun (Single r) = releaseRef r -releaseIncomingRun (Merging _ _ _ mr) = releaseRef mr - -{-# SPECIALISE newIncomingSingleRun :: - Tracer IO (AtLevel MergeTrace) - -> LevelNo - -> Ref (Run IO h) - -> IO (IncomingRun IO h) #-} -newIncomingSingleRun :: - (PrimMonad m, MonadThrow m) - => Tracer m (AtLevel MergeTrace) - -> LevelNo - -> Ref (Run m h) - -> m (IncomingRun m h) -newIncomingSingleRun tr ln r = do - r' <- dupRef r - traceWith tr $ AtLevel ln $ - TraceNewMergeSingleRun (Run.size r') (Run.runFsPathsNumber r') - return (Single r') - -{-# SPECIALISE newIncomingCompletedMergingRun :: - Tracer IO (AtLevel MergeTrace) - -> TableConfig - -> LevelNo - -> MergePolicyForLevel - -> NumRuns - -> MergeDebt - -> Ref (Run IO h) - -> IO (IncomingRun IO h) #-} -newIncomingCompletedMergingRun :: - (MonadMask m, MonadMVar m, MonadSTM m, MonadST m) - => Tracer m (AtLevel MergeTrace) - -> TableConfig - -> LevelNo - -> MergePolicyForLevel - -> NumRuns - -> MergeDebt - -> Ref (Run m h) - -> m (IncomingRun m h) -newIncomingCompletedMergingRun tr conf ln mergePolicy nr mergeDebt r = do - traceWith tr $ AtLevel ln $ - TraceNewMergeCompletedRun (Run.size r) (Run.runFsPathsNumber r) - mr <- MR.newCompleted nr mergeDebt r - let nominalDebt = nominalDebtForLevel conf ln - nominalCredits = nominalDebtAsCredits nominalDebt - nominalCreditsVar <- newPrimVar nominalCredits - return (Merging mergePolicy nominalDebt nominalCreditsVar mr) - -{-# SPECIALISE newIncomingMergingRun :: - Tracer IO (AtLevel MergeTrace) - -> HasFS IO h - -> HasBlockIO IO h - -> ActiveDir - -> UniqCounter IO - -> TableConfig - -> ResolveSerialisedValue - -> MergePolicyForLevel - -> MR.LevelMergeType - -> LevelNo - -> V.Vector (Ref (Run IO h)) - -> IO (IncomingRun IO h) #-} -newIncomingMergingRun :: - (MonadMask m, MonadMVar m, MonadSTM m, MonadST m) - => Tracer m (AtLevel MergeTrace) - -> HasFS m h - -> HasBlockIO m h - -> ActiveDir - -> UniqCounter m - -> TableConfig - -> ResolveSerialisedValue - -> MergePolicyForLevel - -> MR.LevelMergeType - -> LevelNo - -> V.Vector (Ref (Run m h)) - -> m (IncomingRun m h) -newIncomingMergingRun tr hfs hbio activeDir uc - conf@TableConfig { - confDiskCachePolicy, - confFencePointerIndex - } - resolve mergePolicy mergeType ln rs = do - !rn <- uniqueToRunNumber <$> incrUniqCounter uc - let !caching = diskCachePolicyForLevel confDiskCachePolicy ln - !alloc = bloomFilterAllocForLevel conf ln - !indexType = indexTypeForRun confFencePointerIndex - !runPaths = Paths.runPath activeDir rn - traceWith tr $ AtLevel ln $ - TraceNewMerge (V.map Run.size rs) (runNumber runPaths) - caching alloc mergePolicy mergeType - mr <- MR.new hfs hbio resolve caching - alloc indexType mergeType - runPaths rs - let nominalDebt = nominalDebtForLevel conf ln - nominalCredits = NominalCredits 0 - nominalCreditsVar <- newPrimVar nominalCredits - assert (MR.totalMergeDebt mr <= maxMergeDebt conf mergePolicy ln) $ - return (Merging mergePolicy nominalDebt nominalCreditsVar mr) - -{-# SPECIALISE supplyCreditsIncomingRun :: - TableConfig - -> LevelNo - -> IncomingRun IO h - -> NominalCredits - -> IO () #-} --- | Supply a given number of nominal credits to the merge in an incoming run. --- This is a relative addition of credits, not a new absolute total value. -supplyCreditsIncomingRun :: - (MonadSTM m, MonadST m, MonadMVar m, MonadMask m) - => TableConfig - -> LevelNo - -> IncomingRun m h - -> NominalCredits - -> m () -supplyCreditsIncomingRun _ _ (Single _r) _ = return () -supplyCreditsIncomingRun conf ln (Merging _ nominalDebt nominalCreditsVar mr) - deposit = do - (_nominalCredits, - nominalCredits') <- depositNominalCredits nominalDebt nominalCreditsVar - deposit - let !mergeDebt = MR.totalMergeDebt mr - !mergeCredits' = scaleNominalToMergeCredit nominalDebt mergeDebt - nominalCredits' - !thresh = creditThresholdForLevel conf ln - (_suppliedCredits, - _suppliedCredits') <- MR.supplyCreditsAbsolute mr thresh mergeCredits' - --TODO: consider tracing supply of credits - return () - --- | Deposit nominal credits in the local credits var, ensuring the total --- credits does not exceed the total debt. --- --- Depositing /could/ leave the credit higher than the total debt. It is not --- avoided by construction. The scenario is this: when a completed merge is --- underfull, we combine it with the incoming run, so it means we have one run --- fewer on the level then we'd normally have. This means that the level --- becomes full at a later time, so more time passes before we call --- 'MR.expectCompleted' on any levels further down the tree. This means we keep --- supplying nominal credits to levels further down past the point their --- nominal debt is paid off. So the solution here is just to drop any nominal --- credits that are in excess of the nominal debt. --- --- This is /not/ itself thread safe. All 'TableContent' update operations are --- expected to be serialised by the caller. See concurrency comments for --- 'TableContent' for detail. -depositNominalCredits :: - PrimMonad m - => NominalDebt - -> PrimVar (PrimState m) NominalCredits - -> NominalCredits - -> m (NominalCredits, NominalCredits) -depositNominalCredits (NominalDebt nominalDebt) - nominalCreditsVar - (NominalCredits deposit) = do - NominalCredits before <- readPrimVar nominalCreditsVar - let !after = NominalCredits (min (before + deposit) nominalDebt) - writePrimVar nominalCreditsVar after - return (NominalCredits before, after) - --- | Linearly scale a nominal credit (between 0 and the nominal debt) into an --- equivalent merge credit (between 0 and the total merge debt). --- --- Crucially, @100% nominal credit ~~ 100% merge credit@, so when we pay off --- the nominal debt, we also exactly pay off the merge debt. That is: --- --- > scaleNominalToMergeCredit nominalDebt mergeDebt nominalDebt == mergeDebt --- --- (modulo some newtype conversions) --- -scaleNominalToMergeCredit :: - NominalDebt - -> MergeDebt - -> NominalCredits - -> MergeCredits -scaleNominalToMergeCredit (NominalDebt nominalDebt) - (MergeDebt (MergeCredits mergeDebt)) - (NominalCredits nominalCredits) = - -- The scaling involves an operation: (a * b) `div` c - -- but where potentially the variables a,b,c may be bigger than a 32bit - -- integer can hold. This would be the case for runs that have more than - -- 4 billion entries. - -- - -- (This is assuming 64bit Int, the problem would be even worse for 32bit - -- systems. The solution here would also work for 32bit systems, allowing - -- up to, 2^31, 2 billion entries per run.) - -- - -- To work correctly in this case we need higher range for the intermediate - -- result a*b which could be bigger than 64bits can hold. A correct - -- implementation can use Rational, but a fast implementation should use - -- only integer operations. This is relevant because this is on the fast - -- path for small insertions into the table that often do no merging work - -- and just update credit counters. - - -- The fast implementation uses integer operations that produce a 128bit - -- intermediate result for the a*b result, and use a 128bit numerator in - -- the division operation (but 64bit denominator). These are known as - -- "widening multiplication" and "narrowing division". GHC has direct - -- support for these operations as primops: timesWord2# and quotRemWord2#, - -- but they are not exposed through any high level API shipped with GHC. - - -- The specification using Rational is: - let mergeCredits_spec = floor $ toRational nominalCredits - * toRational mergeDebt - / toRational nominalDebt - -- Note that it doesn't matter if we use floor or ceiling here. - -- Rounding errors will not compound because we sum nominal debt and - -- convert absolute nominal to absolute merging credit. We don't - -- convert each deposit and sum all the rounding errors. - -- When nominalCredits == nominalDebt then the result is exact anyway - -- (being mergeDebt) so the rounding mode makes no difference when we - -- get to the end of the merge. Using floor makes things simpler for - -- the fast integer implementation below, so we take that as the spec. - - -- If the nominalCredits is between 0 and nominalDebt then it's - -- guaranteed that the mergeCredit is between 0 and mergeDebt. - -- The mergeDebt fits in an Int, therefore the result does too. - -- Therefore the undefined behaviour case of timesDivABC_fast is - -- avoided and the w2i cannot overflow. - mergeCredits_fast = w2i $ timesDivABC_fast (i2w nominalCredits) - (i2w mergeDebt) - (i2w nominalDebt) - in assert (0 < nominalDebt) $ - assert (0 <= nominalCredits && nominalCredits <= nominalDebt) $ - assert (mergeCredits_spec == mergeCredits_fast) $ - MergeCredits mergeCredits_fast - where - {-# INLINE i2w #-} - {-# INLINE w2i #-} - i2w :: Int -> Word - w2i :: Word -> Int - i2w = fromIntegral - w2i = fromIntegral - --- | Compute @(a * b) `div` c@ for unsigned integers for the full range of --- 64bit unsigned integers, provided that @a <= c@ and thus the result will --- fit in 64bits. --- --- The @a * b@ intermediate result is computed using 128bit precision. --- --- Note: the behaviour is undefined if the result will not fit in 64bits. --- It will probably result in immediate termination with SIGFPE. --- -timesDivABC_fast :: Word -> Word -> Word -> Word -timesDivABC_fast (W# a) (W# b) (W# c) = - case timesWord2# a b of - (# ph, pl #) -> - case quotRemWord2# ph pl c of - (# q, _r #) -> W# q - -{-# SPECIALISE immediatelyCompleteIncomingRun :: - Tracer IO (AtLevel MergeTrace) - -> TableConfig - -> LevelNo - -> IncomingRun IO h - -> IO () #-} --- | Supply enough credits to complete the merge now. -immediatelyCompleteIncomingRun :: - (MonadSTM m, MonadST m, MonadMVar m, MonadMask m) - => Tracer m (AtLevel MergeTrace) - -> TableConfig - -> LevelNo - -> IncomingRun m h - -> m () -immediatelyCompleteIncomingRun tr conf ln ir = - case ir of - Single{} -> return () - Merging _ (NominalDebt nominalDebt) nominalCreditsVar mr -> do - - NominalCredits nominalCredits <- readPrimVar nominalCreditsVar - let !deposit = NominalCredits (nominalDebt - nominalCredits) - supplyCreditsIncomingRun conf ln ir deposit - - -- This ensures the merge is really completed. However, we don't - -- release the merge yet and only briefly inspect the resulting run. - bracket (MR.expectCompleted mr) releaseRef $ \r -> - traceWith tr $ AtLevel ln $ - TraceCompletedMerge (Run.size r) (Run.runFsPathsNumber r) - -{-# SPECIALISE snapshotIncomingRun :: - IncomingRun IO h - -> IO (Either (Ref (Run IO h)) - (MergePolicyForLevel, - NumRuns, - NominalDebt, - NominalCredits, - MergeDebt, - MergeCredits, - MR.MergingRunState MR.LevelMergeType IO h)) #-} -snapshotIncomingRun :: - (PrimMonad m, MonadMVar m) - => IncomingRun m h - -> m (Either (Ref (Run m h)) - (MergePolicyForLevel, - NumRuns, - NominalDebt, - NominalCredits, - MergeDebt, - MergeCredits, - MR.MergingRunState MR.LevelMergeType m h)) -snapshotIncomingRun (Single r) = pure (Left r) -snapshotIncomingRun (Merging mergePolicy nominalDebt nominalCreditsVar mr) = do - (numRuns, mergeDebt, mergeCredit, state) <- MR.snapshot mr - nominalCredits <- readPrimVar nominalCreditsVar - pure (Right (mergePolicy, numRuns, - nominalDebt, nominalCredits, - mergeDebt, mergeCredit, - state)) - {------------------------------------------------------------------------------- Union level -------------------------------------------------------------------------------} @@ -912,30 +543,27 @@ flushWriteBuffer :: -> ActionRegistry m -> TableContent m h -> m (TableContent m h) -flushWriteBuffer tr conf@TableConfig{confFencePointerIndex, confDiskCachePolicy} - resolve hfs hbio root uc reg tc +flushWriteBuffer tr conf resolve hfs hbio root uc reg tc | WB.null (tableWriteBuffer tc) = pure tc | otherwise = do - !n <- incrUniqCounter uc + !uniq <- incrUniqCounter uc let !size = WB.numEntries (tableWriteBuffer tc) !ln = LevelNo 1 - !cache = diskCachePolicyForLevel confDiskCachePolicy ln - !alloc = bloomFilterAllocForLevel conf ln - !indexType = indexTypeForRun confFencePointerIndex - !path = Paths.runPath (Paths.activeDir root) (uniqueToRunNumber n) + (!runParams, + runPaths) = mergingRunParamsForLevel + (Paths.activeDir root) conf uniq ln + traceWith tr $ AtLevel ln $ - TraceFlushWriteBuffer size (runNumber path) cache alloc + TraceFlushWriteBuffer size (runNumber runPaths) runParams r <- withRollback reg - (Run.fromWriteBuffer hfs hbio - cache - alloc - indexType - path + (Run.fromWriteBuffer + hfs hbio + runParams runPaths (tableWriteBuffer tc) (tableWriteBufferBlobs tc)) releaseRef delayedCommit reg (releaseRef (tableWriteBufferBlobs tc)) - wbblobs' <- withRollback reg (WBB.new hfs (Paths.tableBlobPath root n)) + wbblobs' <- withRollback reg (WBB.new hfs (Paths.tableBlobPath root uniq)) releaseRef levels' <- addRunToLevels tr conf resolve hfs hbio root uc r reg (tableLevels tc) @@ -1063,13 +691,9 @@ addRunToLevels tr conf@TableConfig{..} resolve hfs hbio root uc r0 reg levels ul -> m (IncomingRun m h) newMerge mergePolicy mergeType ln rs = do ir <- withRollback reg - (case V.uncons rs of - Just (r, rest) | V.null rest - -> newIncomingSingleRun tr ln r - _ -> newIncomingMergingRun tr hfs hbio - (Paths.activeDir root) uc - conf resolve mergePolicy mergeType - ln rs) + (newIncomingRunAtLevel tr hfs hbio + root uc conf resolve + mergePolicy mergeType ln rs) releaseIncomingRun -- The runs will end up inside the incoming/merging run, with fresh -- references (since newIncoming* will make duplicates). @@ -1077,8 +701,87 @@ addRunToLevels tr conf@TableConfig{..} resolve hfs hbio root uc r0 reg levels ul V.forM_ rs $ \r -> delayedCommit reg (releaseRef r) case confMergeSchedule of Incremental -> pure () - OneShot -> immediatelyCompleteIncomingRun tr conf ln ir + OneShot -> + bracket + (immediatelyCompleteIncomingRun conf ln ir) + releaseRef $ \r -> + + traceWith tr $ AtLevel ln $ + TraceCompletedMerge (Run.size r) (Run.runFsPathsNumber r) + return ir +{-# SPECIALISE newIncomingRunAtLevel :: + Tracer IO (AtLevel MergeTrace) + -> HasFS IO h + -> HasBlockIO IO h + -> SessionRoot + -> UniqCounter IO + -> TableConfig + -> ResolveSerialisedValue + -> MergePolicyForLevel + -> MR.LevelMergeType + -> LevelNo + -> V.Vector (Ref (Run IO h)) + -> IO (IncomingRun IO h) #-} +newIncomingRunAtLevel :: + (MonadMVar m, MonadMask m, MonadSTM m, MonadST m) + => Tracer m (AtLevel MergeTrace) + -> HasFS m h + -> HasBlockIO m h + -> SessionRoot + -> UniqCounter m + -> TableConfig + -> ResolveSerialisedValue + -> MergePolicyForLevel + -> MR.LevelMergeType + -> LevelNo + -> V.Vector (Ref (Run m h)) + -> m (IncomingRun m h) +newIncomingRunAtLevel tr hfs hbio + root uc conf resolve + mergePolicy mergeType ln rs + | Just (r, rest) <- V.uncons rs, V.null rest = do + + traceWith tr $ AtLevel ln $ + TraceNewMergeSingleRun (Run.size r) (Run.runFsPathsNumber r) + + newIncomingSingleRun r + + | otherwise = do + + uniq <- incrUniqCounter uc + let (!runParams, !runPaths) = + mergingRunParamsForLevel (Paths.activeDir root) conf uniq ln + + traceWith tr $ AtLevel ln $ + TraceNewMerge (V.map Run.size rs) (runNumber runPaths) + runParams mergePolicy mergeType + + bracket + (MR.new hfs hbio resolve runParams mergeType runPaths rs) + releaseRef $ \mr -> + assert (MR.totalMergeDebt mr <= maxMergeDebt conf mergePolicy ln) $ + let nominalDebt = nominalDebtForLevel conf ln in + newIncomingMergingRun mergePolicy nominalDebt mr + +mergingRunParamsForLevel :: + ActiveDir + -> TableConfig + -> Unique + -> LevelNo + -> (RunParams, RunFsPaths) +mergingRunParamsForLevel dir + conf@TableConfig { + confDiskCachePolicy, + confFencePointerIndex + } + unique ln = + (RunParams {..}, runPaths) + where + !runParamCaching = diskCachePolicyForLevel confDiskCachePolicy ln + !runParamAlloc = bloomFilterAllocForLevel conf ln + !runParamIndex = indexTypeForRun confFencePointerIndex + !runPaths = Paths.runPath dir (uniqueToRunNumber unique) -- | We use levelling on the last level, unless that is also the first level. mergePolicyForLevel :: @@ -1219,6 +922,9 @@ supplyCredits :: supplyCredits conf deposit levels = iforLevelM_ levels $ \ln (Level ir _rs) -> supplyCreditsIncomingRun conf ln ir deposit + --TODO: consider tracing supply of credits, + -- supplyCreditsIncomingRun could easily return the supplied credits + -- before & after, which may be useful for tracing. maxMergeDebt :: TableConfig -> MergePolicyForLevel -> LevelNo -> MergeDebt maxMergeDebt TableConfig { diff --git a/src/Database/LSMTree/Internal/MergingRun.hs b/src/Database/LSMTree/Internal/MergingRun.hs index 46ecd1b25..e1e674ff7 100644 --- a/src/Database/LSMTree/Internal/MergingRun.hs +++ b/src/Database/LSMTree/Internal/MergingRun.hs @@ -6,6 +6,7 @@ module Database.LSMTree.Internal.MergingRun ( -- * Merging run MergingRun , NumRuns (..) + , RunParams (..) , new , newCompleted , duplicateRuns @@ -61,16 +62,14 @@ import Data.Primitive.PrimVar import qualified Data.Vector as V import Database.LSMTree.Internal.Assertions (assert) import Database.LSMTree.Internal.Entry (NumEntries (..)) -import Database.LSMTree.Internal.Index (IndexType) import Database.LSMTree.Internal.Lookup (ResolveSerialisedValue) import Database.LSMTree.Internal.Merge (IsMergeType (..), - LevelMergeType (..), Merge, StepResult (..), - TreeMergeType (..)) + LevelMergeType (..), Merge, RunParams (..), + StepResult (..), TreeMergeType (..)) import qualified Database.LSMTree.Internal.Merge as Merge import Database.LSMTree.Internal.Paths (RunFsPaths (..)) import Database.LSMTree.Internal.Run (Run) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc) import System.FS.API (HasFS) import System.FS.BlockIO.API (HasBlockIO) @@ -132,9 +131,7 @@ instance NFData MergeKnownCompleted where => HasFS IO h -> HasBlockIO IO h -> ResolveSerialisedValue - -> Run.RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> t -> RunFsPaths -> V.Vector (Ref (Run IO h)) @@ -151,19 +148,17 @@ new :: => HasFS m h -> HasBlockIO m h -> ResolveSerialisedValue - -> Run.RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> t -> RunFsPaths -> V.Vector (Ref (Run m h)) -> m (Ref (MergingRun t m h)) -new hfs hbio resolve caching alloc indexType ty runPaths inputRuns = +new hfs hbio resolve runParams ty runPaths inputRuns = -- If creating the Merge fails, we must release the references again. withActionRegistry $ \reg -> do runs <- V.mapM (\r -> withRollback reg (dupRef r) releaseRef) inputRuns merge <- fromMaybe (error "newMerge: merges can not be empty") - <$> Merge.new hfs hbio caching alloc indexType ty resolve runPaths runs + <$> Merge.new hfs hbio runParams ty resolve runPaths runs let numInputRuns = NumRuns $ V.length runs let mergeDebt = numEntriesToMergeDebt (V.foldMap' Run.size runs) unsafeNew diff --git a/src/Database/LSMTree/Internal/MergingTree.hs b/src/Database/LSMTree/Internal/MergingTree.hs index fbcc7012e..3da3c84bf 100644 --- a/src/Database/LSMTree/Internal/MergingTree.hs +++ b/src/Database/LSMTree/Internal/MergingTree.hs @@ -3,13 +3,14 @@ module Database.LSMTree.Internal.MergingTree ( -- $mergingtrees MergingTree (..) , PreExistingRun (..) + , newCompletedMerge + , newOngoingMerge , newPendingLevelMerge , newPendingUnionMerge , isStructurallyEmpty -- * Internal state , MergingTreeState (..) , PendingMerge (..) - , mkMergingTree ) where import Control.Concurrent.Class.MonadMVar.Strict @@ -102,6 +103,31 @@ data PreExistingRun m h = PreExistingRun !(Ref (Run m h)) | PreExistingMergingRun !(Ref (MergingRun MR.LevelMergeType m h)) +{-# SPECIALISE newCompletedMerge :: + Ref (Run IO h) + -> IO (Ref (MergingTree IO h)) #-} +newCompletedMerge :: + (MonadMVar m, PrimMonad m, MonadMask m) + => Ref (Run m h) + -> m (Ref (MergingTree m h)) +newCompletedMerge run = mkMergingTree . CompletedTreeMerge =<< dupRef run + +{-# SPECIALISE newOngoingMerge :: + Ref (MergingRun MR.TreeMergeType IO h) + -> IO (Ref (MergingTree IO h)) #-} +-- | Create a new 'MergingTree' representing the merge of an ongoing run. +-- The usage of this function is primarily to facilitate the reloading of an +-- ongoing merge from a persistent snapshot. +newOngoingMerge :: + (MonadMVar m, PrimMonad m, MonadMask m) + => Ref (MergingRun MR.TreeMergeType m h) + -> m (Ref (MergingTree m h)) +newOngoingMerge mr = mkMergingTree . OngoingTreeMerge =<< dupRef mr + +{-# SPECIALISE newPendingLevelMerge :: + [PreExistingRun IO h] + -> Maybe (Ref (MergingTree IO h)) + -> IO (Ref (MergingTree IO h)) #-} -- | Create a new 'MergingTree' representing the merge of a sequence of -- pre-existing runs (completed or ongoing, plus a optional final tree). -- This is for merging the entire contents of a table down to a single run @@ -162,6 +188,9 @@ newPendingLevelMerge prs mmt = do then return Nothing else Just <$!> dupRef mt +{-# SPECIALISE newPendingUnionMerge :: + [Ref (MergingTree IO h)] + -> IO (Ref (MergingTree IO h)) #-} -- | Create a new 'MergingTree' representing the union of one or more merging -- trees. This is for unioning the content of multiple tables (represented -- themselves as merging trees). @@ -183,7 +212,7 @@ newPendingUnionMerge :: -> m (Ref (MergingTree m h)) newPendingUnionMerge mts = do mts' <- V.filterM (fmap not . isStructurallyEmpty) (V.fromList mts) - -- isStructurallyEmpty is interruptable even with async exceptions masked, + -- isStructurallyEmpty is interruptible even with async exceptions masked, -- but we use it before allocating new references. mts'' <- V.mapM dupRef mts' case V.uncons mts'' of @@ -191,6 +220,7 @@ newPendingUnionMerge mts = do -> return mt _ -> mkMergingTree (PendingTreeMerge (PendingUnionMerge mts'')) +{-# SPECIALISE isStructurallyEmpty :: Ref (MergingTree IO h) -> IO Bool #-} -- | Test if a 'MergingTree' is \"obviously\" empty by virtue of its structure. -- This is not the same as being empty due to a pending or ongoing merge -- happening to produce an empty run. @@ -205,6 +235,9 @@ isStructurallyEmpty (DeRef MergingTree {mergeState}) = -- It may also turn out to be useful to consider CompletedTreeMerge with -- a zero length runs as empty. +{-# SPECIALISE mkMergingTree :: + MergingTreeState IO h + -> IO (Ref (MergingTree IO h)) #-} -- | Constructor helper. -- -- This adopts the references in the MergingTreeState, so callers should @@ -223,6 +256,7 @@ mkMergingTree mergeTreeState = do , mergeRefCounter } +{-# SPECIALISE finalise :: StrictMVar IO (MergingTreeState IO h) -> IO () #-} finalise :: (MonadMVar m, PrimMonad m, MonadMask m) => StrictMVar m (MergingTreeState m h) -> m () finalise mergeState = releaseMTS =<< readMVar mergeState diff --git a/src/Database/LSMTree/Internal/Run.hs b/src/Database/LSMTree/Internal/Run.hs index decd8a0fa..c80775706 100644 --- a/src/Database/LSMTree/Internal/Run.hs +++ b/src/Database/LSMTree/Internal/Run.hs @@ -14,14 +14,18 @@ module Database.LSMTree.Internal.Run ( , sizeInPages , runFsPaths , runFsPathsNumber + , runDataCaching + , runIndexType , mkRawBlobRef , mkWeakBlobRef -- ** Run creation , fromMutable , fromWriteBuffer - , RunDataCaching (..) + , RunParams (..) -- * Snapshot , openFromDisk + , RunDataCaching (..) + , IndexType (..) ) where import Control.DeepSeq (NFData (..), rwhnf) @@ -40,12 +44,12 @@ import qualified Database.LSMTree.Internal.BlobRef as BlobRef import Database.LSMTree.Internal.BloomFilter (bloomFilterFromSBS) import qualified Database.LSMTree.Internal.CRC32C as CRC import Database.LSMTree.Internal.Entry (NumEntries (..)) -import Database.LSMTree.Internal.Index (Index, IndexType) -import qualified Database.LSMTree.Internal.Index as Index (fromSBS, sizeInPages) +import Database.LSMTree.Internal.Index (Index, IndexType (..)) +import qualified Database.LSMTree.Internal.Index as Index import Database.LSMTree.Internal.Page (NumPages) import Database.LSMTree.Internal.Paths as Paths -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc) -import Database.LSMTree.Internal.RunBuilder (RunBuilder) +import Database.LSMTree.Internal.RunBuilder (RunBuilder, + RunDataCaching (..), RunParams (..)) import qualified Database.LSMTree.Internal.RunBuilder as Builder import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise @@ -112,6 +116,15 @@ runFsPaths (DeRef r) = runRunFsPaths r runFsPathsNumber :: Ref (Run m h) -> RunNumber runFsPathsNumber = Paths.runNumber . runFsPaths +-- | See 'openFromDisk' +runIndexType :: Ref (Run m h) -> IndexType +runIndexType (DeRef r) = Index.indexToIndexType (runIndex r) + +-- | See 'openFromDisk' +runDataCaching :: Ref (Run m h) -> RunDataCaching +runDataCaching (DeRef r) = runRunDataCaching r + + -- | Helper function to make a 'WeakBlobRef' that points into a 'Run'. mkRawBlobRef :: Run m h -> BlobSpan -> RawBlobRef m h mkRawBlobRef Run{runBlobFile} blobspan = @@ -147,14 +160,6 @@ finaliser hfs kopsFile blobFile fsPaths = do FS.removeFile hfs (runIndexPath fsPaths) FS.removeFile hfs (runChecksumsPath fsPaths) --- | Should this run cache key\/ops data in memory? -data RunDataCaching = CacheRunData | NoCacheRunData - deriving stock (Show, Eq) - -instance NFData RunDataCaching where - rnf CacheRunData = () - rnf NoCacheRunData = () - {-# SPECIALISE setRunDataCaching :: HasBlockIO IO h -> FS.Handle h @@ -176,18 +181,18 @@ setRunDataCaching hbio runKOpsFile NoCacheRunData = do FS.hSetNoCache hbio runKOpsFile True {-# SPECIALISE fromMutable :: - RunDataCaching - -> RunBuilder IO h + RunBuilder IO h -> IO (Ref (Run IO h)) #-} -- TODO: make exception safe fromMutable :: (MonadST m, MonadSTM m, MonadMask m) - => RunDataCaching - -> RunBuilder m h + => RunBuilder m h -> m (Ref (Run m h)) -fromMutable runRunDataCaching builder = do - (runHasFS, runHasBlockIO, runRunFsPaths, runFilter, runIndex, runNumEntries) <- - Builder.unsafeFinalise (runRunDataCaching == NoCacheRunData) builder +fromMutable builder = do + (runHasFS, runHasBlockIO, + runRunFsPaths, runFilter, runIndex, + RunParams {runParamCaching = runRunDataCaching}, runNumEntries) <- + Builder.unsafeFinalise builder runKOpsFile <- FS.hOpen runHasFS (runKOpsPath runRunFsPaths) FS.ReadMode -- TODO: openBlobFile should be called with exceptions masked runBlobFile <- openBlobFile runHasFS (runBlobPath runRunFsPaths) FS.ReadMode @@ -198,9 +203,7 @@ fromMutable runRunDataCaching builder = do {-# SPECIALISE fromWriteBuffer :: HasFS IO h -> HasBlockIO IO h - -> RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> RunFsPaths -> WriteBuffer -> Ref (WriteBufferBlobs IO h) @@ -216,20 +219,17 @@ fromWriteBuffer :: (MonadST m, MonadSTM m, MonadMask m) => HasFS m h -> HasBlockIO m h - -> RunDataCaching - -> RunBloomFilterAlloc - -> IndexType + -> RunParams -> RunFsPaths -> WriteBuffer -> Ref (WriteBufferBlobs m h) -> m (Ref (Run m h)) -fromWriteBuffer fs hbio caching alloc indexType fsPaths buffer blobs = do - builder <- Builder.new fs hbio fsPaths (WB.numEntries buffer) - alloc indexType +fromWriteBuffer fs hbio params fsPaths buffer blobs = do + builder <- Builder.new fs hbio params fsPaths (WB.numEntries buffer) for_ (WB.toList buffer) $ \(k, e) -> Builder.addKeyOp builder k (fmap (WBB.mkRawBlobRef blobs) e) --TODO: the fmap entry here reallocates even when there are no blobs - fromMutable caching builder + fromMutable builder {------------------------------------------------------------------------------- Snapshot @@ -249,6 +249,15 @@ fromWriteBuffer fs hbio caching alloc indexType fsPaths buffer blobs = do -- -- Exceptions will be raised when any of the file's contents don't match their -- checksum ('ChecksumError') or can't be parsed ('FileFormatError'). +-- +-- The 'RunDataCaching' and 'IndexType' parameters need to be saved and +-- restored separately because these are not stored in the on-disk +-- representation. Use 'runDataCaching' and 'runIndexType' to obtain these +-- parameters from the open run before persisting to disk. +-- +-- TODO: it may make more sense to persist these parameters with the run's +-- on-disk representation. +-- openFromDisk :: forall m h. (MonadSTM m, MonadMask m, PrimMonad m) diff --git a/src/Database/LSMTree/Internal/RunAcc.hs b/src/Database/LSMTree/Internal/RunAcc.hs index 0ffeaff57..18e43e4c3 100644 --- a/src/Database/LSMTree/Internal/RunAcc.hs +++ b/src/Database/LSMTree/Internal/RunAcc.hs @@ -31,6 +31,7 @@ module Database.LSMTree.Internal.RunAcc ( , PageAcc.entryWouldFitInPage ) where +import Control.DeepSeq (NFData (..)) import Control.Exception (assert) import Control.Monad.ST.Strict import Data.BloomFilter (Bloom, MBloom) @@ -78,12 +79,17 @@ data RunAcc s = RunAcc { -- | See 'Database.LSMTree.Internal.BloomFilterAlloc' data RunBloomFilterAlloc = -- | Bits per element in a filter - RunAllocFixed Word64 - | RunAllocRequestFPR Double + RunAllocFixed !Word64 + | RunAllocRequestFPR !Double -- | Total number of bits for a filter - | RunAllocMonkey Word64 + | RunAllocMonkey !Word64 deriving stock (Show, Eq) +instance NFData RunBloomFilterAlloc where + rnf (RunAllocFixed a) = rnf a + rnf (RunAllocRequestFPR a) = rnf a + rnf (RunAllocMonkey a) = rnf a + -- | @'new' nentries@ starts an incremental run construction. -- -- @nentries@ should be an upper bound on the expected number of entries in the diff --git a/src/Database/LSMTree/Internal/RunBuilder.hs b/src/Database/LSMTree/Internal/RunBuilder.hs index 6c8e05ce3..e23ec9559 100644 --- a/src/Database/LSMTree/Internal/RunBuilder.hs +++ b/src/Database/LSMTree/Internal/RunBuilder.hs @@ -2,6 +2,10 @@ -- module Database.LSMTree.Internal.RunBuilder ( RunBuilder (..) + , RunParams (..) + , RunDataCaching (..) + , RunBloomFilterAlloc (..) + , IndexType (..) , new , addKeyOp , addLargeSerialisedKeyOp @@ -9,6 +13,7 @@ module Database.LSMTree.Internal.RunBuilder ( , close ) where +import Control.DeepSeq (NFData (..)) import Control.Monad (when) import Control.Monad.Class.MonadST (MonadST (..)) import qualified Control.Monad.Class.MonadST as ST @@ -23,11 +28,12 @@ import Database.LSMTree.Internal.BlobRef (RawBlobRef) import Database.LSMTree.Internal.ChecksumHandle import qualified Database.LSMTree.Internal.CRC32C as CRC import Database.LSMTree.Internal.Entry -import Database.LSMTree.Internal.Index (Index, IndexType) +import Database.LSMTree.Internal.Index (Index, IndexType (..)) import Database.LSMTree.Internal.Paths import Database.LSMTree.Internal.RawOverflowPage (RawOverflowPage) import Database.LSMTree.Internal.RawPage (RawPage) -import Database.LSMTree.Internal.RunAcc (RunAcc, RunBloomFilterAlloc) +import Database.LSMTree.Internal.RunAcc (RunAcc, + RunBloomFilterAlloc (..)) import qualified Database.LSMTree.Internal.RunAcc as RunAcc import Database.LSMTree.Internal.Serialise import qualified System.FS.API as FS @@ -47,8 +53,10 @@ import System.FS.BlockIO.API (HasBlockIO) -- __Not suitable for concurrent construction from multiple threads!__ -- data RunBuilder m h = RunBuilder { + runBuilderParams :: !RunParams + -- | The file system paths for all the files used by the run. - runBuilderFsPaths :: !RunFsPaths + , runBuilderFsPaths :: !RunFsPaths -- | The run accumulator. This is the representation used for the -- morally pure subset of the run cnstruction functionality. In @@ -65,13 +73,30 @@ data RunBuilder m h = RunBuilder { , runBuilderHasBlockIO :: !(HasBlockIO m h) } +data RunParams = RunParams { + runParamCaching :: !RunDataCaching, + runParamAlloc :: !RunBloomFilterAlloc, + runParamIndex :: !IndexType + } + deriving stock (Eq, Show) + +instance NFData RunParams where + rnf (RunParams a b c) = rnf a `seq` rnf b `seq` rnf c + +-- | Should this run cache key\/ops data in memory? +data RunDataCaching = CacheRunData | NoCacheRunData + deriving stock (Show, Eq) + +instance NFData RunDataCaching where + rnf CacheRunData = () + rnf NoCacheRunData = () + {-# SPECIALISE new :: HasFS IO h -> HasBlockIO IO h + -> RunParams -> RunFsPaths -> NumEntries - -> RunBloomFilterAlloc - -> IndexType -> IO (RunBuilder IO h) #-} -- | Create an 'RunBuilder' to start building a run. -- @@ -80,19 +105,19 @@ new :: (MonadST m, MonadSTM m) => HasFS m h -> HasBlockIO m h + -> RunParams -> RunFsPaths -> NumEntries -- ^ an upper bound of the number of entries to be added - -> RunBloomFilterAlloc - -> IndexType -> m (RunBuilder m h) -new hfs hbio runBuilderFsPaths numEntries alloc indexType = do - runBuilderAcc <- ST.stToIO $ RunAcc.new numEntries alloc indexType +new hfs hbio runBuilderParams@RunParams{..} runBuilderFsPaths numEntries = do + runBuilderAcc <- ST.stToIO $ + RunAcc.new numEntries runParamAlloc runParamIndex runBuilderBlobOffset <- newPrimVar 0 runBuilderHandles <- traverse (makeHandle hfs) (pathsForRunFiles runBuilderFsPaths) let builder = RunBuilder { runBuilderHasFS = hfs, runBuilderHasBlockIO = hbio, .. } - writeIndexHeader hfs (forRunIndex runBuilderHandles) indexType + writeIndexHeader hfs (forRunIndex runBuilderHandles) runParamIndex return builder {-# SPECIALISE addKeyOp :: @@ -165,9 +190,10 @@ addLargeSerialisedKeyOp RunBuilder{..} key page overflowPages = do for_ chunks $ writeIndexChunk runBuilderHasFS (forRunIndex runBuilderHandles) {-# SPECIALISE unsafeFinalise :: - Bool - -> RunBuilder IO h - -> IO (HasFS IO h, HasBlockIO IO h, RunFsPaths, Bloom SerialisedKey, Index, NumEntries) #-} + RunBuilder IO h + -> IO (HasFS IO h, HasBlockIO IO h, + RunFsPaths, Bloom SerialisedKey, Index, + RunParams, NumEntries) #-} -- | Finish construction of the run. -- Writes the filter and index to file and leaves all written files on disk. -- @@ -176,10 +202,12 @@ addLargeSerialisedKeyOp RunBuilder{..} key page overflowPages = do -- TODO: Ensure proper cleanup even in presence of exceptions. unsafeFinalise :: (MonadST m, MonadSTM m, MonadThrow m) - => Bool -- ^ drop caches - -> RunBuilder m h - -> m (HasFS m h, HasBlockIO m h, RunFsPaths, Bloom SerialisedKey, Index, NumEntries) -unsafeFinalise dropCaches RunBuilder {..} = do + => RunBuilder m h + -> m (HasFS m h, HasBlockIO m h, + RunFsPaths, Bloom SerialisedKey, Index, + RunParams, NumEntries) +-- TODO: consider introducing a type for this big tuple +unsafeFinalise RunBuilder {..} = do -- write final bits (mPage, mChunk, runFilter, runIndex, numEntries) <- ST.stToIO (RunAcc.unsafeFinalise runBuilderAcc) @@ -197,11 +225,13 @@ unsafeFinalise dropCaches RunBuilder {..} = do dropCache runBuilderHasBlockIO (forRunFilterRaw runBuilderHandles) dropCache runBuilderHasBlockIO (forRunIndexRaw runBuilderHandles) -- drop the KOps and blobs files from the cache if asked for - when dropCaches $ do + when (runParamCaching runBuilderParams == NoCacheRunData) $ do dropCache runBuilderHasBlockIO (forRunKOpsRaw runBuilderHandles) dropCache runBuilderHasBlockIO (forRunBlobRaw runBuilderHandles) mapM_ (closeHandle runBuilderHasFS) runBuilderHandles - return (runBuilderHasFS, runBuilderHasBlockIO, runBuilderFsPaths, runFilter, runIndex, numEntries) + return (runBuilderHasFS, runBuilderHasBlockIO, + runBuilderFsPaths, runFilter, runIndex, + runBuilderParams, numEntries) {-# SPECIALISE close :: RunBuilder IO h -> IO () #-} -- | Close a run that is being constructed (has not been finalised yet), diff --git a/src/Database/LSMTree/Internal/Snapshot.hs b/src/Database/LSMTree/Internal/Snapshot.hs index d225abd67..9347fa0fc 100644 --- a/src/Database/LSMTree/Internal/Snapshot.hs +++ b/src/Database/LSMTree/Internal/Snapshot.hs @@ -7,18 +7,28 @@ module Database.LSMTree.Internal.Snapshot ( , SnapLevels (..) , SnapLevel (..) , SnapIncomingRun (..) - , SnapMergingRunState (..) + , SnapMergingRun (..) + -- * MergeTree snapshot format + , SnapMergingTree(..) + , SnapMergingTreeState(..) + , SnapPendingMerge(..) + , SnapPreExistingRun(..) -- * Conversion to levels snapshot format , toSnapLevels + -- * Conversion to merging tree snapshot format + , toSnapMergingTree -- * Write buffer , snapshotWriteBuffer , openWriteBuffer - -- * Runs - , snapshotRuns - , openRuns - , releaseRuns - -- * Opening from levels snapshot format + -- * Run + , SnapshotRun (..) + , snapshotRun + , openRun + -- * Opening snapshot formats + -- ** Levels format , fromSnapLevels + -- ** Merging Tree format + , fromSnapMergingTree -- * Hard links , hardLinkRunFiles ) where @@ -29,13 +39,12 @@ import Control.Concurrent.Class.MonadSTM (MonadSTM) import Control.DeepSeq (NFData (..)) import Control.Monad (void) import Control.Monad.Class.MonadST (MonadST) -import Control.Monad.Class.MonadThrow (MonadMask, bracketOnError) +import Control.Monad.Class.MonadThrow (MonadMask, bracket, + bracketOnError) import Control.Monad.Primitive (PrimMonad) import Control.RefCount -import Control.Tracer (Tracer, nullTracer) import Data.Foldable (sequenceA_, traverse_) import Data.Text (Text) -import Data.Traversable (for) import qualified Data.Vector as V import Database.LSMTree.Internal.Config import Database.LSMTree.Internal.CRC32C (checkCRC) @@ -45,13 +54,14 @@ import qualified Database.LSMTree.Internal.Merge as Merge import Database.LSMTree.Internal.MergeSchedule import Database.LSMTree.Internal.MergingRun (NumRuns (..)) import qualified Database.LSMTree.Internal.MergingRun as MR +import qualified Database.LSMTree.Internal.MergingTree as MT import Database.LSMTree.Internal.Paths (ActiveDir (..), ForBlob (..), ForKOps (..), NamedSnapshotDir (..), RunFsPaths (..), WriteBufferFsPaths (..), fromChecksumsFileForWriteBufferFiles, pathsForRunFiles, - runChecksumsPath, writeBufferBlobPath, + runChecksumsPath, runPath, writeBufferBlobPath, writeBufferChecksumsPath, writeBufferKOpsPath) -import Database.LSMTree.Internal.Run (Run) +import Database.LSMTree.Internal.Run (Run, RunParams) import qualified Database.LSMTree.Internal.Run as Run import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.UniqCounter (UniqCounter, @@ -95,7 +105,7 @@ data SnapshotMetaData = SnapshotMetaData { -- -- One could argue that the 'SnapshotName' could be used to to hold this -- type information, but the file name of snapshot metadata is not guarded - -- by a checksum, wherease the contents of the file are. Therefore using the + -- by a checksum, whereas the contents of the file are. Therefore using the -- 'SnapshotLabel' is safer. snapMetaLabel :: !SnapshotLabel -- | Whether a table is normal or monoidal. @@ -111,12 +121,16 @@ data SnapshotMetaData = SnapshotMetaData { -- | The write buffer. , snapWriteBuffer :: !RunNumber -- | The shape of the levels of the LSM tree. - , snapMetaLevels :: !(SnapLevels RunNumber) + , snapMetaLevels :: !(SnapLevels SnapshotRun) + -- | The state of tree merging of the LSM tree. + , snapMergingTree :: !(Maybe (SnapMergingTree SnapshotRun)) } deriving stock Eq instance NFData SnapshotMetaData where - rnf (SnapshotMetaData a b c d e) = rnf a `seq` rnf b `seq` rnf c `seq` rnf d `seq` rnf e + rnf (SnapshotMetaData a b c d e f) = + rnf a `seq` rnf b `seq` rnf c `seq` + rnf d `seq` rnf e `seq` rnf f {------------------------------------------------------------------------------- Levels snapshot format @@ -156,19 +170,19 @@ instance NFData r => NFData (SnapLevel r) where -- both to zero). -- data SnapIncomingRun r = - SnapMergingRun !MergePolicyForLevel - !NumRuns - !MergeDebt -- ^ The total merge debt. - !NominalCredits -- ^ The nominal credits supplied, and that - -- need to be supplied on snapshot open. - !(SnapMergingRunState MR.LevelMergeType r) - | SnapSingleRun !r + SnapIncomingMergingRun + !MergePolicyForLevel + !NominalDebt + !NominalCredits -- ^ The nominal credits supplied, and that + -- need to be supplied on snapshot open. + !(SnapMergingRun MR.LevelMergeType r) + | SnapIncomingSingleRun !r deriving stock (Eq, Functor, Foldable, Traversable) instance NFData r => NFData (SnapIncomingRun r) where - rnf (SnapMergingRun a b c d e) = - rnf a `seq` rnf b `seq` rnf c `seq` rnf d `seq` rnf e - rnf (SnapSingleRun a) = rnf a + rnf (SnapIncomingMergingRun a b c d) = + rnf a `seq` rnf b `seq` rnf c `seq` rnf d + rnf (SnapIncomingSingleRun a) = rnf a -- | The total number of supplied credits. This total is used on snapshot load -- to restore merging work that was lost when the snapshot was created. @@ -176,14 +190,188 @@ newtype SuppliedCredits = SuppliedCredits { getSuppliedCredits :: Int } deriving stock (Eq, Read) deriving newtype NFData -data SnapMergingRunState t r = - SnapCompletedMerge !r - | SnapOngoingMerge !(V.Vector r) !t +data SnapMergingRun t r = + SnapCompletedMerge !NumRuns !MergeDebt !r + | SnapOngoingMerge !RunParams !MergeCredits !(V.Vector r) !t deriving stock (Eq, Functor, Foldable, Traversable) -instance (NFData t, NFData r) => NFData (SnapMergingRunState t r) where - rnf (SnapCompletedMerge a) = rnf a - rnf (SnapOngoingMerge a b) = rnf a `seq` rnf b +instance (NFData t, NFData r) => NFData (SnapMergingRun t r) where + rnf (SnapCompletedMerge a b c) = rnf a `seq` rnf b `seq` rnf c + rnf (SnapOngoingMerge a b c d) = rnf a `seq` rnf b `seq` rnf c `seq` rnf d + +{------------------------------------------------------------------------------- + Snapshot MergingTree +-------------------------------------------------------------------------------} + +newtype SnapMergingTree r = SnapMergingTree (SnapMergingTreeState r) + deriving stock (Eq, Functor, Foldable, Traversable) + deriving newtype NFData + +data SnapMergingTreeState r = + SnapCompletedTreeMerge !r + | SnapPendingTreeMerge !(SnapPendingMerge r) + | SnapOngoingTreeMerge !(SnapMergingRun MR.TreeMergeType r) + deriving stock (Eq, Functor, Foldable, Traversable) + +instance NFData r => NFData (SnapMergingTreeState r) where + rnf (SnapCompletedTreeMerge a) = rnf a + rnf (SnapPendingTreeMerge a) = rnf a + rnf (SnapOngoingTreeMerge a) = rnf a + +data SnapPendingMerge r = + SnapPendingLevelMerge + ![SnapPreExistingRun r] + !(Maybe (SnapMergingTree r)) + | SnapPendingUnionMerge + ![SnapMergingTree r] + deriving stock (Eq, Functor, Foldable, Traversable) + +instance NFData r => NFData (SnapPendingMerge r) where + rnf (SnapPendingLevelMerge a b) = rnf a `seq` rnf b + rnf (SnapPendingUnionMerge a) = rnf a + +data SnapPreExistingRun r = + SnapPreExistingRun !r + | SnapPreExistingMergingRun !(SnapMergingRun MR.LevelMergeType r) + deriving stock (Eq, Functor, Foldable, Traversable) + +instance NFData r => NFData (SnapPreExistingRun r) where + rnf (SnapPreExistingRun a) = rnf a + rnf (SnapPreExistingMergingRun a) = rnf a + +{------------------------------------------------------------------------------- + Opening from merging tree snapshot format +-------------------------------------------------------------------------------} + +{-# SPECIALISE fromSnapMergingTree :: + HasFS IO h + -> HasBlockIO IO h + -> UniqCounter IO + -> ResolveSerialisedValue + -> ActiveDir + -> ActionRegistry IO + -> SnapMergingTree (Ref (Run IO h)) + -> IO (Ref (MT.MergingTree IO h)) + #-} +-- | Converts a snapshot of a merging tree of runs to a real merging tree. +-- +-- Returns a new reference. Input runs remain owned by the caller. +fromSnapMergingTree :: + forall m h. (MonadMask m, MonadMVar m, MonadSTM m, MonadST m) + => HasFS m h + -> HasBlockIO m h + -> UniqCounter m + -> ResolveSerialisedValue + -> ActiveDir + -> ActionRegistry m + -> SnapMergingTree (Ref (Run m h)) + -> m (Ref (MT.MergingTree m h)) +fromSnapMergingTree hfs hbio uc resolve dir = + go + where + -- Reference strategy: + -- * go returns a fresh reference + -- * go ensures the returned reference will be cleaned up on failure, + -- using withRollback + -- * All results from recursive calls must be released locally on the + -- happy path. + go :: ActionRegistry m + -> SnapMergingTree (Ref (Run m h)) + -> m (Ref (MT.MergingTree m h)) + + go reg (SnapMergingTree (SnapCompletedTreeMerge run)) = + withRollback reg + (MT.newCompletedMerge run) + releaseRef + + go reg (SnapMergingTree (SnapPendingTreeMerge + (SnapPendingLevelMerge prs mmt))) = do + prs' <- traverse (fromSnapPreExistingRun reg) prs + mmt' <- traverse (go reg) mmt + mt <- withRollback reg + (MT.newPendingLevelMerge prs' mmt') + releaseRef + traverse_ (delayedCommit reg . releasePER) prs' + traverse_ (delayedCommit reg . releaseRef) mmt' + return mt + + go reg (SnapMergingTree (SnapPendingTreeMerge + (SnapPendingUnionMerge mts))) = do + mts' <- traverse (go reg) mts + mt <- withRollback reg + (MT.newPendingUnionMerge mts') + releaseRef + traverse_ (delayedCommit reg . releaseRef) mts' + return mt + + go reg (SnapMergingTree (SnapOngoingTreeMerge smrs)) = do + mr <- withRollback reg + (fromSnapMergingRun hfs hbio uc resolve dir smrs) + releaseRef + mt <- withRollback reg + (MT.newOngoingMerge mr) + releaseRef + delayedCommit reg (releaseRef mr) + return mt + + -- Returns fresh refs, which must be released locally. + fromSnapPreExistingRun :: ActionRegistry m + -> SnapPreExistingRun (Ref (Run m h)) + -> m (MT.PreExistingRun m h) + fromSnapPreExistingRun reg (SnapPreExistingRun run) = + MT.PreExistingRun <$> + withRollback reg (dupRef run) releaseRef + fromSnapPreExistingRun reg (SnapPreExistingMergingRun smrs) = + MT.PreExistingMergingRun <$> + withRollback reg + (fromSnapMergingRun hfs hbio uc resolve dir smrs) + releaseRef + + releasePER (MT.PreExistingRun r) = releaseRef r + releasePER (MT.PreExistingMergingRun mr) = releaseRef mr + +{------------------------------------------------------------------------------- + Conversion to merge tree snapshot format +-------------------------------------------------------------------------------} + +{-# SPECIALISE toSnapMergingTree :: Ref (MT.MergingTree IO h) -> IO (SnapMergingTree (Ref (Run IO h))) #-} +toSnapMergingTree :: + (PrimMonad m, MonadMVar m) + => Ref (MT.MergingTree m h) + -> m (SnapMergingTree (Ref (Run m h))) +toSnapMergingTree (DeRef (MT.MergingTree mStateVar _mCounter)) = + withMVar mStateVar $ \mState -> SnapMergingTree <$> toSnapMergingTreeState mState + +{-# SPECIALISE toSnapMergingTreeState :: MT.MergingTreeState IO h -> IO (SnapMergingTreeState (Ref (Run IO h))) #-} +toSnapMergingTreeState :: + (PrimMonad m, MonadMVar m) + => MT.MergingTreeState m h + -> m (SnapMergingTreeState (Ref (Run m h))) +toSnapMergingTreeState (MT.CompletedTreeMerge r) = pure $ SnapCompletedTreeMerge r +toSnapMergingTreeState (MT.PendingTreeMerge p) = SnapPendingTreeMerge <$> toSnapPendingMerge p +toSnapMergingTreeState (MT.OngoingTreeMerge mergingRun) = + SnapOngoingTreeMerge <$> toSnapMergingRun mergingRun + +{-# SPECIALISE toSnapPendingMerge :: MT.PendingMerge IO h -> IO (SnapPendingMerge (Ref (Run IO h))) #-} +toSnapPendingMerge :: + (PrimMonad m, MonadMVar m) + => MT.PendingMerge m h + -> m (SnapPendingMerge (Ref (Run m h))) +toSnapPendingMerge (MT.PendingUnionMerge mts) = + SnapPendingUnionMerge <$> traverse toSnapMergingTree (V.toList mts) +toSnapPendingMerge (MT.PendingLevelMerge pes mmt) = do + pes' <- traverse toSnapPreExistingRun pes + mmt' <- traverse toSnapMergingTree mmt + pure $ SnapPendingLevelMerge (V.toList pes') mmt' + +{-# SPECIALISE toSnapPreExistingRun :: MT.PreExistingRun IO h -> IO (SnapPreExistingRun (Ref (Run IO h))) #-} +toSnapPreExistingRun :: + (PrimMonad m, MonadMVar m) + => MT.PreExistingRun m h + -> m (SnapPreExistingRun (Ref (Run m h))) +toSnapPreExistingRun (MT.PreExistingRun run) = pure $ SnapPreExistingRun run +toSnapPreExistingRun (MT.PreExistingMergingRun peMergingRun) = + SnapPreExistingMergingRun <$> toSnapMergingRun peMergingRun {------------------------------------------------------------------------------- Conversion to levels snapshot format @@ -219,33 +407,36 @@ toSnapIncomingRun :: toSnapIncomingRun ir = do s <- snapshotIncomingRun ir case s of - Left r -> pure $! SnapSingleRun r + Left r -> pure $! SnapIncomingSingleRun r Right (mergePolicy, - numRuns, - _nominalDebt, -- not stored + nominalDebt, nominalCredits, - mergeDebt, - _mergeCredits, -- not stored - mergingRunState) -> do + mergingRun) -> do -- We need to know how many credits were supplied so we can restore merge -- work on snapshot load. - -- TODO: MR.snapshot needs to return duplicated run references, and we - -- need to arrange to release them when the snapshoting is done. - let smrs = toSnapMergingRunState mergingRunState - pure $! - SnapMergingRun - mergePolicy - numRuns - mergeDebt - nominalCredits - smrs - -toSnapMergingRunState :: - MR.MergingRunState t m h - -> SnapMergingRunState t (Ref (Run m h)) -toSnapMergingRunState = \case - MR.CompletedMerge r -> SnapCompletedMerge r - MR.OngoingMerge rs m -> SnapOngoingMerge rs (Merge.mergeType m) + smrs <- toSnapMergingRun mergingRun + pure $! SnapIncomingMergingRun mergePolicy nominalDebt nominalCredits smrs + +{-# SPECIALISE toSnapMergingRun :: + Ref (MR.MergingRun t IO h) + -> IO (SnapMergingRun t (Ref (Run IO h))) #-} +toSnapMergingRun :: + (PrimMonad m, MonadMVar m) + => Ref (MR.MergingRun t m h) + -> m (SnapMergingRun t (Ref (Run m h))) +toSnapMergingRun !mr = do + -- TODO: MR.snapshot needs to return duplicated run references, and we + -- need to arrange to release them when the snapshotting is done. + (numRuns, mergeDebt, mergeCredits, state) <- MR.snapshot mr + case state of + MR.CompletedMerge r -> + pure $! SnapCompletedMerge numRuns mergeDebt r + + MR.OngoingMerge rs m -> + pure $! SnapOngoingMerge runParams mergeCredits rs mergeType + where + runParams = Merge.mergeRunParams m + mergeType = Merge.mergeType m {------------------------------------------------------------------------------- Write Buffer @@ -253,11 +444,11 @@ toSnapMergingRunState = \case {-# SPECIALISE snapshotWriteBuffer :: - ActionRegistry IO - -> HasFS IO h + HasFS IO h -> HasBlockIO IO h -> UniqCounter IO -> UniqCounter IO + -> ActionRegistry IO -> ActiveDir -> NamedSnapshotDir -> WriteBuffer @@ -266,17 +457,17 @@ toSnapMergingRunState = \case #-} snapshotWriteBuffer :: (MonadMVar m, MonadSTM m, MonadST m, MonadMask m) - => ActionRegistry m - -> HasFS m h + => HasFS m h -> HasBlockIO m h -> UniqCounter m -> UniqCounter m + -> ActionRegistry m -> ActiveDir -> NamedSnapshotDir -> WriteBuffer -> Ref (WriteBufferBlobs m h) -> m WriteBufferFsPaths -snapshotWriteBuffer reg hfs hbio activeUc snapUc activeDir snapDir wb wbb = do +snapshotWriteBuffer hfs hbio activeUc snapUc reg activeDir snapDir wb wbb = do -- Write the write buffer and write buffer blobs to the active directory. activeWriteBufferNumber <- uniqueToRunNumber <$> incrUniqCounter activeUc let activeWriteBufferPaths = WriteBufferFsPaths (getActiveDir activeDir) activeWriteBufferNumber @@ -291,13 +482,13 @@ snapshotWriteBuffer reg hfs hbio activeUc snapUc activeDir snapDir wb wbb = do -- Hard link the write buffer and write buffer blobs to the snapshot directory. snapWriteBufferNumber <- uniqueToRunNumber <$> incrUniqCounter snapUc let snapWriteBufferPaths = WriteBufferFsPaths (getNamedSnapshotDir snapDir) snapWriteBufferNumber - hardLink reg hfs hbio + hardLink hfs hbio reg (writeBufferKOpsPath activeWriteBufferPaths) (writeBufferKOpsPath snapWriteBufferPaths) - hardLink reg hfs hbio + hardLink hfs hbio reg (writeBufferBlobPath activeWriteBufferPaths) (writeBufferBlobPath snapWriteBufferPaths) - hardLink reg hfs hbio + hardLink hfs hbio reg (writeBufferChecksumsPath activeWriteBufferPaths) (writeBufferChecksumsPath snapWriteBufferPaths) pure snapWriteBufferPaths @@ -336,7 +527,7 @@ openWriteBuffer reg resolve hfs hbio uc activeDir snapWriteBufferPaths = do activeWriteBufferNumber <- uniqueToInt <$> incrUniqCounter uc let activeWriteBufferBlobPath = getActiveDir activeDir FS.mkFsPath [show activeWriteBufferNumber] <.> "wbblobs" - copyFile reg hfs hbio (writeBufferBlobPath snapWriteBufferPaths) activeWriteBufferBlobPath + copyFile hfs reg (writeBufferBlobPath snapWriteBufferPaths) activeWriteBufferBlobPath writeBufferBlobs <- withRollback reg (WBB.open hfs activeWriteBufferBlobPath FS.AllowExisting) @@ -352,101 +543,106 @@ openWriteBuffer reg resolve hfs hbio uc activeDir snapWriteBufferPaths = do Runs -------------------------------------------------------------------------------} -{-# SPECIALISE snapshotRuns :: - ActionRegistry IO +-- | Information needed to open a 'Run' from disk using 'snapshotRun' and +-- 'openRun'. +-- +-- TODO: one could imagine needing only the 'RunNumber' to identify the files +-- on disk, and the other parameters being stored with the run itself, rather +-- than needing to be supplied. +data SnapshotRun = SnapshotRun { + snapRunNumber :: !RunNumber, + snapRunCaching :: !Run.RunDataCaching, + snapRunIndex :: !Run.IndexType + } + deriving stock Eq + +instance NFData SnapshotRun where + rnf (SnapshotRun a b c) = rnf a `seq` rnf b `seq` rnf c + +{-# SPECIALISE snapshotRun :: + HasFS IO h + -> HasBlockIO IO h -> UniqCounter IO + -> ActionRegistry IO -> NamedSnapshotDir - -> SnapLevels (Ref (Run IO h)) - -> IO (SnapLevels RunNumber) #-} --- | @'snapshotRuns' _ _ snapUc targetDir levels@ creates hard links for all run --- files associated with the runs in @levels@, and puts the new directory --- entries in the @targetDir@ directory. The entries are renamed using @snapUc@. -snapshotRuns :: + -> Ref (Run IO h) + -> IO SnapshotRun #-} +-- | @'snapshotRun' _ _ snapUc _ targetDir run@ creates hard links for all files +-- associated with the @run@, and puts the new directory entries in the +-- @targetDir@ directory. The entries are renamed using @snapUc@. +snapshotRun :: (MonadMask m, PrimMonad m) - => ActionRegistry m + => HasFS m h + -> HasBlockIO m h -> UniqCounter m + -> ActionRegistry m -> NamedSnapshotDir - -> SnapLevels (Ref (Run m h)) - -> m (SnapLevels RunNumber) -snapshotRuns reg snapUc (NamedSnapshotDir targetDir) levels = do - for levels $ \run@(DeRef Run.Run { - Run.runHasFS = hfs, - Run.runHasBlockIO = hbio - }) -> do - rn <- uniqueToRunNumber <$> incrUniqCounter snapUc - let sourcePaths = Run.runFsPaths run - let targetPaths = sourcePaths { runDir = targetDir , runNumber = rn} - hardLinkRunFiles reg hfs hbio sourcePaths targetPaths - pure (runNumber targetPaths) - -{-# SPECIALISE openRuns :: - ActionRegistry IO - -> HasFS IO h + -> Ref (Run m h) + -> m SnapshotRun +snapshotRun hfs hbio snapUc reg (NamedSnapshotDir targetDir) run = do + rn <- uniqueToRunNumber <$> incrUniqCounter snapUc + let sourcePaths = Run.runFsPaths run + let targetPaths = sourcePaths { runDir = targetDir , runNumber = rn} + hardLinkRunFiles hfs hbio reg sourcePaths targetPaths + pure SnapshotRun { + snapRunNumber = runNumber targetPaths, + snapRunCaching = Run.runDataCaching run, + snapRunIndex = Run.runIndexType run + } + +{-# SPECIALISE openRun :: + HasFS IO h -> HasBlockIO IO h - -> TableConfig -> UniqCounter IO + -> ActionRegistry IO -> NamedSnapshotDir -> ActiveDir - -> SnapLevels RunNumber - -> IO (SnapLevels (Ref (Run IO h))) #-} --- | @'openRuns' _ _ _ _ uniqCounter sourceDir targetDir levels@ takes all run --- files that are referenced by @levels@, and hard links them from @sourceDir@ + -> SnapshotRun + -> IO (Ref (Run IO h)) #-} +-- | @'openRun' _ _ uniqCounter _ sourceDir targetDir snaprun@ takes all run +-- files that are referenced by @snaprun@, and hard links them from @sourceDir@ -- into @targetDir@ with new, unique names (using @uniqCounter@). Each set of -- (hard linked) files that represents a run is opened and verified, returning --- 'Run's as a result. +-- 'Run' as a result. -- --- The result must ultimately be released using 'releaseRuns'. -openRuns :: +-- The result must ultimately be released using 'releaseRef'. +openRun :: (MonadMask m, MonadSTM m, MonadST m) - => ActionRegistry m - -> HasFS m h + => HasFS m h -> HasBlockIO m h - -> TableConfig -> UniqCounter m + -> ActionRegistry m -> NamedSnapshotDir -> ActiveDir - -> SnapLevels RunNumber - -> m (SnapLevels (Ref (Run m h))) -openRuns - reg hfs hbio TableConfig{..} uc - (NamedSnapshotDir sourceDir) (ActiveDir targetDir) (SnapLevels levels) = do - levels' <- - V.iforM levels $ \i level -> - let ln = LevelNo (i+1) in - let - caching = diskCachePolicyForLevel confDiskCachePolicy ln - indexType = indexTypeForRun confFencePointerIndex - in - for level $ \runNum -> do - let sourcePaths = RunFsPaths sourceDir runNum - runNum' <- uniqueToRunNumber <$> incrUniqCounter uc - let targetPaths = RunFsPaths targetDir runNum' - hardLinkRunFiles reg hfs hbio sourcePaths targetPaths - - withRollback reg - (Run.openFromDisk hfs hbio caching indexType targetPaths) - releaseRef - pure (SnapLevels levels') - -{-# SPECIALISE releaseRuns :: - ActionRegistry IO -> SnapLevels (Ref (Run IO h)) -> IO () - #-} -releaseRuns :: - (MonadMask m, MonadST m) - => ActionRegistry m -> SnapLevels (Ref (Run m h)) -> m () -releaseRuns reg = traverse_ $ \r -> delayedCommit reg (releaseRef r) + -> SnapshotRun + -> m (Ref (Run m h)) +openRun hfs hbio uc reg + (NamedSnapshotDir sourceDir) (ActiveDir targetDir) + SnapshotRun { + snapRunNumber = runNum, + snapRunCaching = caching, + snapRunIndex = indexType + } = do + let sourcePaths = RunFsPaths sourceDir runNum + runNum' <- uniqueToRunNumber <$> incrUniqCounter uc + let targetPaths = RunFsPaths targetDir runNum' + hardLinkRunFiles hfs hbio reg sourcePaths targetPaths + + withRollback reg + (Run.openFromDisk hfs hbio caching indexType targetPaths) + releaseRef {------------------------------------------------------------------------------- Opening from levels snapshot format -------------------------------------------------------------------------------} {-# SPECIALISE fromSnapLevels :: - ActionRegistry IO - -> HasFS IO h + HasFS IO h -> HasBlockIO IO h - -> TableConfig -> UniqCounter IO + -> TableConfig -> ResolveSerialisedValue + -> ActionRegistry IO -> ActiveDir -> SnapLevels (Ref (Run IO h)) -> IO (Levels IO h) @@ -454,21 +650,19 @@ releaseRuns reg = traverse_ $ \r -> delayedCommit reg (releaseRef r) -- | Duplicates runs and re-creates merging runs. fromSnapLevels :: forall m h. (MonadMask m, MonadMVar m, MonadSTM m, MonadST m) - => ActionRegistry m - -> HasFS m h + => HasFS m h -> HasBlockIO m h - -> TableConfig -> UniqCounter m + -> TableConfig -> ResolveSerialisedValue + -> ActionRegistry m -> ActiveDir -> SnapLevels (Ref (Run m h)) -> m (Levels m h) -fromSnapLevels reg hfs hbio conf uc resolve dir (SnapLevels levels) = +fromSnapLevels hfs hbio uc conf resolve reg dir (SnapLevels levels) = V.iforM levels $ \i -> fromSnapLevel (LevelNo (i+1)) where -- TODO: we may wish to trace the merges created during snapshot restore: - tr :: Tracer m (AtLevel MergeTrace) - tr = nullTracer fromSnapLevel :: LevelNo -> SnapLevel (Ref (Run m h)) -> m (Level m h) fromSnapLevel ln SnapLevel{snapIncoming, snapResidentRuns} = do @@ -485,32 +679,69 @@ fromSnapLevels reg hfs hbio conf uc resolve dir (SnapLevels levels) = LevelNo -> SnapIncomingRun (Ref (Run m h)) -> m (IncomingRun m h) - fromSnapIncomingRun ln (SnapSingleRun run) = - newIncomingSingleRun tr ln run - - fromSnapIncomingRun ln (SnapMergingRun mpfl nr md _nc - (SnapCompletedMerge r)) = - newIncomingCompletedMergingRun tr conf ln mpfl nr md r - - fromSnapIncomingRun ln (SnapMergingRun mpfl _nr _md nc - (SnapOngoingMerge rs mt)) = do - bracketOnError (newIncomingMergingRun tr hfs hbio dir uc - conf resolve - mpfl mt ln rs) releaseIncomingRun $ \ir -> do + fromSnapIncomingRun _ln (SnapIncomingSingleRun run) = + newIncomingSingleRun run + + fromSnapIncomingRun ln (SnapIncomingMergingRun mergePolicy nominalDebt + nominalCredits smrs) = + bracket + (fromSnapMergingRun hfs hbio uc resolve dir smrs) + releaseRef $ \mr -> do + + ir <- newIncomingMergingRun mergePolicy nominalDebt mr + -- This will set the correct nominal credits, but it will not do any + -- more merging work because fromSnapMergingRun already supplies + -- all the merging credits already. + supplyCreditsIncomingRun conf ln ir nominalCredits + return ir + +{-# SPECIALISE fromSnapMergingRun :: + MR.IsMergeType t + => HasFS IO h + -> HasBlockIO IO h + -> UniqCounter IO + -> ResolveSerialisedValue + -> ActiveDir + -> SnapMergingRun t (Ref (Run IO h)) + -> IO (Ref (MR.MergingRun t IO h)) #-} +fromSnapMergingRun :: + (MonadMask m, MonadMVar m, MonadSTM m, MonadST m, MR.IsMergeType t) + => HasFS m h + -> HasBlockIO m h + -> UniqCounter m + -> ResolveSerialisedValue + -> ActiveDir + -> SnapMergingRun t (Ref (Run m h)) + -> m (Ref (MR.MergingRun t m h)) +fromSnapMergingRun _hfs _hbio _uc _resolve _dir + (SnapCompletedMerge numRuns mergeDebt r) = + MR.newCompleted numRuns mergeDebt r + +fromSnapMergingRun hfs hbio uc resolve dir + (SnapOngoingMerge runParams mergeCredits rs mergeType) = do + bracketOnError + (do uniq <- incrUniqCounter uc + let runPaths = runPath dir (uniqueToRunNumber uniq) + MR.new hfs hbio resolve runParams mergeType runPaths rs) + releaseRef $ \mr -> do -- When a snapshot is created, merge progress is lost, so we have to -- redo merging work here. The MergeCredits in SnapMergingRun tracks -- how many credits were supplied before the snapshot was taken. - supplyCreditsIncomingRun conf ln ir nc - return ir + + --TODO: the threshold should be stored with the MergingRun + -- here we want to supply the credits now, so we can use a threshold of 1 + let thresh = MR.CreditThreshold (MR.UnspentCredits 1) + _ <- MR.supplyCreditsAbsolute mr thresh mergeCredits + return mr {------------------------------------------------------------------------------- Hard links -------------------------------------------------------------------------------} {-# SPECIALISE hardLinkRunFiles :: - ActionRegistry IO - -> HasFS IO h + HasFS IO h -> HasBlockIO IO h + -> ActionRegistry IO -> RunFsPaths -> RunFsPaths -> IO () #-} @@ -519,38 +750,38 @@ fromSnapLevels reg hfs hbio conf uc resolve dir (SnapLevels levels) = -- name for the new directory entry. hardLinkRunFiles :: (MonadMask m, PrimMonad m) - => ActionRegistry m - -> HasFS m h + => HasFS m h -> HasBlockIO m h + -> ActionRegistry m -> RunFsPaths -> RunFsPaths -> m () -hardLinkRunFiles reg hfs hbio sourceRunFsPaths targetRunFsPaths = do +hardLinkRunFiles hfs hbio reg sourceRunFsPaths targetRunFsPaths = do let sourcePaths = pathsForRunFiles sourceRunFsPaths targetPaths = pathsForRunFiles targetRunFsPaths - sequenceA_ (hardLink reg hfs hbio <$> sourcePaths <*> targetPaths) - hardLink reg hfs hbio (runChecksumsPath sourceRunFsPaths) (runChecksumsPath targetRunFsPaths) + sequenceA_ (hardLink hfs hbio reg <$> sourcePaths <*> targetPaths) + hardLink hfs hbio reg (runChecksumsPath sourceRunFsPaths) (runChecksumsPath targetRunFsPaths) {-# SPECIALISE hardLink :: - ActionRegistry IO - -> HasFS IO h + HasFS IO h -> HasBlockIO IO h + -> ActionRegistry IO -> FS.FsPath -> FS.FsPath -> IO () #-} --- | @'hardLink' reg hfs hbio sourcePath targetPath@ creates a hard link from +-- | @'hardLink' hfs hbio reg sourcePath targetPath@ creates a hard link from -- @sourcePath@ to @targetPath@. hardLink :: (MonadMask m, PrimMonad m) - => ActionRegistry m - -> HasFS m h + => HasFS m h -> HasBlockIO m h + -> ActionRegistry m -> FS.FsPath -> FS.FsPath -> m () -hardLink reg hfs hbio sourcePath targetPath = do +hardLink hfs hbio reg sourcePath targetPath = do withRollback_ reg (FS.createHardLink hbio sourcePath targetPath) (FS.removeFile hfs targetPath) @@ -561,23 +792,21 @@ hardLink reg hfs hbio sourcePath targetPath = do {-# SPECIALISE copyFile :: - ActionRegistry IO - -> HasFS IO h - -> HasBlockIO IO h + HasFS IO h + -> ActionRegistry IO -> FS.FsPath -> FS.FsPath -> IO () #-} --- | @'copyFile' reg hfs hbio source target@ copies the @source@ path to the @target@ path. +-- | @'copyFile' hfs reg source target@ copies the @source@ path to the @target@ path. copyFile :: (MonadMask m, PrimMonad m) - => ActionRegistry m - -> HasFS m h - -> HasBlockIO m h + => HasFS m h + -> ActionRegistry m -> FS.FsPath -> FS.FsPath -> m () -copyFile reg hfs _hbio sourcePath targetPath = +copyFile hfs reg sourcePath targetPath = flip (withRollback_ reg) (FS.removeFile hfs targetPath) $ FS.withFile hfs sourcePath FS.ReadMode $ \sourceHandle -> FS.withFile hfs targetPath (FS.WriteMode FS.MustBeNew) $ \targetHandle -> do diff --git a/src/Database/LSMTree/Internal/Snapshot/Codec.hs b/src/Database/LSMTree/Internal/Snapshot/Codec.hs index 421905259..814d2ad41 100644 --- a/src/Database/LSMTree/Internal/Snapshot/Codec.hs +++ b/src/Database/LSMTree/Internal/Snapshot/Codec.hs @@ -34,6 +34,9 @@ import Database.LSMTree.Internal.Entry import Database.LSMTree.Internal.MergeSchedule import Database.LSMTree.Internal.MergingRun (NumRuns (..)) import qualified Database.LSMTree.Internal.MergingRun as MR +import Database.LSMTree.Internal.RunBuilder (IndexType (..), + RunBloomFilterAlloc (..), RunDataCaching (..), + RunParams (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Snapshot import qualified System.FS.API as FS @@ -146,6 +149,7 @@ encodeSnapshotMetaData = toLazyByteString . encode . Versioned decodeSnapshotMetaData :: ByteString -> Either DeserialiseFailure SnapshotMetaData decodeSnapshotMetaData bs = second (getVersioned . snd) (deserialiseFromBytes decode bs) + {------------------------------------------------------------------------------- Encoding and decoding -------------------------------------------------------------------------------} @@ -156,7 +160,7 @@ class Encode a where -- | Decoder that is not parameterised by a 'SnapshotVersion'. -- -- Used only for 'SnapshotVersion' and 'Versioned', which live outside the --- 'SnapshotMetaData' type hierachy. +-- 'SnapshotMetaData' type hierarchy. class Decode a where decode :: Decoder s a @@ -217,23 +221,25 @@ instance Decode SnapshotVersion where -- SnapshotMetaData instance Encode SnapshotMetaData where - encode (SnapshotMetaData label tableType config writeBuffer levels) = - encodeListLen 5 + encode (SnapshotMetaData label tableType config writeBuffer levels mergingTree) = + encodeListLen 6 <> encode label <> encode tableType <> encode config <> encode writeBuffer <> encode levels + <> encodeMaybe mergingTree instance DecodeVersioned SnapshotMetaData where decodeVersioned ver@V0 = do - _ <- decodeListLenOf 5 + _ <- decodeListLenOf 6 SnapshotMetaData <$> decodeVersioned ver <*> decodeVersioned ver <*> decodeVersioned ver <*> decodeVersioned ver <*> decodeVersioned ver + <*> decodeMaybe ver -- SnapshotLabel @@ -259,6 +265,25 @@ instance DecodeVersioned SnapshotTableType where 2 -> pure SnapFullTable _ -> fail ("[SnapshotTableType] Unexpected tag: " <> show tag) +instance Encode SnapshotRun where + encode SnapshotRun { snapRunNumber, snapRunCaching, snapRunIndex } = + encodeListLen 4 + <> encodeWord 0 + <> encode snapRunNumber + <> encode snapRunCaching + <> encode snapRunIndex + +instance DecodeVersioned SnapshotRun where + decodeVersioned v@V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (4, 0) -> do snapRunNumber <- decodeVersioned v + snapRunCaching <- decodeVersioned v + snapRunIndex <- decodeVersioned v + pure SnapshotRun{..} + _ -> fail ("[SnapshotRun] Unexpected combination of list length and tag: " <> show (n, tag)) + {------------------------------------------------------------------------------- Encoding and decoding: TableConfig -------------------------------------------------------------------------------} @@ -342,6 +367,75 @@ instance Encode NumEntries where instance DecodeVersioned NumEntries where decodeVersioned V0 = NumEntries <$> decodeInt +-- RunParams and friends + +instance Encode RunParams where + encode RunParams { runParamCaching, runParamAlloc, runParamIndex } = + encodeListLen 4 + <> encodeWord 0 + <> encode runParamCaching + <> encode runParamAlloc + <> encode runParamIndex + +instance DecodeVersioned RunParams where + decodeVersioned v@V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (4, 0) -> do runParamCaching <- decodeVersioned v + runParamAlloc <- decodeVersioned v + runParamIndex <- decodeVersioned v + pure RunParams{..} + _ -> fail ("[RunParams] Unexpected combination of list length and tag: " <> show (n, tag)) + +instance Encode RunDataCaching where + encode CacheRunData = encodeWord 0 + encode NoCacheRunData = encodeWord 1 + +instance DecodeVersioned RunDataCaching where + decodeVersioned V0 = do + tag <- decodeWord + case tag of + 0 -> pure CacheRunData + 1 -> pure NoCacheRunData + _ -> fail ("[RunDataCaching] Unexpected tag: " <> show tag) + +instance Encode IndexType where + encode Ordinary = encodeWord 0 + encode Compact = encodeWord 1 + +instance DecodeVersioned IndexType where + decodeVersioned V0 = do + tag <- decodeWord + case tag of + 0 -> pure Ordinary + 1 -> pure Compact + _ -> fail ("[IndexType] Unexpected tag: " <> show tag) + +instance Encode RunBloomFilterAlloc where + encode (RunAllocFixed bits) = + encodeListLen 2 + <> encodeWord 0 + <> encodeWord64 bits + encode (RunAllocRequestFPR fpr) = + encodeListLen 2 + <> encodeWord 1 + <> encodeDouble fpr + encode (RunAllocMonkey bits) = + encodeListLen 2 + <> encodeWord 2 + <> encodeWord64 bits + +instance DecodeVersioned RunBloomFilterAlloc where + decodeVersioned V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (2, 0) -> RunAllocFixed <$> decodeWord64 + (2, 1) -> RunAllocRequestFPR <$> decodeDouble + (2, 2) -> RunAllocMonkey <$> decodeWord64 + _ -> fail ("[RunBloomFilterAlloc] Unexpected combination of list length and tag: " <> show (n, tag)) + -- BloomFilterAlloc instance Encode BloomFilterAlloc where @@ -427,41 +521,33 @@ instance DecodeVersioned MergeSchedule where -- SnapLevels -instance Encode (SnapLevels RunNumber) where - encode (SnapLevels levels) = - encodeListLen (fromIntegral (V.length levels)) - <> V.foldMap encode levels +instance Encode r => Encode (SnapLevels r) where + encode (SnapLevels levels) = encode levels -instance DecodeVersioned (SnapLevels RunNumber) where - decodeVersioned v@V0 = do - n <- decodeListLen - SnapLevels <$> V.replicateM n (decodeVersioned v) +instance DecodeVersioned r => DecodeVersioned (SnapLevels r) where + decodeVersioned v@V0 = SnapLevels <$> decodeVersioned v -- SnapLevel -instance Encode (SnapLevel RunNumber) where +instance Encode r => Encode (SnapLevel r) where encode (SnapLevel incomingRuns residentRuns) = encodeListLen 2 <> encode incomingRuns <> encode residentRuns -instance DecodeVersioned (SnapLevel RunNumber) where +instance DecodeVersioned r => DecodeVersioned (SnapLevel r) where decodeVersioned v@V0 = do _ <- decodeListLenOf 2 SnapLevel <$> decodeVersioned v <*> decodeVersioned v --- Vector RunNumber +-- Vector -instance Encode (V.Vector RunNumber) where - encode rns = - encodeListLen (fromIntegral (V.length rns)) - <> V.foldMap encode rns +instance Encode r => Encode (V.Vector r) where + encode = encodeVector -instance DecodeVersioned (V.Vector RunNumber) where - decodeVersioned v@V0 = do - n <- decodeListLen - V.replicateM n (decodeVersioned v) +instance DecodeVersioned r => DecodeVersioned (V.Vector r) where + decodeVersioned = decodeVector -- RunNumber @@ -473,30 +559,29 @@ instance DecodeVersioned RunNumber where -- SnapIncomingRun -instance Encode (SnapIncomingRun RunNumber) where - encode (SnapMergingRun mpfl nr md nc smrs) = - encodeListLen 6 +instance Encode r => Encode (SnapIncomingRun r) where + encode (SnapIncomingMergingRun mpfl nd nc smrs) = + encodeListLen 5 <> encodeWord 0 <> encode mpfl - <> encode nr - <> encode md + <> encode nd <> encode nc <> encode smrs - encode (SnapSingleRun x) = + encode (SnapIncomingSingleRun x) = encodeListLen 2 <> encodeWord 1 <> encode x -instance DecodeVersioned (SnapIncomingRun RunNumber) where +instance DecodeVersioned r => DecodeVersioned (SnapIncomingRun r) where decodeVersioned v@V0 = do n <- decodeListLen tag <- decodeWord case (n, tag) of - (6, 0) -> SnapMergingRun <$> - decodeVersioned v <*> decodeVersioned v <*> decodeVersioned v <*> - decodeVersioned v <*> decodeVersioned v - (2, 1) -> SnapSingleRun <$> decodeVersioned v - _ -> fail ("[SnapMergingRun] Unexpected combination of list length and tag: " <> show (n, tag)) + (5, 0) -> SnapIncomingMergingRun + <$> decodeVersioned v <*> decodeVersioned v + <*> decodeVersioned v <*> decodeVersioned v + (2, 1) -> SnapIncomingSingleRun <$> decodeVersioned v + _ -> fail ("[SnapIncomingRun] Unexpected combination of list length and tag: " <> show (n, tag)) -- NumRuns @@ -520,29 +605,42 @@ instance DecodeVersioned MergePolicyForLevel where 1 -> pure LevelLevelling _ -> fail ("[MergePolicyForLevel] Unexpected tag: " <> show tag) --- SnapMergingRunState +-- SnapMergingRun -instance Encode t => Encode (SnapMergingRunState t RunNumber) where - encode (SnapCompletedMerge x) = - encodeListLen 2 +instance (Encode t, Encode r) => Encode (SnapMergingRun t r) where + encode (SnapCompletedMerge nr md r) = + encodeListLen 4 <> encodeWord 0 - <> encode x - encode (SnapOngoingMerge rs mt) = - encodeListLen 3 + <> encode nr + <> encode md + <> encode r + encode (SnapOngoingMerge rp mc rs mt) = + encodeListLen 5 <> encodeWord 1 + <> encode rp + <> encode mc <> encode rs <> encode mt -instance DecodeVersioned t => DecodeVersioned (SnapMergingRunState t RunNumber) where +instance (DecodeVersioned t, DecodeVersioned r) => DecodeVersioned (SnapMergingRun t r) where decodeVersioned v@V0 = do n <- decodeListLen tag <- decodeWord case (n, tag) of - (2, 0) -> SnapCompletedMerge <$> decodeVersioned v - (3, 1) -> SnapOngoingMerge <$> decodeVersioned v <*> decodeVersioned v - _ -> fail ("[SnapMergingRunState] Unexpected combination of list length and tag: " <> show (n, tag)) + (4, 0) -> SnapCompletedMerge <$> decodeVersioned v + <*> decodeVersioned v + <*> decodeVersioned v + (5, 1) -> SnapOngoingMerge <$> decodeVersioned v <*> decodeVersioned v + <*> decodeVersioned v <*> decodeVersioned v + _ -> fail ("[SnapMergingRun] Unexpected combination of list length and tag: " <> show (n, tag)) --- NominalCredits and MergeDebt +-- NominalDebt, NominalCredits, MergeDebt and MergeCredits + +instance Encode NominalDebt where + encode (NominalDebt x) = encodeInt x + +instance DecodeVersioned NominalDebt where + decodeVersioned V0 = NominalDebt <$> decodeInt instance Encode NominalCredits where encode (NominalCredits x) = encodeInt x @@ -556,6 +654,12 @@ instance Encode MergeDebt where instance DecodeVersioned MergeDebt where decodeVersioned V0 = (MergeDebt . MergeCredits) <$> decodeInt +instance Encode MergeCredits where + encode (MergeCredits x) = encodeInt x + +instance DecodeVersioned MergeCredits where + decodeVersioned V0 = MergeCredits <$> decodeInt + -- MergeType instance Encode MR.LevelMergeType where @@ -591,3 +695,121 @@ instance DecodeVersioned MR.TreeMergeType where 1 -> pure MR.MergeLevel 2 -> pure MR.MergeUnion _ -> fail ("[TreeMergeType] Unexpected tag: " <> show tag) + +{------------------------------------------------------------------------------- + Encoding and decoding: SnapMergingTree +-------------------------------------------------------------------------------} + +-- SnapMergingTree + +instance Encode r => Encode (SnapMergingTree r) where + encode (SnapMergingTree tState) = encode tState + +instance DecodeVersioned r => DecodeVersioned (SnapMergingTree r) where + decodeVersioned ver@V0 = SnapMergingTree <$> decodeVersioned ver + +-- SnapMergingTreeState + +instance Encode r => Encode (SnapMergingTreeState r) where + encode (SnapCompletedTreeMerge x) = + encodeListLen 2 + <> encodeWord 0 + <> encode x + encode (SnapPendingTreeMerge x) = + encodeListLen 2 + <> encodeWord 1 + <> encode x + encode (SnapOngoingTreeMerge smrs) = + encodeListLen 2 + <> encodeWord 2 + <> encode smrs + +instance DecodeVersioned r => DecodeVersioned (SnapMergingTreeState r) where + decodeVersioned v@V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (2, 0) -> SnapCompletedTreeMerge <$> decodeVersioned v + (2, 1) -> SnapPendingTreeMerge <$> decodeVersioned v + (2, 2) -> SnapOngoingTreeMerge <$> decodeVersioned v + _ -> fail ("[SnapMergingTreeState] Unexpected combination of list length and tag: " <> show (n, tag)) + +-- SnapPendingMerge + +instance Encode r => Encode (SnapPendingMerge r) where + encode (SnapPendingLevelMerge pe mt) = + encodeListLen 3 + <> encodeWord 0 + <> encodeList pe + <> encodeMaybe mt + encode (SnapPendingUnionMerge mts) = + encodeListLen 2 + <> encodeWord 1 + <> encodeList mts + +instance DecodeVersioned r => DecodeVersioned (SnapPendingMerge r) where + decodeVersioned v@V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (3, 0) -> SnapPendingLevelMerge <$> decodeList v <*> decodeMaybe v + (2, 1) -> SnapPendingUnionMerge <$> decodeList v + _ -> fail ("[SnapPendingMerge] Unexpected combination of list length and tag: " <> show (n, tag)) + +-- SnapPreExistingRun + +instance Encode r => Encode (SnapPreExistingRun r) where + encode (SnapPreExistingRun x) = + encodeListLen 2 + <> encodeWord 0 + <> encode x + encode (SnapPreExistingMergingRun smrs) = + encodeListLen 2 + <> encodeWord 1 + <> encode smrs + +instance DecodeVersioned r => DecodeVersioned (SnapPreExistingRun r) where + decodeVersioned v@V0 = do + n <- decodeListLen + tag <- decodeWord + case (n, tag) of + (2, 0) -> SnapPreExistingRun <$> decodeVersioned v + (2, 1) -> SnapPreExistingMergingRun <$> decodeVersioned v + _ -> fail ("[SnapPreExistingRun] Unexpected combination of list length and tag: " <> show (n, tag)) + +-- Utilities for encoding/decoding Maybe values + +--Note: the Maybe encoding cannot be nested like (Maybe (Maybe a)), but it is +-- ok for fields of records. +encodeMaybe :: Encode a => Maybe a -> Encoding +encodeMaybe = \case + Nothing -> encodeNull + Just en -> encode en + +decodeMaybe :: DecodeVersioned a => SnapshotVersion -> Decoder s (Maybe a) +decodeMaybe v@V0 = do + tok <- peekTokenType + case tok of + TypeNull -> Nothing <$ decodeNull + _ -> Just <$> decodeVersioned v + +encodeList :: Encode a => [a] -> Encoding +encodeList xs = + encodeListLen (fromIntegral (length xs)) + <> foldr (\x r -> encode x <> r) mempty xs + +decodeList :: DecodeVersioned a => SnapshotVersion -> Decoder s [a] +decodeList v = do + n <- decodeListLen + decodeSequenceLenN (flip (:)) [] reverse n (decodeVersioned v) + +encodeVector :: Encode a => V.Vector a -> Encoding +encodeVector xs = + encodeListLen (fromIntegral (V.length xs)) + <> foldr (\x r -> encode x <> r) mempty xs + +decodeVector :: DecodeVersioned a => SnapshotVersion -> Decoder s (V.Vector a) +decodeVector v = do + n <- decodeListLen + decodeSequenceLenN (flip (:)) [] (V.reverse . V.fromList) + n (decodeVersioned v) diff --git a/test/Test/Database/LSMTree/Internal/Merge.hs b/test/Test/Database/LSMTree/Internal/Merge.hs index 0363ce24a..e4aa5894b 100644 --- a/test/Test/Database/LSMTree/Internal/Merge.hs +++ b/test/Test/Database/LSMTree/Internal/Merge.hs @@ -21,7 +21,6 @@ import Database.LSMTree.Internal.PageAcc (entryWouldFitInPage) import Database.LSMTree.Internal.Paths (RunFsPaths (..), pathsForRunFiles) import qualified Database.LSMTree.Internal.Run as Run -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Serialise import Database.LSMTree.Internal.UniqCounter @@ -163,8 +162,8 @@ prop_AbortMerge fs hbio mergeType (Positive stepSize) (SmallList wbs) = do wbs' = fmap serialiseRunData wbs makeInProgressMerge path runs = - Merge.new fs hbio Run.CacheRunData (RunAllocFixed 10) Index.Compact - mergeType mappendValues path (V.fromList runs) >>= \case + Merge.new fs hbio defaultRunParams mergeType mappendValues + path (V.fromList runs) >>= \case Nothing -> return Nothing -- not in progress Just merge -> do -- just do a few steps once, ideally not completing the merge @@ -190,8 +189,8 @@ mergeRuns :: [Ref (Run.Run IO h)] -> IO (Int, Ref (Run.Run IO h)) mergeRuns fs hbio mergeType (Positive stepSize) fsPath runs = do - Merge.new fs hbio Run.CacheRunData (RunAllocFixed 10) Index.Compact - mergeType mappendValues fsPath (V.fromList runs) + Merge.new fs hbio defaultRunParams mergeType mappendValues + fsPath (V.fromList runs) >>= \case Just m -> Merge.stepsToCompletionCounted m stepSize Nothing -> (,) 0 <$> unsafeCreateRunAt fs hbio Index.Compact fsPath diff --git a/test/Test/Database/LSMTree/Internal/Run.hs b/test/Test/Database/LSMTree/Internal/Run.hs index a42360b49..db4a670ab 100644 --- a/test/Test/Database/LSMTree/Internal/Run.hs +++ b/test/Test/Database/LSMTree/Internal/Run.hs @@ -201,7 +201,7 @@ prop_WriteAndOpen fs hbio wb = withActionRegistry $ \reg -> do let paths = Run.runFsPaths written paths' = paths { runNumber = RunNumber 17} - hardLinkRunFiles reg fs hbio paths paths' + hardLinkRunFiles fs hbio reg paths paths' loaded <- openFromDisk fs hbio CacheRunData Index.Compact (simplePath 17) Run.size written @=? Run.size loaded diff --git a/test/Test/Database/LSMTree/Internal/RunBuilder.hs b/test/Test/Database/LSMTree/Internal/RunBuilder.hs index ed3fac40d..618531948 100644 --- a/test/Test/Database/LSMTree/Internal/RunBuilder.hs +++ b/test/Test/Database/LSMTree/Internal/RunBuilder.hs @@ -4,10 +4,9 @@ module Test.Database.LSMTree.Internal.RunBuilder (tests) where import Control.Monad.Class.MonadThrow import Data.Foldable (traverse_) +import Database.LSMTree.Extras.RunData (defaultRunParams) import Database.LSMTree.Internal.Entry (NumEntries (..)) -import qualified Database.LSMTree.Internal.Index as Index (IndexType (Compact)) import Database.LSMTree.Internal.Paths (RunFsPaths (..)) -import Database.LSMTree.Internal.RunAcc (RunBloomFilterAlloc (..)) import qualified Database.LSMTree.Internal.RunBuilder as RunBuilder import Database.LSMTree.Internal.RunNumber import qualified System.FS.API as FS @@ -48,7 +47,7 @@ prop_newInExistingDir hfs hbio = do let runDir = FS.mkFsPath ["a", "b", "c"] FS.createDirectoryIfMissing hfs True runDir bracket - (try (RunBuilder.new hfs hbio (RunFsPaths runDir (RunNumber 17)) (NumEntries 0) (RunAllocFixed 10) Index.Compact)) + (try (RunBuilder.new hfs hbio defaultRunParams (RunFsPaths runDir (RunNumber 17)) (NumEntries 0))) (traverse_ RunBuilder.close) $ pure . \case Left e@FS.FsError{} -> counterexample ("expected a success, but got: " <> show e) $ property False @@ -59,7 +58,7 @@ prop_newInNonExistingDir :: HasFS IO h -> FS.HasBlockIO IO h -> IO Property prop_newInNonExistingDir hfs hbio = do let runDir = FS.mkFsPath ["a", "b", "c"] bracket - (try (RunBuilder.new hfs hbio (RunFsPaths runDir (RunNumber 17)) (NumEntries 0) (RunAllocFixed 10) Index.Compact)) + (try (RunBuilder.new hfs hbio defaultRunParams (RunFsPaths runDir (RunNumber 17)) (NumEntries 0))) (traverse_ RunBuilder.close) $ pure . \case Left FS.FsError{} -> property True Right _ -> @@ -73,10 +72,10 @@ prop_newTwice :: HasFS IO h -> FS.HasBlockIO IO h -> IO Property prop_newTwice hfs hbio = do let runDir = FS.mkFsPath [] bracket - (RunBuilder.new hfs hbio (RunFsPaths runDir (RunNumber 17)) (NumEntries 0) (RunAllocFixed 10) Index.Compact) + (RunBuilder.new hfs hbio defaultRunParams (RunFsPaths runDir (RunNumber 17)) (NumEntries 0)) RunBuilder.close $ \_ -> bracket - (try (RunBuilder.new hfs hbio (RunFsPaths runDir (RunNumber 17)) (NumEntries 0) (RunAllocFixed 10) Index.Compact)) + (try (RunBuilder.new hfs hbio defaultRunParams (RunFsPaths runDir (RunNumber 17)) (NumEntries 0))) (traverse_ RunBuilder.close) $ pure . \case Left FS.FsError{} -> property True Right _ -> diff --git a/test/Test/Database/LSMTree/Internal/Snapshot/Codec.hs b/test/Test/Database/LSMTree/Internal/Snapshot/Codec.hs index 4568d900e..c86d5a65f 100644 --- a/test/Test/Database/LSMTree/Internal/Snapshot/Codec.hs +++ b/test/Test/Database/LSMTree/Internal/Snapshot/Codec.hs @@ -17,6 +17,8 @@ import Database.LSMTree.Internal.Config import Database.LSMTree.Internal.Entry import Database.LSMTree.Internal.MergeSchedule import Database.LSMTree.Internal.MergingRun +import Database.LSMTree.Internal.RunBuilder (IndexType (..), + RunBloomFilterAlloc (..), RunDataCaching (..)) import Database.LSMTree.Internal.RunNumber import Database.LSMTree.Internal.Snapshot import Database.LSMTree.Internal.Snapshot.Codec @@ -152,6 +154,7 @@ testAll test = [ test (Proxy @SnapshotMetaData) , test (Proxy @SnapshotLabel) , test (Proxy @SnapshotTableType) + , test (Proxy @SnapshotRun) -- TableConfig , test (Proxy @TableConfig) , test (Proxy @MergePolicy) @@ -163,18 +166,28 @@ testAll test = [ , test (Proxy @DiskCachePolicy) , test (Proxy @MergeSchedule) -- SnapLevels - , test (Proxy @(SnapLevels RunNumber)) - , test (Proxy @(SnapLevel RunNumber)) - , test (Proxy @(V.Vector RunNumber)) + , test (Proxy @(SnapLevels SnapshotRun)) + , test (Proxy @(SnapLevel SnapshotRun)) + , test (Proxy @(V.Vector SnapshotRun)) , test (Proxy @RunNumber) - , test (Proxy @(SnapIncomingRun RunNumber)) + , test (Proxy @(SnapIncomingRun SnapshotRun)) , test (Proxy @NumRuns) , test (Proxy @MergePolicyForLevel) - , test (Proxy @(SnapMergingRunState LevelMergeType RunNumber)) + , test (Proxy @RunDataCaching) + , test (Proxy @RunBloomFilterAlloc) + , test (Proxy @IndexType) + , test (Proxy @RunParams) + , test (Proxy @(SnapMergingRun LevelMergeType SnapshotRun)) , test (Proxy @MergeDebt) + , test (Proxy @MergeCredits) + , test (Proxy @NominalDebt) , test (Proxy @NominalCredits) , test (Proxy @LevelMergeType) , test (Proxy @TreeMergeType) + , test (Proxy @(SnapMergingTree SnapshotRun)) + , test (Proxy @(SnapMergingTreeState SnapshotRun)) + , test (Proxy @(SnapPendingMerge SnapshotRun)) + , test (Proxy @(SnapPreExistingRun SnapshotRun)) ] {------------------------------------------------------------------------------- @@ -192,10 +205,12 @@ deriving newtype instance Arbitrary a => Arbitrary (Versioned a) -------------------------------------------------------------------------------} instance Arbitrary SnapshotMetaData where - arbitrary = SnapshotMetaData <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary - shrink (SnapshotMetaData a b c d e) = - [ SnapshotMetaData a' b' c' d' e' - | (a', b', c', d', e') <- shrink (a, b, c, d, e)] + arbitrary = SnapshotMetaData <$> + arbitrary <*> arbitrary <*> arbitrary <*> + arbitrary <*> arbitrary <*> arbitrary + shrink (SnapshotMetaData a b c d e f) = + [ SnapshotMetaData a' b' c' d' e' f' + | (a', b', c', d', e', f') <- shrink (a, b, c, d, e, f)] deriving newtype instance Arbitrary SnapshotLabel @@ -203,6 +218,12 @@ instance Arbitrary SnapshotTableType where arbitrary = elements [SnapNormalTable, SnapMonoidalTable] shrink _ = [] +instance Arbitrary SnapshotRun where + arbitrary = SnapshotRun <$> arbitrary <*> arbitrary <*> arbitrary + shrink (SnapshotRun a b c) = + [ SnapshotRun a' b' c' + | (a', b', c') <- shrink (a, b, c)] + {------------------------------------------------------------------------------- Arbitrary: TableConfig -------------------------------------------------------------------------------} @@ -258,13 +279,13 @@ instance Arbitrary MergeSchedule where Arbitrary: SnapLevels -------------------------------------------------------------------------------} -instance Arbitrary (SnapLevels RunNumber) where +instance Arbitrary r => Arbitrary (SnapLevels r) where arbitrary = do n <- chooseInt (0, 10) SnapLevels . V.fromList <$> vector n shrink (SnapLevels x) = SnapLevels . V.fromList <$> shrink (V.toList x) -instance Arbitrary (SnapLevel RunNumber) where +instance Arbitrary r => Arbitrary (SnapLevel r) where arbitrary = SnapLevel <$> arbitrary <*> arbitraryShortVector shrink (SnapLevel a b) = [SnapLevel a' b' | (a', b') <- shrink (a, b)] @@ -273,18 +294,23 @@ arbitraryShortVector = do n <- chooseInt (0, 5) V.fromList <$> vector n -deriving newtype instance Arbitrary RunNumber +instance Arbitrary RunNumber where + arbitrary = RunNumber <$> arbitrarySizedNatural + shrink (RunNumber n) = + -- fewer shrinks + [RunNumber 0 | n > 0] + ++ [RunNumber (n `div` 2) | n >= 2] -instance Arbitrary (SnapIncomingRun RunNumber) where +instance Arbitrary r => Arbitrary (SnapIncomingRun r) where arbitrary = oneof [ - SnapMergingRun <$> arbitrary <*> arbitrary <*> arbitrary - <*> arbitrary <*> arbitrary - , SnapSingleRun <$> arbitrary + SnapIncomingMergingRun <$> arbitrary <*> arbitrary + <*> arbitrary <*> arbitrary + , SnapIncomingSingleRun <$> arbitrary ] - shrink (SnapMergingRun a b c d e) = - [ SnapMergingRun a' b' c' d' e' - | (a', b', c', d', e') <- shrink (a, b, c, d, e) ] - shrink (SnapSingleRun a) = SnapSingleRun <$> shrink a + shrink (SnapIncomingMergingRun a b c d) = + [ SnapIncomingMergingRun a' b' c' d' + | (a', b', c', d') <- shrink (a, b, c, d) ] + shrink (SnapIncomingSingleRun a) = SnapIncomingSingleRun <$> shrink a deriving newtype instance Arbitrary NumRuns @@ -292,28 +318,135 @@ instance Arbitrary MergePolicyForLevel where arbitrary = elements [LevelTiering, LevelLevelling] shrink _ = [] -instance Arbitrary t => Arbitrary (SnapMergingRunState t RunNumber) where +instance (Arbitrary t, Arbitrary r) => Arbitrary (SnapMergingRun t r) where arbitrary = oneof [ - SnapCompletedMerge <$> arbitrary + SnapCompletedMerge <$> arbitrary <*> arbitrary <*> arbitrary , SnapOngoingMerge <$> arbitrary <*> arbitrary + <*> arbitrary <*> arbitrary ] - shrink (SnapCompletedMerge x) = SnapCompletedMerge <$> shrink x - shrink (SnapOngoingMerge x y) = - [ SnapOngoingMerge x' y' | (x', y') <- shrink (x, y) ] + shrink (SnapCompletedMerge a b c) = + [ SnapCompletedMerge a' b' c' + | (a', b', c') <- shrink (a, b, c) ] + shrink (SnapOngoingMerge a b c d) = + [ SnapOngoingMerge a' b' c' d' + | (a', b', c', d') <- shrink (a, b, c, d) ] deriving newtype instance Arbitrary MergeDebt deriving newtype instance Arbitrary MergeCredits +deriving newtype instance Arbitrary NominalDebt deriving newtype instance Arbitrary NominalCredits +{------------------------------------------------------------------------------- + RunParams +-------------------------------------------------------------------------------} + +instance Arbitrary RunParams where + arbitrary = RunParams <$> arbitrary <*> arbitrary <*> arbitrary + shrink (RunParams a b c) = + [ RunParams a' b' c' + | (a', b', c') <- shrink (a, b, c) ] + +instance Arbitrary RunDataCaching where + arbitrary = elements [CacheRunData, NoCacheRunData] + shrink _ = [] + +instance Arbitrary IndexType where + arbitrary = elements [Ordinary, Compact] + shrink _ = [] + +instance Arbitrary RunBloomFilterAlloc where + arbitrary = oneof [ + RunAllocFixed <$> arbitrary + , RunAllocRequestFPR <$> arbitrary + , RunAllocMonkey <$> arbitrary + ] + shrink (RunAllocFixed x) = RunAllocFixed <$> shrink x + shrink (RunAllocRequestFPR x) = RunAllocRequestFPR <$> shrink x + shrink (RunAllocMonkey x) = RunAllocMonkey <$> shrink x + {------------------------------------------------------------------------------- Show -------------------------------------------------------------------------------} deriving stock instance Show SnapshotMetaData +deriving stock instance Show SnapshotRun deriving stock instance Show r => Show (SnapLevels r) deriving stock instance Show r => Show (SnapLevel r) deriving stock instance Show r => Show (SnapIncomingRun r) -deriving stock instance (Show t, Show r) => Show (SnapMergingRunState t r) +deriving stock instance (Show t, Show r) => Show (SnapMergingRun t r) + +deriving stock instance Show r => Show (SnapMergingTree r) +deriving stock instance Show r => Show (SnapMergingTreeState r) +deriving stock instance Show r => Show (SnapPendingMerge r) +deriving stock instance Show r => Show (SnapPreExistingRun r) + deriving stock instance Show MergeDebt deriving stock instance Show MergeCredits +deriving stock instance Show NominalDebt deriving stock instance Show NominalCredits + +{------------------------------------------------------------------------------- + Arbitrary: SnapshotMetaData +-------------------------------------------------------------------------------} + +deriving newtype instance Arbitrary r => Arbitrary (SnapMergingTree r) + +instance Arbitrary r => Arbitrary (SnapMergingTreeState r) where + arbitrary = inductiveMergingTreeState inductiveLimit + shrink (SnapCompletedTreeMerge a) = SnapCompletedTreeMerge <$> shrink a + shrink (SnapPendingTreeMerge a) = SnapPendingTreeMerge <$> shrink a + shrink (SnapOngoingTreeMerge a) = SnapOngoingTreeMerge <$> shrink a + +instance Arbitrary r => Arbitrary (SnapPendingMerge r) where + arbitrary = inductivePendingTreeMerge inductiveLimit + shrink (SnapPendingUnionMerge a) = SnapPendingUnionMerge <$> shrinkList shrink a + shrink (SnapPendingLevelMerge a b) = + [ SnapPendingLevelMerge a' b' | a' <- shrinkList shrink a, b' <- shrink b ] + + +instance Arbitrary r => Arbitrary (SnapPreExistingRun r) where + arbitrary = oneof [ + SnapPreExistingRun <$> arbitrary + , SnapPreExistingMergingRun <$> arbitrary + ] + shrink (SnapPreExistingRun a) = SnapPreExistingRun <$> shrink a + shrink (SnapPreExistingMergingRun a) = SnapPreExistingMergingRun <$> shrink a + +-- | The 'SnapMergingTree' is an inductive data-type and therefore we must limit +-- the recursive depth at which new 'Arbitrary' sub-trees are generated. Hence +-- the need for this limit. This limit is the "gas" for the inductive functions. +-- At reach recursive call, the "gas" value decremented until it reaches zero. +-- Each inductive function ensures it never create a forest of sub-trees greater +-- than the /monotonically decreasing/ gas parameter it received. +inductiveLimit :: Int +inductiveLimit = 4 + +-- | +-- Generate an 'Arbitrary', "gas-limited" 'SnapMergingTree'. +inductiveSized :: Arbitrary r => Int -> Gen (SnapMergingTree r) +inductiveSized = fmap SnapMergingTree . inductiveMergingTreeState + +-- | +-- Generate an 'Arbitrary', "gas-limited" 'SnapMergingTreeState'. +inductiveMergingTreeState :: Arbitrary a => Int -> Gen (SnapMergingTreeState a) +inductiveMergingTreeState gas = oneof [ + SnapCompletedTreeMerge <$> arbitrary + , SnapPendingTreeMerge <$> inductivePendingTreeMerge gas + , SnapOngoingTreeMerge <$> arbitrary + ] + +-- | +-- Generate an 'Arbitrary', "gas-limited" 'SnapPendingMerge'. +inductivePendingTreeMerge :: Arbitrary a => Int -> Gen (SnapPendingMerge a) +inductivePendingTreeMerge gas = oneof [ + SnapPendingLevelMerge <$> genPreExistings <*> genMaybeSubTree + , SnapPendingUnionMerge <$> genListSubtrees + ] + where + subGen = inductiveSized . max 0 $ gas - 1 + -- Define custom generators to ensure that the sub-trees are less than + -- or equal to the "gas" parameter. + genPreExistings = genVectorsUpToBound gas arbitrary + genListSubtrees = genVectorsUpToBound gas subGen + genMaybeSubTree = oneof [ pure Nothing, Just <$> subGen ] + genVectorsUpToBound x gen = oneof $ flip vectorOf gen <$> [ 0 .. x ] diff --git a/test/Test/Database/LSMTree/Internal/Snapshot/Codec/Golden.hs b/test/Test/Database/LSMTree/Internal/Snapshot/Codec/Golden.hs index bed9a431f..c73d5cd3e 100644 --- a/test/Test/Database/LSMTree/Internal/Snapshot/Codec/Golden.hs +++ b/test/Test/Database/LSMTree/Internal/Snapshot/Codec/Golden.hs @@ -4,6 +4,7 @@ module Test.Database.LSMTree.Internal.Snapshot.Codec.Golden import Codec.CBOR.Write (toLazyByteString) import Control.Monad (when) +import Data.Bifunctor (second) import qualified Data.ByteString.Lazy as BSL (writeFile) import Data.Foldable (fold) import qualified Data.List as List @@ -15,9 +16,12 @@ import Database.LSMTree.Common (BloomFilterAlloc (..), import Database.LSMTree.Internal.Config (FencePointerIndex (..), MergePolicy (..), MergeSchedule (..), SizeRatio (..)) import Database.LSMTree.Internal.MergeSchedule - (MergePolicyForLevel (..), NominalCredits (..)) + (MergePolicyForLevel (..), NominalCredits (..), + NominalDebt (..)) import Database.LSMTree.Internal.MergingRun (NumRuns (..)) import qualified Database.LSMTree.Internal.MergingRun as MR +import Database.LSMTree.Internal.RunBuilder (IndexType (..), + RunBloomFilterAlloc (..), RunDataCaching (..)) import Database.LSMTree.Internal.RunNumber (RunNumber (..)) import Database.LSMTree.Internal.Snapshot import Database.LSMTree.Internal.Snapshot.Codec @@ -37,6 +41,7 @@ tests = handleOutputFiles . testGroup , testCodecSnapshotTableType , testCodecTableConfig , testCodecSnapLevels + , testCodecMergingTree ] -- | The mount point is defined as the location of the golden file data directory @@ -45,7 +50,7 @@ goldenDataMountPoint :: MountPoint goldenDataMountPoint = MountPoint "test/golden-file-data/snapshot-codec" -- | Delete output files on test-case success. --- Change the option here if this is undesireable. +-- Change the option here if this is undesirable. handleOutputFiles :: TestTree -> TestTree handleOutputFiles = Tasty.localOption Au.OnPass @@ -80,7 +85,7 @@ snapshotCodecTest name datum = outputAction = do -- Ensure that if the output file already exists, we remove it and -- re-write out the serialized data. This ensures that there are no - -- false-positives, false-negatives, or irrelavent I/O exceptions. + -- false-positives, false-negatives, or irrelevant I/O exceptions. removeIfExists snapshotFsPath BSL.writeFile snapshotHsPath . toLazyByteString $ encode datum @@ -93,7 +98,8 @@ testCodecSnapshotLabel = (tagC, valC) = basicTableConfig valD = basicRunNumber (tagE, valE) = basicSnapLevels - in (fuseAnnotations [tagA, tagB, tagC, tagE ], SnapshotMetaData valA valB valC valD valE) + (tagF, valF) = basicSnapMergingTree + in (fuseAnnotations [tagA, tagB, tagC, tagE, tagF ], SnapshotMetaData valA valB valC valD valE valF) in testCodecBuilder "SnapshotLabels" $ assembler <$> enumerateSnapshotLabel testCodecSnapshotTableType :: TestTree @@ -103,7 +109,8 @@ testCodecSnapshotTableType = (tagC, valC) = basicTableConfig valD = basicRunNumber (tagE, valE) = basicSnapLevels - in (fuseAnnotations [tagA, tagB, tagC, tagE ], SnapshotMetaData valA valB valC valD valE) + (tagF, valF) = basicSnapMergingTree + in (fuseAnnotations [tagA, tagB, tagC, tagE, tagF ], SnapshotMetaData valA valB valC valD valE valF) in testCodecBuilder "SnapshotTables" $ assembler <$> enumerateSnapshotTableType testCodecTableConfig :: TestTree @@ -113,7 +120,8 @@ testCodecTableConfig = (tagB, valB) = basicSnapshotTableType valD = basicRunNumber (tagE, valE) = basicSnapLevels - in (fuseAnnotations [tagA, tagB, tagC, tagE ], SnapshotMetaData valA valB valC valD valE) + (tagF, valF) = basicSnapMergingTree + in (fuseAnnotations [tagA, tagB, tagC, tagE, tagF ], SnapshotMetaData valA valB valC valD valE valF) in testCodecBuilder "SnapshotConfig" $ assembler <$> enumerateTableConfig testCodecSnapLevels :: TestTree @@ -123,9 +131,21 @@ testCodecSnapLevels = (tagB, valB) = basicSnapshotTableType (tagC, valC) = basicTableConfig valD = basicRunNumber - in (fuseAnnotations [tagA, tagB, tagC, tagE ], SnapshotMetaData valA valB valC valD valE) + (tagF, valF) = basicSnapMergingTree + in (fuseAnnotations [tagA, tagB, tagC, tagE, tagF ], SnapshotMetaData valA valB valC valD valE valF) in testCodecBuilder "SnapshotLevels" $ assembler <$> enumerateSnapLevels +testCodecMergingTree :: TestTree +testCodecMergingTree = + let assembler (tagF, valF) = + let (tagA, valA) = basicSnapshotLabel + (tagB, valB) = basicSnapshotTableType + (tagC, valC) = basicTableConfig + valD = basicRunNumber + (tagE, valE) = basicSnapLevels + in (fuseAnnotations [tagA, tagB, tagC, tagE, tagF ], SnapshotMetaData valA valB valC valD valE valF) + in testCodecBuilder "SnapshotMergingTree" $ assembler <$> enumerateSnapMergingTree + testCodecBuilder :: TestName -> [(ComponentAnnotation, SnapshotMetaData)] -> TestTree testCodecBuilder tName metadata = testGroup tName $ uncurry snapshotCodecTest <$> metadata @@ -154,9 +174,12 @@ basicTableConfig = ( fuseAnnotations $ "T0" : replicate 4 blank, defaultTableCon basicRunNumber :: RunNumber basicRunNumber = enumerateRunNumbers -basicSnapLevels :: (ComponentAnnotation, SnapLevels RunNumber) +basicSnapLevels :: (ComponentAnnotation, SnapLevels SnapshotRun) basicSnapLevels = head enumerateSnapLevels +basicSnapMergingTree :: (ComponentAnnotation, Maybe (SnapMergingTree SnapshotRun)) +basicSnapMergingTree = head enumerateSnapMergingTree + {---------------- Enumeration of SnapshotMetaData sub-components ----------------} @@ -195,42 +218,50 @@ enumerateTableConfig = , (g, merge ) <- [("G0", OneShot), ("G1", Incremental)] ] -enumerateSnapLevels :: [(ComponentAnnotation, SnapLevels RunNumber)] +enumerateSnapLevels :: [(ComponentAnnotation, SnapLevels SnapshotRun)] enumerateSnapLevels = fmap (SnapLevels . V.singleton) <$> enumerateSnapLevel {---------------- Enumeration of SnapLevel sub-components ----------------} -enumerateSnapLevel :: [(ComponentAnnotation, SnapLevel RunNumber)] +enumerateSnapLevel :: [(ComponentAnnotation, SnapLevel SnapshotRun)] enumerateSnapLevel = do (a, run) <- enumerateSnapIncomingRun - (b, vec) <- enumerateVectorRunNumber + (b, vec) <- enumerateVectorRunInfo [( fuseAnnotations [ a, b ], SnapLevel run vec)] -enumerateSnapIncomingRun :: [(ComponentAnnotation, SnapIncomingRun RunNumber)] +enumerateSnapIncomingRun :: [(ComponentAnnotation, SnapIncomingRun SnapshotRun)] enumerateSnapIncomingRun = let inSnaps = [ (fuseAnnotations ["R1", a, b], - SnapMergingRun policy numRuns mergeDebt nominalCredits sState) + SnapIncomingMergingRun policy nominalDebt nominalCredits sState) | (a, policy ) <- [("P0", LevelTiering), ("P1", LevelLevelling)] - , numRuns <- NumRuns <$> [ magicNumber1 ] - , mergeDebt <- MR.MergeDebt <$> [ magicNumber2 ] - , nominalCredits <- NominalCredits <$> [ magicNumber1 ] - , (b, sState ) <- enumerateSnapMergingRunState enumerateLevelMergeType + , nominalDebt <- NominalDebt <$> [ magicNumber2 ] + , nominalCredits <- NominalCredits <$> [ magicNumber1 ] + , (b, sState ) <- enumerateSnapMergingRun enumerateLevelMergeType ] in fold - [ [(fuseAnnotations $ "R0" : replicate 4 blank, SnapSingleRun enumerateRunNumbers)] + [ [(fuseAnnotations $ "R0" : replicate 4 blank, + SnapIncomingSingleRun enumerateOpenRunInfo)] , inSnaps ] -enumerateSnapMergingRunState :: - [(ComponentAnnotation, t)] -> [(ComponentAnnotation, SnapMergingRunState t RunNumber)] -enumerateSnapMergingRunState mTypes = - (fuseAnnotations ["C0", blank, blank], SnapCompletedMerge enumerateRunNumbers) : - [ (fuseAnnotations ["C1", a, b], SnapOngoingMerge runVec mType) - | (a, runVec ) <- enumerateVectorRunNumber +enumerateSnapMergingRun :: + [(ComponentAnnotation, t)] + -> [(ComponentAnnotation, SnapMergingRun t SnapshotRun)] +enumerateSnapMergingRun mTypes = + [ (fuseAnnotations ["C0", blank, blank], + SnapCompletedMerge numRuns mergeDebt enumerateOpenRunInfo) + | numRuns <- NumRuns <$> [ magicNumber1 ] + , mergeDebt <- (MR.MergeDebt. MR.MergeCredits) <$> [ magicNumber2 ] + ] + ++ [ (fuseAnnotations ["C1", a, b], + SnapOngoingMerge runParams mergeCredits runVec mType) + | let runParams = enumerateRunParams + , mergeCredits <- MR.MergeCredits <$> [ magicNumber2 ] + , (a, runVec ) <- enumerateVectorRunInfo , (b, mType ) <- mTypes ] @@ -238,13 +269,73 @@ enumerateLevelMergeType :: [(ComponentAnnotation, MR.LevelMergeType)] enumerateLevelMergeType = [("L0", MR.MergeMidLevel), ("L1", MR.MergeLastLevel)] -enumerateVectorRunNumber :: [(ComponentAnnotation, Vector RunNumber)] -enumerateVectorRunNumber = +enumerateVectorRunInfo :: [(ComponentAnnotation, Vector SnapshotRun)] +enumerateVectorRunInfo = [ ("V0", mempty) - , ("V1", V.fromList [RunNumber magicNumber1]) - , ("V2", V.fromList [RunNumber magicNumber1, RunNumber magicNumber2 ]) + , ("V1", V.fromList [enumerateOpenRunInfo]) + , ("V2", V.fromList [enumerateOpenRunInfo, + enumerateOpenRunInfo { + snapRunNumber = RunNumber magicNumber2 + } ]) ] +{---------------- +Enumeration of SnapMergingTree sub-components +----------------} + +enumerateSnapMergingTree :: [(ComponentAnnotation, Maybe (SnapMergingTree SnapshotRun))] +enumerateSnapMergingTree = + let noneTrees = (fuseAnnotations $ "M0" : replicate 11 blank, Nothing) + someTrees = reannotate <$> enumerateSnapMergingTreeState True + reannotate (tag, val) = (fuseAnnotations ["M1", tag], Just val) + in noneTrees : someTrees + +enumerateSnapMergingTreeState :: Bool -> [(ComponentAnnotation, SnapMergingTree SnapshotRun)] +enumerateSnapMergingTreeState expandable = + let s0 = [ (fuseAnnotations $ "S0" : replicate 10 blank, SnapCompletedTreeMerge enumerateOpenRunInfo) ] + s1 = do + (tagX, valX) <- enumerateSnapPendingMerge expandable + [ (fuseAnnotations ["S1", tagX], SnapPendingTreeMerge valX) ] + s2 = do + (tagX, valX) <- enumerateSnapOngoingTreeMerge + [ (fuseAnnotations ["S2", tagX], valX) ] + in second SnapMergingTree <$> fold [ s0, s1, s2 ] + +enumerateSnapOngoingTreeMerge :: [(ComponentAnnotation, SnapMergingTreeState SnapshotRun)] +enumerateSnapOngoingTreeMerge = do + (tagX, valX) <- enumerateSnapMergingRun enumerateTreeMergeType + let value = SnapOngoingTreeMerge valX + pure ( fuseAnnotations $ ["G0", blank, tagX] <> replicate 5 blank, value ) + +enumerateSnapPendingMerge :: Bool -> [(ComponentAnnotation, SnapPendingMerge SnapshotRun)] +enumerateSnapPendingMerge expandable = + let (tagTrees, subTrees) + | not expandable = ("M0", []) + | otherwise = ("M1", snd <$> enumerateSnapMergingTreeState False) + headMay [] = Nothing + headMay (x:_) = Just x + prefix = do + extra <- [False, True ] + (tagPre, valPre) <- enumerateSnapPreExistingRun + (tagExt, valExt) <- + if extra + then second pure <$> enumerateSnapPreExistingRun + else [(fuseAnnotations $ replicate 4 blank, [])] + let preValues = [ valPre ] <> valExt + pure (fuseAnnotations [ "P0", tagPre, tagExt, tagTrees], SnapPendingLevelMerge preValues $ headMay subTrees) + in prefix <> [(fuseAnnotations $ fold [["P1"], replicate 8 blank, [tagTrees]], SnapPendingUnionMerge subTrees)] + +enumerateSnapPreExistingRun :: [(ComponentAnnotation, SnapPreExistingRun SnapshotRun)] +enumerateSnapPreExistingRun = + ( fuseAnnotations ("E0" : replicate 3 blank), SnapPreExistingRun enumerateOpenRunInfo) + : [ (fuseAnnotations ["E1", tagX], SnapPreExistingMergingRun valX) + | (tagX, valX) <- enumerateSnapMergingRun enumerateLevelMergeType + ] + +enumerateTreeMergeType :: [(ComponentAnnotation, MR.TreeMergeType)] +enumerateTreeMergeType = + [("T0", MR.MergeLevel), ("T1", MR.MergeUnion)] + {---------------- Enumeration of SnapshotMetaData sub-sub-components and so on... ----------------} @@ -266,6 +357,26 @@ enumerateDiskCachePolicy = enumerateRunNumbers :: RunNumber enumerateRunNumbers = RunNumber magicNumber2 +--TODO: use a proper enumeration, but don't cause a combinatorial explosion. +enumerateRunParams :: MR.RunParams +enumerateRunParams = + MR.RunParams { + MR.runParamCaching = NoCacheRunData, + MR.runParamAlloc = RunAllocFixed 10, + MR.runParamIndex = Compact + } + +--TODO: use a proper enumeration, but don't cause a combinatorial explosion of +-- golden tests. Perhaps do all combos as a direct golden test, but then where +-- it is embedded, just use one combo. +enumerateOpenRunInfo :: SnapshotRun +enumerateOpenRunInfo = + SnapshotRun { + snapRunNumber = enumerateRunNumbers, + snapRunCaching = CacheRunData, + snapRunIndex = Compact + } + -- Randomly chosen numbers magicNumber1, magicNumber2, magicNumber3 :: Enum e => e magicNumber1 = toEnum 42 diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..31ac1085a Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S0-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S0-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..9b1f35f62 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S0-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..590d4326b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..5bd0547d9 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..5b974736e Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..4486120d3 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..7667b0de6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..69dc6ace9 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..1fe79dfb1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..d8113504b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..47f1a17b2 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E0-__-__-__-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..649852ba1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..5a026e939 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..ac04197c4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..fb1b40ff3 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..410b4f2f4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..4d43bff91 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..e1de6317b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..1004eac79 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..fb21e975c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C0-__-__-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..a70e4e0e0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..d30f39da6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..c7f80bb2c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..6bfc12e36 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..8ac5a949d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..21651a04f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..0bdc26cd6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..32dfefbeb Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..6c2b022d4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L0-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..4ba683df5 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..e53ba2739 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..efe9fbd8b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..44b8ff73f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..f7b32ff5f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..427c00421 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..9fde7f875 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..e930b1da7 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..65f2f4c42 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V0-L1-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..c0474c641 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..15091bb69 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..ce09b41aa Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..390348d28 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..a0442d047 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..73db7d52b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..66a647878 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..64c3e9427 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..091957f8f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L0-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..0bd4d8660 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..3840573eb Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..55c7af36d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..bc8f1d25d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..ca7e10b40 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..fdae3e96e Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..8acfc2db5 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..7827791b6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..155b82ddd Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V1-L1-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..a2efb2dfd Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..4bc4707d1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..9fe7c8237 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..41cacfd41 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..9f9a75d60 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..9d7b18fa4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..f3bce082b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..5bc48a962 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..c72dd416b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L0-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E0-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E0-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..e750d3361 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E0-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C0-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C0-__-__-M1.snapshot.golden new file mode 100644 index 000000000..422987114 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C0-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L0-M1.snapshot.golden new file mode 100644 index 000000000..a5d95db80 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L1-M1.snapshot.golden new file mode 100644 index 000000000..72165c092 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V0-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L0-M1.snapshot.golden new file mode 100644 index 000000000..80d4542ae Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L1-M1.snapshot.golden new file mode 100644 index 000000000..23093dd7e Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V1-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L0-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L0-M1.snapshot.golden new file mode 100644 index 000000000..dfd41d7c9 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L0-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L1-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L1-M1.snapshot.golden new file mode 100644 index 000000000..056b3f0ac Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-E1-C1-V2-L1-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..ce4cb3107 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P0-E1-C1-V2-L1-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P1-__-__-__-__-__-__-__-__-M1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P1-__-__-__-__-__-__-__-__-M1.snapshot.golden new file mode 100644 index 000000000..fe11d1110 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S1-P1-__-__-__-__-__-__-__-__-M1.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C0-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C0-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..bbfd888bf Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C0-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T0-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T0-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..13b0419c0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T0-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T1-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T1-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..b032043d1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V0-T1-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T0-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T0-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..ff166cfbe Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T0-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T1-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T1-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..72c8f6c7c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V1-T1-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T0-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T0-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..582ae9dfa Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T0-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T1-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T1-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..402293641 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M1-S2-G0-__-C1-V2-T1-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index f64223e21..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..fad998201 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1.snapshot.golden deleted file mode 100644 index daec9a9d0..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..2ffe13fc2 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2.snapshot.golden deleted file mode 100644 index 4c19eaaa9..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R0-__-__-__-__-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5cd410e89 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0.snapshot.golden deleted file mode 100644 index af1821287..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8c3a69450 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1.snapshot.golden deleted file mode 100644 index 9fa29f27d..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..eeb5d16ce Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2.snapshot.golden deleted file mode 100644 index 73d5ba179..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C0-__-__-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..cd0d975f8 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0.snapshot.golden deleted file mode 100644 index c9d8ec05d..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..2c64fe9d7 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1.snapshot.golden deleted file mode 100644 index 2ab791ede..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8b0f3e641 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2.snapshot.golden deleted file mode 100644 index 28e95dea5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..ac6608cd5 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0.snapshot.golden deleted file mode 100644 index a45477ef1..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5b42fab71 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1.snapshot.golden deleted file mode 100644 index 43c6ed346..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..863567d0d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2.snapshot.golden deleted file mode 100644 index 5ffbdcdd6..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V0-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..176f2f6d2 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0.snapshot.golden deleted file mode 100644 index 3fd31cdbb..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..3be9ca0d6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1.snapshot.golden deleted file mode 100644 index ab3e2fa5e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..06c0cd520 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2.snapshot.golden deleted file mode 100644 index ac318f27a..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..fbe575dfb Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0.snapshot.golden deleted file mode 100644 index 7e98afdd0..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..32de5aa50 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1.snapshot.golden deleted file mode 100644 index c30beb6de..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..aaecb898c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2.snapshot.golden deleted file mode 100644 index 8e2e2425e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V1-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..12bdc571f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0.snapshot.golden deleted file mode 100644 index 391082117..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..bc9585187 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1.snapshot.golden deleted file mode 100644 index 15f5309a8..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..0aa8b5d84 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2.snapshot.golden deleted file mode 100644 index b2177c258..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..990451133 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0.snapshot.golden deleted file mode 100644 index d36d4b26b..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..d590f35d5 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1.snapshot.golden deleted file mode 100644 index 7c6db8f69..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..a29e1dcf9 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2.snapshot.golden deleted file mode 100644 index 551acf1c5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P0-C1-V2-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..d67a0f1c8 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0.snapshot.golden deleted file mode 100644 index 0c073099d..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..357762c7b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1.snapshot.golden deleted file mode 100644 index af82b738f..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5532f808e Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2.snapshot.golden deleted file mode 100644 index 87b38b7ab..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C0-__-__-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..2d5c85bf2 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0.snapshot.golden deleted file mode 100644 index 55c2bb2c3..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..38eab0038 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1.snapshot.golden deleted file mode 100644 index fa860497e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..bab8e83ed Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2.snapshot.golden deleted file mode 100644 index 64ff2d0b6..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..9f7e76f2f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0.snapshot.golden deleted file mode 100644 index 1290e2388..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..cd8b1e54d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1.snapshot.golden deleted file mode 100644 index 3aeea05a2..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..f248050c4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2.snapshot.golden deleted file mode 100644 index 7fad35275..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V0-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..f2c436a16 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0.snapshot.golden deleted file mode 100644 index 648e240c5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..da694d8d6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1.snapshot.golden deleted file mode 100644 index bd58702ed..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..95657829d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2.snapshot.golden deleted file mode 100644 index d5a385cf4..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..36e8c65aa Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0.snapshot.golden deleted file mode 100644 index 61da53a4c..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..2ea5bd4da Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1.snapshot.golden deleted file mode 100644 index 24d11390d..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..fd07e6788 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2.snapshot.golden deleted file mode 100644 index 0c07f9bf4..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V1-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5d6b789b8 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0.snapshot.golden deleted file mode 100644 index fb26e42a4..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..9d25a6f5f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1.snapshot.golden deleted file mode 100644 index 5d891aa85..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..2eddd844a Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2.snapshot.golden deleted file mode 100644 index 9b4018721..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L0-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c670c4e6c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0.snapshot.golden deleted file mode 100644 index fd63ab5e5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5c9cf09b6 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1.snapshot.golden deleted file mode 100644 index 7045efbd5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V1.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..ca304ccd0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2.snapshot.golden deleted file mode 100644 index 48e2ab483..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T0-__-__-__-__-R1-P1-C1-V2-L1-V2.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..dab3cbb94 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index e8e87c034..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..468dc3669 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index a6a6fa47c..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..327cbad86 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index cc88afacf..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..52bd7af22 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 0de4c0c07..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..dfda6dfe0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index ad2d71166..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8e4143b98 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index d7326f06c..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..3d72ef2c8 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 73560803b..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c287933e0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 9293ffbc0..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5334b5cd0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 31c3c55e6..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..234e4b582 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index e0298d100..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..e12a79c16 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 644ea33d1..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..d956e40b9 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 5c6208a65..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A0-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c3df18e18 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 9ec93c017..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c73128904 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 18e786c70..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..062740891 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 0fcd7c3c7..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..f74a3f99f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 776690030..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8a3759135 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 90d9a7699..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..e813f6aa7 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index c9e8daec4..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..ddaf8fd8e Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index d4824d34d..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..fa32573e1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 3bbc542d5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..3ea1e8eb0 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 0a1200ef1..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..f830ec211 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 1e7e27664..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..57c395cf8 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 9af0fbce5..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8234daef1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 68fc3795c..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A1-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..52f299e13 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index c1c48300f..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c5650c69c Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 3266ad74e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..bf58493b3 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index ddae3c196..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..f528ec127 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 658fe1a1e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..8eeb3458d Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index b96e3076e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..804b27aad Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index cd028899c..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I0-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..d74b65d4b Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 7e34d1a97..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..5b947f899 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 24fcd0f6b..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D0-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..71b1e465f Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index b9bacbae7..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..822640c00 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 84df01a0e..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D1-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..c7b036d54 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index bf4e8a2eb..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G0-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..1ec525ef1 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 8173c3803..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N0-T1-A2-I1-D2-G1-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..4fdc747cd Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index e928daf2a..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N1-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..12a7ce109 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index cfe2ab033..000000000 Binary files a/test/golden-file-data/snapshot-codec/B0-N2-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ diff --git a/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden b/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden new file mode 100644 index 000000000..9bd6a12c4 Binary files /dev/null and b/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0-M0-__-__-__-__-__-__-__-__-__-__-__.snapshot.golden differ diff --git a/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden b/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden deleted file mode 100644 index 9f56f7072..000000000 Binary files a/test/golden-file-data/snapshot-codec/B1-N0-T0-__-__-__-__-R0-__-__-__-__-V0.snapshot.golden and /dev/null differ