Skip to content

Commit 6b643ce

Browse files
committed
Support LSM in snapshot-converter
1 parent df24a18 commit 6b643ce

File tree

3 files changed

+128
-79
lines changed

3 files changed

+128
-79
lines changed

ouroboros-consensus-cardano/app/snapshot-converter.hs

Lines changed: 126 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -38,71 +38,92 @@ import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.BackingStore.Impl.LMDB
3838
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.DbChangelog as V1
3939
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.Lock as V1
4040
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.Snapshots as V1
41+
import Ouroboros.Consensus.Storage.LedgerDB.V2.Args
4142
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.InMemory as InMemory
4243
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.InMemory as V2
44+
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.LSM as LSM
4345
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq as V2
4446
import Ouroboros.Consensus.Util.CRC
4547
import Ouroboros.Consensus.Util.IOLike
48+
import qualified System.Directory as Directory
4649
import System.FS.API
4750
import System.FS.API.Lazy
4851
import System.FS.CRC
4952
import System.FS.IO
5053
import System.FilePath (splitFileName)
54+
import System.IO (hFlush, stdout)
5155
import System.IO.Temp
5256

5357
data Format
54-
= Legacy
55-
| Mem
56-
| LMDB
58+
= Legacy FilePath
59+
| Mem FilePath
60+
| LMDB FilePath
61+
| LSM FilePath FilePath
5762
deriving (Show, Read)
5863

5964
data Config = Config
6065
{ from :: Format
6166
-- ^ Which format the input snapshot is in
62-
, inpath :: FilePath
63-
-- ^ Path to the input snapshot
6467
, to :: Format
6568
-- ^ Which format the output snapshot must be in
66-
, outpath :: FilePath
67-
-- ^ Path to the output snapshot
6869
}
6970

7071
getCommandLineConfig :: IO (Config, BlockType)
7172
getCommandLineConfig =
7273
execParser $
7374
info
74-
((,) <$> parseConfig <*> blockTypeParser <**> helper)
75+
((,) <$> (Config <$> parseConfig In <*> parseConfig Out) <*> blockTypeParser <**> helper)
7576
(fullDesc <> progDesc "Utility for converting snapshots to and from UTxO-HD")
7677

77-
parseConfig :: Parser Config
78-
parseConfig =
79-
Config
80-
<$> argument
81-
auto
82-
( mconcat
83-
[ help "From format (Legacy, Mem or LMDB)"
84-
, metavar "FORMAT-IN"
85-
]
86-
)
87-
<*> strArgument
88-
( mconcat
89-
[ help "Input dir/file. Use relative paths like ./100007913"
90-
, metavar "PATH-IN"
91-
]
92-
)
93-
<*> argument
94-
auto
95-
( mconcat
96-
[ help "To format (Legacy, Mem or LMDB)"
97-
, metavar "FORMAT-OUT"
98-
]
99-
)
100-
<*> strArgument
101-
( mconcat
102-
[ help "Output dir/file Use relative paths like ./100007913"
103-
, metavar "PATH-OUT"
104-
]
105-
)
78+
data InOut = In | Out
79+
80+
inoutForGroup :: InOut -> String
81+
inoutForGroup In = "Input arguments:"
82+
inoutForGroup Out = "Output arguments:"
83+
84+
inoutForHelp :: InOut -> String -> String
85+
inoutForHelp In = ("Input " ++)
86+
inoutForHelp Out = ("Output " ++)
87+
88+
inoutForCommand :: InOut -> String -> String
89+
inoutForCommand In = (++ "-in")
90+
inoutForCommand Out = (++ "-out")
91+
92+
parseConfig :: InOut -> Parser Format
93+
parseConfig io =
94+
( Legacy
95+
<$> parserOptionGroup
96+
(inoutForGroup io)
97+
(parsePath (inoutForCommand io "legacy") (inoutForHelp io "snapshot file"))
98+
)
99+
<|> ( Mem
100+
<$> parserOptionGroup
101+
(inoutForGroup io)
102+
(parsePath (inoutForCommand io "mem") (inoutForHelp io "snapshot dir"))
103+
)
104+
<|> ( LMDB
105+
<$> parserOptionGroup
106+
(inoutForGroup io)
107+
(parsePath (inoutForCommand io "lmdb") (inoutForHelp io "snapshot dir"))
108+
)
109+
<|> ( LSM
110+
<$> parserOptionGroup
111+
(inoutForGroup io)
112+
(parsePath (inoutForCommand io "lsm-snapshot") (inoutForHelp io "snapshot dir"))
113+
<*> parserOptionGroup
114+
(inoutForGroup io)
115+
(parsePath (inoutForCommand io "lsm-database") (inoutForHelp io "LSM database"))
116+
)
117+
118+
parsePath :: String -> String -> Parser FilePath
119+
parsePath optName strHelp =
120+
strOption
121+
( mconcat
122+
[ long optName
123+
, help strHelp
124+
, metavar "PATH"
125+
]
126+
)
106127

107128
-- Helpers
108129

@@ -140,31 +161,6 @@ instance StandardHash blk => Show (Error blk) where
140161
<> err
141162
show (ReadSnapshotCRCError fp err) = "An error occurred while reading the snapshot checksum at " <> show fp <> ": \n\t" <> show err
142163

143-
checkSnapshotFileStructure :: Format -> FsPath -> SomeHasFS IO -> ExceptT (Error blk) IO ()
144-
checkSnapshotFileStructure m p (SomeHasFS fs) = case m of
145-
Legacy -> want (doesFileExist fs) p "is NOT a file"
146-
Mem -> newFormatCheck "tvar"
147-
LMDB -> newFormatCheck "data.mdb"
148-
where
149-
want :: (FsPath -> IO Bool) -> FsPath -> String -> ExceptT (Error blk) IO ()
150-
want fileType path err = do
151-
exists <- Trans.lift $ fileType path
152-
Monad.unless exists $ throwError $ SnapshotFormatMismatch m err
153-
154-
isDir = (doesDirectoryExist, [], "is NOT a directory")
155-
hasTablesDir = (doesDirectoryExist, ["tables"], "DOES NOT contain a \"tables\" directory")
156-
hasState = (doesFileExist, ["state"], "DOES NOT contain a \"state\" file")
157-
hasTables tb = (doesFileExist, ["tables", tb], "DOES NOT contain a \"tables/" <> tb <> "\" file")
158-
159-
newFormatCheck tb =
160-
mapM_
161-
(\(doCheck, extra, err) -> want (doCheck fs) (p </> mkFsPath extra) err)
162-
[ isDir
163-
, hasTablesDir
164-
, hasState
165-
, hasTables tb
166-
]
167-
168164
load ::
169165
forall blk.
170166
( CanStowLedgerTables (LedgerState blk)
@@ -176,10 +172,9 @@ load ::
176172
CodecConfig blk ->
177173
FilePath ->
178174
ExceptT (Error blk) IO (ExtLedgerState blk EmptyMK, LedgerTables (ExtLedgerState blk) ValuesMK)
179-
load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), path, ds)} rr ccfg tempFP =
175+
load config rr ccfg tempFP =
180176
case from config of
181-
Legacy -> do
182-
checkSnapshotFileStructure Legacy path fs
177+
Legacy (pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), path, _)) -> do
183178
(st, checksumAsRead) <-
184179
first unstowLedgerTables
185180
<$> withExceptT
@@ -196,13 +191,11 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
196191
SnapshotError $
197192
InitFailureRead ReadSnapshotDataCorruption
198193
pure (forgetLedgerTables st, projectLedgerTables st)
199-
Mem -> do
200-
checkSnapshotFileStructure Mem path fs
194+
Mem (pathToDiskSnapshot -> Just (fs, _, ds)) -> do
201195
(ls, _) <- withExceptT SnapshotError $ V2.loadSnapshot nullTracer rr ccfg fs ds
202196
let h = V2.currentHandle ls
203197
(V2.state h,) <$> Trans.lift (V2.readAll (V2.tables h) (V2.state h))
204-
LMDB -> do
205-
checkSnapshotFileStructure LMDB path fs
198+
LMDB (pathToDiskSnapshot -> Just (fs, _, ds)) -> do
206199
((dbch, k, bstore), _) <-
207200
withExceptT SnapshotError $
208201
V1.loadSnapshot
@@ -215,7 +208,8 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
215208
values <- Trans.lift (V1.bsReadAll bstore (V1.changelogLastFlushedState dbch))
216209
_ <- Trans.lift $ RR.release k
217210
pure (V1.current dbch, values)
218-
load _ _ _ _ = error "Malformed input path!"
211+
LSM _ _ -> error "unimplemented"
212+
_ -> error "Malformed input path!"
219213

220214
store ::
221215
( CanStowLedgerTables (LedgerState blk)
@@ -227,9 +221,9 @@ store ::
227221
(ExtLedgerState blk EmptyMK, LedgerTables (ExtLedgerState blk) ValuesMK) ->
228222
SomeHasFS IO ->
229223
IO ()
230-
store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), path, DiskSnapshot _ suffix)} ccfg (state, tbs) tempFS =
224+
store config ccfg (state, tbs) tempFS =
231225
case to config of
232-
Legacy -> do
226+
Legacy (p@(pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), path, _))) -> do
233227
crc <-
234228
writeExtLedgerState
235229
fs
@@ -238,11 +232,27 @@ store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS),
238232
(stowLedgerTables $ state `withLedgerTables` tbs)
239233
withFile hasFS (path <.> "checksum") (WriteMode MustBeNew) $ \h ->
240234
Monad.void $ hPutAll hasFS h . BS.toLazyByteString . BS.word32HexFixed $ getCRC crc
241-
Mem -> do
235+
putStrLn "DONE"
236+
putStrLn $
237+
unlines $
238+
[ "You can now copy the file "
239+
++ p
240+
++ " to your `ledger` directory in your ChainDB storage."
241+
, "Note this snapshot can only be used by cardano-node <10.4."
242+
]
243+
Mem (p@(pathToDiskSnapshot -> Just (fs, _, DiskSnapshot _ suffix))) -> do
242244
lseq <- V2.empty state tbs $ V2.newInMemoryLedgerTablesHandle nullTracer fs
243245
let h = V2.currentHandle lseq
244246
Monad.void $ InMemory.implTakeSnapshot ccfg nullTracer fs suffix h
245-
LMDB -> do
247+
putStrLn "DONE"
248+
putStrLn $
249+
unlines $
250+
[ "You can now copy the directory "
251+
++ p
252+
++ " to your `ledger` directory in your ChainDB storage."
253+
, "Note this snapshot can only be used by cardano-node >=10.4 configured to use the InMemory backend (set the \"LedgerDB\".\"Backend\" key in your config file to \"V2InMemory\" or leave it undefined)."
254+
]
255+
LMDB (p@(pathToDiskSnapshot -> Just (fs, _, DiskSnapshot _ suffix))) -> do
246256
chlog <- newTVarIO (V1.empty state)
247257
lock <- V1.mkLedgerDBLock
248258
bs <-
@@ -254,7 +264,43 @@ store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS),
254264
(V1.InitFromValues (pointSlot $ getTip state) state tbs)
255265
Monad.void $ V1.withReadLock lock $ do
256266
V1.implTakeSnapshot chlog ccfg nullTracer (V1.SnapshotsFS fs) bs suffix
257-
store _ _ _ _ = error "Malformed output path!"
267+
putStrLn "DONE"
268+
putStrLn $
269+
unlines $
270+
[ "You can now copy the directory "
271+
++ p
272+
++ " to your `ledger` directory in your ChainDB storage."
273+
, "Note this snapshot can only be used by cardano-node >=10.4 configured to use the LMDB backend (set the \"LedgerDB\".\"Backend\" key in your config file to \"V1LMDB\")."
274+
]
275+
LSM (p@(pathToDiskSnapshot -> Just (fs, _, DiskSnapshot _ suffix))) dbPath -> do
276+
exists <- Directory.doesDirectoryExist dbPath
277+
Monad.when (not exists) $ Directory.createDirectory dbPath
278+
RR.withRegistry $ \reg -> do
279+
(_, SomeHasFSAndBlockIO hasFS blockIO) <- LSM.stdMkBlockIOFS dbPath reg
280+
salt <- LSM.stdGenSalt
281+
LSM.withNewSession nullTracer hasFS blockIO salt (mkFsPath [""]) $ \session -> do
282+
lsmTable <- LSM.tableFromValuesMK reg session tbs
283+
lsmHandle <- LSM.newLSMLedgerTablesHandle nullTracer reg session lsmTable
284+
Monad.void $
285+
LSM.implTakeSnapshot
286+
ccfg
287+
nullTracer
288+
fs
289+
suffix
290+
(V2.StateRef state lsmHandle)
291+
putStrLn "DONE"
292+
putStrLn $
293+
unlines $
294+
[ "You can now:"
295+
, "- copy the directory "
296+
++ p
297+
++ " to your `ledger` directory in your ChainDB storage."
298+
, "- copy the directory "
299+
++ dbPath
300+
++ " to your fast storage device and point to it in your config file."
301+
, "Note this snapshot can only be used by cardano-node >=10.7 configured to use the LSM backend (set the \"LedgerDB\".\"Backend\" key in your config file to \"V2LSM\")."
302+
]
303+
_ -> error "Malformed output path!"
258304

259305
main :: IO ()
260306
main = withStdTerminalHandles $ do
@@ -270,9 +316,10 @@ main = withStdTerminalHandles $ do
270316
withSystemTempDirectory "lmdb" $ \dir -> do
271317
let tempFS = SomeHasFS $ ioHasFS $ MountPoint dir
272318
RR.withRegistry $ \rr -> do
273-
putStrLn "Loading snapshot..."
319+
putStr "Loading snapshot..."
320+
hFlush stdout
274321
state <- either throwIO pure =<< runExceptT (load conf rr ccfg dir)
275-
putStrLn "Loaded snapshot"
276-
putStrLn "Writing snapshot..."
322+
putStrLn "DONE"
323+
putStr "Writing snapshot..."
324+
hFlush stdout
277325
store conf ccfg state tempFS
278-
putStrLn "Written snapshot"

ouroboros-consensus-cardano/ouroboros-consensus-cardano.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ executable snapshot-converter
706706
cardano-crypto-class,
707707
cardano-crypto-wrapper,
708708
contra-tracer,
709+
directory,
709710
filepath,
710711
fs-api,
711712
mtl,

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB/V2/LSM.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ module Ouroboros.Consensus.Storage.LedgerDB.V2.LSM
5151

5252
-- * snapshot-converter
5353
, implTakeSnapshot
54+
, LSM.withNewSession
5455
) where
5556

5657
import Cardano.Binary as CBOR

0 commit comments

Comments
 (0)