on master help sign in
Client.hs + session compiling
commitf12807426b51fa034472d98d6c56434ace4ab552 authorAgentM <agentm@themactionfaction.com> dateMon 30 Nov 2015, 18:27 (11 years ago) parent8e8df34
9 files changed+231−105
ProjectM36/Client.hs+165−84 ProjectM36/DatabaseContext.hs+8 ProjectM36/Error.hs+2 ProjectM36/Server/EntryPoints.hs+5−3 ProjectM36/Server/RemoteCallTypes.hs+18−9 ProjectM36/Session.hs+13 benchmark/bigrel.hs+2−2 project-m36.cabal+13−2 test/Daemon/Main.hs → test/Server/Main.hs+5−5
ProjectM36/Client.hs+165−84
@@ -30,6 +30,9 @@ module ProjectM36.Client
3030 Attribute(..),
3131 attributesFromList,
3232 createNodeId,
33+ createSessionAtCommit,
34+ createSessionAtHead,
35+ closeSession,
3336 TransactionGraphOperator(..),
3437 Atomable,
3538 NodeId(..),
@@ -40,7 +43,6 @@ import qualified ProjectM36.Base as B
4043import ProjectM36.Error
4144import ProjectM36.StaticOptimizer
4245import Control.Monad.State
43−import ProjectM36.Transaction
4446import qualified ProjectM36.RelationalExpression as RE
4547import ProjectM36.TransactionGraph
4648import ProjectM36.TransactionGraph.Persist
@@ -63,6 +65,9 @@ import Control.Concurrent.MVar
6365import qualified Data.Map as M
6466import Control.Distributed.Process.Serializable (Serializable)
6567--import Control.Distributed.Process.Debug
68+import qualified STMContainers.Map as STMMap
69+import ProjectM36.Session
70+import ListT
6671
6772type Hostname = String
6873
@@ -84,9 +89,12 @@ defaultDatabaseName = "base"
8489
8590defaultRemoteConnectionInfo :: ConnectionInfo
8691defaultRemoteConnectionInfo = RemoteProcessConnectionInfo defaultDatabaseName (createNodeId "127.0.0.1" defaultServerPort)
92+
93+type Sessions = STMMap.Map SessionId Session
94+
8795
88−data Connection = InProcessConnection PersistenceStrategy (TVar (DisconnectedTransaction, TransactionGraph)) |
89− RemoteProcessConnection LocalNode ProcessId -- perhaps should reference the local node as well
96+data Connection = InProcessConnection PersistenceStrategy Sessions (TVar TransactionGraph) |
97+ RemoteProcessConnection LocalNode ProcessId
9098
9199data ConnectionError = SetupDatabaseDirectoryError PersistenceError |
92100 IOExceptionError IOException |
@@ -109,16 +117,16 @@ connectProjectM36 :: ConnectionInfo -> IO (Either ConnectionError Connection)
109117--create a new in-memory database/transaction graph
110118connectProjectM36 (InProcessConnectionInfo strat) = do
111119 freshUUID <- nextRandom
112− let bootstrapContext = RE.basicDatabaseContext
113− freshDiscon = newDisconnectedTransaction freshUUID bootstrapContext
120+ let bootstrapContext = RE.basicDatabaseContext
114121 freshGraph = bootstrapTransactionGraph freshUUID bootstrapContext
115122 case strat of
116123 --create date examples graph for now- probably should be empty context in the future
117124 NoPersistence -> do
118− tvar <- newTVarIO (freshDiscon, freshGraph)
119− return $ Right $ InProcessConnection strat tvar
120− MinimalPersistence dbdir -> connectPersistentProjectM36 strat NoDiskSync dbdir freshDiscon freshGraph
121− CrashSafePersistence dbdir -> connectPersistentProjectM36 strat FsyncDiskSync dbdir freshDiscon freshGraph
125+ graphTvar <- newTVarIO freshGraph
126+ sessions <- STMMap.newIO
127+ return $ Right $ InProcessConnection strat sessions graphTvar
128+ MinimalPersistence dbdir -> connectPersistentProjectM36 strat NoDiskSync dbdir freshGraph
129+ CrashSafePersistence dbdir -> connectPersistentProjectM36 strat FsyncDiskSync dbdir freshGraph
122130
123131connectProjectM36 (RemoteProcessConnectionInfo databaseName serverNodeId) = do
124132 connStatus <- newEmptyMVar
@@ -140,14 +148,13 @@ connectProjectM36 (RemoteProcessConnectionInfo databaseName serverNodeId) = do
140148 liftIO $ putMVar connStatus (Right $ RemoteProcessConnection localNode serverProcessId)
141149 status <- takeMVar connStatus
142150 pure status
143−
151+
144152connectPersistentProjectM36 :: PersistenceStrategy ->
145153 DiskSync ->
146154 FilePath ->
147− DisconnectedTransaction ->
148155 TransactionGraph ->
149156 IO (Either ConnectionError Connection)
150−connectPersistentProjectM36 strat sync dbdir freshDiscon freshGraph = do
157+connectPersistentProjectM36 strat sync dbdir freshGraph = do
151158 err <- setupDatabaseDir sync dbdir freshGraph
152159 case err of
153160 Just err' -> return $ Left (SetupDatabaseDirectoryError err')
@@ -156,11 +163,54 @@ connectPersistentProjectM36 strat sync dbdir freshDiscon freshGraph = do
156163 case graph of
157164 Left err' -> return $ Left (SetupDatabaseDirectoryError err')
158165 Right graph' -> do
159− tvar <- newTVarIO (freshDiscon, graph')
160− return $ Right $ InProcessConnection strat tvar
166+ tvarGraph <- newTVarIO graph'
167+ sessions <- STMMap.newIO
168+ return $ Right $ InProcessConnection strat sessions tvarGraph
169+
170+-- | Create a new session at the transaction UUID and return the session's Id.
171+createSessionAtCommit :: UUID -> Connection -> IO (Either RelationalError SessionId)
172+createSessionAtCommit commitUUID conn@(InProcessConnection _ _ _) = do
173+ newSessionId <- nextRandom
174+ atomically $ do
175+ createSessionAtCommit_ commitUUID newSessionId conn
176+createSessionAtCommit uuid conn@(RemoteProcessConnection _ _) = remoteCall conn (CreateSessionAtCommit uuid)
177+
178+createSessionAtCommit_ :: UUID -> SessionId -> Connection -> STM (Either RelationalError SessionId)
179+createSessionAtCommit_ commitUUID newSessionId (InProcessConnection _ sessions graphTvar) = do
180+ graph <- readTVar graphTvar
181+ case transactionForUUID commitUUID graph of
182+ Left err -> pure (Left err)
183+ Right _ -> do
184+ let freshDiscon = DisconnectedTransaction commitUUID RE.basicDatabaseContext
185+ keyDuplication <- STMMap.lookup newSessionId sessions
186+ case keyDuplication of
187+ Just _ -> pure $ Left (SessionIdInUse newSessionId)
188+ Nothing -> do
189+ STMMap.insert (Session freshDiscon) newSessionId sessions
190+ pure $ Right newSessionId
191+createSessionAtCommit_ _ _ (RemoteProcessConnection _ _) = error "createSessionAtCommit_ called on remote connection"
192+
193+createSessionAtHead :: HeadName -> Connection -> IO (Either RelationalError SessionId)
194+createSessionAtHead headn conn@(InProcessConnection _ _ tvar) = do
195+ newSessionId <- nextRandom
196+ atomically $ do
197+ graph <- readTVar tvar
198+ case transactionForHead headn graph of
199+ Nothing -> pure $ Left (NoSuchHeadNameError headn)
200+ Just trans -> createSessionAtCommit_ (transactionUUID trans) newSessionId conn
201+createSessionAtHead headn conn@(RemoteProcessConnection _ _) = remoteCall conn (CreateSessionAtHead headn)
202+
203+-- | Discards a session, eliminating any uncommitted changes present in the session.
204+closeSession :: SessionId -> Connection -> IO ()
205+closeSession sessionId (InProcessConnection _ sessions _) = do
206+ atomically $ do
207+ STMMap.delete sessionId sessions
208+closeSession sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (CloseSession sessionId)
161209
162210close :: Connection -> IO ()
163−close (InProcessConnection _ _) = pure ()
211+close (InProcessConnection _ sessions _) = atomically $ do
212+ traverse_ (\(k,_) -> STMMap.delete k sessions) (STMMap.stream sessions)
213+ pure ()
164214close (RemoteProcessConnection localNode serverProcessId) = do
165215 runProcessResult localNode $ do
166216 call serverProcessId Logout
@@ -174,114 +224,145 @@ runProcessResult localNode proc = do
174224 takeMVar ret
175225
176226remoteCall :: (Serializable a, Serializable b) => Connection -> a -> IO b
177−remoteCall (InProcessConnection _ _) _ = error "remoteCall called on local connection"
227+remoteCall (InProcessConnection _ _ _) _ = error "remoteCall called on local connection"
178228remoteCall (RemoteProcessConnection localNode serverProcessId) arg = runProcessResult localNode $ do
179229 ret <- safeCall serverProcessId arg
180230 case ret of
181231 Left err -> error (show err)
182232 Right ret' -> pure ret'
183233
184−executeRelationalExpr :: Connection -> RelationalExpr -> IO (Either RelationalError Relation)
185−executeRelationalExpr (InProcessConnection _ tvar) expr = atomically $ do
186− ((DisconnectedTransaction _ context), _) <- readTVar tvar
187− return $ evalState (RE.evalRelationalExpr expr) context
188−executeRelationalExpr conn@(RemoteProcessConnection _ _) relExpr = remoteCall conn (ExecuteRelationalExpr relExpr)
234+sessionForSessionId :: SessionId -> Sessions -> STM (Either RelationalError Session)
235+sessionForSessionId sessionId sessions = do
236+ maybeSession <- STMMap.lookup sessionId sessions
237+ pure $ maybe (Left $ NoSuchSession sessionId) Right maybeSession
238+
239+executeRelationalExpr :: SessionId -> Connection -> RelationalExpr -> IO (Either RelationalError Relation)
240+executeRelationalExpr sessionId (InProcessConnection _ sessions _) expr = atomically $ do
241+ eSession <- sessionForSessionId sessionId sessions
242+ case eSession of
243+ Left err -> pure $ Left err
244+ Right (Session (DisconnectedTransaction _ context)) -> pure $ evalState (RE.evalRelationalExpr expr) context
245+executeRelationalExpr sessionId conn@(RemoteProcessConnection _ _) relExpr = remoteCall conn (ExecuteRelationalExpr sessionId relExpr)
189246
190−executeDatabaseContextExpr :: Connection -> DatabaseExpr -> IO (Maybe RelationalError)
191−executeDatabaseContextExpr (InProcessConnection _ tvar) expr = atomically $ do
192− ((DisconnectedTransaction parentUUID context), graph) <- readTVar tvar
193− case runState (RE.evalContextExpr expr) context of
194− (Just err,_) -> return $ Just err
195− (Nothing, context') -> do
196− let newDiscon = DisconnectedTransaction parentUUID context'
197− writeTVar tvar (newDiscon, graph)
247+executeDatabaseContextExpr :: SessionId -> Connection -> DatabaseExpr -> IO (Maybe RelationalError)
248+executeDatabaseContextExpr sessionId (InProcessConnection _ sessions _) expr = atomically $ do
249+ eSession <- sessionForSessionId sessionId sessions
250+ case eSession of
251+ Left err -> pure $ Just err
252+ Right session -> case runState (RE.evalContextExpr expr) (sessionContext session) of
253+ (Just err,_) -> return $ Just err
254+ (Nothing, context') -> do
255+ let newDiscon = DisconnectedTransaction (sessionParentUUID session) context'
256+ newSession = Session newDiscon
257+ STMMap.insert newSession sessionId sessions
198258 return Nothing
199−executeDatabaseContextExpr conn@(RemoteProcessConnection _ _) dbExpr = remoteCall conn (ExecuteDatabaseContextExpr dbExpr)
259+executeDatabaseContextExpr sessionId conn@(RemoteProcessConnection _ _) dbExpr = remoteCall conn (ExecuteDatabaseContextExpr sessionId dbExpr)
200260
201−executeGraphExpr :: Connection -> TransactionGraphOperator -> IO (Maybe RelationalError)
202−executeGraphExpr (InProcessConnection strat tvar) graphExpr = do
261+executeGraphExpr :: SessionId -> Connection -> TransactionGraphOperator -> IO (Maybe RelationalError)
262+executeGraphExpr sessionId (InProcessConnection strat sessions graphTvar) graphExpr = do
203263 freshUUID <- nextRandom
204264 manip <- atomically $ do
205− (discon, graph) <- readTVar tvar
206− case evalGraphOp freshUUID discon graph graphExpr of
207− Left err -> return $ Left err
208− Right (discon', graph') -> do
209− writeTVar tvar (discon', graph')
210− return $ Right (discon', graph')
265+ graph <- readTVar graphTvar
266+ eSession <- sessionForSessionId sessionId sessions
267+ case eSession of
268+ Left err -> pure $ Left err
269+ Right (Session discon) -> case evalGraphOp freshUUID discon graph graphExpr of
270+ Left err -> pure $ Left err
271+ Right (discon', graph') -> do
272+ writeTVar graphTvar graph'
273+ let newSession = Session discon'
274+ STMMap.insert newSession sessionId sessions
275+ pure $ Right graph'
211276 case manip of
212277 Left err -> return $ Just err
213− Right (_, newGraph) -> do
278+ Right newGraph -> do
214279 --update filesystem database, if necessary
215280 --this should really grab a lock at the beginning of the method to be threadsafe
216281 processPersistence strat newGraph
217282 return Nothing
218−executeGraphExpr conn@(RemoteProcessConnection _ _) graphExpr = remoteCall conn (ExecuteGraphExpr graphExpr)
283+executeGraphExpr sessionId conn@(RemoteProcessConnection _ _) graphExpr = remoteCall conn (ExecuteGraphExpr sessionId graphExpr)
219284
220−commit :: Connection -> IO (Maybe RelationalError)
221−commit conn@(InProcessConnection _ _) = executeGraphExpr conn Commit
222−commit conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteGraphExpr Commit)
285+commit :: SessionId -> Connection -> IO (Maybe RelationalError)
286+commit sessionId conn@(InProcessConnection _ _ _) = executeGraphExpr sessionId conn Commit
287+commit sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteGraphExpr sessionId Commit)
223288
224−rollback :: Connection -> IO (Maybe RelationalError)
225−rollback conn@(InProcessConnection _ _) = executeGraphExpr conn Rollback
226−rollback conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteGraphExpr Rollback)
289+rollback :: SessionId -> Connection -> IO (Maybe RelationalError)
290+rollback sessionId conn@(InProcessConnection _ _ _) = executeGraphExpr sessionId conn Rollback
291+rollback sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteGraphExpr sessionId Rollback)
227292
228293processPersistence :: PersistenceStrategy -> TransactionGraph -> IO ()
229294processPersistence NoPersistence _ = return ()
230295processPersistence (MinimalPersistence dbdir) graph = transactionGraphPersist NoDiskSync dbdir graph
231296processPersistence (CrashSafePersistence dbdir) graph = transactionGraphPersist FsyncDiskSync dbdir graph
232297
233−typeForRelationalExpr :: Connection -> RelationalExpr -> IO (Either RelationalError Relation)
234−typeForRelationalExpr conn@(InProcessConnection _ _) relExpr = atomically $ typeForRelationalExprSTM conn relExpr
235−typeForRelationalExpr conn@(RemoteProcessConnection _ _) relExpr = remoteCall conn (ExecuteTypeForRelationalExpr relExpr)
298+typeForRelationalExpr :: SessionId -> Connection -> RelationalExpr -> IO (Either RelationalError Relation)
299+typeForRelationalExpr sessionId conn@(InProcessConnection _ _ _) relExpr = atomically $ typeForRelationalExprSTM sessionId conn relExpr
300+typeForRelationalExpr sessionId conn@(RemoteProcessConnection _ _) relExpr = remoteCall conn (ExecuteTypeForRelationalExpr sessionId relExpr)
236301
237−typeForRelationalExprSTM :: Connection -> RelationalExpr -> STM (Either RelationalError Relation)
238−typeForRelationalExprSTM (InProcessConnection _ tvar) relExpr = do
239− (DisconnectedTransaction _ context, _) <- readTVar tvar
240− pure $ evalState (RE.typeForRelationalExpr relExpr) context
241−typeForRelationalExprSTM _ _ = error "typeForRelationalExprSTM called on non-local connection"
302+typeForRelationalExprSTM :: SessionId -> Connection -> RelationalExpr -> STM (Either RelationalError Relation)
303+typeForRelationalExprSTM sessionId (InProcessConnection _ sessions _) relExpr = do
304+ eSession <- sessionForSessionId sessionId sessions
305+ case eSession of
306+ Left err -> pure $ Left err
307+ Right session -> pure $ evalState (RE.typeForRelationalExpr relExpr) (sessionContext session)
308+
309+typeForRelationalExprSTM _ _ _ = error "typeForRelationalExprSTM called on non-local connection"
242310
243−inclusionDependencies :: Connection -> IO (M.Map IncDepName InclusionDependency)
244−inclusionDependencies (InProcessConnection _ tvar) = do
311+inclusionDependencies :: SessionId -> Connection -> IO (Either RelationalError (M.Map IncDepName InclusionDependency))
312+inclusionDependencies sessionId (InProcessConnection _ sessions _) = do
245313 atomically $ do
246− ((DisconnectedTransaction _ context), _) <- readTVar tvar
247− pure (B.inclusionDependencies context)
248−inclusionDependencies conn@(RemoteProcessConnection _ _) = remoteCall conn RetrieveInclusionDependencies
314+ eSession <- sessionForSessionId sessionId sessions
315+ case eSession of
316+ Left err -> pure $ Left err
317+ Right session -> pure $ Right (B.inclusionDependencies (sessionContext session))
318+
319+inclusionDependencies sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (RetrieveInclusionDependencies sessionId)
249320
250321
251−planForDatabaseContextExpr :: Connection -> DatabaseExpr -> IO (Either RelationalError DatabaseExpr)
252−planForDatabaseContextExpr (InProcessConnection _ tvar) dbExpr = do
322+planForDatabaseContextExpr :: SessionId -> Connection -> DatabaseExpr -> IO (Either RelationalError DatabaseExpr)
323+planForDatabaseContextExpr sessionId (InProcessConnection _ sessions _) dbExpr = do
253324 atomically $ do
254− ((DisconnectedTransaction _ context), _) <- readTVar tvar
255− pure $ evalState (applyStaticDatabaseOptimization dbExpr) context
256−planForDatabaseContextExpr conn@(RemoteProcessConnection _ _) dbExpr = remoteCall conn (RetrievePlanForDatabaseContextExpr dbExpr)
325+ eSession <- sessionForSessionId sessionId sessions
326+ case eSession of
327+ Left err -> pure $ Left err
328+ Right session -> pure $ evalState (applyStaticDatabaseOptimization dbExpr) (sessionContext session)
329+planForDatabaseContextExpr sessionId conn@(RemoteProcessConnection _ _) dbExpr = remoteCall conn (RetrievePlanForDatabaseContextExpr sessionId dbExpr)
257330
258−transactionGraphAsRelation :: Connection -> IO (Either RelationalError Relation)
259−transactionGraphAsRelation (InProcessConnection _ tvar) = do
331+transactionGraphAsRelation :: SessionId -> Connection -> IO (Either RelationalError Relation)
332+transactionGraphAsRelation sessionId (InProcessConnection _ sessions tvar) = do
260333 atomically $ do
261− (discon, graph) <- readTVar tvar
262− pure $ graphAsRelation discon graph
263−transactionGraphAsRelation conn@(RemoteProcessConnection _ _) = remoteCall conn RetrieveTransactionGraph
334+ eSession <- sessionForSessionId sessionId sessions
335+ case eSession of
336+ Left err -> pure $ Left err
337+ Right (Session discon) -> do
338+ graph <- readTVar tvar
339+ pure $ graphAsRelation discon graph
340+
341+transactionGraphAsRelation sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (RetrieveTransactionGraph sessionId)
264342
265343-- | Returns the UUID for the connection's disconnected transaction committed parent transaction.
266−headTransactionUUID :: Connection -> IO (UUID)
267−headTransactionUUID (InProcessConnection _ tvar) = do
344+headTransactionUUID :: SessionId -> Connection -> IO (Maybe UUID)
345+headTransactionUUID sessionId (InProcessConnection _ sessions _) = do
268346 atomically $ do
269− (DisconnectedTransaction parentUUID _, _) <- readTVar tvar
270− pure parentUUID
271−headTransactionUUID conn@(RemoteProcessConnection _ _) = remoteCall conn RetrieveHeadTransactionUUID
347+ eSession <- sessionForSessionId sessionId sessions
348+ case eSession of
349+ Left _ -> pure Nothing
350+ Right session -> pure $ Just (sessionParentUUID session)
351+headTransactionUUID sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (RetrieveHeadTransactionUUID sessionId)
272352
273353-- | Returns Just the name of the head of the current disconnected transaction or Nothing.
274−headName :: Connection -> IO (Maybe HeadName)
275−headName (InProcessConnection _ tvar) = do
354+headName :: SessionId -> Connection -> IO (Maybe HeadName)
355+headName sessionId (InProcessConnection _ sessions graphTvar) = do
276356 atomically $ do
277− (DisconnectedTransaction parentUUID _, graph) <- readTVar tvar
278− pure $ case transactionForUUID parentUUID graph of
279− Left _ -> Nothing
280− Right parentTrans -> headNameForTransaction parentTrans graph
281−headName (RemoteProcessConnection localNode serverProcessId) = do
282− runProcessResult localNode $ do
283− ret <- call serverProcessId ExecuteHeadName
284− pure ret
357+ graph <- readTVar graphTvar
358+ eSession <- sessionForSessionId sessionId sessions
359+ case eSession of
360+ Left _ -> pure $ Nothing
361+ Right session -> pure $ case transactionForUUID (sessionParentUUID session) graph of
362+ Left _ -> Nothing
363+ Right parentTrans -> headNameForTransaction parentTrans graph
364+headName sessionId conn@(RemoteProcessConnection _ _) = remoteCall conn (ExecuteHeadName sessionId)
365+
285366
286367
287368
ProjectM36/DatabaseContext.hs+8
@@ -8,3 +8,11 @@ empty = DatabaseContext { inclusionDependencies = M.empty,
88 relationVariables = M.empty,
99 atomFunctions = HS.empty }
1010
11+-- | convert an existing database context into its constituent expression.
12+databaseContextAsDatabaseContextExpr :: DatabaseContext -> DatabaseExpr
13+databaseContextAsDatabaseContextExpr (DatabaseContext incDeps relVars funcs) = MultipleExpr $ incDepsExprs ++ relVarsExprs ++ funcsExprs
14+ where
15+ relVarsExprs = map (\(name, rel) -> Assign name (ExistingRelation rel)) (M.toList relVars)
16+ incDepsExprs :: [DatabaseExpr]
17+ incDepsExprs = map (\(name, dep) -> AddInclusionDependency name dep) (M.toList incDeps)
18+ funcsExprs = [] -- map (\func -> ) (HS.toList funcs) -- there are no databaseExprs to add atom functions yet
ProjectM36/Error.hs+2
@@ -29,6 +29,8 @@ data RelationalError = NoSuchAttributeNamesError (S.Set AttributeName)
2929 | NoSuchHeadNameError HeadName
3030 | TransactionIsNotAHeadError U.UUID
3131 | TransactionGraphCycleError U.UUID
32+ | SessionIdInUse U.UUID
33+ | NoSuchSession U.UUID
3234 | NoSuchTupleExprFunctionError AtomFunctionName
3335 | AtomTypeMismatchError AtomType AtomType
3436 | AtomTypeNotSupported AttributeName --used by persistent driver
ProjectM36/Server/EntryPoints.hs+5−3
@@ -7,7 +7,7 @@ import Control.Distributed.Process.ManagedProcess (ProcessReply)
77import Control.Distributed.Process.ManagedProcess.Server (reply)
88import Control.Monad.IO.Class (liftIO)
99import Data.Map
10−import Data.UUID (UUID)
10+import Data.UUID (UUID, nextRandom)
1111
1212handleExecuteRelationalExpr :: Connection -> RelationalExpr -> Process (ProcessReply (Either RelationalError Relation) Connection)
1313handleExecuteRelationalExpr conn expr = do
@@ -24,8 +24,10 @@ handleExecuteHeadName conn = do
2424 ret <- liftIO $ headName conn
2525 reply ret conn
2626
27−handleLogin :: Connection -> Process (ProcessReply Bool Connection)
28−handleLogin conn = reply True conn
27+handleLogin :: Connection -> Process (ProcessReply UUID Connection)
28+handleLogin conn = do
29+ sessionId <- liftIO $ nextRandom
30+ reply sessionId conn
2931
3032handleExecuteGraphExpr :: Connection -> TransactionGraphOperator -> Process (ProcessReply (Maybe RelationalError) Connection)
3133handleExecuteGraphExpr conn graphExpr = do
ProjectM36/Server/RemoteCallTypes.hs+18−9
@@ -4,26 +4,35 @@ import ProjectM36.Base
44import ProjectM36.TransactionGraph
55import GHC.Generics
66import Data.Binary
7+import Data.UUID
8+
9+type SessionId = UUID
710
811data Login = Login
912 deriving (Binary, Generic)
1013data Logout = Logout
1114 deriving (Binary, Generic)
12−data ExecuteRelationalExpr = ExecuteRelationalExpr RelationalExpr
15+data ExecuteRelationalExpr = ExecuteRelationalExpr SessionId RelationalExpr
1316 deriving (Binary, Generic)
14−data ExecuteDatabaseContextExpr = ExecuteDatabaseContextExpr DatabaseExpr
17+data ExecuteDatabaseContextExpr = ExecuteDatabaseContextExpr SessionId DatabaseExpr
1518 deriving (Binary, Generic)
16−data ExecuteGraphExpr = ExecuteGraphExpr TransactionGraphOperator
19+data ExecuteGraphExpr = ExecuteGraphExpr SessionId TransactionGraphOperator
1720 deriving (Binary, Generic)
18−data ExecuteHeadName = ExecuteHeadName
21+data ExecuteHeadName = ExecuteHeadName SessionId
1922 deriving (Binary, Generic)
20−data ExecuteTypeForRelationalExpr = ExecuteTypeForRelationalExpr RelationalExpr
23+data ExecuteTypeForRelationalExpr = ExecuteTypeForRelationalExpr SessionId RelationalExpr
2124 deriving (Binary, Generic)
22−data RetrieveInclusionDependencies = RetrieveInclusionDependencies
25+data RetrieveInclusionDependencies = RetrieveInclusionDependencies SessionId
2326 deriving (Binary, Generic)
24−data RetrievePlanForDatabaseContextExpr = RetrievePlanForDatabaseContextExpr DatabaseExpr
27+data RetrievePlanForDatabaseContextExpr = RetrievePlanForDatabaseContextExpr SessionId DatabaseExpr
2528 deriving (Binary, Generic)
26−data RetrieveTransactionGraph = RetrieveTransactionGraph
29+data RetrieveTransactionGraph = RetrieveTransactionGraph SessionId
2730 deriving (Binary, Generic)
28−data RetrieveHeadTransactionUUID = RetrieveHeadTransactionUUID
31+data RetrieveHeadTransactionUUID = RetrieveHeadTransactionUUID SessionId
2932 deriving (Binary, Generic)
33+data CreateSessionAtCommit = CreateSessionAtCommit UUID
34+ deriving (Binary, Generic)
35+data CreateSessionAtHead = CreateSessionAtHead HeadName
36+ deriving (Binary, Generic)
37+data CloseSession = CloseSession SessionId
38+ deriving (Binary, Generic)
ProjectM36/Session.hsnew file+13
@@ -0,0 +1,13 @@
1+module ProjectM36.Session where
2+import ProjectM36.Base
3+import Data.UUID
4+
5+--the persistence of a session is as long as the life of the database (not serialized to disk)
6+-- sessions are not associated with connections and have separate lifetimes
7+data Session = Session DisconnectedTransaction
8+
9+sessionContext :: Session -> DatabaseContext
10+sessionContext (Session (DisconnectedTransaction _ context)) = context
11+
12+sessionParentUUID :: Session -> UUID
13+sessionParentUUID (Session (DisconnectedTransaction parentUUID _)) = parentUUID
benchmark/bigrel.hs+2−2
@@ -56,8 +56,8 @@ matrixRun (BigrelArgs attributeCount tupleCount tutd) = do
5656 let setx = Assign "x" (ExistingRelation (force rel))
5757 context = execState (evalContextExpr setx) dateExamples
5858 interpreted = interpretDatabaseExpr context tutd
59− plan = interpretRODatabaseContextOp context $ ":showplan " ++ tutd
60− displayOpResult plan
59+ --plan = interpretRODatabaseContextOp context $ ":showplan " ++ tutd
60+ --displayOpResult plan
6161 case interpreted of
6262 Right context' -> TIO.putStrLn $ relationAsHTML ((relationVariables context') M.! "x")
6363 Left err -> hPutStrLn stderr (show err)
project-m36.cabal+13−2
@@ -63,6 +63,8 @@ Library
6363 ,network-transport-tcp
6464 ,network-transport
6565 ,distributed-process
66+ ,stm-containers
67+ ,list-t
6668 Exposed-Modules: ProjectM36.Error,
6769 ProjectM36.Transaction,
6870 ProjectM36.TransactionGraph,
@@ -195,6 +197,7 @@ Executable bigrel
195197 main-is: benchmark/bigrel.hs
196198 GHC-Options: -Wall -threaded -rtsopts
197199 GHC-Prof-Options: -fprof-auto -rtsopts -threaded -Wall
200+ C-sources: ProjectM36/DirectoryFsync.c
198201
199202Test-Suite test-tutoriald
200203 Default-Language: Haskell2010
@@ -270,8 +273,16 @@ Test-Suite test-server
270273 GHC-Options: -Wall
271274 C-sources: ProjectM36/DirectoryFsync.c
272275
273−Executable SimpleClient
276+Executable Example-SimpleClient
274277 Default-Language: Haskell2010
275278 Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers
276279 Main-Is: examples/SimpleClient.hs
277− GHC-Options: -Wall
280+ GHC-Options: -Wall
281+ C-sources: ProjectM36/DirectoryFsync.c
282+
283+Executable Example-PersistClient
284+ Default-Language: Haskell2010
285+ Build-Depends: base, HUnit, Cabal, containers, hashable, unordered-containers, mtl, vector, vector-binary-instances, time, hashable-time, bytestring, network-transport-tcp, distributed-process, distributed-process-extras, distributed-process-client-server, uuid, stm, deepseq, deepseq-generics, binary, unix, parallel, cassava, attoparsec, gnuplot, directory, temporary, haskeline, parsec, text, base64-bytestring, data-interval, filepath, transformers
286+ Main-Is: examples/PersistClient.hs
287+ GHC-Options: -Wall
288+ C-sources: ProjectM36/DirectoryFsync.c
test/Daemon/Main.hs → test/Server/Main.hsrenamed+5−5
@@ -1,11 +1,11 @@
11{-# LANGUAGE OverloadedStrings #-}
22{-
3−test client/daemon interaction
3+test client/server interaction
44-}
55import Test.HUnit
66import ProjectM36.Client
7−import ProjectM36.Daemon
8−import ProjectM36.Daemon.Config
7+import ProjectM36.Server
8+import ProjectM36.Server.Config
99import ProjectM36.Relation
1010import ProjectM36.Atom
1111import ProjectM36.TupleSet
@@ -42,10 +42,10 @@ testConnection port = do
4242 let connInfo = RemoteProcessConnectionInfo testDatabaseName (createNodeId "127.0.0.1" port)
4343 connectProjectM36 connInfo
4444
45−-- | A version of 'launchDaemon' which returns the port on which the server is listening on a secondary thread
45+-- | A version of 'launchServer' which returns the port on which the server is listening on a secondary thread
4646launchTestServer :: IO (Port)
4747launchTestServer = do
48− let config = defaultDaemonConfig { databaseName = testDatabaseName }
48+ let config = defaultServerConfig { databaseName = testDatabaseName }
4949 portVar <- newEmptyMVar
5050 _ <- forkIO $ launchServer config (Just portVar) >> pure ()
5151 takeMVar portVar