Rev 59: Both regular import and _update_ancestry are now able to record ghosts. in http://bzr.arbash-meinel.com/plugins/history_db
John Arbash Meinel
john at arbash-meinel.com
Wed Apr 7 21:06:36 BST 2010
At http://bzr.arbash-meinel.com/plugins/history_db
------------------------------------------------------------
revno: 59
revision-id: john at arbash-meinel.com-20100407200620-bg6ehrbisjpl2l3e
parent: john at arbash-meinel.com-20100407195110-7ezlf79dwi69npp3
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: history_db
timestamp: Wed 2010-04-07 15:06:20 -0500
message:
Both regular import and _update_ancestry are now able to record ghosts.
-------------- next part --------------
=== modified file 'history_db.py'
--- a/history_db.py 2010-04-07 19:51:10 +0000
+++ b/history_db.py 2010-04-07 20:06:20 +0000
@@ -264,11 +264,8 @@
# search
pmap = self._branch.repository.get_parent_map([rev_id])
parent_map.update(pmap)
- parent_ids = pmap.get(rev_id, ())
- if not parent_ids or parent_ids == NULL_PARENTS:
- # XXX: We should handle 'not parent_ids' differently, because
- # that means they are a ghost. Currently the table cannot
- # distinguish between a ghost and a root revision.
+ parent_ids = pmap.get(rev_id, None)
+ if parent_ids is None or parent_ids == NULL_PARENTS:
# We can insert this rev directly, because we know its gdfo,
# as it has no parents.
parent_map[rev_id] = ()
@@ -276,6 +273,12 @@
" VALUES (?, ?)", (rev_id, 1))
# Wrap around to populate known quickly
needed.append(rev_id)
+ if parent_ids is None:
+ # This is a ghost, add it to the table
+ self._cursor.execute("INSERT INTO ghost (db_id)"
+ " SELECT db_id FROM revision"
+ " WHERE revision_id = ?",
+ (rev_id,))
continue
for parent_id in pmap[rev_id]:
if parent_id not in known:
=== modified file 'schema.py'
--- a/schema.py 2010-04-04 16:53:08 +0000
+++ b/schema.py 2010-04-07 20:06:20 +0000
@@ -56,6 +56,15 @@
_create_statements.append(parent_parent_index)
# So we can find the *children* of a given node
+
+ghost_t = """
+CREATE TABLE ghost (
+ db_id INTEGER PRIMARY KEY REFERENCES revision
+);
+"""
+_create_statements.append(ghost_t)
+
+
dotted_revno_t = """
CREATE TABLE dotted_revno (
tip_revision INTEGER REFERENCES revision NOT NULL,
@@ -188,12 +197,24 @@
local_missing.discard(rev_id)
missing.update(local_missing)
if missing:
+ ghosts = set()
def get_gdfo(rev_id):
- return graph._nodes[(rev_id,)].gdfo
+ node = graph._nodes[(rev_id,)]
+ if node.gdfo == 1:
+ # First rev, see if this is actually a ghost
+ if node.parent_keys is None:
+ ghosts.add(rev_id)
+ return node.gdfo
cursor.executemany('INSERT INTO revision (revision_id, gdfo)'
' VALUES (?, ?)',
[(m, get_gdfo(m)) for m in missing])
ensure_revisions(cursor, missing, rev_id_to_db_id, graph=graph)
+ if ghosts:
+ # TODO: We could turn this into a "revision_id IN ()", instead...
+ cursor.executemany("INSERT INTO ghost (db_id)"
+ " SELECT db_id FROM revision"
+ " WHERE revision_id = ?",
+ [(g,) for g in ghosts])
def create_dotted_revno(cursor, tip_revision, merged_revision, revno,
=== modified file 'test_importer.py'
--- a/test_importer.py 2010-04-07 19:51:10 +0000
+++ b/test_importer.py 2010-04-07 20:06:20 +0000
@@ -120,8 +120,27 @@
}
return MockBranch(ancestry, 'O')
+ def make_branch_with_ghosts(self):
+ # Simple ancestry:
+ # A
+ # |
+ # B G?
+ # |/|
+ # C D
+ # |/
+ # E
+ #
+ # Both C and D refer to 'G' but that revision isn't actually present
+ ancestry = {'A': (),
+ 'B': ('A',),
+ 'C': ('B', 'G'),
+ 'D': ('G',),
+ 'E': ('C', 'D'),
+ }
+ return MockBranch(ancestry, 'E')
+
def grab_interesting_ids(self, rev_id_to_db_id):
- for rev_id in 'ABCDEFGHIJKLMNO':
+ for rev_id in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ':
setattr(self, '%s_id' % (rev_id,), rev_id_to_db_id.get(rev_id))
def test_build(self):
@@ -138,8 +157,7 @@
b = self.make_interesting_branch()
importer = history_db.Importer(':memory:', b, incremental=False)
importer.do_import()
- db_conn = importer._db_conn
- cur = db_conn.cursor()
+ cur = importer._db_conn.cursor()
revs = cur.execute("SELECT revision_id, db_id, gdfo"
" FROM revision").fetchall()
# Track the db_ids that are assigned
@@ -171,6 +189,24 @@
val.sort()
self.assertEqual(expected, actual)
+ def test_import_records_ghosts(self):
+ b = self.make_branch_with_ghosts()
+ importer = history_db.Importer(':memory:', b, incremental=False)
+ importer.do_import()
+ cur = importer._db_conn.cursor()
+ res = cur.execute("SELECT revision_id"
+ " FROM ghost NATURAL JOIN revision")
+ self.assertEqual(['G'], [r[0] for r in res])
+
+ def test__update_ancestry_records_ghosts(self):
+ b = self.make_branch_with_ghosts()
+ importer = history_db.Importer(':memory:', b, incremental=False)
+ importer._update_ancestry('G')
+ cur = importer._db_conn.cursor()
+ res = cur.execute("SELECT revision_id"
+ " FROM ghost NATURAL JOIN revision")
+ self.assertEqual(['G'], [r[0] for r in res])
+
def test__update_ancestry_from_scratch(self):
b = self.make_interesting_branch()
importer = history_db.Importer(':memory:', b, incremental=False)
More information about the bazaar-commits
mailing list