@@ -38,71 +38,92 @@ import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.BackingStore.Impl.LMDB
38
38
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.DbChangelog as V1
39
39
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.Lock as V1
40
40
import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.Snapshots as V1
41
+ import Ouroboros.Consensus.Storage.LedgerDB.V2.Args
41
42
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.InMemory as InMemory
42
43
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.InMemory as V2
44
+ import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.LSM as LSM
43
45
import qualified Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq as V2
44
46
import Ouroboros.Consensus.Util.CRC
45
47
import Ouroboros.Consensus.Util.IOLike
48
+ import qualified System.Directory as Directory
46
49
import System.FS.API
47
50
import System.FS.API.Lazy
48
51
import System.FS.CRC
49
52
import System.FS.IO
50
53
import System.FilePath (splitFileName )
54
+ import System.IO (hFlush , stdout )
51
55
import System.IO.Temp
52
56
53
57
data Format
54
- = Legacy
55
- | Mem
56
- | LMDB
58
+ = Legacy FilePath
59
+ | Mem FilePath
60
+ | LMDB FilePath
61
+ | LSM FilePath FilePath
57
62
deriving (Show , Read )
58
63
59
64
data Config = Config
60
65
{ from :: Format
61
66
-- ^ Which format the input snapshot is in
62
- , inpath :: FilePath
63
- -- ^ Path to the input snapshot
64
67
, to :: Format
65
68
-- ^ Which format the output snapshot must be in
66
- , outpath :: FilePath
67
- -- ^ Path to the output snapshot
68
69
}
69
70
70
71
getCommandLineConfig :: IO (Config , BlockType )
71
72
getCommandLineConfig =
72
73
execParser $
73
74
info
74
- ((,) <$> parseConfig <*> blockTypeParser <**> helper)
75
+ ((,) <$> ( Config <$> parseConfig In <*> parseConfig Out ) <*> blockTypeParser <**> helper)
75
76
(fullDesc <> progDesc " Utility for converting snapshots to and from UTxO-HD" )
76
77
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
+ )
106
127
107
128
-- Helpers
108
129
@@ -140,31 +161,6 @@ instance StandardHash blk => Show (Error blk) where
140
161
<> err
141
162
show (ReadSnapshotCRCError fp err) = " An error occurred while reading the snapshot checksum at " <> show fp <> " : \n\t " <> show err
142
163
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
-
168
164
load ::
169
165
forall blk .
170
166
( CanStowLedgerTables (LedgerState blk )
@@ -176,10 +172,9 @@ load ::
176
172
CodecConfig blk ->
177
173
FilePath ->
178
174
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 =
180
176
case from config of
181
- Legacy -> do
182
- checkSnapshotFileStructure Legacy path fs
177
+ Legacy (pathToDiskSnapshot -> Just (fs@ (SomeHasFS hasFS), path, _)) -> do
183
178
(st, checksumAsRead) <-
184
179
first unstowLedgerTables
185
180
<$> withExceptT
@@ -196,13 +191,11 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
196
191
SnapshotError $
197
192
InitFailureRead ReadSnapshotDataCorruption
198
193
pure (forgetLedgerTables st, projectLedgerTables st)
199
- Mem -> do
200
- checkSnapshotFileStructure Mem path fs
194
+ Mem (pathToDiskSnapshot -> Just (fs, _, ds)) -> do
201
195
(ls, _) <- withExceptT SnapshotError $ V2. loadSnapshot nullTracer rr ccfg fs ds
202
196
let h = V2. currentHandle ls
203
197
(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
206
199
((dbch, k, bstore), _) <-
207
200
withExceptT SnapshotError $
208
201
V1. loadSnapshot
@@ -215,7 +208,8 @@ load config@Config{inpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS), pa
215
208
values <- Trans. lift (V1. bsReadAll bstore (V1. changelogLastFlushedState dbch))
216
209
_ <- Trans. lift $ RR. release k
217
210
pure (V1. current dbch, values)
218
- load _ _ _ _ = error " Malformed input path!"
211
+ LSM _ _ -> error " unimplemented"
212
+ _ -> error " Malformed input path!"
219
213
220
214
store ::
221
215
( CanStowLedgerTables (LedgerState blk )
@@ -227,9 +221,9 @@ store ::
227
221
(ExtLedgerState blk EmptyMK , LedgerTables (ExtLedgerState blk ) ValuesMK ) ->
228
222
SomeHasFS IO ->
229
223
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 =
231
225
case to config of
232
- Legacy -> do
226
+ Legacy (p @ (pathToDiskSnapshot -> Just (fs @ ( SomeHasFS hasFS), path, _))) -> do
233
227
crc <-
234
228
writeExtLedgerState
235
229
fs
@@ -238,11 +232,27 @@ store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS),
238
232
(stowLedgerTables $ state `withLedgerTables` tbs)
239
233
withFile hasFS (path <.> " checksum" ) (WriteMode MustBeNew ) $ \ h ->
240
234
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
242
244
lseq <- V2. empty state tbs $ V2. newInMemoryLedgerTablesHandle nullTracer fs
243
245
let h = V2. currentHandle lseq
244
246
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
246
256
chlog <- newTVarIO (V1. empty state)
247
257
lock <- V1. mkLedgerDBLock
248
258
bs <-
@@ -254,7 +264,43 @@ store config@Config{outpath = pathToDiskSnapshot -> Just (fs@(SomeHasFS hasFS),
254
264
(V1. InitFromValues (pointSlot $ getTip state) state tbs)
255
265
Monad. void $ V1. withReadLock lock $ do
256
266
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!"
258
304
259
305
main :: IO ()
260
306
main = withStdTerminalHandles $ do
@@ -270,9 +316,10 @@ main = withStdTerminalHandles $ do
270
316
withSystemTempDirectory " lmdb" $ \ dir -> do
271
317
let tempFS = SomeHasFS $ ioHasFS $ MountPoint dir
272
318
RR. withRegistry $ \ rr -> do
273
- putStrLn " Loading snapshot..."
319
+ putStr " Loading snapshot..."
320
+ hFlush stdout
274
321
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
277
325
store conf ccfg state tempFS
278
- putStrLn " Written snapshot"
0 commit comments