##// END OF EJS Templates
manifest: speed up creation of the manifestdict...
manifest: speed up creation of the manifestdict - fold iteration and rawset into parse - avoid creating extra new strings with [:] where possible - speed up node.bin

File last commit:

r4995:e45fc5d0 default
r4995:e45fc5d0 default
Show More
manifest.py
212 lines | 7.6 KiB | text/x-python | PythonLexer
mpm@selenic.com
Break apart hg.py...
r1089 # manifest.py - manifest revision class for mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
mpm@selenic.com
Break apart hg.py...
r1089 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
from revlog import *
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Matt Mackall
Replace demandload with new demandimport
r3877 import array, bisect, struct, mdiff
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 class manifestdict(dict):
Alexis S. L. Carvalho
Fix some bugs introduced during the manifest refactoring
r2857 def __init__(self, mapping=None, flags=None):
if mapping is None: mapping = {}
if flags is None: flags = {}
Matt Mackall
Add manifestflags class
r2831 dict.__init__(self, mapping)
Matt Mackall
Switch to simpler manifestdict
r2839 self._flags = flags
Matt Mackall
manifestflags: eliminate remaining users of direct dict access
r2834 def flags(self, f):
Matt Mackall
Switch to simpler manifestdict
r2839 return self._flags.get(f, "")
Matt Mackall
Add manifestflags class
r2831 def execf(self, f):
"test for executable in manifest flags"
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 return "x" in self.flags(f)
Matt Mackall
Add manifestflags class
r2831 def linkf(self, f):
"test for symlink in manifest flags"
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 return "l" in self.flags(f)
Matt Mackall
Add manifestflags class
r2831 def set(self, f, execf=False, linkf=False):
Alexis S. L. Carvalho
Fix some bugs introduced during the manifest refactoring
r2857 if linkf: self._flags[f] = "l"
elif execf: self._flags[f] = "x"
else: self._flags[f] = ""
Matt Mackall
Add manifestflags class
r2831 def copy(self):
Matt Mackall
Switch to simpler manifestdict
r2839 return manifestdict(dict.copy(self), dict.copy(self._flags))
Matt Mackall
Add manifestflags class
r2831
mpm@selenic.com
Break apart hg.py...
r1089 class manifest(revlog):
Matt Mackall
revlog: simplify revlog version handling...
r4258 def __init__(self, opener):
mpm@selenic.com
Break apart hg.py...
r1089 self.mapcache = None
self.listcache = None
Matt Mackall
revlog: simplify revlog version handling...
r4258 revlog.__init__(self, opener, "00manifest.i")
mpm@selenic.com
Break apart hg.py...
r1089
Matt Mackall
manifest: speed up creation of the manifestdict...
r4995 def parse(self, lines):
mfdict = manifestdict()
for l in lines.splitlines():
f, n = l.split('\0')
if len(n) > 40:
mfdict._flags[f] = n[40:]
mfdict[f] = bin(n[:40])
else:
mfdict[f] = bin(n)
return mfdict
Brendan Cully
Abstract manifest block parsing.
r3196
def readdelta(self, node):
Matt Mackall
manifest: speed up creation of the manifestdict...
r4995 return self.parse(mdiff.patchtext(self.delta(node)))
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
mpm@selenic.com
Break apart hg.py...
r1089 def read(self, node):
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 if node == nullid: return manifestdict() # don't upset local cache
mpm@selenic.com
Break apart hg.py...
r1089 if self.mapcache and self.mapcache[0] == node:
return self.mapcache[1]
text = self.revision(node)
mason@suse.com
Optimize manifest.add...
r1534 self.listcache = array.array('c', text)
Matt Mackall
manifest: speed up creation of the manifestdict...
r4995 mapping = self.parse(text)
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 self.mapcache = (node, mapping)
return mapping
mpm@selenic.com
Break apart hg.py...
r1089
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 def _search(self, m, s, lo=0, hi=None):
'''return a tuple (start, end) that says where to find s within m.
If the string is found m[start:end] are the line containing
that string. If start == end the string was not found and
they indicate the proper sorted insertion point. This was
taken from bisect_left, and modified to find line start/end as
it goes along.
m should be a buffer or a string
s is a string'''
def advance(i, c):
while i < lenm and m[i] != c:
i += 1
return i
lenm = len(m)
if not hi:
hi = lenm
while lo < hi:
mid = (lo + hi) // 2
start = mid
while start > 0 and m[start-1] != '\n':
start -= 1
end = advance(start, '\0')
if m[start:end] < s:
# we know that after the null there are 40 bytes of sha1
# this translates to the bisect lo = mid + 1
lo = advance(end + 40, '\n') + 1
else:
# this translates to the bisect hi = mid
hi = start
end = advance(lo, '\0')
found = m[lo:end]
if cmp(s, found) == 0:
# we know that after the null there are 40 bytes of sha1
end = advance(end + 40, '\n')
return (lo, end+1)
else:
return (lo, lo)
def find(self, node, f):
'''look up entry for a single file efficiently.
Alexis S. L. Carvalho
fix manifest.find
r4159 return (node, flags) pair if found, (None, None) if not.'''
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 if self.mapcache and node == self.mapcache[0]:
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 return self.mapcache[1].get(f), self.mapcache[1].flags(f)
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 text = self.revision(node)
start, end = self._search(text, f)
if start == end:
return None, None
l = text[start:end]
f, n = l.split('\0')
Alexis S. L. Carvalho
fix manifest.find
r4159 return bin(n[:40]), n[40:-1]
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320
Matt Mackall
Remove manifest.readflags
r2841 def add(self, map, transaction, link, p1=None, p2=None,
mpm@selenic.com
Break apart hg.py...
r1089 changed=None):
# apply the changes collected during the bisect loop to our addlist
mason@suse.com
Optimize manifest.add...
r1534 # return a delta suitable for addrevision
def addlistdelta(addlist, x):
# start from the bottom up
mpm@selenic.com
Break apart hg.py...
r1089 # so changes to the offsets don't mess things up.
mason@suse.com
Optimize manifest.add...
r1534 i = len(x)
mpm@selenic.com
Break apart hg.py...
r1089 while i > 0:
i -= 1
mason@suse.com
Optimize manifest.add...
r1534 start = x[i][0]
end = x[i][1]
if x[i][2]:
addlist[start:end] = array.array('c', x[i][2])
mpm@selenic.com
Break apart hg.py...
r1089 else:
del addlist[start:end]
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 return "".join([struct.pack(">lll", d[0], d[1], len(d[2])) + d[2]
mason@suse.com
Optimize manifest.add...
r1534 for d in x ])
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
r3607 def checkforbidden(f):
if '\n' in f or '\r' in f:
raise RevlogError(_("'\\n' and '\\r' disallowed in filenames"))
mpm@selenic.com
Break apart hg.py...
r1089 # if we're using the listcache, make sure it is valid and
# parented by the same node we're diffing against
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 if not (changed and self.listcache and p1 and self.mapcache[0] == p1):
mpm@selenic.com
Break apart hg.py...
r1089 files = map.keys()
files.sort()
Benoit Boissinot
issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
r3607 for f in files:
checkforbidden(f)
Matt Mackall
Fix comment syntax
r1651 # if this is changed to support newlines in filenames,
# be sure to check the templates/ dir again (especially *-raw.tmpl)
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 text = ["%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
for f in files]
mason@suse.com
Optimize manifest.add...
r1534 self.listcache = array.array('c', "".join(text))
mpm@selenic.com
Break apart hg.py...
r1089 cachedelta = None
else:
mason@suse.com
Optimize manifest.add...
r1534 addlist = self.listcache
mpm@selenic.com
Break apart hg.py...
r1089
Benoit Boissinot
issue352: disallow '\n' and '\r' in filenames (dirstate and manifest)
r3607 for f in changed[0]:
checkforbidden(f)
mpm@selenic.com
Break apart hg.py...
r1089 # combine the changed lists into one list for sorting
work = [[x, 0] for x in changed[0]]
work[len(work):] = [[x, 1] for x in changed[1]]
work.sort()
delta = []
mason@suse.com
Optimize manifest.add...
r1534 dstart = None
dend = None
dline = [""]
start = 0
# zero copy representation of addlist as a buffer
addbuf = buffer(addlist)
mpm@selenic.com
Break apart hg.py...
r1089
mason@suse.com
Optimize manifest.add...
r1534 # start with a readonly loop that finds the offset of
# each line and creates the deltas
mpm@selenic.com
Break apart hg.py...
r1089 for w in work:
f = w[0]
# bs will either be the index of the item or the insert point
Vadim Gelfer
fix parsing of tags. make parse errors useful. add new tag tests....
r2320 start, end = self._search(addbuf, f, start)
mpm@selenic.com
Break apart hg.py...
r1089 if w[1] == 0:
Matt Mackall
Remove manifest.readflags
r2841 l = "%s\000%s%s\n" % (f, hex(map[f]), map.flags(f))
mpm@selenic.com
Break apart hg.py...
r1089 else:
mason@suse.com
Optimize manifest.add...
r1534 l = ""
if start == end and w[1] == 1:
# item we want to delete was not found, error out
raise AssertionError(
Benoit Boissinot
fix newline in error message
r3148 _("failed to remove %s from manifest") % f)
mason@suse.com
Optimize manifest.add...
r1534 if dstart != None and dstart <= start and dend >= start:
if dend < end:
dend = end
if l:
dline.append(l)
mpm@selenic.com
Break apart hg.py...
r1089 else:
mason@suse.com
Optimize manifest.add...
r1534 if dstart != None:
delta.append([dstart, dend, "".join(dline)])
dstart = start
dend = end
dline = [l]
mpm@selenic.com
Break apart hg.py...
r1089
mason@suse.com
Optimize manifest.add...
r1534 if dstart != None:
delta.append([dstart, dend, "".join(dline)])
# apply the delta to the addlist, and get a delta for addrevision
cachedelta = addlistdelta(addlist, delta)
mpm@selenic.com
Break apart hg.py...
r1089
mason@suse.com
Optimize manifest.add...
r1534 # the delta is only valid if we've been processing the tip revision
if self.mapcache[0] != self.tip():
cachedelta = None
self.listcache = addlist
Thomas Arendsen Hein
Cleanup of whitespace, indentation and line continuation.
r4633 n = self.addrevision(buffer(self.listcache), transaction, link,
p1, p2, cachedelta)
Matt Mackall
Combine manifest dict and flags dict into a single object...
r2835 self.mapcache = (n, map)
mpm@selenic.com
Break apart hg.py...
r1089
return n