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 5f9eff3f32 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.
This commit is contained in:
Joey Hess 2021-10-20 12:32:46 -04:00
parent f5b642318d
commit d0ef8303cf
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38

View file

@ -100,13 +100,13 @@ commitDb h wa = robustly Nothing 100 (commitDb' h wa)
commitDb' :: DbHandle -> SqlPersistM () -> IO (Either SomeException ()) commitDb' :: DbHandle -> SqlPersistM () -> IO (Either SomeException ())
commitDb' (DbHandle _ jobs) a = do commitDb' (DbHandle _ jobs) a = do
res <- newEmptyMVar res <- newEmptyMVar
putMVar jobs $ ChangeJob $ \runner -> putMVar jobs $ ChangeJob $
liftIO $ putMVar res =<< tryNonAsync (runner a) liftIO . putMVar res =<< tryNonAsync a
takeMVar res takeMVar res
data Job data Job
= QueryJob (SqlPersistM ()) = QueryJob (SqlPersistM ())
| ChangeJob ((SqlPersistM () -> IO ()) -> IO ()) | ChangeJob (SqlPersistM ())
| CloseJob | CloseJob
workerThread :: T.Text -> TableName -> MVar Job -> IO () workerThread :: T.Text -> TableName -> MVar Job -> IO ()
@ -128,16 +128,10 @@ workerThread db tablename jobs = newconn
Left BlockedIndefinitelyOnMVar -> return (return ()) Left BlockedIndefinitelyOnMVar -> return (return ())
Right CloseJob -> return (return ()) Right CloseJob -> return (return ())
Right (QueryJob a) -> a >> loop 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 Right (ChangeJob a) -> do
liftIO (a (runSqliteRobustly tablename db)) a
-- Exit this sqlite connection so the -- Exit the sqlite connection so the
-- change that was just written, using -- database gets updated on disk.
-- a different db handle, is immediately
-- visible to queries.
return newconn return newconn
getjob :: IO (Either BlockedIndefinitelyOnMVar Job) getjob :: IO (Either BlockedIndefinitelyOnMVar Job)