Fix concurrency bug that occurred on the first download from an exporttree remote

Block other threads while the export database is being constructed (or
updated) by the first thread to try to access it.

This work is supported by the NIH-funded NICEMAN (ReproNim TR&D3) project.
This commit is contained in:
Joey Hess 2018-10-22 12:59:10 -04:00
parent fc26fd059b
commit c24e255de1
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
3 changed files with 22 additions and 9 deletions

View file

@ -19,6 +19,8 @@ git-annex (6.20181012) UNRELEASED; urgency=medium
GIT_ANNEX_PACKAGE_INSTALL set. (For Neurodebian packages.) GIT_ANNEX_PACKAGE_INSTALL set. (For Neurodebian packages.)
* v6: Fix database inconsistency that could cause git-annex to * v6: Fix database inconsistency that could cause git-annex to
get confused about whether a locked file's content was present. get confused about whether a locked file's content was present.
* Fix concurrency bug that occurred on the first download from an
exporttree remote.
-- Joey Hess <id@joeyh.name> Sat, 13 Oct 2018 00:52:02 -0400 -- Joey Hess <id@joeyh.name> Sat, 13 Oct 2018 00:52:02 -0400

View file

@ -89,23 +89,32 @@ adjustExportable r = case M.lookup "exporttree" (config r) of
} }
isexport = do isexport = do
db <- openDb (uuid r) db <- openDb (uuid r)
updateflag <- liftIO $ newTVarIO Nothing
updateflag <- liftIO newEmptyTMVarIO -- When multiple threads run this, all except the first
let updateonce = liftIO $ atomically $ -- will block until the first runs doneupdateonce.
ifM (isEmptyTMVar updateflag) -- Returns True when an update should be done and False
( do -- when the update has already been done.
putTMVar updateflag () let startupdateonce = liftIO $ atomically $
readTVar updateflag >>= \case
Nothing -> do
writeTVar updateflag (Just True)
return True return True
, return False Just True -> retry
) Just False -> return False
let doneupdateonce = \updated ->
when updated $
liftIO $ atomically $
writeTVar updateflag (Just False)
-- Get export locations for a key. Checks once -- Get export locations for a key. Checks once
-- if the export log is different than the database and -- if the export log is different than the database and
-- updates the database, to notice when an export has been -- updates the database, to notice when an export has been
-- updated from another repository. -- updated from another repository.
let getexportlocs = \k -> do let getexportlocs = \k -> do
whenM updateonce $ bracket startupdateonce doneupdateonce $ \updatenow ->
updateExportTreeFromLog db when updatenow $
updateExportTreeFromLog db
liftIO $ getExportTree db k liftIO $ getExportTree db k
return $ r return $ r

View file

@ -47,3 +47,5 @@ get sub-01/ses-01/func/sub-01_ses-01_task-Stroop_acq-cf0AP_run-03_physio.tsv.gz
[[!meta author=yoh]] [[!meta author=yoh]]
> [[fixed|done]] --[[Joey]]