revlog: seek to end of file before writing (issue4943) stable
authorGregory Szorc <gregory.szorc@gmail.com>
Thu, 17 Dec 2015 17:16:02 -0800
branchstable
changeset 27430 e240e914d226
parent 27392 00aa37c65e0a
child 27431 8f016345e6b0
child 27441 e47841c8343d
revlog: seek to end of file before writing (issue4943) Revlogs were recently refactored to open file handles in "a+" and use a persistent file handle for reading and writing. This drastically reduced the number of file handles being opened. Unfortunately, it appears that some versions of Solaris lose the file offset when performing a write after the handle has been seeked. The simplest workaround is to seek to EOF on files opened in a+ mode before writing to them, which is what this patch does. Ideally, this code would exist in the vfs layer. However, this would require creating a proxy class for file objects in order to provide a custom implementation of write(). This would add overhead. Since revlogs are the only files we open in a+ mode, the one-off workaround in revlog.py should be sufficient. This patch appears to have little to no impact on performance on my Linux machine.
mercurial/revlog.py
--- a/mercurial/revlog.py	Mon Nov 30 13:47:29 2015 -0600
+++ b/mercurial/revlog.py	Thu Dec 17 17:16:02 2015 -0800
@@ -13,6 +13,7 @@
 
 # import stuff from node for others to import from revlog
 import collections
+import os
 from node import bin, hex, nullid, nullrev
 from i18n import _
 import ancestor, mdiff, parsers, error, util, templatefilters
@@ -1426,6 +1427,20 @@
         return node
 
     def _writeentry(self, transaction, ifh, dfh, entry, data, link, offset):
+        # Files opened in a+ mode have inconsistent behavior on various
+        # platforms. Windows requires that a file positioning call be made
+        # when the file handle transitions between reads and writes. See
+        # 3686fa2b8eee and the mixedfilemodewrapper in windows.py. On other
+        # platforms, Python or the platform itself can be buggy. Some versions
+        # of Solaris have been observed to not append at the end of the file
+        # if the file was seeked to before the end. See issue4943 for more.
+        #
+        # We work around this issue by inserting a seek() before writing.
+        # Note: This is likely not necessary on Python 3.
+        ifh.seek(0, os.SEEK_END)
+	 if dfh:
+            dfh.seek(0, os.SEEK_END)
+
         curr = len(self) - 1
         if not self._inline:
             transaction.add(self.datafile, offset)