From d0ef8303cf8c4f40a1d17bd134af961fd9917ca4 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Wed, 20 Oct 2021 12:32:46 -0400 Subject: [PATCH] avoid using a second db connection for writes This is a potentially breaking change in a very delicate area. However, examining the code path for writes, I don't see any benefit to opening a second db connection for them. If the write throws an exception, commitDb will retry it with a new db connection. A potential benefit to not opening a second db connection, beyond using less resources, is it just might avoid problems in WSL with sqlite that I have hypothesized are caused by multiple db connections. Commit 5f9eff3f32e0101ee673c3dde221f0f27f32e3c8 explains why it needs to shut down the db connection to force the database to be updated on disk: When closeDb does not get called, garbage collection of DbHandle may not give the workterThread time to cleanly shut down before git-annex exits, resulting in a recently written change not reaching disk. --- Database/Handle.hs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Database/Handle.hs b/Database/Handle.hs index f06cd0b08d..9eb32b4e27 100644 --- a/Database/Handle.hs +++ b/Database/Handle.hs @@ -100,13 +100,13 @@ commitDb h wa = robustly Nothing 100 (commitDb' h wa) commitDb' :: DbHandle -> SqlPersistM () -> IO (Either SomeException ()) commitDb' (DbHandle _ jobs) a = do res <- newEmptyMVar - putMVar jobs $ ChangeJob $ \runner -> - liftIO $ putMVar res =<< tryNonAsync (runner a) + putMVar jobs $ ChangeJob $ + liftIO . putMVar res =<< tryNonAsync a takeMVar res data Job = QueryJob (SqlPersistM ()) - | ChangeJob ((SqlPersistM () -> IO ()) -> IO ()) + | ChangeJob (SqlPersistM ()) | CloseJob workerThread :: T.Text -> TableName -> MVar Job -> IO () @@ -128,16 +128,10 @@ workerThread db tablename jobs = newconn Left BlockedIndefinitelyOnMVar -> return (return ()) Right CloseJob -> return (return ()) Right (QueryJob a) -> a >> loop - -- Change is run in a separate database connection - -- since sqlite only supports a single writer at a - -- time, and it may crash the database connection - -- that the write is made to. Right (ChangeJob a) -> do - liftIO (a (runSqliteRobustly tablename db)) - -- Exit this sqlite connection so the - -- change that was just written, using - -- a different db handle, is immediately - -- visible to queries. + a + -- Exit the sqlite connection so the + -- database gets updated on disk. return newconn getjob :: IO (Either BlockedIndefinitelyOnMVar Job)