Author: jukka
Date: Wed Mar 19 18:50:07 2014
New Revision: 1579349
URL: http://svn.apache.org/r1579349
Log:
OAK-850: Degrade gracefully when :childOrder is out of sync
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableRoot.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/AbstractTree.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableRoot.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableRoot.java?rev=1579349&r1=1579348&r2=1579349&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableRoot.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableRoot.java
Wed Mar 19 18:50:07 2014
@@ -196,8 +196,8 @@ class MutableRoot implements Root {
boolean success = source.moveTo(newParent, newName);
if (success) {
- getTree(getParentPath(sourcePath)).updateChildOrder();
- getTree(getParentPath(destPath)).updateChildOrder();
+ getTree(getParentPath(sourcePath)).updateChildOrder(false);
+ getTree(getParentPath(destPath)).updateChildOrder(false);
lastMove = lastMove.setMove(sourcePath, newParent, newName);
updated();
// remember all move operations for further processing in the
commit hooks.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java?rev=1579349&r1=1579348&r2=1579349&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/MutableTree.java
Wed Mar 19 18:50:07 2014
@@ -21,28 +21,23 @@ package org.apache.jackrabbit.oak.core;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Iterables.filter;
-import static com.google.common.collect.Iterables.indexOf;
-import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
import static org.apache.jackrabbit.oak.commons.PathUtils.elements;
import static org.apache.jackrabbit.oak.commons.PathUtils.isAbsolute;
+import static
org.apache.jackrabbit.oak.plugins.tree.TreeConstants.OAK_CHILD_ORDER;
import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.isHidden;
-import java.util.Collections;
-import java.util.Set;
+import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Sets;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.core.MutableRoot.Move;
-import org.apache.jackrabbit.oak.plugins.memory.MultiGenericPropertyState;
-import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.plugins.tree.AbstractTree;
import org.apache.jackrabbit.oak.plugins.tree.TreeConstants;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
@@ -178,13 +173,7 @@ class MutableTree extends AbstractTree {
beforeWrite();
if (parent != null && parent.hasChild(name)) {
nodeBuilder.remove();
- if (parent.hasOrderableChildren()) {
- parent.nodeBuilder.setProperty(
- PropertyBuilder.copy(NAME,
parent.nodeBuilder.getProperty(TreeConstants.OAK_CHILD_ORDER))
- .removeValue(name)
- .getPropertyState()
- );
- }
+ updateChildOrder(false);
root.updated();
return true;
} else {
@@ -198,12 +187,7 @@ class MutableTree extends AbstractTree {
beforeWrite();
if (!super.hasChild(name)) {
nodeBuilder.setChildNode(name);
- if (hasOrderableChildren()) {
- nodeBuilder.setProperty(
- PropertyBuilder.copy(NAME,
nodeBuilder.getProperty(TreeConstants.OAK_CHILD_ORDER))
- .addValue(name)
- .getPropertyState());
- }
+ updateChildOrder(false);
root.updated();
}
return createChild(name);
@@ -213,9 +197,9 @@ class MutableTree extends AbstractTree {
public void setOrderableChildren(boolean enable) {
beforeWrite();
if (enable) {
- ensureChildOrderProperty();
+ updateChildOrder(true);
} else {
- nodeBuilder.removeProperty(TreeConstants.OAK_CHILD_ORDER);
+ nodeBuilder.removeProperty(OAK_CHILD_ORDER);
}
}
@@ -233,37 +217,19 @@ class MutableTree extends AbstractTree {
}
}
// perform the reorder
- parent.ensureChildOrderProperty();
- // all siblings but not this one
- Iterable<String> siblings = filter(
- parent.getChildNames(),
- new Predicate<String>() {
- @Override
- public boolean apply(String name) {
- return !MutableTree.this.name.equals(name);
- }
- });
- // create head and tail
- Iterable<String> head;
- Iterable<String> tail;
+ List<String> names = newArrayList();
+ for (String n : parent.getChildNames()) {
+ if (n.equals(name)) {
+ names.add(this.name);
+ }
+ if (!n.equals(this.name)) {
+ names.add(n);
+ }
+ }
if (name == null) {
- head = siblings;
- tail = Collections.emptyList();
- } else {
- int idx = indexOf(siblings, new Predicate<String>() {
- @Override
- public boolean apply(String sibling) {
- return name.equals(sibling);
- }
- });
- head = Iterables.limit(siblings, idx);
- tail = Iterables.skip(siblings, idx);
- }
- // concatenate head, this name and tail
- parent.nodeBuilder.setProperty(
- MultiGenericPropertyState.nameProperty(
- TreeConstants.OAK_CHILD_ORDER, Iterables.concat(head,
Collections.singleton(getName()), tail))
- );
+ names.add(this.name);
+ }
+ parent.nodeBuilder.setProperty(OAK_CHILD_ORDER, names, NAMES);
root.updated();
return true;
}
@@ -339,26 +305,18 @@ class MutableTree extends AbstractTree {
}
/**
- * Update the child order with children that have been removed or added.
- * Added children are appended to the end of the {@link
org.apache.jackrabbit.oak.plugins.tree.TreeConstants#OAK_CHILD_ORDER}
- * property.
+ * Updates the child order to match any added or removed child nodes that
+ * are not yet reflected in the {@link TreeConstants#OAK_CHILD_ORDER}
+ * property. If the {@code force} flag is set, the child order is set
+ * in any case, otherwise only if the node already is orderable.
+ *
+ * @param force whether to add child order information if it doesn't exist
*/
- void updateChildOrder() {
- if (!hasOrderableChildren()) {
- return;
- }
- Set<String> names = Sets.newLinkedHashSet();
- for (String name : getChildNames()) {
- if (nodeBuilder.hasChildNode(name)) {
- names.add(name);
- }
+ void updateChildOrder(boolean force) {
+ if (force || hasOrderableChildren()) {
+ nodeBuilder.setProperty(PropertyStates.createProperty(
+ OAK_CHILD_ORDER, getChildNames(), Type.NAMES));
}
- for (String name : nodeBuilder.getChildNodeNames()) {
- names.add(name);
- }
- PropertyBuilder<String> builder = PropertyBuilder.array(NAME,
TreeConstants.OAK_CHILD_ORDER);
- builder.setValues(names);
- nodeBuilder.setProperty(builder.getPropertyState());
}
String getPathInternal() {
@@ -435,18 +393,4 @@ class MutableTree extends AbstractTree {
return movesApplied;
}
- /**
- * Ensures that the {@link
org.apache.jackrabbit.oak.plugins.tree.TreeConstants#OAK_CHILD_ORDER} exists.
This method will create
- * the property if it doesn't exist and initialize the value with the names
- * of the children as returned by {@link NodeBuilder#getChildNodeNames()}.
- */
- private void ensureChildOrderProperty() {
- if (!nodeBuilder.hasProperty(TreeConstants.OAK_CHILD_ORDER)) {
- nodeBuilder.setProperty(
-
MultiGenericPropertyState.nameProperty(TreeConstants.OAK_CHILD_ORDER,
nodeBuilder.getChildNodeNames()));
- }
- }
-
}
-
-
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/AbstractTree.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/AbstractTree.java?rev=1579349&r1=1579348&r2=1579349&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/AbstractTree.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/tree/AbstractTree.java
Wed Mar 19 18:50:07 2014
@@ -16,7 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-
package org.apache.jackrabbit.oak.plugins.tree;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -24,18 +23,21 @@ import static com.google.common.base.Pre
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.size;
import static com.google.common.collect.Iterables.transform;
+import static com.google.common.collect.Sets.newLinkedHashSet;
import static org.apache.jackrabbit.oak.api.Tree.Status.MODIFIED;
import static org.apache.jackrabbit.oak.api.Tree.Status.NEW;
import static org.apache.jackrabbit.oak.api.Tree.Status.UNCHANGED;
-import static org.apache.jackrabbit.oak.api.Type.NAME;
+import static org.apache.jackrabbit.oak.api.Type.NAMES;
+import static
org.apache.jackrabbit.oak.plugins.tree.TreeConstants.OAK_CHILD_ORDER;
import static org.apache.jackrabbit.oak.spi.state.NodeStateUtils.isHidden;
-import java.util.Iterator;
+import java.util.Set;
import javax.annotation.Nonnull;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
+
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
@@ -117,42 +119,24 @@ public abstract class AbstractTree imple
* {@code false} otherwise.
*/
protected boolean hasOrderableChildren() {
- return nodeBuilder.hasProperty(TreeConstants.OAK_CHILD_ORDER);
+ return nodeBuilder.hasProperty(OAK_CHILD_ORDER);
}
/**
* Returns the list of child names considering its ordering
- * when the {@link
org.apache.jackrabbit.oak.plugins.tree.TreeConstants#OAK_CHILD_ORDER} property
is set.
+ * when the {@link TreeConstants#OAK_CHILD_ORDER} property is set.
*
* @return the list of child names.
*/
@Nonnull
protected Iterable<String> getChildNames() {
- if (hasOrderableChildren()) {
- return new Iterable<String>() {
- @Override
- public Iterator<String> iterator() {
- return new Iterator<String>() {
- final PropertyState childOrder =
nodeBuilder.getProperty(TreeConstants.OAK_CHILD_ORDER);
- int index;
-
- @Override
- public boolean hasNext() {
- return index < childOrder.count();
- }
-
- @Override
- public String next() {
- return childOrder.getValue(NAME, index++);
- }
-
- @Override
- public void remove() {
- throw new UnsupportedOperationException();
- }
- };
- }
- };
+ PropertyState order = nodeBuilder.getProperty(OAK_CHILD_ORDER);
+ if (order != null && order.getType() == NAMES) {
+ Set<String> names =
newLinkedHashSet(nodeBuilder.getChildNodeNames());
+ Set<String> ordered = newLinkedHashSet(order.getValue(NAMES));
+ ordered.retainAll(names); // remove names of missing child nodes
+ ordered.addAll(names); // insert names of unordered child nodes
+ return ordered;
} else {
return nodeBuilder.getChildNodeNames();
}