comparison hg_delta_editor.py @ 33:a9c15cae50e5

Faster append-only revmap implementation.
author Andreas Hartmetz <ahartmetz@gmail.com>
date Wed, 15 Oct 2008 21:47:48 -0400
parents 1f8854804795
children 50d55c3e0d85
comparison
equal deleted inserted replaced
32:d01196ca1e39 33:a9c15cae50e5
47 raise 47 raise
48 return fun 48 return fun
49 49
50 50
51 class HgChangeReceiver(delta.Editor): 51 class HgChangeReceiver(delta.Editor):
52 def add_to_revmap(self, revnum, branch, node_hash):
53 f = open(self.revmap_file, 'a')
54 f.write(str(revnum) + ' ' + node.hex(node_hash) + ' ' + (branch or '') + '\n')
55 f.flush()
56 f.close()
57 self.revmap[revnum, branch] = node_hash
58
52 def __init__(self, path, ui_=None, subdir='', author_host='', 59 def __init__(self, path, ui_=None, subdir='', author_host='',
53 tag_locations=['tags']): 60 tag_locations=['tags']):
54 """path is the path to the target hg repo. 61 """path is the path to the target hg repo.
55 62
56 subdir is the subdirectory of the edits *on the svn server*. 63 subdir is the subdirectory of the edits *on the svn server*.
65 if self.subdir and self.subdir[0] == '/': 72 if self.subdir and self.subdir[0] == '/':
66 self.subdir = self.subdir[1:] 73 self.subdir = self.subdir[1:]
67 self.revmap = {} 74 self.revmap = {}
68 if os.path.exists(self.revmap_file): 75 if os.path.exists(self.revmap_file):
69 f = open(self.revmap_file) 76 f = open(self.revmap_file)
70 self.revmap = pickle.load(f) 77 for l in f:
78 revnum, node_hash, branch = l.split(' ', 2)
79 if branch == '\n':
80 branch = None
81 else:
82 branch = branch[:-1]
83 self.revmap[int(revnum), branch] = node.bin(node_hash)
71 f.close() 84 f.close()
72 self.branches = {} 85 self.branches = {}
73 if os.path.exists(self.branch_info_file): 86 if os.path.exists(self.branch_info_file):
74 f = open(self.branch_info_file) 87 f = open(self.branch_info_file)
75 self.branches = pickle.load(f) 88 self.branches = pickle.load(f)
104 assert os.path.isfile(self.uuid_file) 117 assert os.path.isfile(self.uuid_file)
105 assert os.path.isfile(self.last_revision_handled_file) 118 assert os.path.isfile(self.last_revision_handled_file)
106 else: 119 else:
107 self.repo = hg.repository(self.ui, repo_path, create=True) 120 self.repo = hg.repository(self.ui, repo_path, create=True)
108 os.makedirs(os.path.dirname(self.uuid_file)) 121 os.makedirs(os.path.dirname(self.uuid_file))
122 open(self.revmap_file, 'w') # make empty file
109 123
110 def clear_current_info(self): 124 def clear_current_info(self):
111 '''Clear the info relevant to a replayed revision so that the next 125 '''Clear the info relevant to a replayed revision so that the next
112 revision can be replayed. 126 revision can be replayed.
113 ''' 127 '''
122 136
123 def _save_metadata(self): 137 def _save_metadata(self):
124 '''Save the Subversion metadata. This should really be called after 138 '''Save the Subversion metadata. This should really be called after
125 every revision is created. 139 every revision is created.
126 ''' 140 '''
127 pickle_atomic(self.revmap, self.revmap_file, self.meta_data_dir)
128 pickle_atomic(self.branches, self.branch_info_file, self.meta_data_dir) 141 pickle_atomic(self.branches, self.branch_info_file, self.meta_data_dir)
129 pickle_atomic(self.tags, self.tag_info_file, self.meta_data_dir) 142 pickle_atomic(self.tags, self.tag_info_file, self.meta_data_dir)
130 143
131 def branches_in_paths(self, paths): 144 def branches_in_paths(self, paths):
132 '''Given a list of paths, return the set of branches that are touched. 145 '''Given a list of paths, return the set of branches that are touched.
371 extra) 384 extra)
372 new_hash = self.repo.commitctx(current_ctx) 385 new_hash = self.repo.commitctx(current_ctx)
373 self.ui.status('committed as %s on branch %s\n' % 386 self.ui.status('committed as %s on branch %s\n' %
374 (node.hex(new_hash), (branch or 'default'))) 387 (node.hex(new_hash), (branch or 'default')))
375 if (rev.revnum, branch) not in self.revmap: 388 if (rev.revnum, branch) not in self.revmap:
376 self.revmap[rev.revnum, branch] = new_hash 389 self.add_to_revmap(rev.revnum, branch, new_hash)
377 self._save_metadata()
378 # now we handle branches that need to be committed without any files 390 # now we handle branches that need to be committed without any files
379 for branch in self.commit_branches_empty: 391 for branch in self.commit_branches_empty:
380 ha = self.get_parent_revision(rev.revnum, branch) 392 ha = self.get_parent_revision(rev.revnum, branch)
381 if ha == node.nullid: 393 if ha == node.nullid:
382 continue 394 continue
401 extra) 413 extra)
402 new_hash = self.repo.commitctx(current_ctx) 414 new_hash = self.repo.commitctx(current_ctx)
403 self.ui.status('committed as %s on branch %s\n' % 415 self.ui.status('committed as %s on branch %s\n' %
404 (node.hex(new_hash), (branch or 'default'))) 416 (node.hex(new_hash), (branch or 'default')))
405 if (rev.revnum, branch) not in self.revmap: 417 if (rev.revnum, branch) not in self.revmap:
406 self.revmap[rev.revnum, branch] = new_hash 418 self.add_to_revmap(rev.revnum, branch, new_hash)
407 self._save_metadata()
408 self.clear_current_info() 419 self.clear_current_info()
409 420
410 @property 421 @property
411 def meta_data_dir(self): 422 def meta_data_dir(self):
412 return os.path.join(self.path, '.hg', 'svn') 423 return os.path.join(self.path, '.hg', 'svn')