changeset 33:a9c15cae50e5

Faster append-only revmap implementation.
author Andreas Hartmetz <ahartmetz@gmail.com>
date Wed, 15 Oct 2008 21:47:48 -0400
parents d01196ca1e39
children 50d55c3e0d85
files fetch_command.py hg_delta_editor.py svncommand.py
diffstat 3 files changed, 33 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/fetch_command.py
+++ b/fetch_command.py
@@ -440,7 +440,7 @@ def stupid_svn_server_pull_rev(ui, svn, 
                                          date,
                                          extra)
             ha = hg_editor.repo.commitctx(current_ctx)
-            hg_editor.revmap[r.revnum, b] = ha
+            hg_editor.add_to_revmap(r.revnum, b, ha)
             hg_editor._save_metadata()
             ui.status('committed as %s on branch %s\n' %
                       (node.hex(ha),  b or 'default'))
--- a/hg_delta_editor.py
+++ b/hg_delta_editor.py
@@ -49,6 +49,13 @@ def stash_exception_on_self(fn):
 
 
 class HgChangeReceiver(delta.Editor):
+    def add_to_revmap(self, revnum, branch, node_hash):
+        f = open(self.revmap_file, 'a')
+        f.write(str(revnum) + ' ' + node.hex(node_hash) + ' ' + (branch or '') + '\n')
+        f.flush()
+        f.close()
+        self.revmap[revnum, branch] = node_hash
+
     def __init__(self, path, ui_=None, subdir='', author_host='',
                  tag_locations=['tags']):
         """path is the path to the target hg repo.
@@ -67,7 +74,13 @@ class HgChangeReceiver(delta.Editor):
         self.revmap = {}
         if os.path.exists(self.revmap_file):
             f = open(self.revmap_file)
-            self.revmap = pickle.load(f)
+            for l in f:
+                revnum, node_hash, branch = l.split(' ', 2)
+                if branch == '\n':
+                    branch = None
+                else:
+                    branch = branch[:-1]
+                self.revmap[int(revnum), branch] = node.bin(node_hash)
             f.close()
         self.branches = {}
         if os.path.exists(self.branch_info_file):
@@ -106,6 +119,7 @@ class HgChangeReceiver(delta.Editor):
         else:
             self.repo = hg.repository(self.ui, repo_path, create=True)
             os.makedirs(os.path.dirname(self.uuid_file))
+            open(self.revmap_file, 'w') # make empty file
 
     def clear_current_info(self):
         '''Clear the info relevant to a replayed revision so that the next
@@ -124,7 +138,6 @@ class HgChangeReceiver(delta.Editor):
         '''Save the Subversion metadata. This should really be called after
         every revision is created.
         '''
-        pickle_atomic(self.revmap, self.revmap_file, self.meta_data_dir)
         pickle_atomic(self.branches, self.branch_info_file, self.meta_data_dir)
         pickle_atomic(self.tags, self.tag_info_file, self.meta_data_dir)
 
@@ -373,8 +386,7 @@ class HgChangeReceiver(delta.Editor):
             self.ui.status('committed as %s on branch %s\n' %
                            (node.hex(new_hash), (branch or 'default')))
             if (rev.revnum, branch) not in self.revmap:
-                self.revmap[rev.revnum, branch] = new_hash
-                self._save_metadata()
+                self.add_to_revmap(rev.revnum, branch, new_hash)
         # now we handle branches that need to be committed without any files
         for branch in self.commit_branches_empty:
             ha = self.get_parent_revision(rev.revnum, branch)
@@ -403,8 +415,7 @@ class HgChangeReceiver(delta.Editor):
             self.ui.status('committed as %s on branch %s\n' %
                            (node.hex(new_hash), (branch or 'default')))
             if (rev.revnum, branch) not in self.revmap:
-                self.revmap[rev.revnum, branch] = new_hash
-                self._save_metadata()
+                self.add_to_revmap(rev.revnum, branch, new_hash)
         self.clear_current_info()
 
     @property
--- a/svncommand.py
+++ b/svncommand.py
@@ -64,6 +64,19 @@ def generate_hg_tags(ui, hg_repo_path, *
         source_ha = hg_editor.get_parent_revision(source[1]+1, source[0])
         f.write('%s tag/%s\n' % (node.hex(source_ha), tag))
 
+def parse_revmap(revmap_filename):
+    revmap = {}
+    f = open(revmap_filename)
+    for l in f:
+        revnum, node_hash, branch = l.split(' ', 2)
+        if branch == '\n':
+            branch = None
+        else:
+            branch = branch[:-1]
+        revmap[int(revnum), branch] = node.bin(node_hash)
+    f.close()
+    return revmap
+
 @register_subcommand('up')
 def update(ui, args, repo, clean=False, **opts):
     """Update to a specified Subversion revision number.
@@ -72,7 +85,7 @@ def update(ui, args, repo, clean=False, 
     rev = int(args[0])
     path = os.path.join(repo.path, 'svn', 'rev_map')
     answers = []
-    for k,v in pickle.load(open(path)).iteritems():
+    for k,v in parse_revmap(path).iteritems():
         if k[0] == rev:
             answers.append((v, k[1]))
     if len(answers) == 1:
@@ -139,8 +152,7 @@ def verify_all_revisions(ui, args, repo,
     args = list(args)
     if args:
         start_rev = int(args.pop(0))
-    revmap_f = open(os.path.join(repo.path, 'svn', 'rev_map'))
-    revmap = pickle.load(revmap_f)
+    revmap = parse_revmap(os.path.join(repo.path, 'svn', 'rev_map'))
     revs = sorted(revmap.keys())
     for revnum, br in revs:
         if revnum < start_rev: