largefiles: copy files into .hg/largefiles atomically stable
authorMartin Geisler <mg@aragost.com>
Thu, 24 Nov 2011 18:13:18 +0100
branchstable
changeset 15572 926bc23d0b6a
parent 15571 809788118aa2
child 15573 a5e5c64cd90b
child 15575 4a4a95029b31
largefiles: copy files into .hg/largefiles atomically Copying from the user cache into .hg/largefiles could fail halfway though with a partially written file.
hgext/largefiles/lfutil.py
tests/test-largefiles-small-disk.t
--- a/hgext/largefiles/lfutil.py	Thu Nov 24 18:12:13 2011 +0100
+++ b/hgext/largefiles/lfutil.py	Thu Nov 24 18:13:18 2011 +0100
@@ -77,8 +77,11 @@
     try:
         util.oslink(src, dest)
     except OSError:
-        # if hardlinks fail, fallback on copy
-        shutil.copyfile(src, dest)
+        # if hardlinks fail, fallback on atomic copy
+        dst = util.atomictempfile(dest)
+        for chunk in util.filechunkiter(open(src)):
+            dst.write(chunk)
+        dst.close()
         os.chmod(dest, os.stat(src).st_mode)
 
 def usercachepath(ui, hash):
--- a/tests/test-largefiles-small-disk.t	Thu Nov 24 18:12:13 2011 +0100
+++ b/tests/test-largefiles-small-disk.t	Thu Nov 24 18:13:18 2011 +0100
@@ -15,6 +15,10 @@
   >     yield f.read(4)
   >     raise IOError(errno.ENOSPC, os.strerror(errno.ENOSPC))
   > util.filechunkiter = filechunkiter
+  > #
+  > def oslink(src, dest):
+  >     raise OSError("no hardlinks, try copying instead")
+  > util.oslink = oslink
   > EOF
 
   $ echo "[extensions]" >> $HGRCPATH
@@ -37,3 +41,28 @@
 
   >>> import os; os.path.exists("$HOME/.cache/largefiles/")
   False
+
+Make the commit with space on the device:
+
+  $ hg commit -m big
+
+Now make a clone with a full disk, and make sure lfutil.link function
+makes copies instead of hardlinks:
+
+  $ cd ..
+  $ hg --config extensions.criple=$TESTTMP/criple.py clone --pull alice bob
+  requesting all changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  updating to branch default
+  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+  getting changed largefiles
+  abort: No space left on device
+  [255]
+
+The largefile is not created in .hg/largefiles:
+
+  $ ls bob/.hg/largefiles
+  dirstate