@@ -72,7 +72,7 @@ import Control.Concurrent.Class.MonadSTM (MonadSTM (..))
7272import Control.Concurrent.Class.MonadSTM.RWVar (RWVar )
7373import qualified Control.Concurrent.Class.MonadSTM.RWVar as RW
7474import Control.DeepSeq
75- import Control.Monad (unless , void , when )
75+ import Control.Monad (unless )
7676import Control.Monad.Class.MonadST (MonadST (.. ))
7777import Control.Monad.Class.MonadThrow
7878import Control.Monad.Fix (MonadFix )
@@ -100,7 +100,8 @@ import Database.LSMTree.Internal.Lookup (ByteCountDiscrepancy,
100100 ResolveSerialisedValue , lookupsIO )
101101import Database.LSMTree.Internal.MergeSchedule
102102import Database.LSMTree.Internal.Paths (SessionRoot (.. ),
103- SnapshotName )
103+ SnapshotMetaDataChecksumFile (.. ),
104+ SnapshotMetaDataFile (.. ), SnapshotName )
104105import qualified Database.LSMTree.Internal.Paths as Paths
105106import Database.LSMTree.Internal.Range (Range (.. ))
106107import Database.LSMTree.Internal.Run (Run )
@@ -115,7 +116,6 @@ import qualified Database.LSMTree.Internal.WriteBuffer as WB
115116import qualified Database.LSMTree.Internal.WriteBufferBlobs as WBB
116117import qualified System.FS.API as FS
117118import System.FS.API (FsError , FsErrorPath (.. ), FsPath , HasFS )
118- import qualified System.FS.API.Lazy as FS
119119import qualified System.FS.BlockIO.API as FS
120120import System.FS.BlockIO.API (HasBlockIO )
121121
@@ -1077,9 +1077,17 @@ createSnapshot resolve snap label tableType t = do
10771077 let conf = tableConfig t
10781078 withOpenTable t $ \ thEnv -> do
10791079 let hfs = tableHasFS thEnv
1080- let snapPath = Paths. snapshot (tableSessionRoot thEnv) snap
1081- FS. doesFileExist (tableHasFS thEnv) snapPath >>= \ b ->
1082- when b $ throwIO (ErrSnapshotExists snap)
1080+
1081+ -- Guard that the snapshot does not exist already
1082+ let snapDir = Paths. namedSnapshotDir (tableSessionRoot thEnv) snap
1083+ doesSnapshotExist <-
1084+ FS. doesDirectoryExist (tableHasFS thEnv) (Paths. getNamedSnapshotDir snapDir)
1085+ if doesSnapshotExist then
1086+ throwIO (ErrSnapshotExists snap)
1087+ else
1088+ -- we assume the snapshots directory already exists, so we just have to
1089+ -- create the directory for this specific snapshot.
1090+ FS. createDirectory hfs (Paths. getNamedSnapshotDir snapDir)
10831091
10841092 -- For the temporary implementation it is okay to just flush the buffer
10851093 -- before taking the snapshot.
@@ -1110,13 +1118,10 @@ createSnapshot resolve snap label tableType t = do
11101118 -- consistent.
11111119
11121120 snappedLevels <- snapLevels (tableLevels content)
1113- let snapContents = encodeSnapshotMetaData (SnapshotMetaData label tableType (tableConfig t) snappedLevels)
1114-
1115- FS. withFile
1116- (tableHasFS thEnv)
1117- snapPath
1118- (FS. WriteMode FS. MustBeNew ) $ \ h ->
1119- void $ FS. hPutAll (tableHasFS thEnv) h snapContents
1121+ let snapMetaData = SnapshotMetaData label tableType (tableConfig t) snappedLevels
1122+ SnapshotMetaDataFile contentPath = Paths. snapshotMetaDataFile snapDir
1123+ SnapshotMetaDataChecksumFile checksumPath = Paths. snapshotMetaDataChecksumFile snapDir
1124+ writeFileSnapshotMetaData hfs contentPath checksumPath snapMetaData
11201125
11211126 pure $! numSnapRuns snappedLevels
11221127
@@ -1142,20 +1147,20 @@ openSnapshot sesh label tableType override snap resolve = do
11421147 traceWith (sessionTracer sesh) $ TraceOpenSnapshot snap override
11431148 withOpenSession sesh $ \ seshEnv -> do
11441149 withTempRegistry $ \ reg -> do
1145- let hfs = sessionHasFS seshEnv
1146- hbio = sessionHasBlockIO seshEnv
1147- snapPath = Paths. snapshot (sessionRoot seshEnv) snap
1148- FS. doesFileExist hfs snapPath >>= \ b ->
1150+ let hfs = sessionHasFS seshEnv
1151+ hbio = sessionHasBlockIO seshEnv
1152+
1153+ -- Guard that the snapshot exists
1154+ let snapDir = Paths. namedSnapshotDir (sessionRoot seshEnv) snap
1155+ FS. doesDirectoryExist hfs (Paths. getNamedSnapshotDir snapDir) >>= \ b ->
11491156 unless b $ throwIO (ErrSnapshotNotExists snap)
1150- bs <- FS. withFile
1151- hfs
1152- snapPath
1153- FS. ReadMode $ \ h ->
1154- FS. hGetAll (sessionHasFS seshEnv) h
11551157
1156- snapMetaData <- case decodeSnapshotMetaData bs of
1158+ let SnapshotMetaDataFile contentPath = Paths. snapshotMetaDataFile snapDir
1159+ SnapshotMetaDataChecksumFile checksumPath = Paths. snapshotMetaDataChecksumFile snapDir
1160+ snapMetaData <- readFileSnapshotMetaData hfs contentPath checksumPath >>= \ case
11571161 Left e -> throwIO (ErrSnapshotDeserialiseFailure e snap)
11581162 Right x -> pure x
1163+
11591164 let SnapshotMetaData label' tableType' conf snappedLevels = snapMetaData
11601165
11611166 unless (tableType == tableType') $
@@ -1195,10 +1200,12 @@ deleteSnapshot sesh snap = do
11951200 traceWith (sessionTracer sesh) $ TraceDeleteSnapshot snap
11961201 withOpenSession sesh $ \ seshEnv -> do
11971202 let hfs = sessionHasFS seshEnv
1198- snapPath = Paths. snapshot (sessionRoot seshEnv) snap
1199- FS. doesFileExist hfs snapPath >>= \ b ->
1200- unless b $ throwIO (ErrSnapshotNotExists snap)
1201- FS. removeFile hfs snapPath
1203+
1204+ let snapDir = Paths. namedSnapshotDir (sessionRoot seshEnv) snap
1205+ doesSnapshotExist <-
1206+ FS. doesDirectoryExist (sessionHasFS seshEnv) (Paths. getNamedSnapshotDir snapDir)
1207+ unless doesSnapshotExist $ throwIO (ErrSnapshotNotExists snap)
1208+ FS. removeDirectoryRecursive hfs (Paths. getNamedSnapshotDir snapDir)
12021209
12031210{-# SPECIALISE listSnapshots :: Session IO h -> IO [SnapshotName] #-}
12041211-- | See 'Database.LSMTree.Common.listSnapshots'.
@@ -1219,8 +1226,9 @@ listSnapshots sesh = do
12191226 case Paths. mkSnapshotName s of
12201227 Nothing -> pure Nothing
12211228 Just snap -> do
1222- -- check that it is a file
1223- b <- FS. doesFileExist hfs (Paths. snapshot root snap)
1229+ -- check that it is a directory
1230+ b <- FS. doesDirectoryExist hfs
1231+ (Paths. getNamedSnapshotDir $ Paths. namedSnapshotDir root snap)
12241232 if b then pure $ Just snap
12251233 else pure $ Nothing
12261234
0 commit comments