[PATCH] do binary search for -r date:....

Robert Widhopf-Fenk hack at robf.de
Sat May 20 23:59:26 BST 2006


On Saturday, May 20, 2006 at 03:16:15, Olaf Conradi wrote:
> On Sat, May 20, 2006 at 12:58:54AM +0200, Robert Widhopf-Fenk wrote:
> Content-Description: message body text
> > The current implementation does a linear search to find
> > the specified date, which is dead slow for a tree with
> > may revisions.
> > 
> > The attached patch does a binary search to find it.
> 
> +1 on binary searching
> 
> -1 on this implementation
> 
> These routines are very easy to make a mistake in.
[...]

In deed.

> This also demonstrates why I don't like while True loops ;)
> 
> I prefer the implementation of Guillaume Pinot, which uses python's
> bisect:

Attached is Guillaumes version against current bzr.dev with
added branch.lock_read() and branch.unlock() around the call
to bisect.

I was not aware of bisect and Guillaumes and your work on
this ... ;-/

Robert

-------------- next part --------------
=== modified file 'NEWS'
--- NEWS	
+++ NEWS	
@@ -1,6 +1,8 @@
 IN DEVELOPMENT
 
   IMPROVEMENTS:
+
+   * Speedup improvement for 'date:'-revision search. (Guillaume Pinot).
 
    * On Unix, detect terminal width using an ioctl not just $COLUMNS.
      Use terminal width for single-line logs from ``bzr log --line`` and

=== modified file 'bzrlib/revisionspec.py'
--- bzrlib/revisionspec.py	
+++ bzrlib/revisionspec.py	
@@ -17,6 +17,7 @@
 
 import datetime
 import re
+import bisect
 from bzrlib.errors import BzrError, NoSuchRevision, NoCommits
 
 _marker = []
@@ -248,6 +249,18 @@
 SPEC_TYPES.append(RevisionSpec_tag)
 
 
+class RevisionSpec_revs:
+    def __init__(self, revs, branch):
+        self.revs = revs
+        self.branch = branch
+    def __getitem__(self, index):
+        r = self.branch.repository.get_revision(self.revs[index])
+        # TODO: Handle timezone.
+        return datetime.datetime.fromtimestamp(r.timestamp)
+    def __len__(self):
+        return len(self.revs)
+
+
 class RevisionSpec_date(RevisionSpec):
     prefix = 'date:'
     _date_re = re.compile(
@@ -295,14 +308,14 @@
 
             dt = datetime.datetime(year=year, month=month, day=day,
                     hour=hour, minute=minute, second=second)
-        first = dt
-        for i in range(len(revs)):
-            r = branch.repository.get_revision(revs[i])
-            # TODO: Handle timezone.
-            dt = datetime.datetime.fromtimestamp(r.timestamp)
-            if first <= dt:
-                return RevisionInfo(branch, i+1)
-        return RevisionInfo(branch, None)
+
+        branch.lock_read()
+        rev = bisect.bisect(RevisionSpec_revs(revs, branch), dt)
+        branch.unlock()
+        if rev == len(revs):
+            return RevisionInfo(branch, None)
+        else:
+            return RevisionInfo(branch, rev + 1)
 
 SPEC_TYPES.append(RevisionSpec_date)
 

=== modified file 'bzrlib/tests/test_revisionnamespaces.py'
--- bzrlib/tests/test_revisionnamespaces.py	
+++ bzrlib/tests/test_revisionnamespaces.py	
@@ -50,6 +50,8 @@
 
         self.assertEquals(RevisionSpec('date:today').in_history(b),
                           (2, 'a at r-0-2'))
+        self.assertRaises(NoSuchRevision,
+                          RevisionSpec('date:tomorrow').in_history, b)
         self.assertEquals(RevisionSpec('date:yesterday').in_history(b),
                           (1, 'a at r-0-1'))
         self.assertEquals(RevisionSpec('before:date:today').in_history(b),



More information about the bazaar mailing list