mercurial/appendfile.py
changeset 4261 cd7b36b7869c
parent 4260 bdbfc2193524
child 4265 94bb953b43e5
--- a/mercurial/appendfile.py	Thu Mar 22 20:10:46 2007 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-# 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.
-
-import cStringIO, changelog, errno, manifest, os, tempfile, util
-
-# 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.'''
-
-    def __init__(self, fp, tmpname):
-        if tmpname:
-            self.tmpname = tmpname
-            self.tmpfp = util.posixfile(self.tmpname, 'ab+')
-        else:
-            fd, self.tmpname = tempfile.mkstemp(prefix="hg-appendfile-")
-            os.close(fd)
-            self.tmpfp = util.posixfile(self.tmpname, 'ab+')
-        self.realfp = fp
-        self.offset = fp.tell()
-        # real file is not written by anyone else. cache its size so
-        # seek and read can be fast.
-        self.realsize = util.fstat(fp).st_size
-        self.name = fp.name
-
-    def end(self):
-        self.tmpfp.flush() # make sure the stat is correct
-        return self.realsize + util.fstat(self.tmpfp).st_size
-
-    def tell(self):
-        return self.offset
-
-    def flush(self):
-        self.tmpfp.flush()
-
-    def close(self):
-        self.realfp.close()
-        self.tmpfp.close()
-
-    def seek(self, offset, whence=0):
-        '''virtual file offset spans real file and temp file.'''
-        if whence == 0:
-            self.offset = offset
-        elif whence == 1:
-            self.offset += offset
-        elif whence == 2:
-            self.offset = self.end() + offset
-
-        if self.offset < self.realsize:
-            self.realfp.seek(self.offset)
-        else:
-            self.tmpfp.seek(self.offset - self.realsize)
-
-    def read(self, count=-1):
-        '''only trick here is reads that span real file and temp file.'''
-        fp = cStringIO.StringIO()
-        old_offset = self.offset
-        if self.offset < self.realsize:
-            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:
-                self.tmpfp.seek(self.offset - self.realsize)
-            s = self.tmpfp.read(count)
-            fp.write(s)
-            self.offset += len(s)
-        return fp.getvalue()
-
-    def write(self, s):
-        '''append to temp file.'''
-        self.tmpfp.seek(0, 2)
-        self.tmpfp.write(s)
-        # all writes are appends, so offset must go to end of file.
-        self.offset = self.realsize + self.tmpfp.tell()
-
-class appendopener(object):
-    '''special opener for files that only read or append.'''
-
-    def __init__(self, opener):
-        self.realopener = opener
-        self.tmpname = None
-
-    def __call__(self, name, mode='r'):
-        '''open file.'''
-        # only handle .i file
-        if not name.endswith("."):
-            return self.realopener(name, mode)
-        assert mode in 'ra+'
-        try:
-            realfp = self.realopener(name, 'r')
-        except IOError, err:
-            if err.errno != errno.ENOENT: raise
-            self.realfp = self.realopener(name, 'w+')
-        fp = appendfile(realfp, self.tmpname)
-        if tmpname is None:
-            self.tmpname = fp.tmpname
-            self.name = name
-        return fp
-
-    def writedata(self):
-        '''copy data from temp files to real files.'''
-        if not self.tmpname:
-            return
-        ifp = open(self.tmpname, 'rb')
-        ofp = self.realopener(self.name, 'a')
-        for chunk in util.filechunkiter(ifp):
-            ofp.write(chunk)
-        ifp.close()
-        os.unlink(self.tmpname)
-        ofp.close()
-
-    def cleanup(self):
-        '''delete temp files (this discards unwritten data!)'''
-        if self.tmpname:
-            os.unlink(self.tmpname)
-
-# files for changelog and manifest are in different appendopeners, so
-# not mixed up together.
-
-class appendchangelog(changelog.changelog, appendopener):
-    def __init__(self, opener):
-        appendopener.__init__(self, opener)
-        changelog.changelog.__init__(self, self)
-    def checkinlinesize(self, fp, tr):
-        return