[dna-commits] DNA SVN: r681 - in trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models: common and 1 other directory.

dna-commits at lists.jboss.org dna-commits at lists.jboss.org
Thu Dec 11 14:42:19 EST 2008


Author: rhauch
Date: 2008-12-11 14:42:19 -0500 (Thu, 11 Dec 2008)
New Revision: 681

Added:
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/ChangeLogEntity.java
Modified:
   trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java
Log:
DNA-40 
Added a table to store the change log, and changed BasicModel to include it in its schema (though it is not currently populated in BasicModel).  Also added some explanatory JavaDocs to BasicModel.

Modified: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java	2008-12-11 17:41:47 UTC (rev 680)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/basic/BasicModel.java	2008-12-11 19:42:19 UTC (rev 681)
@@ -26,13 +26,65 @@
 import org.hibernate.ejb.Ejb3Configuration;
 import org.jboss.dna.connector.store.jpa.JpaConnectorI18n;
 import org.jboss.dna.connector.store.jpa.Model;
+import org.jboss.dna.connector.store.jpa.models.common.ChangeLogEntity;
 import org.jboss.dna.connector.store.jpa.models.common.NamespaceEntity;
 import org.jboss.dna.graph.ExecutionContext;
+import org.jboss.dna.graph.requests.CopyBranchRequest;
+import org.jboss.dna.graph.requests.DeleteBranchRequest;
+import org.jboss.dna.graph.requests.MoveBranchRequest;
+import org.jboss.dna.graph.requests.ReadBranchRequest;
 import org.jboss.dna.graph.requests.processor.RequestProcessor;
 
 /**
  * Database model that stores node properties as opaque records and children as transparent records. Large property values are
  * stored separately.
+ * <p>
+ * The set of tables used in this model includes:
+ * <ul>
+ * <li>Namespaces - the set of namespace URIs used in paths, property names, and property values.</li>
+ * <li>Properties - the properties for each node, stored in a serialized (and optionally compressed) form.</li>
+ * <li>Large values - property values larger than a certain size will be broken out into this table, where they are tracked by
+ * their SHA-1 has and shared by all properties that have that same value. The values are stored in a binary (and optionally
+ * compressed) form.</li>
+ * <li>Children - the children for each node, where each child is represented by a separate record. This approach makes it
+ * possible to efficiently work with nodes containing large numbers of children, where adding and removing child nodes is largely
+ * independent of the number of children. Also, working with properties is also completely independent of the number of child
+ * nodes.</li>
+ * <li>Subgraph - a working area for efficiently computing the space of a subgraph; see below</li>
+ * <li>Change log - a record of the changes that have been made to the repository. This is used to distribute change events across
+ * multiple distributed processes, and to allow a recently-connected client to identify the set of changes that have been made
+ * since a particular time or date. Changes are serialized into a binary, compressed format.</i></li>
+ * <li>Options - the parameters for this store's configuration (common to all models)</li>
+ * </ul>
+ * </p>
+ * <h3>Subgraph queries</h3>
+ * <p>
+ * This database model contains two tables that are used in an efficient mechanism to find all of the nodes in the subgraph below
+ * a certain node. This process starts by creating a record for the subgraph query, and then proceeds by executing a join to find
+ * all the children of the top-level node, and inserting them into the database (in a working area associated with the subgraph
+ * query). Then, another join finds all the children of those children and inserts them into the same working area. This continues
+ * until the maximum depth has been reached, or until there are no more children (whichever comes first). All of the nodes in the
+ * subgraph are then represented by records in the working area, and can be used to quickly and efficient work with the subgraph
+ * nodes. When finished, the mechanism deletes the records in the working area associated with the subgraph query.
+ * </p>
+ * <p>
+ * This subgraph query mechanism is extremely efficient, performing one join/insert statement <i>per level of the subgraph</i>,
+ * and is completely independent of the number of nodes in the subgraph. For example, consider a subgraph of node A, where A has
+ * 10 children, and each child contains 10 children, and each grandchild contains 10 children. This subgraph has a total of 1111
+ * nodes (1 root + 10 children + 10*10 grandchildren + 10*10*10 great-grandchildren). Finding the nodes in this subgraph would
+ * normally require 1 query per node (in other words, 1111 queries). But with this subgraph query mechanism, all of the nodes in
+ * the subgraph can be found with 1 insert plus 4 additional join/inserts.
+ * </p>
+ * <p>
+ * This mechanism has the added benefit that the set of nodes in the subgraph are kept in a working area in the database, meaning
+ * they don't have to be pulled into memory.
+ * </p>
+ * <p>
+ * Subgraph queries are used to efficiently process a number of different requests, including {@link ReadBranchRequest},
+ * {@link DeleteBranchRequest}, {@link MoveBranchRequest}, and {@link CopyBranchRequest}. Processing each of these kinds of
+ * requests requires knowledge of the subgraph, and in fact all but the <code>ReadBranchRequest</code> need to know the complete
+ * subgraph.
+ * </p>
  * 
  * @author Randall Hauch
  */
@@ -76,6 +128,7 @@
         configurator.addAnnotatedClass(ChildId.class);
         configurator.addAnnotatedClass(SubgraphQueryEntity.class);
         configurator.addAnnotatedClass(SubgraphNodeEntity.class);
+        configurator.addAnnotatedClass(ChangeLogEntity.class);
 
         // Set the cache information for each persistent class ...
         // configurator.setProperty("hibernate.ejb.classcache." + KidpackNode.class.getName(), "read-write");

Added: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/ChangeLogEntity.java
===================================================================
--- trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/ChangeLogEntity.java	                        (rev 0)
+++ trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/ChangeLogEntity.java	2008-12-11 19:42:19 UTC (rev 681)
@@ -0,0 +1,148 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors. 
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.dna.connector.store.jpa.models.common;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import org.hibernate.annotations.Index;
+import org.jboss.dna.graph.properties.DateTime;
+import org.jboss.dna.graph.properties.basic.JodaDateTime;
+
+/**
+ * Represents a record of the changes that have been made to the repository. The actual change events are serialized and stored in
+ * a binary (and compressed) format.
+ * 
+ * @author Randall Hauch
+ */
+ at Entity
+ at Table( name = "DNA_CHANGELOG" )
+ at org.hibernate.annotations.Table( appliesTo = "DNA_CHANGELOG", indexes = @Index( name = "NS_CHANGE_TS_INX", columnNames = {"UTC_TIMESTAMP"} ) )
+ at NamedQueries( {
+    @NamedQuery( name = "ChangeLogEntity.findBetween", query = "select entry from ChangeLogEntity as entry where entry.timestampInUtc >= :start and entry.timestampInUtc <= :end" ),
+    @NamedQuery( name = "ChangeLogEntity.deleteBefore", query = "delete ChangeLogEntity entry where entry.timestampInUtc < :timestamp" )} )
+public class ChangeLogEntity {
+
+    @Id
+    @GeneratedValue( strategy = GenerationType.AUTO )
+    @Column( name = "ID", updatable = false )
+    private Long id;
+
+    @Column( name = "USERNAME", updatable = false, nullable = false, length = 64, unique = false )
+    private String username;
+
+    @Column( name = "UTC_TIMESTAMP", updatable = false, nullable = false, unique = false )
+    private long timestampInUtc;
+
+    @Column( name = "CHANGE_COUNT", updatable = false, nullable = false, unique = false )
+    private int numChanges;
+
+    @Lob
+    @Column( name = "CHANGES", updatable = false, nullable = false, unique = false )
+    private byte[] changes;
+
+    public ChangeLogEntity( String username,
+                            DateTime timestamp,
+                            int numChanges,
+                            byte[] changes ) {
+        this.username = username;
+        this.timestampInUtc = timestamp.toUtcTimeZone().getMilliseconds();
+        this.numChanges = numChanges;
+        this.changes = changes;
+    }
+
+    /**
+     * @return id
+     */
+    public Long getId() {
+        return id;
+    }
+
+    /**
+     * @return username
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * @return timestampInUtc
+     */
+    public long getTimestampInUtc() {
+        return timestampInUtc;
+    }
+
+    /**
+     * @return changes
+     */
+    public byte[] getChanges() {
+        return changes;
+    }
+
+    /**
+     * @return numChanges
+     */
+    public int getNumChanges() {
+        return numChanges;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#hashCode()
+     */
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals( Object obj ) {
+        if (obj == this) return true;
+        if (obj instanceof ChangeLogEntity) {
+            ChangeLogEntity that = (ChangeLogEntity)obj;
+            return id.equals(that.id);
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        return "" + numChanges + " changes by " + username + " at " + new JodaDateTime(timestampInUtc);
+    }
+}


Property changes on: trunk/extensions/dna-connector-store-jpa/src/main/java/org/jboss/dna/connector/store/jpa/models/common/ChangeLogEntity.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain




More information about the dna-commits mailing list