Merge branch 'dbdir'

This commit is contained in:
Joey Hess 2022-08-12 13:07:12 -04:00
commit 428af29281
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
37 changed files with 201 additions and 146 deletions

View file

@ -27,6 +27,7 @@ module Annex (
inRepo,
fromRepo,
calcRepo,
calcRepo',
getGitConfig,
overrideGitConfig,
changeGitRepo,
@ -361,6 +362,11 @@ calcRepo a = do
s <- getState id
liftIO $ a (repo s) (gitconfig s)
calcRepo' :: (Git.Repo -> GitConfig -> a) -> Annex a
calcRepo' f = do
s <- getState id
pure $ f (repo s) (gitconfig s)
{- Gets the GitConfig settings. -}
getGitConfig :: Annex GitConfig
getGitConfig = getState gitconfig

View file

@ -87,7 +87,7 @@ mergeToAdjustedBranch tomerge (origbranch, adj) mergeconfig canresolvemerge comm
whenM (doesFileExist src) $ do
dest <- relPathDirToFile git_dir src'
let dest' = toRawFilePath tmpgit P.</> dest
createDirectoryUnder git_dir
createDirectoryUnder [git_dir]
(P.takeDirectory dest')
void $ createLinkOrCopy src' dest'
-- This reset makes git merge not care
@ -115,7 +115,7 @@ mergeToAdjustedBranch tomerge (origbranch, adj) mergeconfig canresolvemerge comm
setup = do
whenM (doesDirectoryExist d) $
removeDirectoryRecursive d
createDirectoryUnder git_dir (toRawFilePath d)
createDirectoryUnder [git_dir] (toRawFilePath d)
cleanup _ = removeDirectoryRecursive d
{- A merge commit has been made between the basisbranch and

View file

@ -83,7 +83,7 @@ watchChangedRefs = do
g <- gitRepo
let gittop = Git.localGitDir g
let refdir = gittop P.</> "refs"
liftIO $ createDirectoryUnder gittop refdir
liftIO $ createDirectoryUnder [gittop] refdir
let notifyhook = Just $ notifyHook chan
let hooks = mkWatchHooks

View file

@ -6,7 +6,7 @@ import Common as X
import Types as X
import Key as X
import Types.UUID as X
import Annex as X (gitRepo, inRepo, fromRepo, calcRepo)
import Annex as X (gitRepo, inRepo, fromRepo, calcRepo, calcRepo')
import Annex.Locations as X
import Annex.Debug as X (fastDebug, debug)
import Messages as X

View file

@ -137,7 +137,7 @@ withContentLockFile :: Key -> (Maybe RawFilePath -> Annex a) -> Annex a
withContentLockFile k a = do
v <- getVersion
if versionNeedsWritableContentFiles v
then withSharedLock gitAnnexContentLockLock $ do
then fromRepo gitAnnexContentLockLock >>= \lck -> withSharedLock lck $ do
{- While the lock is held, check to see if the git
- config has changed, and reload it if so. This
- updates the annex.version after the v10 upgrade,
@ -156,7 +156,7 @@ withContentLockFile k a = do
reloadConfig
getVersion
go (v')
else (go v)
else go v
where
go v = contentLockFile k v >>= a

View file

@ -412,8 +412,10 @@ importKeys remote importtreeconfig importcontent thirdpartypopulated importablec
| importcontent = a
| otherwise = reuseVectorClockWhile a
withciddb = withExclusiveLock gitAnnexContentIdentifierLock .
bracket CIDDb.openDb CIDDb.closeDb
withciddb a = do
cidlck <- calcRepo' gitAnnexContentIdentifierLock
withExclusiveLock cidlck $
bracket CIDDb.openDb CIDDb.closeDb a
run cidmap importing db = do
largematcher <- largeFilesMatcher

View file

@ -281,4 +281,6 @@ data JournalLocked = ProduceJournalLocked
{- Runs an action that modifies the journal, using locking to avoid
- contention with other git-annex processes. -}
lockJournal :: (JournalLocked -> Annex a) -> Annex a
lockJournal a = withExclusiveLock gitAnnexJournalLock $ a ProduceJournalLocked
lockJournal a = do
lck <- fromRepo gitAnnexJournalLock
withExclusiveLock lck $ a ProduceJournalLocked

View file

@ -37,7 +37,7 @@ module Annex.Locations (
gitAnnexBadDir,
gitAnnexBadLocation,
gitAnnexUnusedLog,
gitAnnexKeysDb,
gitAnnexKeysDbDir,
gitAnnexKeysDbLock,
gitAnnexKeysDbIndexCache,
gitAnnexFsckState,
@ -321,38 +321,42 @@ gitAnnexUnusedLog :: RawFilePath -> Git.Repo -> RawFilePath
gitAnnexUnusedLog prefix r = gitAnnexDir r P.</> (prefix <> "unused")
{- .git/annex/keysdb/ contains a database of information about keys. -}
gitAnnexKeysDb :: Git.Repo -> RawFilePath
gitAnnexKeysDb r = gitAnnexDir r P.</> "keysdb"
gitAnnexKeysDbDir :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexKeysDbDir r c = fromMaybe (gitAnnexDir r) (annexDbDir c) P.</> "keysdb"
{- Lock file for the keys database. -}
gitAnnexKeysDbLock :: Git.Repo -> RawFilePath
gitAnnexKeysDbLock r = gitAnnexKeysDb r <> ".lck"
gitAnnexKeysDbLock :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexKeysDbLock r c = gitAnnexKeysDbDir r c <> ".lck"
{- Contains the stat of the last index file that was
- reconciled with the keys database. -}
gitAnnexKeysDbIndexCache :: Git.Repo -> RawFilePath
gitAnnexKeysDbIndexCache r = gitAnnexKeysDb r <> ".cache"
gitAnnexKeysDbIndexCache :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexKeysDbIndexCache r c = gitAnnexKeysDbDir r c <> ".cache"
{- .git/annex/fsck/uuid/ is used to store information about incremental
- fscks. -}
gitAnnexFsckDir :: UUID -> Git.Repo -> RawFilePath
gitAnnexFsckDir u r = gitAnnexDir r P.</> "fsck" P.</> fromUUID u
gitAnnexFsckDir :: UUID -> Git.Repo -> Maybe GitConfig -> RawFilePath
gitAnnexFsckDir u r mc = case annexDbDir =<< mc of
Nothing -> go (gitAnnexDir r)
Just d -> go d
where
go d = d P.</> "fsck" P.</> fromUUID u
{- used to store information about incremental fscks. -}
gitAnnexFsckState :: UUID -> Git.Repo -> RawFilePath
gitAnnexFsckState u r = gitAnnexFsckDir u r P.</> "state"
gitAnnexFsckState u r = gitAnnexFsckDir u r Nothing P.</> "state"
{- Directory containing database used to record fsck info. -}
gitAnnexFsckDbDir :: UUID -> Git.Repo -> RawFilePath
gitAnnexFsckDbDir u r = gitAnnexFsckDir u r P.</> "fsckdb"
gitAnnexFsckDbDir :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexFsckDbDir u r c = gitAnnexFsckDir u r (Just c) P.</> "fsckdb"
{- Directory containing old database used to record fsck info. -}
gitAnnexFsckDbDirOld :: UUID -> Git.Repo -> RawFilePath
gitAnnexFsckDbDirOld u r = gitAnnexFsckDir u r P.</> "db"
gitAnnexFsckDbDirOld :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexFsckDbDirOld u r c = gitAnnexFsckDir u r (Just c) P.</> "db"
{- Lock file for the fsck database. -}
gitAnnexFsckDbLock :: UUID -> Git.Repo -> RawFilePath
gitAnnexFsckDbLock u r = gitAnnexFsckDir u r P.</> "fsck.lck"
gitAnnexFsckDbLock :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexFsckDbLock u r c = gitAnnexFsckDir u r (Just c) P.</> "fsck.lck"
{- .git/annex/fsckresults/uuid is used to store results of git fscks -}
gitAnnexFsckResultsLog :: UUID -> Git.Repo -> RawFilePath
@ -384,20 +388,22 @@ gitAnnexMoveLock r = gitAnnexDir r P.</> "move.lck"
{- .git/annex/export/ is used to store information about
- exports to special remotes. -}
gitAnnexExportDir :: Git.Repo -> RawFilePath
gitAnnexExportDir r = gitAnnexDir r P.</> "export"
gitAnnexExportDir :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexExportDir r c = fromMaybe (gitAnnexDir r) (annexDbDir c) P.</> "export"
{- Directory containing database used to record export info. -}
gitAnnexExportDbDir :: UUID -> Git.Repo -> RawFilePath
gitAnnexExportDbDir u r = gitAnnexExportDir r P.</> fromUUID u P.</> "exportdb"
gitAnnexExportDbDir :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexExportDbDir u r c =
gitAnnexExportDir r c P.</> fromUUID u P.</> "exportdb"
{- Lock file for export state for a special remote. -}
gitAnnexExportLock :: UUID -> Git.Repo -> RawFilePath
gitAnnexExportLock u r = gitAnnexExportDbDir u r <> ".lck"
{- Lock file for export database. -}
gitAnnexExportLock :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexExportLock u r c = gitAnnexExportDbDir u r c <> ".lck"
{- Lock file for updating the export state for a special remote. -}
gitAnnexExportUpdateLock :: UUID -> Git.Repo -> RawFilePath
gitAnnexExportUpdateLock u r = gitAnnexExportDbDir u r <> ".upl"
{- Lock file for updating the export database with information from the
- repository. -}
gitAnnexExportUpdateLock :: UUID -> Git.Repo -> GitConfig -> RawFilePath
gitAnnexExportUpdateLock u r c = gitAnnexExportDbDir u r c <> ".upl"
{- Log file used to keep track of files that were in the tree exported to a
- remote, but were excluded by its preferred content settings. -}
@ -409,12 +415,13 @@ gitAnnexExportExcludeLog u r = gitAnnexDir r P.</> "export.ex" P.</> fromUUID u
- (This used to be "cid", but a problem with the database caused it to
- need to be rebuilt with a new name.)
-}
gitAnnexContentIdentifierDbDir :: Git.Repo -> RawFilePath
gitAnnexContentIdentifierDbDir r = gitAnnexDir r P.</> "cidsdb"
gitAnnexContentIdentifierDbDir :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexContentIdentifierDbDir r c =
fromMaybe (gitAnnexDir r) (annexDbDir c) P.</> "cidsdb"
{- Lock file for writing to the content id database. -}
gitAnnexContentIdentifierLock :: Git.Repo -> RawFilePath
gitAnnexContentIdentifierLock r = gitAnnexContentIdentifierDbDir r <> ".lck"
gitAnnexContentIdentifierLock :: Git.Repo -> GitConfig -> RawFilePath
gitAnnexContentIdentifierLock r c = gitAnnexContentIdentifierDbDir r c <> ".lck"
{- .git/annex/schedulestate is used to store information about when
- scheduled jobs were last run. -}

View file

@ -21,7 +21,6 @@ module Annex.LockFile (
import Annex.Common
import Annex
import Types.LockCache
import qualified Git
import Annex.Perms
import Annex.LockPool
@ -63,9 +62,8 @@ changeLockCache a = do
{- Runs an action with a shared lock held. If an exclusive lock is held,
- blocks until it becomes free. -}
withSharedLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex a
withSharedLock getlockfile a = debugLocks $ do
lockfile <- fromRepo getlockfile
withSharedLock :: RawFilePath -> Annex a -> Annex a
withSharedLock lockfile a = debugLocks $ do
createAnnexDirectory $ P.takeDirectory lockfile
mode <- annexFileMode
bracket (lock mode lockfile) (liftIO . dropLock) (const a)
@ -78,16 +76,15 @@ withSharedLock getlockfile a = debugLocks $ do
{- Runs an action with an exclusive lock held. If the lock is already
- held, blocks until it becomes free. -}
withExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex a
withExclusiveLock getlockfile a = bracket
(takeExclusiveLock getlockfile)
withExclusiveLock :: RawFilePath -> Annex a -> Annex a
withExclusiveLock lockfile a = bracket
(takeExclusiveLock lockfile)
(liftIO . dropLock)
(const a)
{- Takes an exclusive lock, blocking until it's free. -}
takeExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex LockHandle
takeExclusiveLock getlockfile = debugLocks $ do
lockfile <- fromRepo getlockfile
takeExclusiveLock :: RawFilePath -> Annex LockHandle
takeExclusiveLock lockfile = debugLocks $ do
createAnnexDirectory $ P.takeDirectory lockfile
mode <- annexFileMode
lock mode lockfile
@ -100,9 +97,8 @@ takeExclusiveLock getlockfile = debugLocks $ do
{- Tries to take an exclusive lock and run an action. If the lock is
- already held, returns Nothing. -}
tryExclusiveLock :: (Git.Repo -> RawFilePath) -> Annex a -> Annex (Maybe a)
tryExclusiveLock getlockfile a = debugLocks $ do
lockfile <- fromRepo getlockfile
tryExclusiveLock :: RawFilePath -> Annex a -> Annex (Maybe a)
tryExclusiveLock lockfile a = debugLocks $ do
createAnnexDirectory $ P.takeDirectory lockfile
mode <- annexFileMode
bracket (lock mode lockfile) (liftIO . unlock) go

View file

@ -106,13 +106,16 @@ annexFileMode = withShared $ return . go
go _ = stdFileMode
sharedmode = combineModes groupSharedModes
{- Creates a directory inside the gitAnnexDir, creating any parent
- directories up to and including the gitAnnexDir.
{- Creates a directory inside the gitAnnexDir (or possibly the dbdir),
- creating any parent directories up to and including the gitAnnexDir.
- Makes directories with appropriate permissions. -}
createAnnexDirectory :: RawFilePath -> Annex ()
createAnnexDirectory dir = do
top <- parentDir <$> fromRepo gitAnnexDir
createDirectoryUnder' top dir createdir
tops <- annexDbDir <$> Annex.getGitConfig >>= return . \case
Nothing -> [top]
Just dbdir -> [top, parentDir dbdir]
createDirectoryUnder' tops dir createdir
where
createdir p = do
liftIO $ R.createDirectory p
@ -126,7 +129,7 @@ createAnnexDirectory dir = do
createWorkTreeDirectory :: RawFilePath -> Annex ()
createWorkTreeDirectory dir = do
fromRepo repoWorkTree >>= liftIO . \case
Just wt -> createDirectoryUnder wt dir
Just wt -> createDirectoryUnder [wt] dir
-- Should never happen, but let whatever tries to write
-- to the directory be what throws an exception, as that
-- will be clearer than an exception from here.

View file

@ -65,9 +65,11 @@ flush = do
- git locking files. So, only one queue is allowed to flush at a time.
-}
flush' :: Git.Queue.Queue Annex -> Annex (Git.Queue.Queue Annex)
flush' q = withExclusiveLock gitAnnexGitQueueLock $ do
showStoringStateAction
Git.Queue.flush q =<< gitRepo
flush' q = do
lck <- fromRepo gitAnnexGitQueueLock
withExclusiveLock lck $ do
showStoringStateAction
Git.Queue.flush q =<< gitRepo
{- Gets the size of the queue. -}
size :: Annex Int

View file

@ -33,7 +33,7 @@ replaceGitAnnexDirFile = replaceFile createAnnexDirectory
replaceGitDirFile :: FilePath -> (FilePath -> Annex a) -> Annex a
replaceGitDirFile = replaceFile $ \dir -> do
top <- fromRepo localGitDir
liftIO $ createDirectoryUnder top dir
liftIO $ createDirectoryUnder [top] dir
{- replaceFile on a worktree file. -}
replaceWorkTreeFile :: FilePath -> (FilePath -> Annex a) -> Annex a

View file

@ -27,7 +27,7 @@ withOtherTmp a = do
Annex.addCleanupAction OtherTmpCleanup cleanupOtherTmp
tmpdir <- fromRepo gitAnnexTmpOtherDir
tmplck <- fromRepo gitAnnexTmpOtherLock
withSharedLock (const tmplck) $ do
withSharedLock tmplck $ do
void $ createAnnexDirectory tmpdir
a tmpdir
@ -56,7 +56,7 @@ withEventuallyCleanedOtherTmp = bracket setup cleanup
cleanupOtherTmp :: Annex ()
cleanupOtherTmp = do
tmplck <- fromRepo gitAnnexTmpOtherLock
void $ tryIO $ tryExclusiveLock (const tmplck) $ do
void $ tryIO $ tryExclusiveLock tmplck $ do
tmpdir <- fromRawFilePath <$> fromRepo gitAnnexTmpOtherDir
void $ liftIO $ tryIO $ removeDirectoryRecursive tmpdir
oldtmp <- fromRawFilePath <$> fromRepo gitAnnexTmpOtherDirOld

View file

@ -34,7 +34,7 @@ mergeThread = namedThread "Merger" $ do
g <- liftAnnex gitRepo
let gitd = Git.localGitDir g
let dir = gitd P.</> "refs"
liftIO $ createDirectoryUnder gitd dir
liftIO $ createDirectoryUnder [gitd] dir
let hook a = Just <$> asIO2 (runHandler a)
changehook <- hook onChange
errhook <- hook onErr

View file

@ -17,6 +17,9 @@ git-annex (10.20220725) UNRELEASED; urgency=medium
* When bup split fails, display its stderr.
* Avoid running multiple bup split processes concurrently, since
bup is not concurrency safe.
* Added annex.dbdir config which can be used to move sqlite databases
to a different filesystem than the git-annex repo, when the repo is on
a filesystem that sqlite does not work well in.
-- Joey Hess <id@joeyh.name> Mon, 25 Jul 2022 15:35:45 -0400

View file

@ -375,12 +375,14 @@ logMove srcuuid destuuid deststartedwithcopy key a = go =<< setup
setup = do
logf <- fromRepo gitAnnexMoveLog
lckf <- fromRepo gitAnnexMoveLock
-- Only log when there was no copy.
unless deststartedwithcopy $
appendLogFile logf gitAnnexMoveLock logline
appendLogFile logf lckf logline
return logf
cleanup logf = do
lck <- fromRepo gitAnnexMoveLock
-- This buffers the log file content in memory.
-- The log file length is limited to the number of
-- concurrent jobs, times the number of times a move
@ -388,13 +390,14 @@ logMove srcuuid destuuid deststartedwithcopy key a = go =<< setup
-- That could grow without bounds given enough time,
-- so the log is also truncated to the most recent
-- 100 items.
modifyLogFile logf gitAnnexMoveLock
modifyLogFile logf lck
(filter (/= logline) . reverse . take 100 . reverse)
go logf
-- Only need to check log when there is a copy.
| deststartedwithcopy = do
wasnocopy <- checkLogFile (fromRawFilePath logf) gitAnnexMoveLock
lck <- fromRepo gitAnnexMoveLock
wasnocopy <- checkLogFile (fromRawFilePath logf) lck
(== logline)
if wasnocopy
then go' logf False

View file

@ -41,7 +41,7 @@ configureSmudgeFilter = unlessM (fromRepo Git.repoIsLocalBare) $ do
gfs <- readattr gf
gittop <- Git.localGitDir <$> gitRepo
liftIO $ unless ("filter=annex" `isInfixOf` (lfs ++ gfs)) $ do
createDirectoryUnder gittop (P.takeDirectory lf)
createDirectoryUnder [gittop] (P.takeDirectory lf)
writeFile (fromRawFilePath lf) (lfs ++ "\n" ++ unlines stdattr)
where
readattr = liftIO . catchDefaultIO "" . readFileStrict . fromRawFilePath

View file

@ -78,7 +78,7 @@ AnnexBranch
-}
openDb :: Annex ContentIdentifierHandle
openDb = do
dbdir <- fromRepo gitAnnexContentIdentifierDbDir
dbdir <- calcRepo' gitAnnexContentIdentifierDbDir
let db = dbdir P.</> "db"
ifM (liftIO $ not <$> R.doesPathExist db)
( initDb db $ void $

View file

@ -99,7 +99,7 @@ ExportTreeCurrent
-}
openDb :: UUID -> Annex ExportHandle
openDb u = do
dbdir <- fromRepo (gitAnnexExportDbDir u)
dbdir <- calcRepo' (gitAnnexExportDbDir u)
let db = dbdir P.</> "db"
unlessM (liftIO $ R.doesPathExist db) $ do
initDb db $ void $
@ -263,8 +263,9 @@ updateExportDb = runExportDiffUpdater $ mkExportDiffUpdater removeold addnew
-}
writeLockDbWhile :: ExportHandle -> Annex a -> Annex a
writeLockDbWhile db@(ExportHandle _ u) a = do
updatelck <- takeExclusiveLock (gitAnnexExportUpdateLock u)
withExclusiveLock (gitAnnexExportLock u) $ do
updatelck <- takeExclusiveLock =<< calcRepo' (gitAnnexExportUpdateLock u)
exlck <- calcRepo' (gitAnnexExportLock u)
withExclusiveLock exlck $ do
bracket_ (setup updatelck) cleanup a
where
setup updatelck = do
@ -285,15 +286,17 @@ data ExportUpdateResult = ExportUpdateSuccess | ExportUpdateConflict
- not. Either way, it will block until the update is complete.
-}
updateExportTreeFromLog :: ExportHandle -> Annex ExportUpdateResult
updateExportTreeFromLog db@(ExportHandle _ u) =
updateExportTreeFromLog db@(ExportHandle _ u) = do
-- If another process or thread is performing the update,
-- this will block until it's done.
withExclusiveLock (gitAnnexExportUpdateLock u) $ do
exlck <- calcRepo' (gitAnnexExportUpdateLock u)
withExclusiveLock exlck $ do
lck <- calcRepo' (gitAnnexExportLock u)
-- If the database is locked by something else,
-- this will not run the update. But, in that case,
-- writeLockDbWhile is running, and has already
-- completed the update, so we don't need to do anything.
mr <- tryExclusiveLock (gitAnnexExportLock u) $
mr <- tryExclusiveLock lck $
updateExportTreeFromLog' db
case mr of
Just r -> return r

View file

@ -60,29 +60,31 @@ Fscked
- or unknown behavior.
-}
newPass :: UUID -> Annex Bool
newPass u = isJust <$> tryExclusiveLock (gitAnnexFsckDbLock u) go
newPass u = do
lck <- calcRepo' (gitAnnexFsckDbLock u)
isJust <$> tryExclusiveLock lck go
where
go = do
removedb =<< fromRepo (gitAnnexFsckDbDir u)
removedb =<< fromRepo (gitAnnexFsckDbDirOld u)
removedb =<< calcRepo' (gitAnnexFsckDbDir u)
removedb =<< calcRepo' (gitAnnexFsckDbDirOld u)
removedb = liftIO . void . tryIO . removeDirectoryRecursive . fromRawFilePath
{- Opens the database, creating it if it doesn't exist yet. -}
openDb :: UUID -> Annex FsckHandle
openDb u = do
dbdir <- fromRepo (gitAnnexFsckDbDir u)
dbdir <- calcRepo' (gitAnnexFsckDbDir u)
let db = dbdir P.</> "db"
unlessM (liftIO $ R.doesPathExist db) $ do
initDb db $ void $
runMigrationSilent migrateFsck
lockFileCached =<< fromRepo (gitAnnexFsckDbLock u)
lockFileCached =<< calcRepo' (gitAnnexFsckDbLock u)
h <- liftIO $ H.openDbQueue db "fscked"
return $ FsckHandle h u
closeDb :: FsckHandle -> Annex ()
closeDb (FsckHandle h u) = do
liftIO $ H.closeDbQueue h
unlockFile =<< fromRepo (gitAnnexFsckDbLock u)
unlockFile =<< calcRepo' (gitAnnexFsckDbLock u)
addDb :: FsckHandle -> Key -> IO ()
addDb (FsckHandle h _) k = H.queueDb h checkcommit $

View file

@ -10,6 +10,7 @@
module Database.Init where
import Annex.Common
import qualified Annex
import Annex.Perms
import Utility.FileMode
import Utility.Directory.Create
@ -34,9 +35,13 @@ initDb db migration = do
let tmpdbdir = dbdir <> ".tmp"
let tmpdb = tmpdbdir P.</> "db"
let tdb = T.pack (fromRawFilePath tmpdb)
gc <- Annex.getGitConfig
top <- parentDir <$> fromRepo gitAnnexDir
let tops = case annexDbDir gc of
Just topdbdir -> [top, parentDir topdbdir]
Nothing -> [top]
liftIO $ do
createDirectoryUnder top tmpdbdir
createDirectoryUnder tops tmpdbdir
runSqliteInfo (enableWAL tdb) migration
setAnnexDirPerm tmpdbdir
-- Work around sqlite bug that prevents it from honoring

View file

@ -118,15 +118,17 @@ runWriterIO a = runWriter (liftIO . a)
openDb :: Bool -> DbState -> Annex DbState
openDb _ st@(DbOpen _) = return st
openDb False DbUnavailable = return DbUnavailable
openDb forwrite _ = catchPermissionDenied permerr $ withExclusiveLock gitAnnexKeysDbLock $ do
dbdir <- fromRepo gitAnnexKeysDb
let db = dbdir P.</> "db"
dbexists <- liftIO $ R.doesPathExist db
case dbexists of
True -> open db
False -> do
initDb db SQL.createTables
open db
openDb forwrite _ = do
lck <- calcRepo' gitAnnexKeysDbLock
catchPermissionDenied permerr $ withExclusiveLock lck $ do
dbdir <- calcRepo' gitAnnexKeysDbDir
let db = dbdir P.</> "db"
dbexists <- liftIO $ R.doesPathExist db
case dbexists of
True -> open db
False -> do
initDb db SQL.createTables
open db
where
-- If permissions don't allow opening the database, and it's being
-- opened for read, treat it as if it does not exist.
@ -248,7 +250,7 @@ isInodeKnown i s = or <$> runReaderIO ((:[]) <$$> SQL.isInodeKnown i s)
reconcileStaged :: H.DbQueue -> Annex ()
reconcileStaged qh = unlessM (Git.Config.isBare <$> gitRepo) $ do
gitindex <- inRepo currentIndexFile
indexcache <- fromRawFilePath <$> fromRepo gitAnnexKeysDbIndexCache
indexcache <- fromRawFilePath <$> calcRepo' gitAnnexKeysDbIndexCache
withTSDelta (liftIO . genInodeCache gitindex) >>= \case
Just cur -> readindexcache indexcache >>= \case
Nothing -> go cur indexcache =<< getindextree

View file

@ -269,7 +269,7 @@ explodePackedRefsFile r = do
let gitd = localGitDir r
let dest = gitd P.</> fromRef' ref
let dest' = fromRawFilePath dest
createDirectoryUnder gitd (parentDir dest)
createDirectoryUnder [gitd] (parentDir dest)
unlessM (doesFileExist dest') $
writeFile dest' (fromRef sha)

View file

@ -1,6 +1,6 @@
{- git-annex log files
-
- Copyright 2018-2020 Joey Hess <id@joeyh.name>
- Copyright 2018-2022 Joey Hess <id@joeyh.name>
-
- Licensed under the GNU AGPL version 3 or higher.
-}
@ -20,7 +20,6 @@ import Annex.Common
import Annex.Perms
import Annex.LockFile
import Annex.ReplaceFile
import qualified Git
import Utility.Tmp
import qualified Data.ByteString.Lazy as L
@ -51,7 +50,7 @@ withLogHandle f a = do
-- | Appends a line to a log file, first locking it to prevent
-- concurrent writers.
appendLogFile :: RawFilePath -> (Git.Repo -> RawFilePath) -> L.ByteString -> Annex ()
appendLogFile :: RawFilePath -> RawFilePath -> L.ByteString -> Annex ()
appendLogFile f lck c =
createDirWhenNeeded f $
withExclusiveLock lck $ do
@ -69,7 +68,7 @@ appendLogFile f lck c =
--
-- The file is locked to prevent concurrent writers, and it is written
-- atomically.
modifyLogFile :: RawFilePath -> (Git.Repo -> RawFilePath) -> ([L.ByteString] -> [L.ByteString]) -> Annex ()
modifyLogFile :: RawFilePath -> RawFilePath -> ([L.ByteString] -> [L.ByteString]) -> Annex ()
modifyLogFile f lck modf = withExclusiveLock lck $ do
ls <- liftIO $ fromMaybe []
<$> tryWhenExists (L8.lines <$> L.readFile f')
@ -89,7 +88,7 @@ modifyLogFile f lck modf = withExclusiveLock lck $ do
-- action is concurrently modifying the file. It does not lock the file,
-- for speed, but instead relies on the fact that a log file usually
-- ends in a newline.
checkLogFile :: FilePath -> (Git.Repo -> RawFilePath) -> (L.ByteString -> Bool) -> Annex Bool
checkLogFile :: FilePath -> RawFilePath -> (L.ByteString -> Bool) -> Annex Bool
checkLogFile f lck matchf = withExclusiveLock lck $ bracket setup cleanup go
where
setup = liftIO $ tryWhenExists $ openFile f ReadMode
@ -123,7 +122,7 @@ fullLines = go []
--
-- Locking is used to prevent writes to to the log file while this
-- is running.
streamLogFile :: FilePath -> (Git.Repo -> RawFilePath) -> (String -> Annex ()) -> Annex ()
streamLogFile :: FilePath -> RawFilePath -> (String -> Annex ()) -> Annex ()
streamLogFile f lck a = withExclusiveLock lck $ bracketOnError setup cleanup go
where
setup = liftIO $ tryWhenExists $ openFile f ReadMode

View file

@ -19,7 +19,8 @@ import qualified Data.ByteString.Lazy as L
smudgeLog :: Key -> TopFilePath -> Annex ()
smudgeLog k f = do
logf <- fromRepo gitAnnexSmudgeLog
appendLogFile logf gitAnnexSmudgeLock $ L.fromStrict $
lckf <- fromRepo gitAnnexSmudgeLock
appendLogFile logf lckf $ L.fromStrict $
serializeKey' k <> " " <> getTopFilePath f
-- | Streams all smudged files, and then empties the log at the end.
@ -32,7 +33,8 @@ smudgeLog k f = do
streamSmudged :: (Key -> TopFilePath -> Annex ()) -> Annex ()
streamSmudged a = do
logf <- fromRepo gitAnnexSmudgeLog
streamLogFile (fromRawFilePath logf) gitAnnexSmudgeLock $ \l ->
lckf <- fromRepo gitAnnexSmudgeLock
streamLogFile (fromRawFilePath logf) lckf $ \l ->
case parse l of
Nothing -> noop
Just (k, f) -> a k f

View file

@ -24,8 +24,9 @@ import Data.Time.Clock.POSIX
writeUpgradeLog :: RepoVersion -> POSIXTime-> Annex ()
writeUpgradeLog v t = do
logfile <- fromRepo gitAnnexUpgradeLog
appendLogFile logfile gitAnnexUpgradeLock $ encodeBL $
logf <- fromRepo gitAnnexUpgradeLog
lckf <- fromRepo gitAnnexUpgradeLock
appendLogFile logf lckf $ encodeBL $
show (fromRepoVersion v) ++ " " ++ show t
readUpgradeLog :: Annex [(RepoVersion, POSIXTime)]

View file

@ -336,5 +336,5 @@ lockBup writer r a = do
let remoteid = fromUUID (uuid r)
let lck = dir P.</> remoteid <> ".lck"
if writer
then withExclusiveLock (const lck) a
else withSharedLock (const lck) a
then withExclusiveLock lck a
else withSharedLock lck a

View file

@ -182,7 +182,7 @@ storeKeyM :: RawFilePath -> ChunkConfig -> CopyCoWTried -> Storer
storeKeyM d chunkconfig cow k c m =
ifM (checkDiskSpaceDirectory d k)
( do
void $ liftIO $ tryIO $ createDirectoryUnder d tmpdir
void $ liftIO $ tryIO $ createDirectoryUnder [d] tmpdir
store
, giveup "Not enough free disk space."
)
@ -229,7 +229,7 @@ checkDiskSpaceDirectory d k = do
finalizeStoreGeneric :: RawFilePath -> RawFilePath -> RawFilePath -> IO ()
finalizeStoreGeneric d tmp dest = do
removeDirGeneric (fromRawFilePath d) dest'
createDirectoryUnder d (parentDir dest)
createDirectoryUnder [d] (parentDir dest)
renameDirectory (fromRawFilePath tmp) dest'
-- may fail on some filesystems
void $ tryIO $ do
@ -309,7 +309,7 @@ checkPresentGeneric' d check = ifM check
storeExportM :: RawFilePath -> CopyCoWTried -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex ()
storeExportM d cow src _k loc p = do
liftIO $ createDirectoryUnder d (P.takeDirectory dest)
liftIO $ createDirectoryUnder [d] (P.takeDirectory dest)
-- Write via temp file so that checkPresentGeneric will not
-- see it until it's fully stored.
viaTmp go (fromRawFilePath dest) ()
@ -337,7 +337,7 @@ checkPresentExportM d _k loc =
renameExportM :: RawFilePath -> Key -> ExportLocation -> ExportLocation -> Annex (Maybe ())
renameExportM d _k oldloc newloc = liftIO $ do
createDirectoryUnder d (P.takeDirectory dest)
createDirectoryUnder [d] (P.takeDirectory dest)
renameFile (fromRawFilePath src) (fromRawFilePath dest)
removeExportLocation d oldloc
return (Just ())
@ -502,7 +502,7 @@ retrieveExportWithContentIdentifierM ii dir cow loc cid dest gk p =
storeExportWithContentIdentifierM :: IgnoreInodes -> RawFilePath -> CopyCoWTried -> FilePath -> Key -> ExportLocation -> [ContentIdentifier] -> MeterUpdate -> Annex ContentIdentifier
storeExportWithContentIdentifierM ii dir cow src _k loc overwritablecids p = do
liftIO $ createDirectoryUnder dir (toRawFilePath destdir)
liftIO $ createDirectoryUnder [dir] (toRawFilePath destdir)
withTmpFileIn destdir template $ \tmpf tmph -> do
liftIO $ hClose tmph
void $ liftIO $ fileCopier cow src tmpf p Nothing

View file

@ -79,7 +79,7 @@ storeLegacyChunked' meterupdate chunksize (d:dests) bs c = do
storeHelper :: FilePath -> (RawFilePath -> RawFilePath -> IO ()) -> Key -> ([FilePath] -> IO [FilePath]) -> FilePath -> FilePath -> IO ()
storeHelper repotop finalizer key storer tmpdir destdir = do
void $ liftIO $ tryIO $ createDirectoryUnder
(toRawFilePath repotop)
[toRawFilePath repotop]
(toRawFilePath tmpdir)
Legacy.storeChunks key tmpdir destdir storer recorder (legacyFinalizer finalizer)
where

View file

@ -388,7 +388,7 @@ store' repo r rsyncopts accessmethod
| not $ Git.repoIsUrl repo =
byteStorer $ \k b p -> guardUsable repo (giveup "cannot access remote") $ liftIO $ do
let tmpdir = Git.repoPath repo P.</> "tmp" P.</> keyFile k
void $ tryIO $ createDirectoryUnder (Git.repoPath repo) tmpdir
void $ tryIO $ createDirectoryUnder [Git.repoPath repo] tmpdir
let tmpf = tmpdir P.</> keyFile k
meteredWriteFile p (fromRawFilePath tmpf) b
let destdir = parentDir $ toRawFilePath $ gCryptLocation repo k

View file

@ -245,7 +245,8 @@ adjustExportImport' isexport isimport r rs = do
oldcids <- liftIO $ concat
<$> mapM (ContentIdentifier.getContentIdentifiers db rs) oldks
newcid <- storeExportWithContentIdentifier (importActions r) f k loc oldcids p
withExclusiveLock gitAnnexContentIdentifierLock $ do
cidlck <- calcRepo' gitAnnexContentIdentifierLock
withExclusiveLock cidlck $ do
liftIO $ ContentIdentifier.recordContentIdentifier db rs newcid k
liftIO $ ContentIdentifier.flushDbQueue db
recordContentIdentifier rs newcid k
@ -280,8 +281,10 @@ adjustExportImport' isexport isimport r rs = do
( do
db <- ContentIdentifier.openDb
ContentIdentifier.needsUpdateFromLog db >>= \case
Just v -> withExclusiveLock gitAnnexContentIdentifierLock $
ContentIdentifier.updateFromLog db v
Just v -> do
cidlck <- calcRepo' gitAnnexContentIdentifierLock
withExclusiveLock cidlck $
ContentIdentifier.updateFromLog db v
Nothing -> noop
liftIO $ atomically $ putTMVar dbtv db
return db

View file

@ -817,7 +817,7 @@ test_lock_force = intmpclonerepo $ do
Database.Keys.removeInodeCaches k
Database.Keys.closeDb
liftIO . removeWhenExistsWith R.removeLink
=<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache
=<< Annex.calcRepo' Annex.Locations.gitAnnexKeysDbIndexCache
writecontent annexedfile "test_lock_force content"
git_annex_shouldfail "lock" [annexedfile] "lock of modified file should not be allowed"
git_annex "lock" ["--force", annexedfile] "lock --force of modified file"

View file

@ -119,6 +119,7 @@ data GitConfig = GitConfig
, annexVerify :: Bool
, annexPidLock :: Bool
, annexPidLockTimeout :: Seconds
, annexDbDir :: Maybe RawFilePath
, annexAddUnlocked :: GlobalConfigurable (Maybe String)
, annexSecureHashesOnly :: Bool
, annexRetry :: Maybe Integer
@ -212,6 +213,7 @@ extractGitConfig configsource r = GitConfig
, annexPidLock = getbool (annexConfig "pidlock") False
, annexPidLockTimeout = Seconds $ fromMaybe 300 $
getmayberead (annexConfig "pidlocktimeout")
, annexDbDir = toRawFilePath <$> getmaybe (annexConfig "dbdir")
, annexAddUnlocked = configurable Nothing $
fmap Just $ getmaybe (annexConfig "addunlocked")
, annexSecureHashesOnly = getbool (annexConfig "securehashesonly") False

View file

@ -37,17 +37,17 @@ upgrade automatic = do
-- The old content identifier database is deleted here, but the
-- new database is not populated. It will be automatically
-- populated from the git-annex branch the next time it is used.
removeOldDb gitAnnexContentIdentifierDbDirOld
removeOldDb . fromRawFilePath =<< fromRepo gitAnnexContentIdentifierDbDirOld
liftIO . removeWhenExistsWith R.removeLink
=<< fromRepo gitAnnexContentIdentifierLockOld
-- The export databases are deleted here. The new databases
-- will be populated by the next thing that needs them, the same
-- way as they would be in a fresh clone.
removeOldDb gitAnnexExportDir
removeOldDb . fromRawFilePath =<< calcRepo' gitAnnexExportDir
populateKeysDb
removeOldDb gitAnnexKeysDbOld
removeOldDb . fromRawFilePath =<< fromRepo gitAnnexKeysDbOld
liftIO . removeWhenExistsWith R.removeLink
=<< fromRepo gitAnnexKeysDbIndexCacheOld
liftIO . removeWhenExistsWith R.removeLink
@ -72,9 +72,8 @@ gitAnnexContentIdentifierDbDirOld r = gitAnnexDir r P.</> "cids"
gitAnnexContentIdentifierLockOld :: Git.Repo -> RawFilePath
gitAnnexContentIdentifierLockOld r = gitAnnexContentIdentifierDbDirOld r <> ".lck"
removeOldDb :: (Git.Repo -> RawFilePath) -> Annex ()
removeOldDb getdb = do
db <- fromRawFilePath <$> fromRepo getdb
removeOldDb :: FilePath -> Annex ()
removeOldDb db =
whenM (liftIO $ doesDirectoryExist db) $ do
v <- liftIO $ tryNonAsync $
#if MIN_VERSION_directory(1,2,7)

View file

@ -71,7 +71,8 @@ performUpgrade automatic = do
{- Take a lock to ensure that there are no other git-annex
- processes running that are using the old content locking method. -}
withExclusiveLock gitAnnexContentLockLock $ do
lck <- fromRepo gitAnnexContentLockLock
withExclusiveLock lck $ do
{- When core.sharedRepository is set, object files
- used to have their write bits set. That can now be
- removed, if the user the upgrade is running as has

View file

@ -31,10 +31,10 @@ import qualified Utility.RawFilePath as R
import Utility.PartialPrelude
{- Like createDirectoryIfMissing True, but it will only create
- missing parent directories up to but not including the directory
- in the first parameter.
- missing parent directories up to but not including a directory
- from the first parameter.
-
- For example, createDirectoryUnder "/tmp/foo" "/tmp/foo/bar/baz"
- For example, createDirectoryUnder ["/tmp/foo"] "/tmp/foo/bar/baz"
- will create /tmp/foo/bar if necessary, but if /tmp/foo does not exist,
- it will throw an exception.
-
@ -45,40 +45,43 @@ import Utility.PartialPrelude
- FilePath (or the same as it), it will fail with an exception
- even if the second FilePath's parent directory already exists.
-
- Either or both of the FilePaths can be relative, or absolute.
- The FilePaths can be relative, or absolute.
- They will be normalized as necessary.
-
- Note that, the second FilePath, if relative, is relative to the current
- working directory, not to the first FilePath.
- working directory.
-}
createDirectoryUnder :: RawFilePath -> RawFilePath -> IO ()
createDirectoryUnder topdir dir =
createDirectoryUnder' topdir dir R.createDirectory
createDirectoryUnder :: [RawFilePath] -> RawFilePath -> IO ()
createDirectoryUnder topdirs dir =
createDirectoryUnder' topdirs dir R.createDirectory
createDirectoryUnder'
:: (MonadIO m, MonadCatch m)
=> RawFilePath
=> [RawFilePath]
-> RawFilePath
-> (RawFilePath -> m ())
-> m ()
createDirectoryUnder' topdir dir0 mkdir = do
p <- liftIO $ relPathDirToFile topdir dir0
let dirs = P.splitDirectories p
-- Catch cases where the dir is not beneath the topdir.
createDirectoryUnder' topdirs dir0 mkdir = do
relps <- liftIO $ forM topdirs $ \topdir -> relPathDirToFile topdir dir0
let relparts = map P.splitDirectories relps
-- Catch cases where dir0 is not beneath a topdir.
-- If the relative path between them starts with "..",
-- it's not. And on Windows, if they are on different drives,
-- the path will not be relative.
if headMaybe dirs == Just ".." || P.isAbsolute p
then liftIO $ ioError $ customerror userErrorType
("createDirectoryFrom: not located in " ++ fromRawFilePath topdir)
-- If dir0 is the same as the topdir, don't try to create
-- it, but make sure it does exist.
else if null dirs
then liftIO $ unlessM (doesDirectoryExist (fromRawFilePath topdir)) $
ioError $ customerror doesNotExistErrorType
"createDirectoryFrom: does not exist"
else createdirs $
map (topdir P.</>) (reverse (scanl1 (P.</>) dirs))
let notbeneath = \(_topdir, (relp, dirs)) ->
headMaybe dirs /= Just ".." && not (P.isAbsolute relp)
case filter notbeneath $ zip topdirs (zip relps relparts) of
((topdir, (_relp, dirs)):_)
-- If dir0 is the same as the topdir, don't try to
-- create it, but make sure it does exist.
| null dirs ->
liftIO $ unlessM (doesDirectoryExist (fromRawFilePath topdir)) $
ioError $ customerror doesNotExistErrorType $
"createDirectoryFrom: " ++ fromRawFilePath topdir ++ " does not exist"
| otherwise -> createdirs $
map (topdir P.</>) (reverse (scanl1 (P.</>) dirs))
_ -> liftIO $ ioError $ customerror userErrorType
("createDirectoryFrom: not located in " ++ unwords (map fromRawFilePath topdirs))
where
customerror t s = mkIOError t s Nothing (Just (fromRawFilePath dir0))

View file

@ -1228,6 +1228,15 @@ repository, using [[git-annex-config]]. See its man page for a list.)
file system. This timeout prevents git-annex waiting forever in such a
situation.
* `annex.dbdir`
The directory where git-annex should store its sqlite databases.
The default location is inside `.git/annex/`.
Certian filesystems, such as cifs, may not support locking operations
that sqlite needs, and setting this to a directory on another filesystem
can work around such a problem.
* `annex.cachecreds`
When "true" (the default), git-annex will cache credentials used to