mercurial/revlog.py
changeset 1598 14d1f1868bf6
parent 1559 59b3639df0a9
child 1659 bfa90d9a3b77
--- a/mercurial/revlog.py	Tue Dec 27 12:52:25 2005 -0600
+++ b/mercurial/revlog.py	Tue Dec 27 13:09:49 2005 -0600
@@ -188,6 +188,7 @@
         self.datafile = datafile
         self.opener = opener
         self.cache = None
+        self.chunkcache = None
 
         try:
             i = self.opener(self.indexfile).read()
@@ -473,6 +474,35 @@
         """apply a list of patches to a string"""
         return mdiff.patches(t, pl)
 
+    def chunk(self, rev):
+        start, length = self.start(rev), self.length(rev)
+        end = start + length
+
+        def loadcache():
+            cache_length = max(4096 * 1024, length) # 4Mo
+            df = self.opener(self.datafile)
+            df.seek(start)
+            self.chunkcache = (start, df.read(cache_length))
+
+        if not self.chunkcache:
+            loadcache()
+
+        cache_start = self.chunkcache[0]
+        cache_end = cache_start + len(self.chunkcache[1])
+        if start >= cache_start and end <= cache_end:
+            # it is cached
+            offset = start - cache_start
+        else:
+            loadcache()
+            offset = 0
+
+        #def checkchunk():
+        #    df = self.opener(self.datafile)
+        #    df.seek(start)
+        #    return df.read(length)
+        #assert s == checkchunk()
+        return decompress(self.chunkcache[1][offset:offset + length])
+
     def delta(self, node):
         """return or calculate a delta between a node and its predecessor"""
         r = self.rev(node)
@@ -481,10 +511,7 @@
             return self.diff(self.revision(self.node(r - 1)),
                              self.revision(node))
         else:
-            f = self.opener(self.datafile)
-            f.seek(self.start(r))
-            data = f.read(self.length(r))
-        return decompress(data)
+            return self.chunk(r)
 
     def revision(self, node):
         """return an uncompressed revision of a given"""
@@ -494,33 +521,22 @@
         # look up what we need to read
         text = None
         rev = self.rev(node)
-        start, length, base, link, p1, p2, node = self.index[rev]
-        end = start + length
-        if base != rev: start = self.start(base)
+        base = self.base(rev)
 
         # do we have useful data cached?
         if self.cache and self.cache[1] >= base and self.cache[1] < rev:
             base = self.cache[1]
-            start = self.start(base + 1)
             text = self.cache[2]
-            last = 0
-
-        f = self.opener(self.datafile)
-        f.seek(start)
-        data = f.read(end - start)
-
-        if text is None:
-            last = self.length(base)
-            text = decompress(data[:last])
+        else:
+            text = self.chunk(base)
 
         bins = []
         for r in xrange(base + 1, rev + 1):
-            s = self.length(r)
-            bins.append(decompress(data[last:last + s]))
-            last = last + s
+            bins.append(self.chunk(r))
 
         text = mdiff.patches(text, bins)
 
+        p1, p2 = self.parents(node)
         if node != hash(text, p1, p2):
             raise RevlogError(_("integrity check failed on %s:%d")
                           % (self.datafile, rev))
@@ -650,7 +666,7 @@
                 #print "next x"
                 gx = x.next()
 
-    def group(self, nodelist, lookup, infocollect = None):
+    def group(self, nodelist, lookup, infocollect=None):
         """calculate a delta group
 
         Given a list of changeset revs, return a set of deltas and
@@ -660,7 +676,6 @@
         changesets. parent is parent[0]
         """
         revs = [self.rev(n) for n in nodelist]
-        needed = dict.fromkeys(revs, 1)
 
         # if we don't have any revisions touched by these changesets, bail
         if not revs:
@@ -671,88 +686,30 @@
         p = self.parents(self.node(revs[0]))[0]
         revs.insert(0, self.rev(p))
 
-        # for each delta that isn't contiguous in the log, we need to
-        # reconstruct the base, reconstruct the result, and then
-        # calculate the delta. We also need to do this where we've
-        # stored a full version and not a delta
-        for i in xrange(0, len(revs) - 1):
-            a, b = revs[i], revs[i + 1]
-            if a + 1 != b or self.base(b) == b:
-                for j in xrange(self.base(a), a + 1):
-                    needed[j] = 1
-                for j in xrange(self.base(b), b + 1):
-                    needed[j] = 1
-
-        # calculate spans to retrieve from datafile
-        needed = needed.keys()
-        needed.sort()
-        spans = []
-        oo = -1
-        ol = 0
-        for n in needed:
-            if n < 0: continue
-            o = self.start(n)
-            l = self.length(n)
-            if oo + ol == o: # can we merge with the previous?
-                nl = spans[-1][2]
-                nl.append((n, l))
-                ol += l
-                spans[-1] = (oo, ol, nl)
-            else:
-                oo = o
-                ol = l
-                spans.append((oo, ol, [(n, l)]))
-
-        # read spans in, divide up chunks
-        chunks = {}
-        for span in spans:
-            # we reopen the file for each span to make http happy for now
-            f = self.opener(self.datafile)
-            f.seek(span[0])
-            data = f.read(span[1])
-
-            # divide up the span
-            pos = 0
-            for r, l in span[2]:
-                chunks[r] = decompress(data[pos: pos + l])
-                pos += l
-
         # helper to reconstruct intermediate versions
         def construct(text, base, rev):
-            bins = [chunks[r] for r in xrange(base + 1, rev + 1)]
+            bins = [self.chunk(r) for r in xrange(base + 1, rev + 1)]
             return mdiff.patches(text, bins)
 
         # build deltas
-        deltas = []
         for d in xrange(0, len(revs) - 1):
             a, b = revs[d], revs[d + 1]
-            n = self.node(b)
+            na = self.node(a)
+            nb = self.node(b)
 
             if infocollect is not None:
-                infocollect(n)
+                infocollect(nb)
 
             # do we need to construct a new delta?
             if a + 1 != b or self.base(b) == b:
-                if a >= 0:
-                    base = self.base(a)
-                    ta = chunks[self.base(a)]
-                    ta = construct(ta, base, a)
-                else:
-                    ta = ""
-
-                base = self.base(b)
-                if a > base:
-                    base = a
-                    tb = ta
-                else:
-                    tb = chunks[self.base(b)]
-                tb = construct(tb, base, b)
+                ta = self.revision(na)
+                tb = self.revision(nb)
                 d = self.diff(ta, tb)
             else:
-                d = chunks[b]
+                d = self.chunk(b)
 
-            p = self.parents(n)
-            meta = n + p[0] + p[1] + lookup(n)
+            p = self.parents(nb)
+            meta = nb + p[0] + p[1] + lookup(nb)
             l = struct.pack(">l", len(meta) + len(d) + 4)
             yield l
             yield meta