diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2011-10-01 20:49:36 +0000 |
---|---|---|
committer | Lorry <lorry@roadtrain.codethink.co.uk> | 2012-09-27 13:27:51 +0000 |
commit | 921ced43c48c1d170452a7b251b94cc96ec8dd44 (patch) | |
tree | 3c4a89176ea67fe4c7bf7b375488361a823c95fa /mercurial/revlog.py | |
parent | 9039c805b0a7e36220101323f82735f08a104b37 (diff) | |
download | mercurial-tarball-master.tar.gz |
Imported from /srv/lorry/lorry-area/mercurial-tarball/mercurial-1.9.3.tar.gz.HEADmercurial-1.9.3master
Diffstat (limited to 'mercurial/revlog.py')
-rw-r--r-- | mercurial/revlog.py | 210 |
1 files changed, 88 insertions, 122 deletions
diff --git a/mercurial/revlog.py b/mercurial/revlog.py index 8ed1d82..97151aa 100644 --- a/mercurial/revlog.py +++ b/mercurial/revlog.py @@ -75,6 +75,35 @@ def hash(text, p1, p2): s.update(text) return s.digest() +def compress(text): + """ generate a possibly-compressed representation of text """ + if not text: + return ("", text) + l = len(text) + bin = None + if l < 44: + pass + elif l > 1000000: + # zlib makes an internal copy, thus doubling memory usage for + # large files, so lets do this in pieces + z = zlib.compressobj() + p = [] + pos = 0 + while pos < l: + pos2 = pos + 2**20 + p.append(z.compress(text[pos:pos2])) + pos = pos2 + p.append(z.flush()) + if sum(map(len, p)) < l: + bin = "".join(p) + else: + bin = _compress(text) + if bin is None or len(bin) > l: + if text[0] == '\0': + return ("", text) + return ('u', text) + return ("", bin) + def decompress(bin): """ decompress the given input """ if not bin: @@ -83,10 +112,7 @@ def decompress(bin): if t == '\0': return bin if t == 'x': - try: - return _decompress(bin) - except zlib.error, e: - raise RevlogError(_("revlog decompress error: %s") % str(e)) + return _decompress(bin) if t == 'u': return bin[1:] raise RevlogError(_("unknown compression type %r") % t) @@ -148,7 +174,7 @@ class revlogio(object): def parseindex(self, data, inline): # call the C implementation to parse the index data index, cache = parsers.parse_index2(data, inline) - return index, getattr(index, 'nodemap', None), cache + return index, None, cache def packentry(self, entry, node, version, rev): p = _pack(indexformatng, *entry) @@ -200,10 +226,9 @@ class revlog(object): self._nodepos = None v = REVLOG_DEFAULT_VERSION - opts = getattr(opener, 'options', None) - if opts is not None: - if 'revlogv1' in opts: - if 'generaldelta' in opts: + if hasattr(opener, 'options'): + if 'revlogv1' in opener.options: + if 'generaldelta' in opener.options: v |= REVLOGGENERALDELTA else: v = 0 @@ -262,28 +287,10 @@ class revlog(object): self.rev(self.node(0)) return self._nodecache - def hasnode(self, node): - try: - self.rev(node) - return True - except KeyError: - return False - - def clearcaches(self): - try: - self._nodecache.clearcaches() - except AttributeError: - self._nodecache = {nullid: nullrev} - self._nodepos = None - def rev(self, node): try: return self._nodecache[node] - except RevlogError: - # parsers.c radix tree lookup failed - raise LookupError(node, self.indexfile, _('no node')) except KeyError: - # pure python cache lookup failed n = self._nodecache i = self.index p = self._nodepos @@ -332,35 +339,47 @@ class revlog(object): return len(t) size = rawsize - def ancestors(self, revs, stoprev=0): + def reachable(self, node, stop=None): + """return the set of all nodes ancestral to a given node, including + the node itself, stopping when stop is matched""" + reachable = set((node,)) + visit = [node] + if stop: + stopn = self.rev(stop) + else: + stopn = 0 + while visit: + n = visit.pop(0) + if n == stop: + continue + if n == nullid: + continue + for p in self.parents(n): + if self.rev(p) < stopn: + continue + if p not in reachable: + reachable.add(p) + visit.append(p) + return reachable + + def ancestors(self, *revs): """Generate the ancestors of 'revs' in reverse topological order. - Does not generate revs lower than stoprev. Yield a sequence of revision numbers starting with the parents of each revision in revs, i.e., each revision is *not* considered an ancestor of itself. Results are in breadth-first order: parents of each rev in revs, then parents of those, etc. Result does not include the null revision.""" - visit = util.deque(revs) + visit = list(revs) seen = set([nullrev]) while visit: - for parent in self.parentrevs(visit.popleft()): - if parent < stoprev: - continue + for parent in self.parentrevs(visit.pop(0)): if parent not in seen: visit.append(parent) seen.add(parent) yield parent - def incancestors(self, revs, stoprev=0): - """Identical to ancestors() except it also generates the - revisions, 'revs'""" - for rev in revs: - yield rev - for rev in self.ancestors(revs, stoprev): - yield rev - - def descendants(self, revs): + def descendants(self, *revs): """Generate the descendants of 'revs' in revision order. Yield a sequence of revision numbers starting with a child of @@ -383,10 +402,13 @@ class revlog(object): def findcommonmissing(self, common=None, heads=None): """Return a tuple of the ancestors of common and the ancestors of heads - that are not ancestors of common. In revset terminology, we return the - tuple: + that are not ancestors of common. - ::common, (::heads) - (::common) + More specifically, the second element is a list of nodes N such that + every N satisfies the following constraints: + + 1. N is an ancestor of some node in 'heads' + 2. N is not an ancestor of any node in 'common' The list is sorted by revision number, meaning it is topologically sorted. @@ -403,15 +425,15 @@ class revlog(object): heads = [self.rev(n) for n in heads] # we want the ancestors, but inclusive - has = set(self.ancestors(common)) + has = set(self.ancestors(*common)) has.add(nullrev) has.update(common) # take all ancestors from heads that aren't in has missing = set() - visit = util.deque(r for r in heads if r not in has) + visit = [r for r in heads if r not in has] while visit: - r = visit.popleft() + r = visit.pop(0) if r in missing: continue else: @@ -597,10 +619,6 @@ class revlog(object): return (orderedout, roots, heads) def headrevs(self): - try: - return self.index.headrevs() - except AttributeError: - pass count = len(self) if not count: return [nullrev] @@ -662,7 +680,7 @@ class revlog(object): def descendant(self, start, end): if start == nullrev: return True - for i in self.descendants([start]): + for i in self.descendants(start): if i == end: return True elif i > end: @@ -688,7 +706,7 @@ class revlog(object): return self.node(c) def _match(self, id): - if isinstance(id, int): + if isinstance(id, (long, int)): # rev return self.node(id) if len(id) == 20: @@ -722,15 +740,6 @@ class revlog(object): pass def _partialmatch(self, id): - try: - return self.index.partialmatch(id) - except RevlogError: - # parsers.c radix tree lookup gave multiple matches - raise LookupError(id, self.indexfile, _("ambiguous identifier")) - except (AttributeError, ValueError): - # we are pure python, or key was too short to search radix tree - pass - if id in self._pcache: return self._pcache[id] @@ -790,10 +799,9 @@ class revlog(object): readahead = max(65536, length) df.seek(offset) d = df.read(readahead) - df.close() self._addchunk(offset, d) if readahead > length: - return util.buffer(d, 0, length) + return d[:length] return d def _getchunk(self, offset, length): @@ -806,7 +814,7 @@ class revlog(object): if cachestart >= 0 and cacheend <= l: if cachestart == 0 and cacheend == l: return d # avoid a copy - return util.buffer(d, cachestart, cacheend - cachestart) + return d[cachestart:cacheend] return self._loadchunk(offset, length) @@ -839,22 +847,13 @@ class revlog(object): def revdiff(self, rev1, rev2): """return or calculate a delta between two revisions""" if rev1 != nullrev and self.deltaparent(rev2) == rev1: - return str(self._chunk(rev2)) + return self._chunk(rev2) - return mdiff.textdiff(self.revision(rev1), - self.revision(rev2)) - - def revision(self, nodeorrev): - """return an uncompressed revision of a given node or revision - number. - """ - if isinstance(nodeorrev, int): - rev = nodeorrev - node = self.node(rev) - else: - node = nodeorrev - rev = None + return mdiff.textdiff(self.revision(self.node(rev1)), + self.revision(self.node(rev2))) + def revision(self, node): + """return an uncompressed revision of a given node""" cachedrev = None if node == nullid: return "" @@ -865,8 +864,7 @@ class revlog(object): # look up what we need to read text = None - if rev is None: - rev = self.rev(node) + rev = self.rev(node) # check rev flags if self.flags(rev) & ~REVIDX_KNOWN_FLAGS: @@ -898,7 +896,7 @@ class revlog(object): self._chunkraw(base, rev) if text is None: - text = str(self._chunkbase(base)) + text = self._chunkbase(base) bins = [self._chunk(r) for r in chain] text = mdiff.patches(text, bins) @@ -947,9 +945,9 @@ class revlog(object): e = self._io.packentry(self.index[i], self.node, self.version, i) fp.write(e) - # if we don't call close, the temp file will never replace the + # if we don't call rename, the temp file will never replace the # real index - fp.close() + fp.rename() tr.replace(self.indexfile, trindex * self._io.size) self._chunkclear() @@ -979,35 +977,6 @@ class revlog(object): dfh.close() ifh.close() - def compress(self, text): - """ generate a possibly-compressed representation of text """ - if not text: - return ("", text) - l = len(text) - bin = None - if l < 44: - pass - elif l > 1000000: - # zlib makes an internal copy, thus doubling memory usage for - # large files, so lets do this in pieces - z = zlib.compressobj() - p = [] - pos = 0 - while pos < l: - pos2 = pos + 2**20 - p.append(z.compress(text[pos:pos2])) - pos = pos2 - p.append(z.flush()) - if sum(map(len, p)) < l: - bin = "".join(p) - else: - bin = _compress(text) - if bin is None or len(bin) > l: - if text[0] == '\0': - return ("", text) - return ('u', text) - return ("", bin) - def _addrevision(self, node, text, transaction, link, p1, p2, cachedelta, ifh, dfh): """internal function to add revisions to the log @@ -1040,7 +1009,7 @@ class revlog(object): t = buildtext() ptext = self.revision(self.node(rev)) delta = mdiff.textdiff(ptext, t) - data = self.compress(delta) + data = compress(delta) l = len(data[1]) + len(data[0]) if basecache[0] == rev: chainbase = basecache[1] @@ -1084,7 +1053,7 @@ class revlog(object): textlen = len(text) if d is None or dist > textlen * 2: text = buildtext() - data = self.compress(text) + data = compress(text) l = len(data[1]) + len(data[0]) base = chainbase = curr @@ -1163,7 +1132,6 @@ class revlog(object): """ # track the base of the current delta log - content = [] node = None r = len(self) @@ -1194,8 +1162,6 @@ class revlog(object): deltabase = chunkdata['deltabase'] delta = chunkdata['delta'] - content.append(node) - link = linkmapper(cs) if node in self.nodemap: # this can happen if two branches make the same change @@ -1203,7 +1169,7 @@ class revlog(object): continue for p in (p1, p2): - if p not in self.nodemap: + if not p in self.nodemap: raise LookupError(p, self.indexfile, _('unknown parent')) @@ -1225,7 +1191,7 @@ class revlog(object): dfh.close() ifh.close() - return content + return node def strip(self, minlink, transaction): """truncate the revlog on the first revision with a linkrev >= minlink @@ -1239,7 +1205,7 @@ class revlog(object): So we truncate the revlog on the first of these revisions, and trust that the caller has saved the revisions that shouldn't be - removed and that it'll re-add them after this truncation. + removed and that it'll readd them after this truncation. """ if len(self) == 0: return |