Mercurial > hg > gitweb
changeset 4265:94bb953b43e5
Merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Fri, 23 Mar 2007 01:04:21 -0500 |
parents | cd7b36b7869c (diff) bda63383d529 (current diff) |
children | f38f90a177dc |
files | mercurial/commands.py |
diffstat | 13 files changed, 144 insertions(+), 268 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/appendfile.py Wed Mar 21 14:06:25 2007 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +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 - # key: file name, value: appendfile name - self.tmpnames = {} - - def __call__(self, name, mode='r'): - '''open file.''' - - assert mode in 'ra+' - 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 - - def writedata(self): - '''copy data from temp files to real files.''' - # write .d file before .i file. - tmpnames = self.tmpnames.items() - tmpnames.sort() - for name, tmpname in tmpnames: - ifp = open(tmpname, 'rb') - ofp = self.realopener(name, 'a') - for chunk in util.filechunkiter(ifp): - ofp.write(chunk) - ifp.close() - os.unlink(tmpname) - del self.tmpnames[name] - ofp.close() - - def cleanup(self): - '''delete temp files (this discards unwritten data!)''' - for tmpname in self.tmpnames.values(): - os.unlink(tmpname) - -# files for changelog and manifest are in different appendopeners, so -# not mixed up together. - -class appendchangelog(changelog.changelog, appendopener): - def __init__(self, opener, version): - appendopener.__init__(self, opener) - changelog.changelog.__init__(self, self, version) - def checkinlinesize(self, fp, tr): - return - -class appendmanifest(manifest.manifest, appendopener): - def __init__(self, opener, version): - appendopener.__init__(self, opener) - manifest.manifest.__init__(self, self, version) - def checkinlinesize(self, fp, tr): - return
--- a/mercurial/bundlerepo.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/bundlerepo.py Fri Mar 23 01:04:21 2007 -0500 @@ -17,7 +17,7 @@ import localrepo, changelog, manifest, filelog, revlog class bundlerevlog(revlog.revlog): - def __init__(self, opener, indexfile, datafile, bundlefile, + def __init__(self, opener, indexfile, bundlefile, linkmapper=None): # How it works: # to retrieve a revision, we need to know the offset of @@ -28,7 +28,7 @@ # len(index[r]). If the tuple is bigger than 7, it is a bundle # (it is bigger since we store the node to which the delta is) # - revlog.revlog.__init__(self, opener, indexfile, datafile) + revlog.revlog.__init__(self, opener, indexfile) self.bundlefile = bundlefile self.basemap = {} def chunkpositer(): @@ -140,20 +140,19 @@ class bundlechangelog(bundlerevlog, changelog.changelog): def __init__(self, opener, bundlefile): changelog.changelog.__init__(self, opener) - bundlerevlog.__init__(self, opener, self.indexfile, self.datafile, - bundlefile) + bundlerevlog.__init__(self, opener, self.indexfile, bundlefile) class bundlemanifest(bundlerevlog, manifest.manifest): def __init__(self, opener, bundlefile, linkmapper): manifest.manifest.__init__(self, opener) - bundlerevlog.__init__(self, opener, self.indexfile, self.datafile, - bundlefile, linkmapper) + bundlerevlog.__init__(self, opener, self.indexfile, bundlefile, + linkmapper) class bundlefilelog(bundlerevlog, filelog.filelog): def __init__(self, opener, path, bundlefile, linkmapper): filelog.filelog.__init__(self, opener, path) - bundlerevlog.__init__(self, opener, self.indexfile, self.datafile, - bundlefile, linkmapper) + bundlerevlog.__init__(self, opener, self.indexfile, bundlefile, + linkmapper) class bundlerepository(localrepo.localrepository): def __init__(self, ui, path, bundlename):
--- a/mercurial/changelog.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/changelog.py Fri Mar 23 01:04:21 2007 -0500 @@ -26,10 +26,88 @@ def _string_unescape(text): return text.decode('string_escape') +class appender: + '''the changelog index must be update last on disk, so we use this class + to delay writes to it''' + def __init__(self, fp, buf): + self.data = buf + self.fp = fp + self.offset = fp.tell() + self.size = util.fstat(fp).st_size + + def end(self): + return self.size + len("".join(self.data)) + def tell(self): + return self.offset + def flush(self): + pass + def close(self): + close(self.fp) + + def seek(self, offset, whence=0): + '''virtual file offset spans real file and data''' + if whence == 0: + self.offset = offset + elif whence == 1: + self.offset += offset + elif whence == 2: + self.offset = self.end() + offset + if self.offset < self.size: + self.fp.seek(self.offset) + + def read(self, count=-1): + '''only trick here is reads that span real file and data''' + ret = "" + old_offset = self.offset + if self.offset < self.size: + s = self.fp.read(count) + ret = s + self.offset += len(s) + if count > 0: + count -= len(s) + if count != 0: + doff = self.offset - self.size + self.data.insert(0, "".join(self.data)) + del self.data[1:] + s = self.data[0][doff:doff+count] + self.offset += len(s) + ret += s + return ret + + def write(self, s): + self.data.append(s) + self.offset += len(s) + class changelog(revlog): - def __init__(self, opener, defversion=REVLOGV0): - revlog.__init__(self, opener, "00changelog.i", "00changelog.d", - defversion) + def __init__(self, opener): + revlog.__init__(self, opener, "00changelog.i") + + def delayupdate(self): + "delay visibility of index updates to other readers" + self._realopener = self.opener + self.opener = self._appendopener + self._delaybuf = [] + + def finalize(self, tr): + "finalize index updates" + self.opener = self._realopener + if self._delaybuf: + fp = self.opener(self.indexfile, 'a') + fp.write("".join(self._delaybuf)) + fp.close() + del self._delaybuf + self.checkinlinesize(tr) + + def _appendopener(self, name, mode='r'): + fp = self._realopener(name, mode) + if not name == self.indexfile: + return fp + return appender(fp, self._delaybuf) + + def checkinlinesize(self, tr, fp=None): + if self.opener == self._appendopener: + return + return revlog.checkinlinesize(self, tr, fp) def decode_extra(self, text): extra = {}
--- a/mercurial/commands.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/commands.py Fri Mar 23 01:04:21 2007 -0500 @@ -666,7 +666,7 @@ def debugancestor(ui, index, rev1, rev2): """find the ancestor revision of two revisions in a given index""" - r = revlog.revlog(util.opener(os.getcwd(), audit=False), index, "", 0) + r = revlog.revlog(util.opener(os.getcwd(), audit=False), index) a = r.ancestor(r.lookup(rev1), r.lookup(rev2)) ui.write("%d:%s\n" % (r.rev(a), hex(a))) @@ -794,9 +794,8 @@ ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f)) def debugdata(ui, file_, rev): - """dump the contents of an data file revision""" - r = revlog.revlog(util.opener(os.getcwd(), audit=False), - file_[:-2] + ".i", file_, 0) + """dump the contents of a data file revision""" + r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i") try: ui.write(r.revision(r.lookup(rev))) except KeyError: @@ -816,7 +815,7 @@ def debugindex(ui, file_): """dump the contents of an index file""" - r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0) + r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_) ui.write(" rev offset length base linkrev" + " nodeid p1 p2\n") for i in xrange(r.count()): @@ -828,7 +827,7 @@ def debugindexdot(ui, file_): """dump an index DAG as a .dot file""" - r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_, "", 0) + r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_) ui.write("digraph G {\n") for i in xrange(r.count()): node = r.node(i)
--- a/mercurial/filelog.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/filelog.py Fri Mar 23 01:04:21 2007 -0500 @@ -9,11 +9,9 @@ import os class filelog(revlog): - def __init__(self, opener, path, defversion=REVLOG_DEFAULT_VERSION): + def __init__(self, opener, path): revlog.__init__(self, opener, - "/".join(("data", self.encodedir(path + ".i"))), - "/".join(("data", self.encodedir(path + ".d"))), - defversion) + "/".join(("data", self.encodedir(path + ".i")))) # This avoids a collision between a file named foo and a dir named # foo.i or foo.d
--- a/mercurial/hgweb/hgweb_mod.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/hgweb/hgweb_mod.py Fri Mar 23 01:04:21 2007 -0500 @@ -1018,7 +1018,7 @@ def do_capabilities(self, req): caps = ['lookup', 'changegroupsubset'] if self.configbool('server', 'uncompressed'): - caps.append('stream=%d' % self.repo.revlogversion) + caps.append('stream=%d' % self.repo.changelog.version) # XXX: make configurable and/or share code with do_unbundle: unbundleversions = ['HG10GZ', 'HG10BZ', 'HG10UN'] if unbundleversions:
--- a/mercurial/localrepo.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/localrepo.py Fri Mar 23 01:04:21 2007 -0500 @@ -7,7 +7,7 @@ from node import * from i18n import _ -import repo, appendfile, changegroup +import repo, changegroup import changelog, dirstate, filelog, manifest, context import re, lock, transaction, tempfile, stat, mdiff, errno, ui import os, revlog, time, util @@ -88,34 +88,14 @@ except IOError: pass - v = self.ui.configrevlog() - self.revlogversion = int(v.get('format', revlog.REVLOG_DEFAULT_FORMAT)) - self.revlogv1 = self.revlogversion != revlog.REVLOGV0 - fl = v.get('flags', None) - flags = 0 - if fl != None: - for x in fl.split(): - flags |= revlog.flagstr(x) - elif self.revlogv1: - flags = revlog.REVLOG_DEFAULT_FLAGS - - v = self.revlogversion | flags - self.manifest = manifest.manifest(self.sopener, v) - self.changelog = changelog.changelog(self.sopener, v) + self.changelog = changelog.changelog(self.sopener) + self.sopener.defversion = self.changelog.version + self.manifest = manifest.manifest(self.sopener) fallback = self.ui.config('ui', 'fallbackencoding') if fallback: util._fallbackencoding = fallback - # the changelog might not have the inline index flag - # on. If the format of the changelog is the same as found in - # .hgrc, apply any flags found in the .hgrc as well. - # Otherwise, just version from the changelog - v = self.changelog.version - if v == self.revlogversion: - v |= flags - self.revlogversion = v - self.tagscache = None self.branchcache = None self.nodetagscache = None @@ -493,7 +473,7 @@ def file(self, f): if f[0] == '/': f = f[1:] - return filelog.filelog(self.sopener, f, self.revlogversion) + return filelog.filelog(self.sopener, f) def changectx(self, changeid=None): return context.changectx(self, changeid) @@ -1802,55 +1782,45 @@ # write changelog data to temp files so concurrent readers will not see # inconsistent view - cl = None - try: - cl = appendfile.appendchangelog(self.sopener, - self.changelog.version) + cl = self.changelog + cl.delayupdate() + oldheads = len(cl.heads()) - oldheads = len(cl.heads()) + # pull off the changeset group + self.ui.status(_("adding changesets\n")) + cor = cl.count() - 1 + chunkiter = changegroup.chunkiter(source) + if cl.addgroup(chunkiter, csmap, tr, 1) is None: + raise util.Abort(_("received changelog group is empty")) + cnr = cl.count() - 1 + changesets = cnr - cor - # pull off the changeset group - self.ui.status(_("adding changesets\n")) - cor = cl.count() - 1 - chunkiter = changegroup.chunkiter(source) - if cl.addgroup(chunkiter, csmap, tr, 1) is None: - raise util.Abort(_("received changelog group is empty")) - cnr = cl.count() - 1 - changesets = cnr - cor + # pull off the manifest group + self.ui.status(_("adding manifests\n")) + chunkiter = changegroup.chunkiter(source) + # no need to check for empty manifest group here: + # if the result of the merge of 1 and 2 is the same in 3 and 4, + # no new manifest will be created and the manifest group will + # be empty during the pull + self.manifest.addgroup(chunkiter, revmap, tr) - # pull off the manifest group - self.ui.status(_("adding manifests\n")) + # process the files + self.ui.status(_("adding file changes\n")) + while 1: + f = changegroup.getchunk(source) + if not f: + break + self.ui.debug(_("adding %s revisions\n") % f) + fl = self.file(f) + o = fl.count() chunkiter = changegroup.chunkiter(source) - # no need to check for empty manifest group here: - # if the result of the merge of 1 and 2 is the same in 3 and 4, - # no new manifest will be created and the manifest group will - # be empty during the pull - self.manifest.addgroup(chunkiter, revmap, tr) - - # process the files - self.ui.status(_("adding file changes\n")) - while 1: - f = changegroup.getchunk(source) - if not f: - break - self.ui.debug(_("adding %s revisions\n") % f) - fl = self.file(f) - o = fl.count() - chunkiter = changegroup.chunkiter(source) - if fl.addgroup(chunkiter, revmap, tr) is None: - raise util.Abort(_("received file revlog group is empty")) - revisions += fl.count() - o - files += 1 - - cl.writedata() - finally: - if cl: - cl.cleanup() + if fl.addgroup(chunkiter, revmap, tr) is None: + raise util.Abort(_("received file revlog group is empty")) + revisions += fl.count() - o + files += 1 # make changelog see real files again - self.changelog = changelog.changelog(self.sopener, - self.changelog.version) - self.changelog.checkinlinesize(tr) + cl.finalize(tr) newheads = len(self.changelog.heads()) heads = ""
--- a/mercurial/manifest.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/manifest.py Fri Mar 23 01:04:21 2007 -0500 @@ -35,11 +35,10 @@ return manifestdict(dict.copy(self), dict.copy(self._flags)) class manifest(revlog): - def __init__(self, opener, defversion=REVLOGV0): + def __init__(self, opener): self.mapcache = None self.listcache = None - revlog.__init__(self, opener, "00manifest.i", "00manifest.d", - defversion) + revlog.__init__(self, opener, "00manifest.i") def parselines(self, lines): for l in lines.splitlines(1):
--- a/mercurial/revlog.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/revlog.py Fri Mar 23 01:04:21 2007 -0500 @@ -311,8 +311,7 @@ remove data, and can use some simple techniques to avoid the need for locking while reading. """ - def __init__(self, opener, indexfile, datafile, - defversion=REVLOG_DEFAULT_VERSION): + def __init__(self, opener, indexfile): """ create a revlog object @@ -320,13 +319,15 @@ and can be used to implement COW semantics or the like. """ self.indexfile = indexfile - self.datafile = datafile + self.datafile = indexfile[:-2] + ".d" self.opener = opener self.indexstat = None self.cache = None self.chunkcache = None - self.defversion = defversion + self.defversion=REVLOG_DEFAULT_VERSION + if hasattr(opener, "defversion"): + self.defversion = opener.defversion self.load() def load(self):
--- a/mercurial/sshserver.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/sshserver.py Fri Mar 23 01:04:21 2007 -0500 @@ -73,7 +73,7 @@ caps = ['unbundle', 'lookup', 'changegroupsubset'] if self.ui.configbool('server', 'uncompressed'): - caps.append('stream=%d' % self.repo.revlogversion) + caps.append('stream=%d' % self.repo.changelog.version) self.respond("capabilities: %s\n" % (' '.join(caps),)) def do_lock(self):
--- a/mercurial/statichttprepo.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/statichttprepo.py Fri Mar 23 01:04:21 2007 -0500 @@ -32,7 +32,6 @@ def __init__(self, ui, path): self._url = path self.ui = ui - self.revlogversion = 0 self.path = (path + "/.hg") self.opener = opener(self.path)
--- a/mercurial/ui.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/ui.py Fri Mar 23 01:04:21 2007 -0500 @@ -325,12 +325,6 @@ result.append(os.path.expanduser(value)) return result - def configrevlog(self): - result = {} - for key, value in self.configitems("revlog"): - result[key.lower()] = value - return result - def username(self): """Return default username to be used in commits.
--- a/mercurial/verify.py Wed Mar 21 14:06:25 2007 -0700 +++ b/mercurial/verify.py Fri Mar 23 01:04:21 2007 -0500 @@ -39,8 +39,8 @@ elif revlogv1: warn(_("warning: `%s' uses revlog format 0") % name) - revlogv1 = repo.revlogversion != revlog.REVLOGV0 - if repo.ui.verbose or revlogv1 != repo.revlogv1: + revlogv1 = repo.changelog.version != revlog.REVLOGV0 + if repo.ui.verbose or not revlogv1: repo.ui.status(_("repository uses revlog format %d\n") % (revlogv1 and 1 or 0))