Skip to content

Commit ab5bf50

Browse files
committed
A reference implementation for the unified LSM-Tree class
1 parent c88bf05 commit ab5bf50

File tree

2 files changed

+113
-0
lines changed

2 files changed

+113
-0
lines changed

lsm-tree.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ test-suite lsm-tree-test
348348
Database.LSMTree.Class.Monoidal
349349
Database.LSMTree.Class.Normal
350350
Database.LSMTree.Model
351+
Database.LSMTree.Model.IO
351352
Database.LSMTree.Model.IO.Monoidal
352353
Database.LSMTree.Model.IO.Normal
353354
Database.LSMTree.Model.Session

test/Database/LSMTree/Model/IO.hs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
{-# LANGUAGE TypeFamilies #-}
2+
3+
-- | An instance of `Class.IsTable`, modelling potentially closed sessions in
4+
-- @IO@ by lifting the pure session model from "Database.LSMTree.Model.Session".
5+
module Database.LSMTree.Model.IO (
6+
Err (..)
7+
, Session (..)
8+
, Class.SessionArgs (NoSessionArgs)
9+
, Table (..)
10+
, TableConfig (..)
11+
, BlobRef (..)
12+
, Cursor (..)
13+
-- * helpers
14+
, runInOpenSession
15+
, convLookupResult
16+
, convQueryResult
17+
, convUpdate
18+
) where
19+
20+
import Control.Concurrent.Class.MonadSTM.Strict
21+
import Control.Exception (Exception)
22+
import Control.Monad.Class.MonadThrow (MonadThrow (..))
23+
import qualified Database.LSMTree.Class as Class
24+
import Database.LSMTree.Model.Session (TableConfig (..))
25+
import qualified Database.LSMTree.Model.Session as Model
26+
27+
newtype Session m = Session (StrictTVar m (Maybe Model.Model))
28+
29+
data Table m k v b = Table {
30+
_thSession :: !(Session m)
31+
, _thTable :: !(Model.Table k v b)
32+
}
33+
34+
data BlobRef m b = BlobRef {
35+
_brSession :: !(Session m)
36+
, _brBlobRef :: !(Model.BlobRef b)
37+
}
38+
39+
data Cursor m k v b = Cursor {
40+
_cSession :: !(Session m)
41+
, _cCursor :: !(Model.Cursor k v b)
42+
}
43+
44+
newtype Err = Err (Model.Err)
45+
deriving stock Show
46+
deriving anyclass Exception
47+
48+
runInOpenSession :: (MonadSTM m, MonadThrow (STM m)) => Session m -> Model.ModelM a -> m a
49+
runInOpenSession (Session var) action = atomically $ do
50+
readTVar var >>= \case
51+
Nothing -> error "session closed"
52+
Just m -> do
53+
let (r, m') = Model.runModelM action m
54+
case r of
55+
Left e -> throwSTM (Err e)
56+
Right x -> writeTVar var (Just m') >> pure x
57+
58+
instance Class.IsSession Session where
59+
data SessionArgs Session m = NoSessionArgs
60+
openSession NoSessionArgs = Session <$> newTVarIO (Just $! Model.initModel)
61+
closeSession (Session var) = atomically $ writeTVar var Nothing
62+
deleteSnapshot s x = runInOpenSession s $ Model.deleteSnapshot x
63+
listSnapshots s = runInOpenSession s $ Model.listSnapshots
64+
65+
instance Class.IsTable Table where
66+
type Session Table = Session
67+
type TableConfig Table = Model.TableConfig
68+
type BlobRef Table = BlobRef
69+
type Cursor Table = Cursor
70+
71+
new s x = Table s <$> runInOpenSession s (Model.new x)
72+
close (Table s t) = runInOpenSession s (Model.close t)
73+
lookups (Table s t) x1 = fmap convLookupResult . fmap (fmap (BlobRef s)) <$>
74+
runInOpenSession s (Model.lookups x1 t)
75+
updates (Table s t) x1 = runInOpenSession s (Model.updates Model.getResolve (fmap (fmap convUpdate) x1) t)
76+
inserts (Table s t) x1 = runInOpenSession s (Model.inserts Model.getResolve x1 t)
77+
deletes (Table s t) x1 = runInOpenSession s (Model.deletes Model.getResolve x1 t)
78+
mupserts (Table s t) x1 = runInOpenSession s (Model.mupserts Model.getResolve x1 t)
79+
80+
rangeLookup (Table s t) x1 = fmap convQueryResult . fmap (fmap (BlobRef s)) <$>
81+
runInOpenSession s (Model.rangeLookup x1 t)
82+
retrieveBlobs _ s x1 = runInOpenSession s (Model.retrieveBlobs (fmap _brBlobRef x1))
83+
84+
newCursor k (Table s t) = Cursor s <$> runInOpenSession s (Model.newCursor k t)
85+
closeCursor _ (Cursor s c) = runInOpenSession s (Model.closeCursor c)
86+
readCursor _ x1 (Cursor s c) = fmap convQueryResult . fmap (fmap (BlobRef s)) <$>
87+
runInOpenSession s (Model.readCursor x1 c)
88+
89+
createSnapshot x1 x2 (Table s t) = runInOpenSession s (Model.createSnapshot x1 x2 t)
90+
openSnapshot s x1 x2 = Table s <$> runInOpenSession s (Model.openSnapshot x1 x2)
91+
92+
duplicate (Table s t) = Table s <$> runInOpenSession s (Model.duplicate t)
93+
94+
union (Table s1 t1) (Table _s2 t2) =
95+
Table s1 <$> runInOpenSession s1 (Model.union Model.getResolve t1 t2)
96+
97+
convLookupResult :: Model.LookupResult v b -> Class.LookupResult v b
98+
convLookupResult = \case
99+
Model.NotFound -> Class.NotFound
100+
Model.Found v -> Class.Found v
101+
Model.FoundWithBlob v b -> Class.FoundWithBlob v b
102+
103+
convQueryResult :: Model.QueryResult k v b -> Class.QueryResult k v b
104+
convQueryResult = \case
105+
Model.FoundInQuery k v -> Class.FoundInQuery k v
106+
Model.FoundInQueryWithBlob k v b -> Class.FoundInQueryWithBlob k v b
107+
108+
convUpdate :: Class.Update v b -> Model.Update v b
109+
convUpdate = \case
110+
Class.Insert v b -> Model.Insert v b
111+
Class.Delete -> Model.Delete
112+
Class.Mupsert v -> Model.Mupsert v

0 commit comments

Comments
 (0)