]> arthur.barton.de Git - bup.git/commitdiff
git.PackWriter: avoid pack corruption if interrupted by a signal.
authorAvery Pennarun <apenwarr@gmail.com>
Fri, 12 Mar 2010 23:46:40 +0000 (18:46 -0500)
committerAvery Pennarun <apenwarr@gmail.com>
Sat, 13 Mar 2010 02:44:36 +0000 (21:44 -0500)
PackWriter tries to "finish" a half-written pack in its destructor if
interrupted.  To do this, it flushes the stream, seeks back to the beginning
to update the sha1sum and object count, then runs git-index-pack on it to
create the .idx file.

However, sometimes if you were unlucky, you'd interrupt PackWriter partway
through writing an object to the pack.  If only half an object exists at the
end, it would have the wrong header and thus come out as corrupt when
index-pack would run.

Since our objects are meant to be small anyway, just make sure we write
everything all in one file.write() operation.  The files themselves are
buffered, so this wouldn't survive a surprise termination of the whole
unix process, but we wouldn't run index-pack in that case anyway, so it
doesn't matter.

Now when I press ctrl-c in 'bup save', it consistently writes the half-saved
objects as it should.

lib/bup/git.py

index 4c5a6acb6f58639d091eb542e1799729e817393f..5a688931a48e68fea0cb4f46ef5d6472a34185f6 100644 (file)
@@ -351,9 +351,14 @@ class PackWriter:
     def _raw_write(self, datalist):
         self._open()
         f = self.file
-        for d in datalist:
-            f.write(d)
-            self.outbytes += len(d)
+        # in case we get interrupted (eg. KeyboardInterrupt), it's best if
+        # the file never has a *partial* blob.  So let's make sure it's
+        # all-or-nothing.  (The blob shouldn't be very big anyway, thanks
+        # to our hashsplit algorithm.)  f.write() does its own buffering,
+        # but that's okay because we'll flush it in _end().
+        oneblob = ''.join(datalist)
+        f.write(oneblob)
+        self.outbytes += len(oneblob)
         self.count += 1
 
     def _write(self, bin, type, content):