on master help sign in
WIP: transaction graph reads and writes now working
b522248AgentM
ProjectM36/Base.hs+3
@@ -261,3 +261,6 @@ data AttributeNames = AttributeNames (S.Set AttributeName) |
261
261
262instance Binary AttributeNames
262instance Binary AttributeNames
263
263
264+data PersistenceStrategy = NoPersistence | --no filesystem persistence/memory-only database
265+ MinimalPersistence --fsync off
266+ --CrashSafePersistence --full fsync- not yet implemented
ProjectM36/Transaction/Persist.hs+16−9
@@ -10,6 +10,12 @@ import System.FilePath
10import System.Directory
10import System.Directory
11import qualified Data.Text as T
11import qualified Data.Text as T
12import Control.Monad
12import Control.Monad
13+import ProjectM36.RelationalExpression (basicAtomFunctions)
14+
15+getDirectoryNames :: FilePath -> IO [FilePath]
16+getDirectoryNames path = do
17+ subpaths <- getDirectoryContents path
18+ return $ filter (\n -> n `notElem` ["..", "."]) subpaths
13
19
14tempTransactionDir :: FilePath -> U.UUID -> FilePath
20tempTransactionDir :: FilePath -> U.UUID -> FilePath
15tempTransactionDir dbdir transUUID = dbdir </> "." ++ U.toString transUUID
21tempTransactionDir dbdir transUUID = dbdir </> "." ++ U.toString transUUID
@@ -18,16 +24,16 @@ transactionDir :: FilePath -> U.UUID -> FilePath
18transactionDir dbdir transUUID = dbdir </> U.toString transUUID
24transactionDir dbdir transUUID = dbdir </> U.toString transUUID
19
25
20transactionInfoPath :: FilePath -> FilePath
26transactionInfoPath :: FilePath -> FilePath
21−transactionInfoPath = (</>) "info"
27+transactionInfoPath transdir = transdir </> "info"
22
28
23relvarsDir :: FilePath -> FilePath
29relvarsDir :: FilePath -> FilePath
24−relvarsDir = (</>) "relvars"
30+relvarsDir transdir = transdir </> "relvars"
25
31
26incDepsDir :: FilePath -> FilePath
32incDepsDir :: FilePath -> FilePath
27−incDepsDir = (</>) "incdeps"
33+incDepsDir transdir = transdir </> "incdeps"
28
34
29atomFuncsDir :: FilePath -> FilePath
35atomFuncsDir :: FilePath -> FilePath
30−atomFuncsDir = (</>) "atomfuncs"
36+atomFuncsDir transdir = transdir </> "atomfuncs"
31
37
32readTransaction :: FilePath -> U.UUID -> IO (Either PersistenceError Transaction)
38readTransaction :: FilePath -> U.UUID -> IO (Either PersistenceError Transaction)
33readTransaction dbdir transUUID = do
39readTransaction dbdir transUUID = do
@@ -39,7 +45,8 @@ readTransaction dbdir transUUID = do
39 relvars <- readRelVars transDir
45 relvars <- readRelVars transDir
40 transInfo <- liftM B.decode $ BS.readFile (transactionInfoPath transDir)
46 transInfo <- liftM B.decode $ BS.readFile (transactionInfoPath transDir)
41 incDeps <- readIncDeps transDir
47 incDeps <- readIncDeps transDir
42− atomFuncs <- readAtomFuncs transDir
48+ --atomFuncs <- readAtomFuncs transDir -- not yet supported since there is no bytecode to serialize yet
49+ let atomFuncs = basicAtomFunctions
43 let newContext = DatabaseContext { inclusionDependencies = incDeps,
50 let newContext = DatabaseContext { inclusionDependencies = incDeps,
44 relationVariables = relvars,
51 relationVariables = relvars,
45 atomFunctions = atomFuncs }
52 atomFunctions = atomFuncs }
@@ -75,19 +82,19 @@ writeRelVars transDir relvars = mapM_ (writeRelVar transDir) $ M.toList relvars
75readRelVars :: FilePath -> IO (M.Map RelVarName Relation)
82readRelVars :: FilePath -> IO (M.Map RelVarName Relation)
76readRelVars transDir = do
83readRelVars transDir = do
77 let relvarsPath = relvarsDir transDir
84 let relvarsPath = relvarsDir transDir
78− relvarNames <- getDirectoryContents relvarsPath
85+ relvarNames <- getDirectoryNames relvarsPath
79 relvars <- mapM (\name -> do
86 relvars <- mapM (\name -> do
80 rel <- liftM B.decode $ BS.readFile (relvarsPath </> name)
87 rel <- liftM B.decode $ BS.readFile (relvarsPath </> name)
81 return (T.pack name, rel)) relvarNames
88 return (T.pack name, rel)) relvarNames
82 return $ M.fromList relvars
89 return $ M.fromList relvars
83
90
84writeAtomFuncs :: FilePath -> AtomFunctions -> IO ()
91writeAtomFuncs :: FilePath -> AtomFunctions -> IO ()
85−writeAtomFuncs transDir funcs = mapM_ (writeAtomFunc (atomFuncsDir transDir)) $ HS.toList funcs
92+writeAtomFuncs transDir funcs = mapM_ (writeAtomFunc transDir) $ HS.toList funcs
86
93
87--all the atom functions are in one file (???)
94--all the atom functions are in one file (???)
88readAtomFuncs :: FilePath -> IO (AtomFunctions)
95readAtomFuncs :: FilePath -> IO (AtomFunctions)
89readAtomFuncs transDir = do
96readAtomFuncs transDir = do
90− funcNames <- getDirectoryContents (incDepsDir transDir)
97+ funcNames <- getDirectoryNames (atomFuncsDir transDir)
91 funcs <- mapM (readAtomFunc transDir) (map T.pack funcNames)
98 funcs <- mapM (readAtomFunc transDir) (map T.pack funcNames)
92 return $ HS.fromList funcs
99 return $ HS.fromList funcs
93
100
@@ -119,6 +126,6 @@ readIncDep transDir incdepName = do
119readIncDeps :: FilePath -> IO (M.Map IncDepName InclusionDependency)
126readIncDeps :: FilePath -> IO (M.Map IncDepName InclusionDependency)
120readIncDeps transDir = do
127readIncDeps transDir = do
121 let incDepsPath = incDepsDir transDir
128 let incDepsPath = incDepsDir transDir
122− incDepNames <- getDirectoryContents incDepsPath
129+ incDepNames <- getDirectoryNames incDepsPath
123 incDeps <- mapM (readIncDep transDir) (map T.pack incDepNames)
130 incDeps <- mapM (readIncDep transDir) (map T.pack incDepNames)
124 return $ M.fromList incDeps
131 return $ M.fromList incDeps
ProjectM36/TransactionGraph.hs−1
@@ -8,7 +8,6 @@ import qualified Data.Map as M
8import Control.Applicative ((<$>))
8import Control.Applicative ((<$>))
9import Control.Monad
9import Control.Monad
10
10
11−
12bootstrapTransactionGraph :: U.UUID -> DatabaseContext -> TransactionGraph
11bootstrapTransactionGraph :: U.UUID -> DatabaseContext -> TransactionGraph
13bootstrapTransactionGraph freshUUID context = TransactionGraph bootstrapHeads bootstrapTransactions
12bootstrapTransactionGraph freshUUID context = TransactionGraph bootstrapHeads bootstrapTransactions
14 where
13 where
ProjectM36/TransactionGraph/Persist.hs+31−19
@@ -18,6 +18,7 @@ import Control.Monad (foldM)
18import Data.Either (isRight)
18import Data.Either (isRight)
19import Data.Maybe (catMaybes)
19import Data.Maybe (catMaybes)
20
20
21+
21{-
22{-
22The "m36v1" file at the top-level of the destination directory contains the the transaction graph as a set of UUIDs referencing their parents (1 or more)
23The "m36v1" file at the top-level of the destination directory contains the the transaction graph as a set of UUIDs referencing their parents (1 or more)
23Each Transaction is written to it own directory named by its UUID. Partially written transactions UUIDs are prefixed with a "." to indicate incompleteness in the graph.
24Each Transaction is written to it own directory named by its UUID. Partially written transactions UUIDs are prefixed with a "." to indicate incompleteness in the graph.
@@ -25,10 +26,10 @@ Each Transaction is written to it own directory named by its UUID. Partially wri
25-}
26-}
26
27
27transactionLogPath :: FilePath -> FilePath
28transactionLogPath :: FilePath -> FilePath
28−transactionLogPath = (</>) "m36v1"
29+transactionLogPath dbdir = dbdir </> "m36v1"
29
30
30−headsDir :: FilePath -> FilePath
31+headsPath :: FilePath -> FilePath
31−headsDir = (</>) "heads"
32+headsPath dbdir = dbdir </> "heads"
32
33
33{-
34{-
34verify that the database directory is valid or bootstrap it
35verify that the database directory is valid or bootstrap it
@@ -54,6 +55,8 @@ bootstrapDatabaseDir :: FilePath -> TransactionGraph -> IO ()
54bootstrapDatabaseDir dbdir bootstrapGraph = do
55bootstrapDatabaseDir dbdir bootstrapGraph = do
55 createDirectory dbdir
56 createDirectory dbdir
56 transactionGraphPersist dbdir bootstrapGraph
57 transactionGraphPersist dbdir bootstrapGraph
58+ putStrLn "Bootstrapped DB."
59+
57
60
58{-
61{-
59incrementally updates an existing database directory
62incrementally updates an existing database directory
@@ -70,24 +73,26 @@ transactionGraphPersist destDirectory graph = do
70 return ()
73 return ()
71
74
72{-
75{-
73−write a head datum to the file system
76+write graph heads to a file which can be atomically swapped
74−1. create a symlink in a temporary directory
75−2. atomically rename it
76-}
77-}
77−--should updating all the heads be atomic (create temp directory and new symlinks for every persistence?
78+--writing the heads in a directory is a synchronization nightmare, so just write the binary to a file and swap atomically
78transactionGraphHeadsPersist :: FilePath -> TransactionGraph -> IO ()
79transactionGraphHeadsPersist :: FilePath -> TransactionGraph -> IO ()
79transactionGraphHeadsPersist dbdir graph = do
80transactionGraphHeadsPersist dbdir graph = do
80− let writeHead headsPath (headName, trans) = do
81+ let headFileStr :: (HeadName, Transaction) -> String
81− let symlinkPath = ".." </> U.toString (transactionUUID trans)
82+ headFileStr (headName, trans) = T.unpack headName ++ " " ++ U.toString (transactionUUID trans)
82− createSymbolicLink symlinkPath (headsPath </> T.unpack headName)
83− finalHeadsDir = headsDir dbdir
84− withTempDirectory dbdir ".headsdir.XXXXX" $ \newHeadsDir -> do
83+ withTempDirectory dbdir ".heads.tmp" $ \tempHeadsDir -> do
85− let tempHeadsDir = (newHeadsDir </> "heads")
84+ let tempHeadsPath = tempHeadsDir </> "heads"
86− createDirectory tempHeadsDir
87− mapM_ (writeHead tempHeadsDir) $ M.toList (transactionHeadsForGraph graph)
85+ headsStrLines = map headFileStr $ M.toList (transactionHeadsForGraph graph)
88− --move the new heads dir into place atomically
86+ writeFile tempHeadsPath $ intercalate "\n" headsStrLines
89− renameDirectory tempHeadsDir finalHeadsDir
87+ rename tempHeadsPath (headsPath dbdir)
90−
88+
89+transactionGraphHeadsLoad :: FilePath -> IO [(HeadName,U.UUID)]
90+transactionGraphHeadsLoad dbdir = do
91+ headsData <- readFile (headsPath dbdir)
92+ let headsAssocs = map (\l -> let headName:uuidStr:[] = words l in
93+ (headName,uuidStr)
94+ ) (lines headsData)
95+ return [(T.pack headName, uuid) | (headName, Just uuid) <- map (\(h,u) -> (h, U.fromString u)) headsAssocs]
91
96
92{-
97{-
93load any transactions which are not already part of the incoming transaction graph
98load any transactions which are not already part of the incoming transaction graph
@@ -99,13 +104,20 @@ transactionGraphLoad dbdir graphIn = do
99 --optimization: perform tail-bisection search to find last-recorded transaction in the existing stream- replay the rest
104 --optimization: perform tail-bisection search to find last-recorded transaction in the existing stream- replay the rest
100 --read in all missing transactions from transaction directories and add to graph
105 --read in all missing transactions from transaction directories and add to graph
101 uuidInfo <- readGraphUUIDFile dbdir
106 uuidInfo <- readGraphUUIDFile dbdir
107+ freshHeadsAssoc <- transactionGraphHeadsLoad dbdir
102 case uuidInfo of
108 case uuidInfo of
103 Left err -> return $ Left err
109 Left err -> return $ Left err
104 Right info -> do
110 Right info -> do
105 let folder = \eitherGraph transUUID -> case eitherGraph of
111 let folder = \eitherGraph transUUID -> case eitherGraph of
106 Left err -> return $ Left err
112 Left err -> return $ Left err
107 Right graph -> readTransactionIfNecessary dbdir transUUID graph
113 Right graph -> readTransactionIfNecessary dbdir transUUID graph
108− foldM folder (Right graphIn) (map fst info)
114+ loadedGraph <- foldM folder (Right graphIn) (map fst info)
115+ case loadedGraph of
116+ Left err -> return $ Left err
117+ Right freshGraph -> do
118+ let maybeTransHeads = [(headName, transactionForUUID uuid freshGraph) | (headName, uuid) <- freshHeadsAssoc]
119+ freshHeads = M.fromList [(headName,trans) | (headName, Right trans) <- maybeTransHeads]
120+ return $ Right $ TransactionGraph freshHeads (transactionsForGraph freshGraph)
109
121
110{-
122{-
111if the transaction with the UUID argument is not yet part of the graph, then read the transaction and add it - this does not update the heads
123if the transaction with the UUID argument is not yet part of the graph, then read the transaction and add it - this does not update the heads
ProjectM36/TransactionGraph/Show.hs−1
@@ -5,7 +5,6 @@ import ProjectM36.Relation
5import ProjectM36.Tuple
5import ProjectM36.Tuple
6import ProjectM36.TupleSet
6import ProjectM36.TupleSet
7import ProjectM36.Error
7import ProjectM36.Error
8−import ProjectM36.Transaction
9import ProjectM36.TransactionGraph
8import ProjectM36.TransactionGraph
10import qualified ProjectM36.Attribute as A
9import qualified ProjectM36.Attribute as A
11import qualified Data.HashSet as HS
10import qualified Data.HashSet as HS
TutorialD/Interpreter.hs+25−21
@@ -6,7 +6,6 @@ import TutorialD.Interpreter.DatabaseExpr
6import TutorialD.Interpreter.TransactionGraphOperator
6import TutorialD.Interpreter.TransactionGraphOperator
7import ProjectM36.Base
7import ProjectM36.Base
8import ProjectM36.TransactionGraph
8import ProjectM36.TransactionGraph
9−import ProjectM36.TransactionGraph.Persist
10import Text.Parsec
9import Text.Parsec
11import Text.Parsec.String
10import Text.Parsec.String
12import Control.Monad.State
11import Control.Monad.State
@@ -42,45 +41,50 @@ promptText (DisconnectedTransaction parentUUID _) graph = "TutorialD (" `T.appen
42 Nothing -> T.pack (show $ transactionUUID parentTrans)
41 Nothing -> T.pack (show $ transactionUUID parentTrans)
43 Just headName -> headName
42 Just headName -> headName
44
43
45−interpret :: U.UUID -> DisconnectedTransaction -> TransactionGraph -> String -> (TutorialDOperatorResult, DisconnectedTransaction, TransactionGraph)
44+interpret :: U.UUID -> DisconnectedTransaction -> TransactionGraph -> String -> (TutorialDOperatorResult, DisconnectedTransaction, TransactionGraph, TransactionGraphWasUpdated)
46interpret freshUUID discon@(DisconnectedTransaction parentUUID context) graph inputString = case parse interpreterParserP "" inputString of
45interpret freshUUID discon@(DisconnectedTransaction parentUUID context) graph inputString = case parse interpreterParserP "" inputString of
47− Left err -> (DisplayErrorResult (T.pack $ show err), discon, graph)
46+ Left err -> (DisplayErrorResult (T.pack $ show err), discon, graph, False)
48− Right (RODatabaseContextOp execOp) -> (evalRODatabaseContextOp context execOp, discon, graph)
47+ Right (RODatabaseContextOp execOp) -> (evalRODatabaseContextOp context execOp, discon, graph, False)
49 Right (DatabaseExprOp execOp) -> case evalDatabaseExpr True context execOp of
48 Right (DatabaseExprOp execOp) -> case evalDatabaseExpr True context execOp of
50− Left err -> (DisplayErrorResult $ T.pack (show err), discon, graph)
49+ Left err -> (DisplayErrorResult $ T.pack (show err), discon, graph, False)
51− Right context' -> (QuietSuccessResult, DisconnectedTransaction parentUUID context', graph)
50+ Right context' -> (QuietSuccessResult, DisconnectedTransaction parentUUID context', graph, False)
52 Right (GraphOp execOp) -> case evalGraphOp freshUUID discon graph execOp of
51 Right (GraphOp execOp) -> case evalGraphOp freshUUID discon graph execOp of
53− Left err -> (DisplayErrorResult $ T.pack (show err), discon, graph)
52+ Left err -> (DisplayErrorResult $ T.pack (show err), discon, graph, False)
54− Right (discon', graph', result') -> (result', discon', graph')
53+ Right (discon', graph', result') -> (result', discon', graph', True)
54+
55+data InterpreterConfig = InterpreterConfig {
56+ persistenceStrategy :: PersistenceStrategy,
57+ databaseDirectory :: FilePath
58+ }
55
59
56−reprLoop :: FilePath -> DisconnectedTransaction -> TransactionGraph -> IO ()
60+reprLoop :: InterpreterConfig -> DisconnectedTransaction -> TransactionGraph -> IO ()
57−reprLoop transGraphDir currentTransaction graph = do
61+reprLoop config currentTransaction graph = do
58 homeDirectory <- getHomeDirectory
62 homeDirectory <- getHomeDirectory
59 let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
63 let settings = defaultSettings {historyFile = Just (homeDirectory ++ "/.tutd_history")}
60
64
61 maybeLine <- runInputT settings $ getInputLine (T.unpack (promptText currentTransaction graph))
65 maybeLine <- runInputT settings $ getInputLine (T.unpack (promptText currentTransaction graph))
62
66
63− let roloop = reprLoop transGraphDir currentTransaction graph
67+ let roloop = reprLoop config currentTransaction graph
64 case maybeLine of
68 case maybeLine of
65 Nothing -> return ()
69 Nothing -> return ()
66 Just line -> do
70 Just line -> do
67 newUUID <- nextRandom
71 newUUID <- nextRandom
68− case interpret newUUID currentTransaction graph line of
72+ let (opResult, disconTrans, updatedGraph, graphWasUpdated) = interpret newUUID currentTransaction graph line
73+ when graphWasUpdated $ processPersistence (databaseDirectory config) (persistenceStrategy config) updatedGraph
74+ case (opResult, disconTrans, updatedGraph) of
69 (QuitResult, _, _) -> return ()
75 (QuitResult, _, _) -> return ()
70 (DisplayErrorResult err, _, _) -> TIO.hPutStrLn stderr ("ERROR: " `T.append` err) >> roloop
76 (DisplayErrorResult err, _, _) -> TIO.hPutStrLn stderr ("ERROR: " `T.append` err) >> roloop
71− (DisplayIOResult outio, updatedTrans, updatedGraph) -> do
77+ (DisplayIOResult outio, updatedTrans', updatedGraph') -> do
72 outio
78 outio
73− reprLoop transGraphDir updatedTrans updatedGraph
79+ reprLoop config updatedTrans' updatedGraph'
74− (DisplayResult out, updatedTrans, updatedGraph) -> do
80+ (DisplayResult out, updatedTrans', updatedGraph') -> do
75 TIO.putStrLn out
81 TIO.putStrLn out
82+ --assume that the DisplayResult type implies that the transaction graph was not updated
83+ reprLoop config updatedTrans' updatedGraph'
84+ (QuietSuccessResult, updatedTrans', updatedGraph') -> do
76 --save the current transaction graph
85 --save the current transaction graph
77− transactionGraphPersist transGraphDir updatedGraph
78− reprLoop transGraphDir updatedTrans updatedGraph
79− (QuietSuccessResult, updatedTrans, updatedGraph) -> do
80− --save the current transaction graph
81− transactionGraphPersist transGraphDir updatedGraph
82 TIO.putStrLn "Done."
86 TIO.putStrLn "Done."
83− reprLoop transGraphDir updatedTrans updatedGraph
87+ reprLoop config updatedTrans' updatedGraph'
84
88
85--used by :dumpGraph
89--used by :dumpGraph
86{-
90{-
TutorialD/Interpreter/Base.hs+7
@@ -10,6 +10,7 @@ import qualified Data.List as L
10import qualified Data.Vector as V
10import qualified Data.Vector as V
11import qualified Data.Text.IO as TIO
11import qualified Data.Text.IO as TIO
12import System.IO
12import System.IO
13+import ProjectM36.TransactionGraph.Persist
13
14
14lexer :: Token.TokenParser ()
15lexer :: Token.TokenParser ()
15lexer = Token.makeTokenParser tutD
16lexer = Token.makeTokenParser tutD
@@ -64,6 +65,8 @@ data TutorialDOperatorResult = QuitResult |
64 DisplayIOResult (IO ()) |
65 DisplayIOResult (IO ()) |
65 DisplayErrorResult StringType |
66 DisplayErrorResult StringType |
66 QuietSuccessResult
67 QuietSuccessResult
68+
69+type TransactionGraphWasUpdated = Bool
67
70
68displayOpResult :: TutorialDOperatorResult -> IO ()
71displayOpResult :: TutorialDOperatorResult -> IO ()
69displayOpResult QuitResult = return ()
72displayOpResult QuitResult = return ()
@@ -71,3 +74,7 @@ displayOpResult (DisplayResult out) = TIO.putStrLn out
71displayOpResult (DisplayIOResult ioout) = ioout
74displayOpResult (DisplayIOResult ioout) = ioout
72displayOpResult (DisplayErrorResult err) = TIO.hPutStrLn stderr ("ERR: " `T.append` err)
75displayOpResult (DisplayErrorResult err) = TIO.hPutStrLn stderr ("ERR: " `T.append` err)
73displayOpResult QuietSuccessResult = return ()
76displayOpResult QuietSuccessResult = return ()
77+
78+processPersistence :: FilePath -> PersistenceStrategy -> TransactionGraph -> IO ()
79+processPersistence _ NoPersistence _ = return ()
80+processPersistence dbdir MinimalPersistence graph = transactionGraphPersist dbdir graph
TutorialD/tutd.hs+12−8
@@ -7,6 +7,7 @@ import ProjectM36.Transaction
7import ProjectM36.Base
7import ProjectM36.Base
8import System.IO
8import System.IO
9import Data.UUID.V4 (nextRandom)
9import Data.UUID.V4 (nextRandom)
10+import qualified Data.Text as T
10
11
11main :: IO ()
12main :: IO ()
12main = do
13main = do
@@ -14,16 +15,19 @@ main = do
14 let currentHeadName = "master"
15 let currentHeadName = "master"
15 --if the database is empty, bootstrap it with the bootstrap graph
16 --if the database is empty, bootstrap it with the bootstrap graph
16 bootstrapGraph = bootstrapTransactionGraph freshUUID dateExamples
17 bootstrapGraph = bootstrapTransactionGraph freshUUID dateExamples
18+ interpreterConfig = InterpreterConfig { persistenceStrategy = MinimalPersistence,
17− dbdir = "/tmp/testdb"
19+ databaseDirectory = "/tmp/testdb" }
20+ dbdir = databaseDirectory interpreterConfig
18− err <- setupDatabaseDir dbdir bootstrapGraph
21+ err <- setupDatabaseDir dbdir bootstrapGraph
19 case err of
22 case err of
20− Just err -> hPutStrLn stderr $ "Database setup failed: " ++ show err
23+ Just err' -> hPutStrLn stderr $ "Database setup failed: " ++ show err'
21 Nothing -> do
24 Nothing -> do
22 freshGraph <- transactionGraphLoad dbdir emptyTransactionGraph
25 freshGraph <- transactionGraphLoad dbdir emptyTransactionGraph
23 case freshGraph of
26 case freshGraph of
24− Left err -> hPutStrLn stderr $ "Database load failed: " ++ show err
27+ Left err'' -> hPutStrLn stderr $ "Database load failed: " ++ show err''
25− Right freshGraph' -> do
26− let headTransaction = case transactionForHead currentHeadName freshGraph' of { Just x -> x; _ -> undefined}
28+ Right freshGraph' -> case transactionForHead currentHeadName freshGraph' of
29+ Nothing -> hPutStrLn stderr $ "Failed to find head transaction for " ++ T.unpack currentHeadName ++ "."
30+ Just headTransaction -> do
27− currentTransaction = newDisconnectedTransaction (transactionUUID headTransaction) (transactionContext headTransaction)
31+ let currentTransaction = newDisconnectedTransaction (transactionUUID headTransaction) (transactionContext headTransaction)
28− reprLoop dbdir currentTransaction freshGraph'
32+ reprLoop interpreterConfig currentTransaction freshGraph'
29
33
project-m36.cabal+6
@@ -73,6 +73,12 @@ Test-Suite test-static-optimizer
73 Build-Depends: base,HUnit,Cabal
73 Build-Depends: base,HUnit,Cabal
74 GHC-Options: -Wall
74 GHC-Options: -Wall
75
75
76+Test-Suite test-transactiongraph-persist
77+ type: exitcode-stdio-1.0
78+ main-is: test/TransactionGraph/Persist.hs
79+ Build-Depends: base,HUnit,Cabal
80+ GHC-Options: -Wall
81+
76benchmark bench
82benchmark bench
77 type: exitcode-stdio-1.0
83 type: exitcode-stdio-1.0
78 main-is: benchmark/Relation.hs
84 main-is: benchmark/Relation.hs