Skip to content

Commit a2a03c6

Browse files
committed
Revisit snapshot labels
Require the user to pass in snapshot labels explicitly. The responsibility of managing label falls on the user, just like the user has the reponsibility of managing snapshot names.
1 parent 1559cc8 commit a2a03c6

File tree

15 files changed

+164
-160
lines changed

15 files changed

+164
-160
lines changed

bench/macro/lsm-tree-bench-wp8.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ type K = BS.ShortByteString
8787
type V = BS.ShortByteString
8888
type B = Void
8989

90-
instance LSM.Labellable (K, V, B) where
91-
makeSnapshotLabel _ = "K V B"
90+
label :: LSM.SnapshotLabel
91+
label = LSM.SnapshotLabel "K V B"
9292

9393
-- | We generate 34 byte keys by using a PRNG to extend a word64 to 32 bytes
9494
-- and then appending two constant bytes. This corresponds relatively closely
@@ -418,7 +418,7 @@ doSetup' gopts opts = do
418418
| i <- NE.toList batch
419419
]
420420

421-
LSM.createSnapshot name tbl
421+
LSM.createSnapshot label name tbl
422422

423423
-------------------------------------------------------------------------------
424424
-- dry-run
@@ -577,7 +577,7 @@ doRun gopts opts = do
577577
-- necessary for testing to load the whole snapshot).
578578
tbl <- if check opts
579579
then LSM.new @IO @K @V @B session (mkTableConfigRun gopts LSM.defaultTableConfig)
580-
else LSM.openSnapshot @IO @K @V @B session (mkTableConfigOverride gopts) name
580+
else LSM.openSnapshot @IO @K @V @B session (mkTableConfigOverride gopts) label name
581581

582582
-- In checking mode, compare each output against a pure reference.
583583
checkvar <- newIORef $ pureReference

src/Database/LSMTree.hs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ module Database.LSMTree (
6666
-- * Durability (snapshots)
6767
, SnapshotName
6868
, Common.mkSnapshotName
69-
, Common.Labellable (..)
69+
, Common.SnapshotLabel (..)
7070
, createSnapshot
7171
, openSnapshot
7272
, Common.TableConfigOverride
@@ -464,42 +464,40 @@ retrieveBlobs (Internal.Session' (sesh :: Internal.Session m h)) refs =
464464
-------------------------------------------------------------------------------}
465465

466466
{-# SPECIALISE createSnapshot ::
467-
(Common.Labellable (k, v, blob), ResolveValue v)
468-
=> SnapshotName
467+
ResolveValue v
468+
=> Common.SnapshotLabel
469+
-> SnapshotName
469470
-> Table IO k v blob
470471
-> IO () #-}
471472
createSnapshot :: forall m k v blob.
472473
( IOLike m
473-
, Common.Labellable (k, v, blob)
474474
, ResolveValue v
475475
)
476-
=> SnapshotName
476+
=> Common.SnapshotLabel
477+
-> SnapshotName
477478
-> Table m k v blob
478479
-> m ()
479-
createSnapshot snap (Internal.Table' t) =
480+
createSnapshot label snap (Internal.Table' t) =
480481
void $ Internal.createSnapshot (resolve (Proxy @v)) snap label Internal.SnapFullTable t
481-
where
482-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v, blob))
483482

484483
{-# SPECIALISE openSnapshot ::
485-
(Common.Labellable (k, v, blob), ResolveValue v)
484+
ResolveValue v
486485
=> Session IO
487486
-> Common.TableConfigOverride
487+
-> Common.SnapshotLabel
488488
-> SnapshotName
489489
-> IO (Table IO k v blob ) #-}
490490
openSnapshot :: forall m k v blob.
491491
( IOLike m
492-
, Common.Labellable (k, v, blob)
493492
, ResolveValue v
494493
)
495494
=> Session m
496495
-> Common.TableConfigOverride -- ^ Optional config override
496+
-> Common.SnapshotLabel
497497
-> SnapshotName
498498
-> m (Table m k v blob)
499-
openSnapshot (Internal.Session' sesh) override snap =
499+
openSnapshot (Internal.Session' sesh) override label snap =
500500
Internal.Table' <$!> Internal.openSnapshot sesh label Internal.SnapFullTable override snap (resolve (Proxy @v))
501-
where
502-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v, blob))
503501

504502
{-------------------------------------------------------------------------------
505503
Mutiple writable tables

src/Database/LSMTree/Common.hs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module Database.LSMTree.Common (
1818
-- * Small types
1919
, Internal.Range (..)
2020
-- * Snapshots
21-
, Labellable (..)
21+
, SnapshotLabel (..)
2222
, deleteSnapshot
2323
, listSnapshots
2424
-- ** Snapshot names
@@ -52,8 +52,7 @@ import Control.Monad.Class.MonadThrow
5252
import Control.Monad.Primitive (PrimMonad)
5353
import Control.Tracer (Tracer)
5454
import Data.Kind (Type)
55-
import Data.Text (Text)
56-
import Data.Typeable (Proxy, Typeable)
55+
import Data.Typeable (Typeable)
5756
import qualified Database.LSMTree.Internal as Internal
5857
import qualified Database.LSMTree.Internal.BlobRef as Internal
5958
import qualified Database.LSMTree.Internal.Config as Internal
@@ -62,6 +61,7 @@ import qualified Database.LSMTree.Internal.MergeSchedule as Internal
6261
import qualified Database.LSMTree.Internal.Paths as Internal
6362
import qualified Database.LSMTree.Internal.Range as Internal
6463
import Database.LSMTree.Internal.Serialise.Class
64+
import Database.LSMTree.Internal.Snapshot (SnapshotLabel (..))
6565
import System.FS.API (FsPath, HasFS)
6666
import System.FS.BlockIO.API (HasBlockIO)
6767
import System.FS.IO (HandleIO)
@@ -186,13 +186,6 @@ closeSession (Internal.Session' sesh) = Internal.closeSession sesh
186186
Snapshots
187187
-------------------------------------------------------------------------------}
188188

189-
-- TODO: we might replace this with some other form of dynamic checking of
190-
-- snapshot types. For example, we could ask the user to produce a label/version
191-
-- directly instead, instead of deriving the label from a type using this type
192-
-- class.
193-
class Labellable a where
194-
makeSnapshotLabel :: Proxy a -> Text
195-
196189
{-# SPECIALISE deleteSnapshot ::
197190
Session IO
198191
-> Internal.SnapshotName

src/Database/LSMTree/Internal/Snapshot.hs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,12 @@ import System.FS.BlockIO.API (HasBlockIO)
5757
Snapshot metadata
5858
-------------------------------------------------------------------------------}
5959

60-
-- | Custom text to include in a snapshot file
60+
-- | Custom, user-supplied text that is included in the metadata.
61+
--
62+
-- The main use case for a 'SnapshotLabel' is for the user to supply textual
63+
-- information about the key\/value\/blob type for the table that corresponds to
64+
-- the snapshot. This information is used to dynamically check that a snapshot
65+
-- is opened at the correct key\/value\/blob type.
6166
newtype SnapshotLabel = SnapshotLabel Text
6267
deriving stock (Show, Eq)
6368

@@ -66,17 +71,11 @@ data SnapshotTableType = SnapNormalTable | SnapMonoidalTable | SnapFullTable
6671
deriving stock (Show, Eq)
6772

6873
data SnapshotMetaData = SnapshotMetaData {
69-
-- | Custom, user-supplied text that is included in the metadata.
70-
--
71-
-- The main use case for this field is for the user to supply textual
72-
-- information about the key\/value\/blob type for the table that
73-
-- corresponds to the snapshot. This information can then be used to
74-
-- dynamically check that a snapshot is opened at the correct
75-
-- key\/value\/blob type.
74+
-- | See 'SnapshotLabel'.
7675
--
7776
-- One could argue that the 'SnapshotName' could be used to to hold this
78-
-- information, but the file name of snapshot metadata is not guarded by a
79-
-- checksum, wherease the contents of the file are. Therefore using the
77+
-- type information, but the file name of snapshot metadata is not guarded
78+
-- by a checksum, wherease the contents of the file are. Therefore using the
8079
-- 'SnapshotLabel' is safer.
8180
snapMetaLabel :: !SnapshotLabel
8281
-- | Whether a table is normal or monoidal.

src/Database/LSMTree/Monoidal.hs

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ module Database.LSMTree.Monoidal (
8383
-- * Durability (snapshots)
8484
, SnapshotName
8585
, Common.mkSnapshotName
86-
, Common.Labellable (..)
86+
, Common.SnapshotLabel (..)
8787
, createSnapshot
8888
, openSnapshot
8989
, Common.TableConfigOverride
@@ -517,8 +517,9 @@ mupserts t = updates t . fmap (second Mupsert)
517517
-------------------------------------------------------------------------------}
518518

519519
{-# SPECIALISE createSnapshot ::
520-
(ResolveValue v, Common.Labellable (k, v))
521-
=> SnapshotName
520+
ResolveValue v
521+
=> Common.SnapshotLabel
522+
-> SnapshotName
522523
-> Table IO k v
523524
-> IO () #-}
524525
-- | Make the current value of a table durable on-disk by taking a snapshot and
@@ -546,20 +547,19 @@ mupserts t = updates t . fmap (second Mupsert)
546547
createSnapshot :: forall m k v.
547548
( IOLike m
548549
, ResolveValue v
549-
, Common.Labellable (k, v)
550550
)
551-
=> SnapshotName
551+
=> Common.SnapshotLabel
552+
-> SnapshotName
552553
-> Table m k v
553554
-> m ()
554-
createSnapshot snap (Internal.MonoidalTable t) =
555+
createSnapshot label snap (Internal.MonoidalTable t) =
555556
Internal.createSnapshot (resolve @v Proxy) snap label Internal.SnapMonoidalTable t
556-
where
557-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v))
558557

559558
{-# SPECIALISE openSnapshot ::
560-
(ResolveValue v, Common.Labellable (k, v))
559+
ResolveValue v
561560
=> Session IO
562561
-> Common.TableConfigOverride
562+
-> Common.SnapshotLabel
563563
-> SnapshotName
564564
-> IO (Table IO k v) #-}
565565
-- | Open a table from a named snapshot, returning a new table.
@@ -583,13 +583,13 @@ createSnapshot snap (Internal.MonoidalTable t) =
583583
openSnapshot :: forall m k v.
584584
( IOLike m
585585
, ResolveValue v
586-
, Common.Labellable (k, v)
587586
)
588587
=> Session m
589588
-> Common.TableConfigOverride -- ^ Optional config override
589+
-> Common.SnapshotLabel
590590
-> SnapshotName
591591
-> m (Table m k v)
592-
openSnapshot (Internal.Session' sesh) override snap =
592+
openSnapshot (Internal.Session' sesh) override label snap =
593593
Internal.MonoidalTable <$>
594594
Internal.openSnapshot
595595
sesh
@@ -598,8 +598,6 @@ openSnapshot (Internal.Session' sesh) override snap =
598598
override
599599
snap
600600
(resolve @v Proxy)
601-
where
602-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v))
603601

604602
{-------------------------------------------------------------------------------
605603
Multiple writable tables

src/Database/LSMTree/Normal.hs

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ module Database.LSMTree.Normal (
8484
-- * Durability (snapshots)
8585
, SnapshotName
8686
, Common.mkSnapshotName
87-
, Common.Labellable (..)
87+
, Common.SnapshotLabel (..)
8888
, createSnapshot
8989
, openSnapshot
9090
, Common.TableConfigOverride
@@ -115,7 +115,7 @@ import Control.Exception (throw)
115115
import Control.Monad
116116
import Data.Bifunctor (Bifunctor (..))
117117
import Data.Kind (Type)
118-
import Data.Typeable (Proxy (..), eqT, type (:~:) (Refl))
118+
import Data.Typeable (eqT, type (:~:) (Refl))
119119
import qualified Data.Vector as V
120120
import Database.LSMTree.Common (BlobRef (BlobRef), IOLike, Range (..),
121121
SerialiseKey, SerialiseValue, Session, SnapshotName,
@@ -635,8 +635,8 @@ retrieveBlobs (Internal.Session' (sesh :: Internal.Session m h)) refs =
635635
-------------------------------------------------------------------------------}
636636

637637
{-# SPECIALISE createSnapshot ::
638-
Common.Labellable (k, v, blob)
639-
=> SnapshotName
638+
Common.SnapshotLabel
639+
-> SnapshotName
640640
-> Table IO k v blob
641641
-> IO () #-}
642642
-- | Make the current value of a table durable on-disk by taking a snapshot and
@@ -647,6 +647,11 @@ retrieveBlobs (Internal.Session' (sesh :: Internal.Session m h)) refs =
647647
-- via that name. Names are strings and the management of the names is up to
648648
-- the user of the library.
649649
--
650+
-- Snapshot labels are included in the snapshot metadata when a snapshot is
651+
-- created. Labels are text and the management of the labels is up to the user
652+
-- of the library. Labels assigns a dynamically checked "type" to a snapshot.
653+
-- See 'Common.SnapshotLabel' for more information.
654+
--
650655
-- The names correspond to disk files, which imposes some constraints on length
651656
-- and what characters can be used.
652657
--
@@ -661,25 +666,26 @@ retrieveBlobs (Internal.Session' (sesh :: Internal.Session m h)) refs =
661666
-- * It is safe to concurrently make snapshots from any table, provided that
662667
-- the snapshot names are distinct (otherwise this would be a race).
663668
createSnapshot :: forall m k v blob.
664-
( IOLike m
665-
, Common.Labellable (k, v, blob)
666-
)
667-
=> SnapshotName
669+
IOLike m
670+
=> Common.SnapshotLabel
671+
-> SnapshotName
668672
-> Table m k v blob
669673
-> m ()
670-
createSnapshot snap (Internal.NormalTable t) =
674+
createSnapshot label snap (Internal.NormalTable t) =
671675
Internal.createSnapshot const snap label Internal.SnapNormalTable t
672-
where
673-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v, blob))
674676

675677
{-# SPECIALISE openSnapshot ::
676-
Common.Labellable (k, v, blob)
677-
=> Session IO
678+
Session IO
678679
-> Common.TableConfigOverride
680+
-> Common.SnapshotLabel
679681
-> SnapshotName
680682
-> IO (Table IO k v blob ) #-}
681683
-- | Open a table from a named snapshot, returning a new table.
682684
--
685+
-- This function requires passing in an expected label that will be checked
686+
-- against the label that was included in the snapshot metadata. If there is a
687+
-- mismatch, an exception is thrown.
688+
--
683689
-- NOTE: close tables using 'close' as soon as they are
684690
-- unused.
685691
--
@@ -697,14 +703,13 @@ createSnapshot snap (Internal.NormalTable t) =
697703
-- 'openSnapshot' \@IO \@Bool \@Bool \@Bool session "intTable"
698704
-- @
699705
openSnapshot :: forall m k v blob.
700-
( IOLike m
701-
, Common.Labellable (k, v, blob)
702-
)
706+
IOLike m
703707
=> Session m
704708
-> Common.TableConfigOverride -- ^ Optional config override
709+
-> Common.SnapshotLabel
705710
-> SnapshotName
706711
-> m (Table m k v blob)
707-
openSnapshot (Internal.Session' sesh) override snap =
712+
openSnapshot (Internal.Session' sesh) override label snap =
708713
Internal.NormalTable <$!>
709714
Internal.openSnapshot
710715
sesh
@@ -713,8 +718,6 @@ openSnapshot (Internal.Session' sesh) override snap =
713718
override
714719
snap
715720
const
716-
where
717-
label = Internal.SnapshotLabel $ Common.makeSnapshotLabel (Proxy @(k, v, blob))
718721

719722
{-------------------------------------------------------------------------------
720723
Mutiple writable tables

0 commit comments

Comments
 (0)