{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Ouroboros.Consensus.Storage.LedgerDB.V1.Snapshots
( loadSnapshot
, takeSnapshot
, snapshotToStatePath
, snapshotToTablesPath
) where
import Codec.CBOR.Encoding
import Codec.Serialise
import qualified Control.Monad as Monad
import Control.Monad.Except
import qualified Control.Monad.Trans as Trans (lift)
import Control.Tracer
import Data.Functor.Contravariant ((>$<))
import qualified Data.List as List
import Ouroboros.Consensus.Block
import Ouroboros.Consensus.Ledger.Abstract
import Ouroboros.Consensus.Ledger.Extended
import Ouroboros.Consensus.Ledger.SupportsProtocol
import Ouroboros.Consensus.Storage.LedgerDB.API
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots
import Ouroboros.Consensus.Storage.LedgerDB.V1.Args
import Ouroboros.Consensus.Storage.LedgerDB.V1.BackingStore
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.BackingStore as V1
import Ouroboros.Consensus.Storage.LedgerDB.V1.DbChangelog
import Ouroboros.Consensus.Storage.LedgerDB.V1.Lock
import Ouroboros.Consensus.Util.Args (Complete)
import Ouroboros.Consensus.Util.Enclose
import Ouroboros.Consensus.Util.IOLike
import System.FS.API
takeSnapshot ::
( IOLike m
, LedgerDbSerialiseConstraints blk
, LedgerSupportsProtocol blk
) =>
StrictTVar m (DbChangelog' blk) ->
CodecConfig blk ->
Tracer m (TraceSnapshotEvent blk) ->
SnapshotsFS m ->
BackingStore' m blk ->
Maybe String ->
ReadLocked m (Maybe (DiskSnapshot, RealPoint blk))
takeSnapshot :: forall (m :: * -> *) blk.
(IOLike m, LedgerDbSerialiseConstraints blk,
LedgerSupportsProtocol blk) =>
StrictTVar m (DbChangelog' blk)
-> CodecConfig blk
-> Tracer m (TraceSnapshotEvent blk)
-> SnapshotsFS m
-> BackingStore' m blk
-> Maybe String
-> ReadLocked m (Maybe (DiskSnapshot, RealPoint blk))
takeSnapshot StrictTVar m (DbChangelog' blk)
ldbvar CodecConfig blk
ccfg Tracer m (TraceSnapshotEvent blk)
tracer (SnapshotsFS SomeHasFS m
hasFS') BackingStore' m blk
backingStore Maybe String
suffix = m (Maybe (DiskSnapshot, RealPoint blk))
-> ReadLocked m (Maybe (DiskSnapshot, RealPoint blk))
forall (m :: * -> *) a. m a -> ReadLocked m a
readLocked (m (Maybe (DiskSnapshot, RealPoint blk))
-> ReadLocked m (Maybe (DiskSnapshot, RealPoint blk)))
-> m (Maybe (DiskSnapshot, RealPoint blk))
-> ReadLocked m (Maybe (DiskSnapshot, RealPoint blk))
forall a b. (a -> b) -> a -> b
$ do
state <- DbChangelog' blk -> ExtLedgerState blk EmptyMK
forall (l :: LedgerStateKind). DbChangelog l -> l EmptyMK
changelogLastFlushedState (DbChangelog' blk -> ExtLedgerState blk EmptyMK)
-> m (DbChangelog' blk) -> m (ExtLedgerState blk EmptyMK)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> StrictTVar m (DbChangelog' blk) -> m (DbChangelog' blk)
forall (m :: * -> *) a. MonadSTM m => StrictTVar m a -> m a
readTVarIO StrictTVar m (DbChangelog' blk)
ldbvar
case pointToWithOriginRealPoint (castPoint (getTip state)) of
WithOrigin (RealPoint blk)
Origin ->
Maybe (DiskSnapshot, RealPoint blk)
-> m (Maybe (DiskSnapshot, RealPoint blk))
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (DiskSnapshot, RealPoint blk)
forall a. Maybe a
Nothing
NotOrigin RealPoint blk
t -> do
let number :: Word64
number = SlotNo -> Word64
unSlotNo (RealPoint blk -> SlotNo
forall blk. RealPoint blk -> SlotNo
realPointSlot RealPoint blk
t)
snapshot :: DiskSnapshot
snapshot = Word64 -> Maybe String -> DiskSnapshot
DiskSnapshot Word64
number Maybe String
suffix
diskSnapshots <- SomeHasFS m -> m [DiskSnapshot]
forall (m :: * -> *). Monad m => SomeHasFS m -> m [DiskSnapshot]
listSnapshots SomeHasFS m
hasFS'
if List.any (== DiskSnapshot number suffix) diskSnapshots
then
return Nothing
else do
encloseTimedWith (TookSnapshot snapshot t >$< tracer) $
writeSnapshot hasFS' backingStore (encodeDiskExtLedgerState ccfg) snapshot state
return $ Just (snapshot, t)
writeSnapshot ::
MonadThrow m =>
SomeHasFS m ->
BackingStore' m blk ->
(ExtLedgerState blk EmptyMK -> Encoding) ->
DiskSnapshot ->
ExtLedgerState blk EmptyMK ->
m ()
writeSnapshot :: forall (m :: * -> *) blk.
MonadThrow m =>
SomeHasFS m
-> BackingStore' m blk
-> (ExtLedgerState blk EmptyMK -> Encoding)
-> DiskSnapshot
-> ExtLedgerState blk EmptyMK
-> m ()
writeSnapshot fs :: SomeHasFS m
fs@(SomeHasFS HasFS m h
hasFS) BackingStore' m blk
backingStore ExtLedgerState blk EmptyMK -> Encoding
encLedger DiskSnapshot
snapshot ExtLedgerState blk EmptyMK
cs = do
HasFS m h -> HasCallStack => FsPath -> m ()
forall (m :: * -> *) h. HasFS m h -> HasCallStack => FsPath -> m ()
createDirectory HasFS m h
hasFS (DiskSnapshot -> FsPath
snapshotToDirPath DiskSnapshot
snapshot)
crc <- SomeHasFS m
-> (ExtLedgerState blk EmptyMK -> Encoding)
-> FsPath
-> ExtLedgerState blk EmptyMK
-> m CRC
forall (m :: * -> *) blk.
MonadThrow m =>
SomeHasFS m
-> (ExtLedgerState blk EmptyMK -> Encoding)
-> FsPath
-> ExtLedgerState blk EmptyMK
-> m CRC
writeExtLedgerState SomeHasFS m
fs ExtLedgerState blk EmptyMK -> Encoding
encLedger (DiskSnapshot -> FsPath
snapshotToStatePath DiskSnapshot
snapshot) ExtLedgerState blk EmptyMK
cs
writeSnapshotMetadata
fs
snapshot
SnapshotMetadata
{ snapshotBackend = bsSnapshotBackend backingStore
, snapshotChecksum = crc
}
bsCopy
backingStore
cs
(snapshotToTablesPath snapshot)
snapshotToStatePath :: DiskSnapshot -> FsPath
snapshotToStatePath :: DiskSnapshot -> FsPath
snapshotToStatePath = [String] -> FsPath
mkFsPath ([String] -> FsPath)
-> (DiskSnapshot -> [String]) -> DiskSnapshot -> FsPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\String
x -> [String
x, String
"state"]) (String -> [String])
-> (DiskSnapshot -> String) -> DiskSnapshot -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiskSnapshot -> String
snapshotToDirName
snapshotToTablesPath :: DiskSnapshot -> FsPath
snapshotToTablesPath :: DiskSnapshot -> FsPath
snapshotToTablesPath = [String] -> FsPath
mkFsPath ([String] -> FsPath)
-> (DiskSnapshot -> [String]) -> DiskSnapshot -> FsPath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (\String
x -> [String
x, String
"tables"]) (String -> [String])
-> (DiskSnapshot -> String) -> DiskSnapshot -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiskSnapshot -> String
snapshotToDirName
loadSnapshot ::
forall m blk.
( IOLike m
, LedgerDbSerialiseConstraints blk
, LedgerSupportsProtocol blk
, LedgerSupportsLedgerDB blk
) =>
Tracer m V1.FlavorImplSpecificTrace ->
Complete BackingStoreArgs m ->
CodecConfig blk ->
SnapshotsFS m ->
DiskSnapshot ->
ExceptT
(SnapshotFailure blk)
m
((DbChangelog' blk, LedgerBackingStore m (ExtLedgerState blk)), RealPoint blk)
loadSnapshot :: forall (m :: * -> *) blk.
(IOLike m, LedgerDbSerialiseConstraints blk,
LedgerSupportsProtocol blk, LedgerSupportsLedgerDB blk) =>
Tracer m FlavorImplSpecificTrace
-> Complete BackingStoreArgs m
-> CodecConfig blk
-> SnapshotsFS m
-> DiskSnapshot
-> ExceptT
(SnapshotFailure blk)
m
((DbChangelog' blk, LedgerBackingStore m (ExtLedgerState blk)),
RealPoint blk)
loadSnapshot Tracer m FlavorImplSpecificTrace
tracer Complete BackingStoreArgs m
bss CodecConfig blk
ccfg fs :: SnapshotsFS m
fs@(SnapshotsFS SomeHasFS m
fs') DiskSnapshot
s = do
(extLedgerSt, checksumAsRead) <-
(ReadIncrementalErr -> SnapshotFailure blk)
-> ExceptT ReadIncrementalErr m (ExtLedgerState blk EmptyMK, CRC)
-> ExceptT
(SnapshotFailure blk) m (ExtLedgerState blk EmptyMK, CRC)
forall (m :: * -> *) e e' a.
Functor m =>
(e -> e') -> ExceptT e m a -> ExceptT e' m a
withExceptT (ReadSnapshotErr -> SnapshotFailure blk
forall blk. ReadSnapshotErr -> SnapshotFailure blk
InitFailureRead (ReadSnapshotErr -> SnapshotFailure blk)
-> (ReadIncrementalErr -> ReadSnapshotErr)
-> ReadIncrementalErr
-> SnapshotFailure blk
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReadIncrementalErr -> ReadSnapshotErr
ReadSnapshotFailed) (ExceptT ReadIncrementalErr m (ExtLedgerState blk EmptyMK, CRC)
-> ExceptT
(SnapshotFailure blk) m (ExtLedgerState blk EmptyMK, CRC))
-> ExceptT ReadIncrementalErr m (ExtLedgerState blk EmptyMK, CRC)
-> ExceptT
(SnapshotFailure blk) m (ExtLedgerState blk EmptyMK, CRC)
forall a b. (a -> b) -> a -> b
$
SomeHasFS m
-> (forall s. Decoder s (ExtLedgerState blk EmptyMK))
-> (forall s. Decoder s (HeaderHash blk))
-> FsPath
-> ExceptT ReadIncrementalErr m (ExtLedgerState blk EmptyMK, CRC)
forall (m :: * -> *) blk.
IOLike m =>
SomeHasFS m
-> (forall s. Decoder s (ExtLedgerState blk EmptyMK))
-> (forall s. Decoder s (HeaderHash blk))
-> FsPath
-> ExceptT ReadIncrementalErr m (ExtLedgerState blk EmptyMK, CRC)
readExtLedgerState SomeHasFS m
fs' (CodecConfig blk -> forall s. Decoder s (ExtLedgerState blk EmptyMK)
forall blk.
(DecodeDisk blk (LedgerState blk EmptyMK),
DecodeDisk blk (ChainDepState (BlockProtocol blk)),
DecodeDisk blk (AnnTip blk)) =>
CodecConfig blk -> forall s. Decoder s (ExtLedgerState blk EmptyMK)
decodeDiskExtLedgerState CodecConfig blk
ccfg) Decoder s (HeaderHash blk)
forall s. Decoder s (HeaderHash blk)
forall a s. Serialise a => Decoder s a
decode (DiskSnapshot -> FsPath
snapshotToStatePath DiskSnapshot
s)
snapshotMeta <-
withExceptT (InitFailureRead . ReadMetadataError (snapshotToMetadataPath s)) $
loadSnapshotMetadata fs' s
case (bss, snapshotBackend snapshotMeta) of
(Complete BackingStoreArgs m
InMemoryBackingStoreArgs, SnapshotBackend
UTxOHDMemSnapshot) -> () -> ExceptT (SnapshotFailure blk) m ()
forall a. a -> ExceptT (SnapshotFailure blk) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
(LMDBBackingStoreArgs String
_ HKD Identity LMDBLimits
_ Dict MonadIOPrim m
_, SnapshotBackend
UTxOHDLMDBSnapshot) -> () -> ExceptT (SnapshotFailure blk) m ()
forall a. a -> ExceptT (SnapshotFailure blk) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
(Complete BackingStoreArgs m
_, SnapshotBackend
_) ->
SnapshotFailure blk -> ExceptT (SnapshotFailure blk) m ()
forall a. SnapshotFailure blk -> ExceptT (SnapshotFailure blk) m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError (SnapshotFailure blk -> ExceptT (SnapshotFailure blk) m ())
-> SnapshotFailure blk -> ExceptT (SnapshotFailure blk) m ()
forall a b. (a -> b) -> a -> b
$ ReadSnapshotErr -> SnapshotFailure blk
forall blk. ReadSnapshotErr -> SnapshotFailure blk
InitFailureRead (ReadSnapshotErr -> SnapshotFailure blk)
-> ReadSnapshotErr -> SnapshotFailure blk
forall a b. (a -> b) -> a -> b
$ FsPath -> MetadataErr -> ReadSnapshotErr
ReadMetadataError (DiskSnapshot -> FsPath
snapshotToMetadataPath DiskSnapshot
s) MetadataErr
MetadataBackendMismatch
Monad.when (checksumAsRead /= snapshotChecksum snapshotMeta) $
throwError $
InitFailureRead $
ReadSnapshotDataCorruption
case pointToWithOriginRealPoint (castPoint (getTip extLedgerSt)) of
WithOrigin (RealPoint blk)
Origin -> SnapshotFailure blk
-> ExceptT
(SnapshotFailure blk)
m
((DbChangelog' blk, LedgerBackingStore m (ExtLedgerState blk)),
RealPoint blk)
forall a. SnapshotFailure blk -> ExceptT (SnapshotFailure blk) m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError SnapshotFailure blk
forall blk. SnapshotFailure blk
InitFailureGenesis
NotOrigin RealPoint blk
pt -> do
backingStore <- m (LedgerBackingStore m (ExtLedgerState blk))
-> ExceptT
(SnapshotFailure blk) m (LedgerBackingStore m (ExtLedgerState blk))
forall (m :: * -> *) a.
Monad m =>
m a -> ExceptT (SnapshotFailure blk) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
Trans.lift (Tracer m FlavorImplSpecificTrace
-> Complete BackingStoreArgs m
-> SnapshotsFS m
-> ExtLedgerState blk EmptyMK
-> FsPath
-> m (LedgerBackingStore m (ExtLedgerState blk))
forall (m :: * -> *) (l :: LedgerStateKind).
(IOLike m, HasLedgerTables l, HasCallStack,
CanUpgradeLedgerTables l, MemPackIdx l EmptyMK ~ l EmptyMK,
SerializeTablesWithHint l) =>
Tracer m FlavorImplSpecificTrace
-> Complete BackingStoreArgs m
-> SnapshotsFS m
-> l EmptyMK
-> FsPath
-> m (LedgerBackingStore m l)
restoreBackingStore Tracer m FlavorImplSpecificTrace
tracer Complete BackingStoreArgs m
bss SnapshotsFS m
fs ExtLedgerState blk EmptyMK
extLedgerSt (DiskSnapshot -> FsPath
snapshotToTablesPath DiskSnapshot
s))
let chlog = ExtLedgerState blk EmptyMK -> DbChangelog' blk
forall (l :: LedgerStateKind).
(HasLedgerTables l, GetTip l) =>
l EmptyMK -> DbChangelog l
empty ExtLedgerState blk EmptyMK
extLedgerSt
pure ((chlog, backingStore), pt)