You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2012/10/17 17:59:10 UTC

svn commit: r1399318 - in /subversion/trunk/notes/directory-index: dirindex.py schema.sql

Author: brane
Date: Wed Oct 17 15:59:09 2012
New Revision: 1399318

URL: http://svn.apache.org/viewvc?rev=1399318&view=rev
Log:
Work in progress: new filesystem index prototype.

* notes/directory-index/schema.sql
  (branch): Remove table and all associated queries.
  (txn): Add trigger for populating initial treeid.
  (noderev): noderev.id replaces previous usage of branch.id in the noderev
   table; noderev.nodeid and noderev.branchid default to it for new
   branches/nodes.
   -- Add appropriate trigger to populate these columns, and branch index.
  (TXN_UPDATE_INITIAL_TREEID): Removed, replaced by trigger.
  (NODEREV_COUNT_SUCCESSORS): Removed.
  (NODEVIEW_LIST_DIRECTORY, NODEVIEW_LIST_TRANSIENT_DIRECTORY):
   Fix bug in treeid filter subquery.

* notes/directory-index/dirindex.py (SQLclass.__init__): Remove redundant import.
  (Txn._put): Initial treeid is now populated by trigger.
  (Branch): Remove, including all references.
  (NodeRev.__str__): Include noderev.id in output.
  (NodeRev._put): Reflect trigger actions in wrapped object.
  (NodeRev._count_successors): Removed.
  (NodeRev._branch, NodeRev._revise): Fix implementation.
  (NodeRev.__setitem__): Better handling of virtual fields name and dename.
  (__greek_tree, greektree): New; populate index with the greek tree.
  (simpletest): Reimplement using greektree. Fix recursive dir listing.

Modified:
    subversion/trunk/notes/directory-index/dirindex.py
    subversion/trunk/notes/directory-index/schema.sql

Modified: subversion/trunk/notes/directory-index/dirindex.py
URL: http://svn.apache.org/viewvc/subversion/trunk/notes/directory-index/dirindex.py?rev=1399318&r1=1399317&r2=1399318&view=diff
==============================================================================
--- subversion/trunk/notes/directory-index/dirindex.py (original)
+++ subversion/trunk/notes/directory-index/dirindex.py Wed Oct 17 15:59:09 2012
@@ -42,7 +42,6 @@ class SQLclass(object):
     def __init__(self):
         import cStringIO
         import pkgutil
-        import re
 
         comment_rx = re.compile(r"\s*--.*$")
         header_rx = re.compile(r"^---(?P<kind>STATEMENT|SCRIPT)"
@@ -215,7 +214,6 @@ class Txn(SQLobject):
             self.created = self._now()
         super(Txn, self)._put(cursor)
         if self.treeid is None:
-            SQL.TXN_UPDATE_INITIAL_TREEID(cursor, id = self.id)
             self.treeid = self.id
 
     @classmethod
@@ -253,49 +251,6 @@ class Txn(SQLobject):
         SQL.TXN_CLEANUP(cursor, id = self.id)
 
 
-class Branch(SQLobject):
-    """O/R mapping for the "branch" table."""
-
-    _columns = ("id", "treeid", "nodeid", "origin", "state")
-    _put_statement = SQL.BRANCH_INSERT
-    _get_statement = SQL.BRANCH_GET
-
-    # state
-    TRANSIENT = "T"
-    PERMANENT = "P"
-
-    def __init__(self, **kwargs):
-        super(Branch, self).__init__(**kwargs)
-        if self.state is None:
-            self.state = self.TRANSIENT
-
-    def _put(self, cursor):
-        super(Branch, self)._put(cursor)
-        if self.nodeid is None:
-            SQL.BRANCH_UPDATE_INITIAL_NODEID(cursor, id = self.id)
-            self.nodeid = self.id
-
-    @classmethod
-    def _update_treeid(cls, cursor, new_txn, old_txn):
-        SQL.BRANCH_UPDATE_TREEID(cursor,
-                                 new_treeid = new_txn.treeid,
-                                 old_treeid = old_txn.treeid)
-
-    @classmethod
-    def _history(cls, cursor, nodeid):
-        SQL.BRANCH_HISTORY(cursor, nodeid = nodeid)
-        for row in cursor:
-            yield cls._from_row(row)
-
-    @classmethod
-    def _commit(cls, cursor, txn):
-        SQL.BRANCH_COMMIT(cursor, treeid = txn.treeid)
-
-    @classmethod
-    def _cleanup(cls, cursor, txn):
-        SQL.BRANCH_CLEANUP(cursor, treeid = txn.treeid)
-
-
 class NodeRev(SQLobject):
     """O/R mapping for the noderev/string/nodeview table."""
 
@@ -330,8 +285,8 @@ class NodeRev(SQLobject):
             self.state = self.TRANSIENT
 
     def __str__(self):
-        return "%d %c %s%s" % (self.treeid, self.opcode, self.name,
-                               self._isdir and '/' or '')
+        return "%d(%d) %c %s%s" % (self.id, self.treeid, self.opcode,
+                                   self.name, self._isdir and '/' or '')
 
     # Opcode names
     __opnames = {ADD: "add",
@@ -384,6 +339,10 @@ class NodeRev(SQLobject):
                 assert self.dename is not None
                 self.denameid = self.__stringid(cursor, self.dename)
         super(NodeRev, self)._put(cursor)
+        if self.nodeid is None:
+            self.nodeid = self.id
+        if self.branch is None:
+            self.branch = self.id
 
     @classmethod
     def _update_treeid(cls, cursor, new_txn, old_txn):
@@ -472,10 +431,6 @@ class NodeRev(SQLobject):
         track.close(cls.__find(cursor, parent.branch, parts[-1], txn))
         return track
 
-    def _count_successors(self, cursor):
-        SQL.NODEREV_COUNT_SUCCESSORS(cursor, origin = self.id)
-        return int(cursor.fetchone()[0])
-
     def _listdir(self, cursor, txn):
         assert self._isdir
         if txn.state != txn.PERMANENT:
@@ -501,17 +456,13 @@ class NodeRev(SQLobject):
 
     def _branch(self, cursor, parent, txn, replaced=False):
         assert txn._uncommitted
-        branch = Branch(treeid = txn.treeid,
-                        nodeid = self.nodeid,
-                        origin = self.branch)
-        branch._put(cursor)
         if self._isdir:
             opcode = replaced and self.LAZY_BREPLACE or self.LAZY
         else:
             opcode = replaced and self.BREPLACE or self.BRANCH
         node = self._revise(opcode, txn)
         node.parent = parent.id
-        node.branch = branch.id
+        node.branch = None
         node._put(cursor)
         return node
 
@@ -519,7 +470,9 @@ class NodeRev(SQLobject):
         assert txn._uncommitted
         noderev = NodeRev._clone(self)
         noderev.treeid = txn.treeid
+        noderev.origin = self.id
         noderev.opcode = opcode
+        return noderev
 
     __readonly = frozenset(("name",))
     def __setitem__(self, key, value):
@@ -528,7 +481,10 @@ class NodeRev(SQLobject):
         if key == "dename":
             name = self.__normtext(value)
             value = self.__text(value)
-            super(NodeRev, self).__setitem__("name", name)
+            if name != self.name:
+                super(NodeRev, self).__setitem__("name", name)
+                super(NodeRev, self).__setitem__("nameid", None)
+            super(NodeRev, self).__setitem__("denameid", None)
         super(NodeRev, self).__setitem__(key, value)
 
     def __getitem__(self, key):
@@ -680,12 +636,10 @@ class Index(object):
     def commit_txn(self, txn, revision):
         txn._commit(self.cursor, revision)
         NodeRev._commit(self.cursor, txn)
-        Branch._commit(self.cursor, txn)
 
     def abort_txn(self, txn):
         txn._abort(self.cursor)
         NodeRev._cleanup(self.cursor, txn)
-        Branch._cleanup(self.cursor, txn)
         txn._cleanup(self.cursor)
 
     def listdir(self, txn, noderev):
@@ -743,11 +697,9 @@ class Index(object):
             newnode = origin._branch(self.cursor, parent.id, txn,
                                      replaced = (oldnode is not None))
         else:
-            branch = Branch(treeid = txn.treeid)
-            branch._put(self.cursor)
             newnode = NodeRev(treeid = txn.treeid,
-                              nodeid = branch.nodeid,
-                              branch = branch.id,
+                              nodeid = None,
+                              branch = None,
                               parent = parent.id,
                               kind = kind,
                               opcode = opcode)
@@ -777,6 +729,45 @@ class Tree(object):
         index.rollback()
 
 
+__greek_tree = {
+    'iota': 'file',
+    'A': {
+        'mu': 'file',
+        'B': {
+            'lambda': 'file',
+            'E': {
+                'alpha': 'file',
+                'beta': 'file'},
+            'F': 'dir'},
+        'C': 'dir',
+        'D': {
+            'G': {
+                'pi': 'file',
+                'rho': 'file',
+                'tau': 'file'},
+            'H': {
+                'chi': 'file',
+                'psi': 'file',
+                'omega': 'file'}
+            }
+        }
+    }
+def greektree(ix, tx):
+    def populate(track, items):
+        print 'Populating', track
+        for name, kind in items.iteritems():
+            if kind == 'file':
+                node = ix.add(tx, track, name, NodeRev.FILE)
+            else:
+                node = ix.add(tx, track, name, NodeRev.DIR)
+            print 'Added', node, 'node:', node.noderev
+            if isinstance(kind, dict):
+                populate(node, kind)
+
+    root = ix.lookup(tx)
+    populate(root, __greek_tree)
+
+
 def simpletest(database):
     ix = Index(database)
     ix.initialize()
@@ -789,37 +780,34 @@ def simpletest(database):
         print "root track:", root
         print "root noderev", root.noderev
 
-        print "Add A/foo"
+        print 'Create greek tree'
         tx = ix.new_txn(0)
         print "transaction:", tx
-        parent = ix.add(tx, root, "A", NodeRev.DIR)
-        print "A track:", parent
-        print "A noderev", parent.noderev
-
-        node = ix.add(tx, parent, "foo", NodeRev.FILE)
-        print "foo track:", node
-        print "foo noderev", node.noderev
+        greektree(ix, tx)
         ix.commit_txn(tx, 1)
         ix.commit()
 
+
+        def listdir(noderev, prefix):
+            for n in ix.listdir(tx, noderev):
+                print prefix, str(n)
+                if n._isdir:
+                    listdir(n, prefix + "  ")
+
         print "List contents"
         tx = ix.get_txn()
         print "transaction:", tx
         root = ix.lookup(tx)
         print str(root.noderev)
-        for n1 in ix.listdir(tx, root.noderev):
-            print " ", str(n1)
-            if n1._isdir:
-                for n2 in ix.listdir(tx, n1):
-                    print "   ", str(n2)
-
-        print "Lookup A"
-        track = ix.lookup(tx, None, "A")
-        print str(track.noderev)
-
-        print "Lookup A/foo"
-        track = ix.lookup(tx, None, "A/foo")
-        print str(track.noderev)
+        listdir(root.noderev, " ")
+
+        print "Lookup iota"
+        track = ix.lookup(tx, None, "iota")
+        print str(track), str(track.noderev)
+
+        print "Lookup A/D/H/psi"
+        track = ix.lookup(tx, None, "A/D/H/psi")
+        print str(track), str(track.noderev)
     finally:
         ix.close()
 

Modified: subversion/trunk/notes/directory-index/schema.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/notes/directory-index/schema.sql?rev=1399318&r1=1399317&r2=1399318&view=diff
==============================================================================
--- subversion/trunk/notes/directory-index/schema.sql (original)
+++ subversion/trunk/notes/directory-index/schema.sql Wed Oct 17 15:59:09 2012
@@ -22,7 +22,6 @@
 DROP VIEW IF EXISTS nodeview;
 DROP TABLE IF EXISTS noderev;
 DROP TABLE IF EXISTS string;
-DROP TABLE IF EXISTS branch;
 DROP TABLE IF EXISTS txn;
 
 
@@ -61,36 +60,10 @@ CREATE TABLE txn (
 
 CREATE INDEX txn_revision_idx ON txn(revision);
 
-
--- Branches -- unique forks in the nodes' history
-CREATE TABLE branch (
-  -- branch identifier
-  id        integer NOT NULL PRIMARY KEY,
-
-  -- the transaction in which the branch was created
-  treeid    integer NOT NULL REFERENCES txn(id),
-
-  -- the node to which this branch belongs; refers to the initial
-  -- branch of the node
-  nodeid    integer NULL REFERENCES branch(id),
-
-  -- the source branch from which this branch was forked
-  origin    integer NULL REFERENCES branch(id),
-
-  -- mark branches in uncommitted transactions so that they can be
-  -- ignored by branch traversals
-  -- T = transient (uncommitted), P = permanent (committed)
-  state     character(1) NOT NULL DEFAULT 'T',
-
-  -- sanity check: enumerated value validation
-  CONSTRAINT enumeration_validation CHECK (state IN ('T', 'P')),
-
-  -- sanity check: ye can't be yer own daddy
-  CONSTRAINT genetic_diversity CHECK (id <> origin)
-);
-
-CREATE INDEX branch_txn_idx ON branch(treeid);
-CREATE INDEX branch_node_idx ON branch(nodeid);
+CREATE TRIGGER txn_ensure_treeid AFTER INSERT ON txn
+BEGIN
+  UPDATE txn SET treeid = NEW.id WHERE treeid IS NULL AND id = NEW.id;
+END;
 
 
 -- File names -- lookup table of strings
@@ -108,18 +81,19 @@ CREATE TABLE noderev (
   -- the transaction in which the node was changed
   treeid    integer NOT NULL REFERENCES txn(id),
 
-  -- the node identifier; a new node will get the ID of its initial
-  -- branch
-  nodeid    integer NOT NULL REFERENCES branch(id),
+  -- the node identifier
+  -- a new node will get the ID of its initial noderev.id
+  nodeid    integer NULL REFERENCES noderev(id),
 
   -- this node revision's immediate predecessor
   origin    integer NULL REFERENCES noderev(id),
 
   -- the parent (directory) of this node revision -- tree graph
-  parent    integer NULL REFERENCES branch(id),
+  parent    integer NULL REFERENCES noderev(id),
 
   -- the branch that this node revision belongs to -- history graph
-  branch    integer NOT NULL REFERENCES branch(id),
+  -- a new branch will get the ID of its initial noderev.id
+  branch    integer NULL REFERENCES noderev(id),
 
   -- the indexable, NFC-normalized name of this noderev within its parent
   nameid    integer NOT NULL REFERENCES string(id),
@@ -171,8 +145,15 @@ CREATE TABLE noderev (
 CREATE UNIQUE INDEX noderev_tree_idx ON noderev(parent,nameid,treeid,opcode);
 CREATE INDEX noderev_txn_idx ON noderev(treeid);
 CREATE INDEX nodefev_node_idx ON noderev(nodeid);
+CREATE INDEX noderev_branch_idx ON noderev(branch);
 CREATE INDEX noderev_successor_idx ON noderev(origin);
 
+CREATE TRIGGER noderev_ensure_node_and_branch AFTER INSERT ON noderev
+BEGIN
+    UPDATE noderev SET nodeid = NEW.id WHERE nodeid IS NULL AND id = NEW.id;
+    UPDATE noderev SET branch = NEW.id WHERE branch IS NULL AND id = NEW.id;
+END;
+
 
 CREATE VIEW nodeview AS
   SELECT
@@ -188,7 +169,6 @@ CREATE VIEW nodeview AS
 
 INSERT INTO txn (id, treeid, revision, created, state)
   VALUES (0, 0, 0, 'EPOCH', 'P');
-INSERT INTO branch (id, treeid, nodeid, state) VALUES (0, 0, 0, 'P');
 INSERT INTO string (id, val) VALUES (0, '');
 INSERT INTO noderev (id, treeid, nodeid, branch,
                      nameid, denameid, kind, opcode, state)
@@ -199,9 +179,6 @@ INSERT INTO noderev (id, treeid, nodeid,
 INSERT INTO txn (treeid, revision, created, author)
   VALUES (:treeid, :revision, :created, :author);
 
----STATEMENT TXN_UPDATE_INITIAL_TREEID
-UPDATE txn SET treeid = :id WHERE id = :id;
-
 ---STATEMENT TXN_GET
 SELECT * FROM txn WHERE id = :id;
 
@@ -230,28 +207,6 @@ UPDATE txn SET state = 'D' WHERE id = :i
 ---STATEMENT TXN_CLEANUP
 DELETE FROM txn WHERE id = :id;
 
----STATEMENT BRANCH_INSERT
-INSERT INTO branch (nodeid, treeid, origin)
-  VALUES (:nodeid, :treeid, :origin);
-
----STATEMENT BRANCH_UPDATE_INITIAL_NODEID
-UPDATE branch SET nodeid = :id WHERE id = :id;
-
----STATEMENT BRANCH_UPDATE_TREEID
-UPDATE branch SET treeid = :new_treeid WHERE treeid = :old_treeid;
-
----STATEMENT BRANCH_GET
-SELECT * FROM branch WHERE id = :id;
-
----STATEMENT BRANCH_HISTORY
-SELECT * from branch WHERE nodeid = :nodeid ORDER BY id ASC;
-
----STATEMENT BRANCH_COMMIT
-UPDATE branch SET state = 'P' WHERE treeid = :treeid;
-
----STATEMENT BRANCH_CLEANUP
-DELETE FROM branch WHERE treeid = :treeid;
-
 ---STATEMENT STRING_INSERT
 INSERT INTO string (val) VALUES (:val);
 
@@ -273,9 +228,6 @@ UPDATE noderev SET opcode = :opcode WHER
 ---STATEMENT NODEVIEW_GET
 SELECT * FROM nodeview WHERE id = :id;
 
----STATEMENT NODEREV_COUNT_SUCCESSORS
-SELECT COUNT(id) FROM noderev WHERE origin = :origin;
-
 ---STATEMENT NODEREV_COMMIT
 UPDATE noderev SET state = 'P' WHERE treeid = :treeid;
 
@@ -309,7 +261,8 @@ ORDER BY treeid DESC LIMIT 1;
 ---STATEMENT NODEVIEW_LIST_DIRECTORY
 SELECT * FROM nodeview
   JOIN (SELECT nameid, MAX(treeid) AS treeid FROM noderev
-        WHERE treeid <= :treeid AND state = 'P') AS filter
+        WHERE treeid <= :treeid AND state = 'P'
+        GROUP BY nameid) AS filter
     ON nodeview.nameid = filter.nameid AND nodeview.treeid = filter.treeid
 WHERE parent = :parent AND opcode <> 'D'
 ORDER BY nodeview.name ASC;
@@ -317,7 +270,8 @@ ORDER BY nodeview.name ASC;
 ---STATEMENT NODEVIEW_LIST_TRANSIENT_DIRECTORY
 SELECT * FROM nodeview
   JOIN (SELECT nameid, MAX(treeid) AS treeid FROM noderev
-        WHERE treeid < :treeid AND state = 'P' OR treeid = :treeid) AS filter
+        WHERE treeid < :treeid AND state = 'P' OR treeid = :treeid
+        GROUP BY nameid) AS filter
     ON nodeview.nameid = filter.name AND nodeview.treeid = filter.treeid
 WHERE parent = :parent AND opcode <> 'D'
 ORDER BY nodeview.name ASC;