##// END OF EJS Templates
gpg extension: Always remove temporary files created by 'hg sigcheck'.
gpg extension: Always remove temporary files created by 'hg sigcheck'.

File last commit:

r2177:6886bc0b merge default
r2231:9a2f4b2e default
Show More
appendfile.py
156 lines | 5.3 KiB | text/x-python | PythonLexer
Vadim Gelfer
forgot to add new module.
r1999 # appendfile.py - special classes to make repo updates atomic
#
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from demandload import *
Vadim Gelfer
fix file handling bugs on windows....
r2176 demandload(globals(), "cStringIO changelog errno manifest os tempfile util")
Vadim Gelfer
forgot to add new module.
r1999
# writes to metadata files are ordered. reads: changelog, manifest,
# normal files. writes: normal files, manifest, changelog.
# manifest contains pointers to offsets in normal files. changelog
# contains pointers to offsets in manifest. if reader reads old
# changelog while manifest or normal files are written, it has no
# pointers into new parts of those files that are maybe not consistent
# yet, so will not read them.
# localrepo.addchangegroup thinks it writes changelog first, then
# manifest, then normal files (this is order they are available, and
# needed for computing linkrev fields), but uses appendfile to hide
# updates from readers. data not written to manifest or changelog
# until all normal files updated. write manifest first, then
# changelog.
# with this write ordering, readers cannot see inconsistent view of
# repo during update.
class appendfile(object):
'''implement enough of file protocol to append to revlog file.
appended data is written to temp file. reads and seeks span real
file and temp file. readers cannot see appended data until
writedata called.'''
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 def __init__(self, fp, tmpname):
if tmpname:
self.tmpname = tmpname
Vadim Gelfer
fix file handling bugs on windows....
r2176 self.tmpfp = util.posixfile(self.tmpname, 'ab+')
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 else:
Thomas Arendsen Hein
Use better names (hg-{usage}-{random}.{suffix}) for temporary files.
r2165 fd, self.tmpname = tempfile.mkstemp(prefix="hg-appendfile-")
Vadim Gelfer
fix file handling bugs on windows....
r2176 os.close(fd)
self.tmpfp = util.posixfile(self.tmpname, 'ab+')
Vadim Gelfer
forgot to add new module.
r1999 self.realfp = fp
Vadim Gelfer
fix appendfile problem on macos....
r2010 self.offset = fp.tell()
Vadim Gelfer
forgot to add new module.
r1999 # real file is not written by anyone else. cache its size so
# seek and read can be fast.
Vadim Gelfer
fix file handling bugs on windows....
r2176 self.realsize = util.fstat(fp).st_size
self.name = fp.name
Vadim Gelfer
forgot to add new module.
r1999
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 def end(self):
self.tmpfp.flush() # make sure the stat is correct
Vadim Gelfer
fix file handling bugs on windows....
r2176 return self.realsize + util.fstat(self.tmpfp).st_size
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089
def tell(self):
return self.offset
def flush(self):
self.tmpfp.flush()
def close(self):
self.realfp.close()
self.tmpfp.close()
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075
def seek(self, offset, whence=0):
Vadim Gelfer
forgot to add new module.
r1999 '''virtual file offset spans real file and temp file.'''
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 if whence == 0:
self.offset = offset
elif whence == 1:
self.offset += offset
elif whence == 2:
self.offset = self.end() + offset
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 if self.offset < self.realsize:
Vadim Gelfer
forgot to add new module.
r1999 self.realfp.seek(self.offset)
else:
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 self.tmpfp.seek(self.offset - self.realsize)
Vadim Gelfer
forgot to add new module.
r1999
def read(self, count=-1):
'''only trick here is reads that span real file and temp file.'''
fp = cStringIO.StringIO()
old_offset = self.offset
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 if self.offset < self.realsize:
Vadim Gelfer
forgot to add new module.
r1999 s = self.realfp.read(count)
fp.write(s)
self.offset += len(s)
if count > 0:
count -= len(s)
if count != 0:
if old_offset != self.offset:
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 self.tmpfp.seek(self.offset - self.realsize)
Vadim Gelfer
forgot to add new module.
r1999 s = self.tmpfp.read(count)
fp.write(s)
self.offset += len(s)
return fp.getvalue()
def write(self, s):
'''append to temp file.'''
Vadim Gelfer
work around python bug on solaris 10....
r2027 self.tmpfp.seek(0, 2)
Vadim Gelfer
forgot to add new module.
r1999 self.tmpfp.write(s)
# all writes are appends, so offset must go to end of file.
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 self.offset = self.realsize + self.tmpfp.tell()
Vadim Gelfer
forgot to add new module.
r1999
class appendopener(object):
'''special opener for files that only read or append.'''
def __init__(self, opener):
self.realopener = opener
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 # key: file name, value: appendfile name
self.tmpnames = {}
Vadim Gelfer
forgot to add new module.
r1999
def __call__(self, name, mode='r'):
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 '''open file.'''
Vadim Gelfer
forgot to add new module.
r1999
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 assert mode in 'ra+'
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 try:
realfp = self.realopener(name, 'r')
except IOError, err:
if err.errno != errno.ENOENT: raise
realfp = self.realopener(name, 'w+')
tmpname = self.tmpnames.get(name)
fp = appendfile(realfp, tmpname)
if tmpname is None:
self.tmpnames[name] = fp.tmpname
return fp
Vadim Gelfer
forgot to add new module.
r1999
def writedata(self):
'''copy data from temp files to real files.'''
# write .d file before .i file.
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 tmpnames = self.tmpnames.items()
tmpnames.sort()
for name, tmpname in tmpnames:
fp = open(tmpname, 'rb')
s = fp.read()
fp.close()
Vadim Gelfer
remove appendfile data as soon as not needed.
r2102 os.unlink(tmpname)
Vadim Gelfer
make appendfile simpler so it does not break with revlogng on windows....
r2089 fp = self.realopener(name, 'a')
fp.write(s)
fp.close()
Vadim Gelfer
forgot to add new module.
r1999 # files for changelog and manifest are in different appendopeners, so
# not mixed up together.
class appendchangelog(changelog.changelog, appendopener):
mason@suse.com
Additional appendfile fixes for interleaved data/index files...
r2082 def __init__(self, opener, version):
Vadim Gelfer
forgot to add new module.
r1999 appendopener.__init__(self, opener)
mason@suse.com
Additional appendfile fixes for interleaved data/index files...
r2082 changelog.changelog.__init__(self, self, version)
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 def checkinlinesize(self, fp, tr):
return
Vadim Gelfer
forgot to add new module.
r1999
class appendmanifest(manifest.manifest, appendopener):
mason@suse.com
Additional appendfile fixes for interleaved data/index files...
r2082 def __init__(self, opener, version):
Vadim Gelfer
forgot to add new module.
r1999 appendopener.__init__(self, opener)
mason@suse.com
Additional appendfile fixes for interleaved data/index files...
r2082 manifest.manifest.__init__(self, self, version)
mason@suse.com
Make the appendfile class inline-data index friendly...
r2075 def checkinlinesize(self, fp, tr):
return