[PATCH 2 of 3] obsolete: append new markers to obsstore file instead of rewriting everything

Adrian Buehlmann adrian at cadifra.com
Sun Jul 15 16:12:57 CDT 2012


On 2012-07-15 14:38, Pierre-Yves David wrote:
> On Sun, Jul 15, 2012 at 01:40:58PM +0200, Adrian Buehlmann wrote:
>> On 2012-07-04 02:26, Pierre-Yves David wrote:
>>> diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
>>> --- a/mercurial/obsolete.py
>>> +++ b/mercurial/obsolete.py
>>> @@ -209,12 +209,14 @@
>>>          """Write all markers on disk
>>>  
>>>          After this operation, "new" markers are considered "known"."""
>>> +        # XXX: transaction logic should be used
>>>          if self._new:
>>> -            # XXX: transaction logic should be used here. But for
>>> -            # now rewriting the whole file is good enough.
>>> -            f = self.sopener('obsstore', 'wb', atomictemp=True)
>>> +            f = self.sopener('obsstore', 'ab')
>>>              try:
>>> -                self._writemarkers(f)
>>> +                if f.tell() == 0:
>>> +                    # plain new obsstore
>>> +                    f.write(_pack('>B', _fmversion))
>>> +                _writemarkers(f.write, self._new)
>>>                  f.close()
>>>                  self._new[:] = []
>>>              except: # re-raises
>>
>> This was pushed as http://selenic.com/repo/hg/rev/95d785ccb4e5
>>
>> Bisecting reveals that it is the first changeset that causes test-obsolete.t to
>> fail on Windows with:
>>
>> --- C:\Users\adi\hgrepos\hg-main\tests\test-obsolete.t
>> +++ C:\Users\adi\hgrepos\hg-main\tests\test-obsolete.t.err
>> @@ -43,8 +43,8 @@
>>    created new head
>>    $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
>>    $ hg debugobsolete
>> -  245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f 0 {'date': '56 12', 'user': 'test'}
>> -  cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
>> +  abort: parsing obsolete marker: metadata is too short, 42 bytes expected, got 16777216
>> +  [255]
>>
>> See also
>>
>> http://hgbuildbot.kublai.com/builders/Windows%202008%20R2%20hg%20tests/builds/148/steps/run-tests.py%20%28python2.6%29/logs/stdio
>>
> 
> Looking at the error message, it seems that the version headers where not
> written. Is there any specific behavion windows regarding open(xxx, 'ab') or
> f.tell() ?

Yeah. Windows fun again.

It turns out that file objects on Windows [1] seem to behave strangely,
compared to Linux: after f = open(..., 'ab'), f.tell() returns 0L on
Windows for nonzero (!) files, whereas on Linux, it returns the size of
the file.

[1] as seen here with Python 2.7.3 (default, Apr 10 2012, 23:24:47) [MSC
v.1500 64 bit (AMD64)] on win32)

This hack lets test-obsolete.t pass for me on Windows:

diff --git a/mercurial/obsolete.py b/mercurial/obsolete.py
--- a/mercurial/obsolete.py
+++ b/mercurial/obsolete.py
@@ -47,15 +47,15 @@
 - N*20 bytes: new changesets identifiers.

 - M bytes: metadata as a sequence of nul-terminated strings. Each
   string contains a key and a value, separated by a color ':', without
   additional encoding. Keys cannot contain '\0' or ':' and values
   cannot contain '\0'.
 """
-import struct
+import struct, os
 from mercurial import util, base85
 from i18n import _

 _pack = struct.pack
 _unpack = struct.unpack


@@ -190,14 +190,15 @@
         marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata))
         self.add(transaction, marker)

     def add(self, transaction, marker):
         """Add a new marker to the store"""
         if marker not in self._all:
             f = self.sopener('obsstore', 'ab')
+            f.seek(0, os.SEEK_END)
             try:
                 offset = f.tell()
                 transaction.add('obsstore', offset)
                 if offset == 0:
                     # new file add version header
                     f.write(_pack('>B', _fmversion))
                 _writemarkers(f.write, [marker])


More information about the Mercurial-devel mailing list