jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject svn commit: r1124779 - in /jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk: api/MicroKernelException.java store/CommitBuilder.java store/NodeDelta.java store/ObjectStore.java
Date Thu, 19 May 2011 13:52:58 GMT
Author: stefan
Date: Thu May 19 13:52:58 2011
New Revision: 1124779

URL: http://svn.apache.org/viewvc?rev=1124779&view=rev
Log:
MicroKernel prototype (WIP)

Modified:
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernelException.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java
    jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernelException.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernelException.java?rev=1124779&r1=1124778&r2=1124779&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernelException.java
(original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernelException.java
Thu May 19 13:52:58 2011
@@ -19,7 +19,7 @@ package org.apache.jackrabbit.mk.api;
 /**
  * Exception thrown by methods of the <code>MicroKernel</code> API
  */
-public class MicroKernelException extends Exception {
+public class MicroKernelException extends RuntimeException {
 
     public MicroKernelException() {
         super();

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java?rev=1124779&r1=1124778&r2=1124779&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
(original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
Thu May 19 13:52:58 2011
@@ -198,7 +198,7 @@ public class CommitBuilder {
             newCommit.setRootNodeId(rootNodeId);
             newRevId = store.putCommit(newCommit);
 
-            store.setHeadCommit(newRevId);
+            store.setHeadCommitId(newRevId);
         } finally {
             store.unlockHead();
         }
@@ -283,6 +283,16 @@ public class CommitBuilder {
         return rootNodeId;
     }
 
+    /**
+     * Performs a three-way merge of the trees rooted at <code>ourRoot</code>,
+     * <code>theirRoot</code>, using the tree at <code>baseRoot</code>
as reference.
+     *
+     * @param baseRoot
+     * @param ourRoot
+     * @param theirRoot
+     * @return id of merged root node
+     * @throws Exception
+     */
     String /* id of merged root node */ mergeTree(Node baseRoot, Node ourRoot, Node theirRoot)
throws Exception {
         // we're going to use the staging area for the merge process,
         // clear it first
@@ -295,42 +305,62 @@ public class CommitBuilder {
     }
 
     void mergeNode(Node baseNode, Node ourNode, Node theirNode, String path) throws Exception
{
+        // todo review/verify correctness of merge algorithm
         NodeDelta theirChanges = new NodeDelta(baseNode, theirNode);
         NodeDelta ourChanges = new NodeDelta(baseNode, ourNode);
-        if (!theirChanges.conflictsWith(ourChanges)) {
-            // merge non-conflicting changes
-            MutableNode mergedNode = new MutableNode(theirNode);
-            staged.put(path, mergedNode);
-
-            mergedNode.getProperties().putAll(ourChanges.getAddedProperties());
-            mergedNode.getProperties().putAll(ourChanges.getChangedProperties());
-            for (String name : ourChanges.getRemovedProperties().keySet()) {
-                mergedNode.getProperties().remove(name);
-            }
-
-            mergedNode.getChildNodeEntries().putAll(ourChanges.getAddedChildNodes());
-            mergedNode.getChildNodeEntries().putAll(ourChanges.getChangedChildNodes());
-            for (String name : ourChanges.getRemovedChildNodes().keySet()) {
-                mergedNode.getChildNodeEntries().remove(name);
-            }
-            // we're done!
-        } else {
-            // todo resolve/report merge conflict
-
-            MutableNode mergedNode = new MutableNode(theirNode);
-            staged.put(path, mergedNode);
-
-            // identify mutually changed child nodes and merge those
-            Set<String> mutuallyChangedChildNodes = new HashSet<String>(theirChanges.getChangedChildNodes().keySet());
-            mutuallyChangedChildNodes.retainAll(ourChanges.getChangedChildNodes().keySet());
-
-            for (String name : mutuallyChangedChildNodes) {
-                Node baseChild = store.getNode(baseNode.getChildNodeEntries().get(name));
-                Node ourChild = store.getNode(ourNode.getChildNodeEntries().get(name));
-                Node theirChild = store.getNode(theirNode.getChildNodeEntries().get(name));
-                // recurse
-                mergeNode(baseChild, ourChild, theirChild, PathUtil.concat(path, name));
+
+        // merge non-conflicting changes
+        MutableNode mergedNode = new MutableNode(theirNode);
+        staged.put(path, mergedNode);
+
+        mergedNode.getProperties().putAll(ourChanges.getAddedProperties());
+        mergedNode.getProperties().putAll(ourChanges.getChangedProperties());
+        for (String name : ourChanges.getRemovedProperties().keySet()) {
+            mergedNode.getProperties().remove(name);
+        }
+
+        mergedNode.getChildNodeEntries().putAll(ourChanges.getAddedChildNodes());
+        mergedNode.getChildNodeEntries().putAll(ourChanges.getChangedChildNodes());
+        for (String name : ourChanges.getRemovedChildNodes().keySet()) {
+            mergedNode.getChildNodeEntries().remove(name);
+        }
+
+        List<NodeDelta.Conflict> conflicts = theirChanges.listConflicts(ourChanges);
+        // resolve/report merge conflicts
+        for (NodeDelta.Conflict conflict : conflicts) {
+            String conflictName = conflict.getName();
+            String conflictPath = PathUtil.concat(path, conflictName);
+            switch (conflict.getType()) {
+                case PROPERTY_VALUE_CONFLICT:
+                    throw new Exception(
+                            "concurrent modification of property " + conflictPath
+                                    + " with conflicting values: \""
+                                    + ourNode.getProperties().get(conflictName)
+                                    + "\", \""
+                                    + theirNode.getProperties().get(conflictName));
+
+                case NODE_CONTENT_CONFLICT: {
+                    if (ourChanges.getChangedChildNodes().containsKey(conflictName)) {
+                        // modified subtrees
+                        Node baseChild = store.getNode(baseNode.getChildNodeEntries().get(conflictName));
+                        Node ourChild = store.getNode(ourNode.getChildNodeEntries().get(conflictName));
+                        Node theirChild = store.getNode(theirNode.getChildNodeEntries().get(conflictName));
+                        // merge the dirty subtrees recursively
+                        mergeNode(baseChild, ourChild, theirChild, PathUtil.concat(path,
conflictName));
+                    } else {
+                        // todo handle/merge colliding node additions
+                    }
+                }
+
+                case REMOVED_DIRTY_NODE_CONFLICT:
+                    mergedNode.getProperties().remove(conflictName);
+                    break;
+
+                case REMOVED_DIRTY_PROPERTY_CONFLICT:
+                    mergedNode.getChildNodeEntries().remove(conflictName);
+                    break;
             }
+
         }
     }
 

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java?rev=1124779&r1=1124778&r2=1124779&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java
(original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java
Thu May 19 13:52:58 2011
@@ -16,7 +16,9 @@
  */
 package org.apache.jackrabbit.mk.store;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -24,6 +26,30 @@ import java.util.Map;
  */
 public class NodeDelta implements NodeDiffHandler {
 
+    public static enum ConflictType {
+        /**
+         * same property has been added or set, but with differing values
+         */
+        PROPERTY_VALUE_CONFLICT,
+        /**
+         * child nodes with identical name have been added or modified, but
+         * with differing id's; the corresponding node subtrees are hence differing
+         * and potentially conflicting.
+         */
+        NODE_CONTENT_CONFLICT,
+        /**
+         * a modified property has been deleted
+         */
+        REMOVED_DIRTY_PROPERTY_CONFLICT,
+        /**
+         * a child node entry pointing to a modified subtree has been deleted
+         */
+        REMOVED_DIRTY_NODE_CONFLICT
+    }
+
+    final Node node1;
+    final Node node2;
+
     Map<String, String> addedProperties = new HashMap<String, String>();
     Map<String, String> removedProperties = new HashMap<String, String>();
     Map<String, String> changedProperties = new HashMap<String, String>();
@@ -33,6 +59,9 @@ public class NodeDelta implements NodeDi
     Map<String, String> changedChildNodes = new HashMap<String, String>();
 
     public NodeDelta(Node node1, Node node2) throws Exception {
+        this.node1 = node1;
+        this.node2 = node2;
+
         NodeUtils.diff("/", node1, node2, this);
     }
 
@@ -61,82 +90,82 @@ public class NodeDelta implements NodeDi
     }
 
     public boolean conflictsWith(NodeDelta other) {
-        // assume that both delta's were built with the *same* base node revision
+        return !listConflicts(other).isEmpty();
+    }
 
-        /*
-            (potentially) conflicting if:
+    public List<Conflict> listConflicts(NodeDelta other) {
+        // assume that both delta's were built using the *same* base node revision
+        if (!node1.getId().equals(other.node1)) {
+            throw new IllegalArgumentException("other and this NodeDelta object are expected
to share common node1 instance");
+        }
 
-            added1 != added2
-            mod1 != mod2
-            mod1 != del2
-            del1 != mod2
-        */
+        List<Conflict> conflicts = new ArrayList<Conflict>();
 
         // properties
 
         Map<String, String> otherAdded = other.getAddedProperties();
-        for (Map.Entry added : addedProperties.entrySet()) {
+        for (Map.Entry<String, String> added : addedProperties.entrySet()) {
             String otherValue = otherAdded.get(added.getKey());
             if (otherValue != null && !added.getValue().equals(otherValue)) {
                 // same property added with conflicting values
-                return true;
+                conflicts.add(new Conflict(ConflictType.PROPERTY_VALUE_CONFLICT, added.getKey()));
             }
         }
 
         Map<String, String> otherChanged = other.getChangedProperties();
         Map<String, String> otherRemoved = other.getRemovedProperties();
-        for (Map.Entry changed : changedProperties.entrySet()) {
+        for (Map.Entry<String, String> changed : changedProperties.entrySet()) {
             String otherValue = otherChanged.get(changed.getKey());
             if (otherValue != null && !changed.getValue().equals(otherValue)) {
                 // same property changed with conflicting values
-                return true;
+                conflicts.add(new Conflict(ConflictType.PROPERTY_VALUE_CONFLICT, changed.getKey()));
             }
             if (otherRemoved.containsKey(changed.getKey())) {
                 // changed property has been removed
-                return true;
+                conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_PROPERTY_CONFLICT,
changed.getKey()));
             }
         }
 
-        for (Map.Entry removed : removedProperties.entrySet()) {
+        for (Map.Entry<String, String> removed : removedProperties.entrySet()) {
             if (otherChanged.containsKey(removed.getKey())) {
                 // removed property has been changed
-                return true;
+                conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_PROPERTY_CONFLICT,
removed.getKey()));
             }
         }
 
         // child node entries
 
         otherAdded = other.getAddedChildNodes();
-        for (Map.Entry added : addedChildNodes.entrySet()) {
+        for (Map.Entry<String, String> added : addedChildNodes.entrySet()) {
             String otherValue = otherAdded.get(added.getKey());
             if (otherValue != null && !added.getValue().equals(otherValue)) {
                 // same child node entry added with different target id's
-                return true;
+                conflicts.add(new Conflict(ConflictType.NODE_CONTENT_CONFLICT, added.getKey()));
             }
         }
 
         otherChanged = other.getChangedChildNodes();
         otherRemoved = other.getRemovedChildNodes();
-        for (Map.Entry changed : changedChildNodes.entrySet()) {
+        for (Map.Entry<String, String> changed : changedChildNodes.entrySet()) {
             String otherValue = otherChanged.get(changed.getKey());
             if (otherValue != null && !changed.getValue().equals(otherValue)) {
                 // same child node entry changed with different target id's
-                return true;
+                conflicts.add(new Conflict(ConflictType.NODE_CONTENT_CONFLICT, changed.getKey()));
             }
             if (otherRemoved.containsKey(changed.getKey())) {
                 // changed child node entry has been removed
-                return true;
+                conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_NODE_CONFLICT, changed.getKey()));
             }
         }
 
-        for (Map.Entry removed : removedChildNodes.entrySet()) {
+        for (Map.Entry<String, String> removed : removedChildNodes.entrySet()) {
             if (otherChanged.containsKey(removed.getKey())) {
                 // removed child node entry has been changed
-                return true;
+                conflicts.add(new Conflict(ConflictType.REMOVED_DIRTY_NODE_CONFLICT, removed.getKey()));
             }
         }
 
-        return false;
+        return conflicts;
     }
 
     //------------------------------------------------------< NodeDiffHandler >
@@ -165,4 +194,30 @@ public class NodeDelta implements NodeDi
                                  String oldId, String newId) {
         changedChildNodes.put(childName, newId);
     }
+
+    //--------------------------------------------------------< inner classes >
+
+   public static class Conflict {
+
+       final ConflictType type;
+       final String name;
+
+       /**
+        *
+        * @param type conflict type
+        * @param name name of conflicting property or child node
+        */
+       Conflict(ConflictType type, String name) {
+           this.type = type;
+           this.name = name;
+       }
+
+       public ConflictType getType() {
+           return type;
+       }
+
+       public String getName() {
+           return name;
+       }
+   }
 }

Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java?rev=1124779&r1=1124778&r2=1124779&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java
(original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java
Thu May 19 13:52:58 2011
@@ -104,7 +104,7 @@ public class ObjectStore implements Cons
         return getCommit(store.getHeadCommitId());
     }
 
-    public void setHeadCommit(String commitId) throws Exception {
+    public void setHeadCommitId(String commitId) throws Exception {
         if (!initialized) {
             throw new IllegalStateException("not initialized");
         }



Mime
View raw message