Copy with a reflink when exporting a tree to a directory special remote

Remote.Directory makes a temp file, then calls this, and since the temp
file exists, it prevented probing if CoW works.

Note that deleting the empty file does mean there's a small window for a
race. If another process is also exporting to the remote, that could let it
make the same temp file. However, the temp filename actually has the
processes's pid in it, which avoids that being a problem.

This may have been a reversion caused by commits around
63d508e885, but I haven't gone back and
tested to be sure. The directory special remote had supposedly supported
CoW for this going back to about half a year before that.

Sponsored-by: Graham Spencer on Patreon
This commit is contained in:
Joey Hess 2023-03-28 13:06:11 -04:00
parent d2d7d766d8
commit a5709dcc22
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
3 changed files with 22 additions and 5 deletions

View file

@ -31,17 +31,15 @@ newCopyCoWTried = CopyCoWTried <$> newEmptyMVar
{- Copies a file is copy-on-write is supported. Otherwise, returns False.
-
- The destination file must not exist yet, or it will fail to make a CoW copy,
- and will return false.
- The destination file must not exist yet (or may exist but be empty),
- or it will fail to make a CoW copy, and will return false.
-}
tryCopyCoW :: CopyCoWTried -> FilePath -> FilePath -> MeterUpdate -> IO Bool
tryCopyCoW (CopyCoWTried copycowtried) src dest meterupdate =
-- If multiple threads reach this at the same time, they
-- will both try CoW, which is acceptable.
ifM (isEmptyMVar copycowtried)
-- If dest exists, don't try CoW, since it would
-- have to be deleted first.
( ifM (doesFileExist dest)
( ifM destfilealreadypopulated
( return False
, do
ok <- docopycow
@ -62,6 +60,22 @@ tryCopyCoW (CopyCoWTried copycowtried) src dest meterupdate =
docopycow = watchFileSize dest meterupdate $
copyCoW CopyTimeStamps src dest
dest' = toRawFilePath dest
-- Check if the dest file already exists, which would prevent
-- probing CoW. If the file exists but is empty, there's no benefit
-- to resuming from it when CoW does not work, so remove it.
destfilealreadypopulated =
tryIO (R.getFileStatus dest') >>= \case
Left _ -> return False
Right st -> do
sz <- getFileSize' dest' st
if sz == 0
then tryIO (removeFile dest) >>= \case
Right () -> return False
Left _ -> return True
else return True
data CopyMethod = CopiedCoW | Copied
{- Copies from src to dest, updating a meter. Preserves mode and mtime.

View file

@ -9,6 +9,7 @@ git-annex (10.20230322) UNRELEASED; urgency=medium
the view branch.
* Windows: Support urls like "file:///c:/path"
* addurl, importfeed: Fix failure when annex.securehashesonly is set.
* Copy with a reflink when exporting a tree to a directory special remote.
-- Joey Hess <id@joeyh.name> Thu, 23 Mar 2023 15:04:41 -0400

View file

@ -40,3 +40,5 @@ After running, a `btrfs filesystem du ...` tells me that the `repo` and `import`
---
In general: Thank you so much for this wonderful piece of software, I'm using it for years now and manage virtually everything with it (audio, video, pictures, important documents, papers, …).
> [[fixed|done]] --[[Joey]]