Skip to content

Commit 036f60e

Browse files
authored
Merge pull request #557 from IntersectMBO/jdral/sync-snap-dir
Bugfix: synchronise the snapshot directory and its contents
2 parents 285fbaa + 714f8b6 commit 036f60e

File tree

4 files changed

+66
-46
lines changed

4 files changed

+66
-46
lines changed

blockio-api/src/System/FS/BlockIO/API.hs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ module System.FS.BlockIO.API (
3030
, LockFileHandle (..)
3131
-- ** Storage synchronisation
3232
, synchroniseFile
33+
, synchroniseDirectoryRecursive
3334
-- * Defaults for the real file system
3435
, tryLockFileIO
3536
, createHardLinkIO
@@ -39,6 +40,7 @@ module System.FS.BlockIO.API (
3940
) where
4041

4142
import Control.DeepSeq
43+
import Control.Monad (forM_)
4244
import Control.Monad.Class.MonadThrow (MonadCatch (bracketOnError),
4345
MonadThrow (..), bracketOnError, try)
4446
import Control.Monad.Primitive (PrimMonad (PrimState))
@@ -60,6 +62,7 @@ import qualified System.IO as GHC
6062
import System.IO.Error (doesNotExistErrorType, ioeSetErrorString,
6163
mkIOError)
6264
import System.Posix.Types (ByteCount, FileOffset)
65+
import Text.Printf
6366

6467
-- | Abstract interface for submitting large batches of I\/O operations.
6568
data HasBlockIO m h = HasBlockIO {
@@ -258,6 +261,7 @@ hDropCacheAll hbio h = hAdviseAll hbio h AdviceDontNeed
258261
Storage synchronisation
259262
-------------------------------------------------------------------------------}
260263

264+
{-# SPECIALISE synchroniseFile :: HasFS IO h -> HasBlockIO IO h -> FsPath -> IO () #-}
261265
-- TODO: currently, we perform an explicit check to see if the file exists and
262266
-- throw an error when it does not exist. We would prefer to be able to rely on
263267
-- withFile to throw an error for us that we could rethrow with an upated
@@ -284,6 +288,37 @@ synchroniseFile hfs hbio path = do
284288
(mkIOError doesNotExistErrorType "synchroniseFile" Nothing Nothing)
285289
("synchroniseFile: file does not exist")
286290

291+
{-# SPECIALISE synchroniseDirectoryRecursive ::
292+
HasFS IO h
293+
-> HasBlockIO IO h
294+
-> FsPath
295+
-> IO ()
296+
#-}
297+
-- | Synchronise a directory and recursively its contents with the storage
298+
-- device.
299+
synchroniseDirectoryRecursive ::
300+
MonadThrow m
301+
=> HasFS m h
302+
-> HasBlockIO m h
303+
-> FsPath
304+
-> m ()
305+
synchroniseDirectoryRecursive hfs hbio path = do
306+
entries <- FS.listDirectory hfs path
307+
forM_ entries $ \entry -> do
308+
let path' = path FS.</> FS.mkFsPath [entry]
309+
isFile <- FS.doesFileExist hfs path'
310+
if isFile then
311+
synchroniseFile hfs hbio path'
312+
else do
313+
isDirectory <- FS.doesDirectoryExist hfs path'
314+
if isDirectory then do
315+
synchroniseDirectoryRecursive hfs hbio path'
316+
synchroniseDirectory hbio path'
317+
else
318+
error $ printf
319+
"listDirectoryRecursive: %s is not a file or directory"
320+
(show path')
321+
287322
{-------------------------------------------------------------------------------
288323
File locks
289324
-------------------------------------------------------------------------------}

src/Database/LSMTree/Internal.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,15 +1174,18 @@ createSnapshot snap label tableType t = do
11741174
snapLevels <- toSnapLevels (tableLevels content)
11751175

11761176
-- Hard link runs into the named snapshot directory
1177-
snapLevels' <- snapshotRuns reg hbio snapUc snapDir snapLevels
1177+
snapLevels' <- snapshotRuns reg snapUc snapDir snapLevels
1178+
1179+
-- Release the table content
1180+
releaseTableContent reg content
11781181

11791182
let snapMetaData = SnapshotMetaData label tableType (tableConfig t) snapWriteBufferNumber snapLevels'
11801183
SnapshotMetaDataFile contentPath = Paths.snapshotMetaDataFile snapDir
11811184
SnapshotMetaDataChecksumFile checksumPath = Paths.snapshotMetaDataChecksumFile snapDir
11821185
writeFileSnapshotMetaData hfs contentPath checksumPath snapMetaData
11831186

1184-
-- Release the table content
1185-
releaseTableContent reg content
1187+
-- Make the directory and its contents durable.
1188+
FS.synchroniseDirectoryRecursive hfs hbio (Paths.getNamedSnapshotDir snapDir)
11861189

11871190
{-# SPECIALISE openSnapshot ::
11881191
Session IO h

src/Database/LSMTree/Internal/Snapshot.hs

Lines changed: 24 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,14 @@ module Database.LSMTree.Internal.Snapshot (
2222
-- * Opening from levels snapshot format
2323
, fromSnapLevels
2424
-- * Hard links
25-
, HardLinkDurable (..)
2625
, hardLinkRunFiles
2726
) where
2827

2928
import Control.ActionRegistry
3029
import Control.Concurrent.Class.MonadMVar.Strict
3130
import Control.Concurrent.Class.MonadSTM (MonadSTM)
3231
import Control.DeepSeq (NFData (..))
33-
import Control.Monad (void, when)
32+
import Control.Monad (void)
3433
import Control.Monad.Class.MonadST (MonadST)
3534
import Control.Monad.Class.MonadThrow (MonadMask)
3635
import Control.Monad.Primitive (PrimMonad)
@@ -271,13 +270,13 @@ snapshotWriteBuffer reg hfs hbio activeUc snapUc activeDir snapDir wb wbb = do
271270
-- Hard link the write buffer and write buffer blobs to the snapshot directory.
272271
snapWriteBufferNumber <- uniqueToRunNumber <$> incrUniqCounter snapUc
273272
let snapWriteBufferPaths = WriteBufferFsPaths (getNamedSnapshotDir snapDir) snapWriteBufferNumber
274-
hardLink reg hfs hbio HardLinkDurable
273+
hardLink reg hfs hbio
275274
(writeBufferKOpsPath activeWriteBufferPaths)
276275
(writeBufferKOpsPath snapWriteBufferPaths)
277-
hardLink reg hfs hbio HardLinkDurable
276+
hardLink reg hfs hbio
278277
(writeBufferBlobPath activeWriteBufferPaths)
279278
(writeBufferBlobPath snapWriteBufferPaths)
280-
hardLink reg hfs hbio HardLinkDurable
279+
hardLink reg hfs hbio
281280
(writeBufferChecksumsPath activeWriteBufferPaths)
282281
(writeBufferChecksumsPath snapWriteBufferPaths)
283282
pure snapWriteBufferPaths
@@ -334,36 +333,30 @@ openWriteBuffer reg resolve hfs hbio uc activeDir snapWriteBufferPaths = do
334333

335334
{-# SPECIALISE snapshotRuns ::
336335
ActionRegistry IO
337-
-> HasBlockIO IO h
338336
-> UniqCounter IO
339337
-> NamedSnapshotDir
340338
-> SnapLevels (Ref (Run IO h))
341339
-> IO (SnapLevels RunNumber) #-}
342340
-- | @'snapshotRuns' _ _ snapUc targetDir levels@ creates hard links for all run
343341
-- files associated with the runs in @levels@, and puts the new directory
344342
-- entries in the @targetDir@ directory. The entries are renamed using @snapUc@.
345-
-- The hard links and the @targetDir@ are made durable on disk.
346343
snapshotRuns ::
347344
(MonadMask m, PrimMonad m)
348345
=> ActionRegistry m
349-
-> HasBlockIO m h
350346
-> UniqCounter m
351347
-> NamedSnapshotDir
352348
-> SnapLevels (Ref (Run m h))
353349
-> m (SnapLevels RunNumber)
354-
snapshotRuns reg hbio0 snapUc (NamedSnapshotDir targetDir) levels = do
355-
levels' <-
356-
for levels $ \run@(DeRef Run.Run {
357-
Run.runHasFS = hfs,
358-
Run.runHasBlockIO = hbio
359-
}) -> do
360-
rn <- uniqueToRunNumber <$> incrUniqCounter snapUc
361-
let sourcePaths = Run.runFsPaths run
362-
let targetPaths = sourcePaths { runDir = targetDir , runNumber = rn}
363-
hardLinkRunFiles reg hfs hbio HardLinkDurable sourcePaths targetPaths
364-
pure (runNumber targetPaths)
365-
FS.synchroniseDirectory hbio0 targetDir
366-
pure levels'
350+
snapshotRuns reg snapUc (NamedSnapshotDir targetDir) levels = do
351+
for levels $ \run@(DeRef Run.Run {
352+
Run.runHasFS = hfs,
353+
Run.runHasBlockIO = hbio
354+
}) -> do
355+
rn <- uniqueToRunNumber <$> incrUniqCounter snapUc
356+
let sourcePaths = Run.runFsPaths run
357+
let targetPaths = sourcePaths { runDir = targetDir , runNumber = rn}
358+
hardLinkRunFiles reg hfs hbio sourcePaths targetPaths
359+
pure (runNumber targetPaths)
367360

368361
{-# SPECIALISE openRuns ::
369362
ActionRegistry IO
@@ -404,7 +397,7 @@ openRuns
404397
let sourcePaths = RunFsPaths sourceDir runNum
405398
runNum' <- uniqueToRunNumber <$> incrUniqCounter uc
406399
let targetPaths = RunFsPaths targetDir runNum'
407-
hardLinkRunFiles reg hfs hbio NoHardLinkDurable sourcePaths targetPaths
400+
hardLinkRunFiles reg hfs hbio sourcePaths targetPaths
408401

409402
withRollback reg
410403
(Run.openFromDisk hfs hbio caching targetPaths)
@@ -490,64 +483,53 @@ fromSnapLevels reg hfs hbio conf@TableConfig{..} uc resolve dir (SnapLevels leve
490483
Hard links
491484
-------------------------------------------------------------------------------}
492485

493-
data HardLinkDurable = HardLinkDurable | NoHardLinkDurable
494-
deriving stock Eq
495-
496486
{-# SPECIALISE hardLinkRunFiles ::
497487
ActionRegistry IO
498488
-> HasFS IO h
499489
-> HasBlockIO IO h
500-
-> HardLinkDurable
501490
-> RunFsPaths
502491
-> RunFsPaths
503492
-> IO () #-}
504-
-- | @'hardLinkRunFiles' _ _ _ dur sourcePaths targetPaths@ creates a hard link
505-
-- for each @sourcePaths@ path using the corresponding @targetPaths@ path as the
506-
-- name for the new directory entry. If @dur == HardLinkDurabl@, the links will
507-
-- also be made durable on disk.
493+
-- | @'hardLinkRunFiles' _ _ _ sourcePaths targetPaths@ creates a hard link for
494+
-- each @sourcePaths@ path using the corresponding @targetPaths@ path as the
495+
-- name for the new directory entry.
508496
hardLinkRunFiles ::
509497
(MonadMask m, PrimMonad m)
510498
=> ActionRegistry m
511499
-> HasFS m h
512500
-> HasBlockIO m h
513-
-> HardLinkDurable
514501
-> RunFsPaths
515502
-> RunFsPaths
516503
-> m ()
517-
hardLinkRunFiles reg hfs hbio dur sourceRunFsPaths targetRunFsPaths = do
504+
hardLinkRunFiles reg hfs hbio sourceRunFsPaths targetRunFsPaths = do
518505
let sourcePaths = pathsForRunFiles sourceRunFsPaths
519506
targetPaths = pathsForRunFiles targetRunFsPaths
520-
sequenceA_ (hardLink reg hfs hbio dur <$> sourcePaths <*> targetPaths)
521-
hardLink reg hfs hbio dur (runChecksumsPath sourceRunFsPaths) (runChecksumsPath targetRunFsPaths)
507+
sequenceA_ (hardLink reg hfs hbio <$> sourcePaths <*> targetPaths)
508+
hardLink reg hfs hbio (runChecksumsPath sourceRunFsPaths) (runChecksumsPath targetRunFsPaths)
522509

523510
{-# SPECIALISE
524511
hardLink ::
525512
ActionRegistry IO
526513
-> HasFS IO h
527514
-> HasBlockIO IO h
528-
-> HardLinkDurable
529515
-> FS.FsPath
530516
-> FS.FsPath
531517
-> IO ()
532518
#-}
533-
-- | @'hardLink' reg hfs hbio dur sourcePath targetPath@ creates a hard link
534-
-- from @sourcePath@ to @targetPath@.
519+
-- | @'hardLink' reg hfs hbio sourcePath targetPath@ creates a hard link from
520+
-- @sourcePath@ to @targetPath@.
535521
hardLink ::
536522
(MonadMask m, PrimMonad m)
537523
=> ActionRegistry m
538524
-> HasFS m h
539525
-> HasBlockIO m h
540-
-> HardLinkDurable
541526
-> FS.FsPath
542527
-> FS.FsPath
543528
-> m ()
544-
hardLink reg hfs hbio dur sourcePath targetPath = do
529+
hardLink reg hfs hbio sourcePath targetPath = do
545530
withRollback_ reg
546531
(FS.createHardLink hbio sourcePath targetPath)
547532
(FS.removeFile hfs targetPath)
548-
when (dur == HardLinkDurable) $
549-
FS.synchroniseFile hfs hbio targetPath
550-
551533

552534
{-------------------------------------------------------------------------------
553535
Copy file

test/Test/Database/LSMTree/Internal/Run.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ prop_WriteAndOpen fs hbio wb =
200200
withActionRegistry $ \reg -> do
201201
let paths = Run.runFsPaths written
202202
paths' = paths { runNumber = RunNumber 17}
203-
hardLinkRunFiles reg fs hbio NoHardLinkDurable paths paths'
203+
hardLinkRunFiles reg fs hbio paths paths'
204204
loaded <- openFromDisk fs hbio CacheRunData (simplePath 17)
205205

206206
Run.size written @=? Run.size loaded

0 commit comments

Comments
 (0)