hi, hmm, I didn't notice the failure in my checkout and cannot reproduce, but it must be related to recent changes.
how often do you see the failure? regards marcel > -----Original Message----- > From: Angela Schreiber > Sent: Donnerstag, 12. September 2013 19:12 > To: [email protected]; Marcel Reutegger > Subject: Re: svn commit: r1522553 - in /jackrabbit/oak/trunk/oak-core/src: > main/java/org/apache/jackrabbit/oak/plugins/mongomk/ > test/java/org/apache/jackrabbit/oak/plugins/mongomk/ > > hi marcel > > could it be that this commit is related to the following test failure? > i experience it in a up to date checkout of the trunk. > > regards > angela > > concurrent[1](org.apache.jackrabbit.oak.jcr.ConcurrentFileOperationsTest) > Time elapsed: 0.473 sec <<< ERROR! > javax.jcr.RepositoryException: OakKernel0001: Failed to merge changes to > the underlying MicroKernel > at > org.apache.jackrabbit.oak.api.CommitFailedException.asRepositoryExceptio > n(C > ommitFailedException.java:242) > at > org.apache.jackrabbit.oak.api.CommitFailedException.asRepositoryExceptio > n(C > ommitFailedException.java:207) > at > org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.newRepositoryExce > pti > on(SessionDelegate.java:434) > at > org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.save(SessionDelegat > e > .java:297) > at > org.apache.jackrabbit.oak.jcr.session.SessionImpl$8.perform(SessionImpl.ja > v > a:399) > at > org.apache.jackrabbit.oak.jcr.session.SessionImpl$8.perform(SessionImpl.ja > v > a:396) > at > org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.perform(SessionDel > eg > ate.java:124) > at > org.apache.jackrabbit.oak.jcr.session.SessionImpl.perform(SessionImpl.java: > 117) > at > org.apache.jackrabbit.oak.jcr.session.SessionImpl.save(SessionImpl.java:396 > ) > at > org.apache.jackrabbit.oak.jcr.ConcurrentFileOperationsTest$1.run(Concurre > nt > FileOperationsTest.java:103) > at java.lang.Thread.run(Thread.java:680) > Caused by: org.apache.jackrabbit.oak.api.CommitFailedException: > OakKernel0001: Failed to merge changes to the underlying MicroKernel > at > org.apache.jackrabbit.oak.kernel.KernelNodeStoreBranch$Persisted.merge( > Kern > elNodeStoreBranch.java:384) > at > org.apache.jackrabbit.oak.kernel.KernelNodeStoreBranch.merge(KernelNod > eStor > eBranch.java:136) > at > org.apache.jackrabbit.oak.core.AbstractRoot$2.run(AbstractRoot.java:247) > at > org.apache.jackrabbit.oak.core.AbstractRoot$2.run(AbstractRoot.java:243) > at java.security.AccessController.doPrivileged(Native Method) > at javax.security.auth.Subject.doAs(Subject.java:337) > at > org.apache.jackrabbit.oak.core.AbstractRoot.commit(AbstractRoot.java:242) > at > org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate.save(SessionDelegat > e > .java:295) > ... 7 more > Caused by: org.apache.jackrabbit.mk.api.MicroKernelException: Conflicting > concurrent change. Update operation failed: key: 0:/ update > {_collisions.r1411315f24a-0-1=CONTAINS_MAP_ENTRY false, > _collisions.r1411315f251-0-1=CONTAINS_MAP_ENTRY false, > _collisions.r1411315f3f6-0-1=CONTAINS_MAP_ENTRY false, > _collisions.r1411315f402-0-1=CONTAINS_MAP_ENTRY false, _modified=SET > 275800941, _revisions.r1411315f24a-0-1=SET_MAP_ENTRY c-r1411315f404-0- > 1, > _revisions.r1411315f251-0-1=SET_MAP_ENTRY c-r1411315f404-0-1, > _revisions.r1411315f3f6-0-1=SET_MAP_ENTRY c-r1411315f404-0-1, > _revisions.r1411315f402-0-1=SET_MAP_ENTRY c-r1411315f404-0-1} > at > org.apache.jackrabbit.oak.plugins.mongomk.MongoMK.merge(MongoMK.ja > va:1130) > at > org.apache.jackrabbit.oak.kernel.KernelNodeStore.merge(KernelNodeStore > .java > :208) > at > org.apache.jackrabbit.oak.kernel.KernelNodeStoreBranch$Persisted.merge( > Kern > elNodeStoreBranch.java:378) > ... 14 more > > > > > > > On 9/12/13 2:45 PM, "[email protected]" <[email protected]> > wrote: > > >Author: mreutegg > >Date: Thu Sep 12 12:45:19 2013 > >New Revision: 1522553 > > > >URL: http://svn.apache.org/r1522553 > >Log: > >OAK-926: MongoMK: split documents when they are too large > >- Generalize access to previous documents (WIP) > > > >Added: > > > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java (with props) > > > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java (with props) > >Modified: > > > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/NodeDocument.java > > > >jackrabbit/oak/trunk/oak- > core/src/test/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/DocumentSplitTest.java > > > >Modified: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/NodeDocument.java > >URL: > >http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak- > core/src/main/java/o > >rg/apache/jackrabbit/oak/plugins/mongomk/NodeDocument.java?rev=152 > 2553&r1= > >1522552&r2=1522553&view=diff > >========================================================= > ================= > >==== > >--- > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/NodeDocument.java (original) > >+++ > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/NodeDocument.java Thu Sep 12 12:45:19 2013 > >@@ -16,8 +16,6 @@ > > */ > > package org.apache.jackrabbit.oak.plugins.mongomk; > > > >-import java.util.AbstractMap; > >-import java.util.AbstractSet; > > import java.util.ArrayList; > > import java.util.Collections; > > import java.util.Comparator; > >@@ -44,10 +42,8 @@ import org.slf4j.LoggerFactory; > > import com.google.common.base.Function; > > import com.google.common.base.Predicate; > > import com.google.common.collect.Iterables; > >-import com.google.common.collect.Iterators; > > import com.google.common.collect.Maps; > > > >-import static com.google.common.base.Preconditions.checkArgument; > > import static com.google.common.base.Preconditions.checkNotNull; > > > > /** > >@@ -186,7 +182,7 @@ public class NodeDocument extends Docume > > */ > > public boolean containsRevision(@Nonnull Revision revision) { > > String rev = checkNotNull(revision).toString(); > >- if (getRevisionsMap().containsKey(rev)) { > >+ if (getLocalRevisions().containsKey(rev)) { > > return true; > > } > > for (NodeDocument prev : getPreviousDocs(revision)) { > >@@ -219,7 +215,7 @@ public class NodeDocument extends Docume > > public SortedMap<Revision, Revision> > >getUncommittedRevisions(RevisionContext context) { > > // only look at revisions in this document. > > // uncommitted revisions are not split off > >- Map<String, String> valueMap = getRevisionsMap(); > >+ Map<String, String> valueMap = getLocalRevisions(); > > SortedMap<Revision, Revision> revisions = > > new TreeMap<Revision, > >Revision>(context.getRevisionComparator()); > > for (Map.Entry<String, String> commit : valueMap.entrySet()) { > >@@ -244,11 +240,7 @@ public class NodeDocument extends Docume > > */ > > @CheckForNull > > public String getCommitRootPath(String revision) { > >- @SuppressWarnings("unchecked") > >- Map<String, Integer> valueMap = (Map<String, Integer>) > >get(COMMIT_ROOT); > >- if (valueMap == null) { > >- return null; > >- } > >+ Map<String, Integer> valueMap = getCommitRoot(); > > Integer depth = valueMap.get(revision); > > if (depth != null) { > > String p = Utils.getPathFromId(getId()); > >@@ -274,13 +266,9 @@ public class NodeDocument extends Docume > > CollisionHandler handler) { > > SortedSet<String> revisions = new > >TreeSet<String>(Collections.reverseOrder()); > > revisions.addAll(getRevisions().keySet()); > >- if (data.containsKey(COMMIT_ROOT)) { > >- revisions.addAll(((Map<String, Integer>) > >get(COMMIT_ROOT)).keySet()); > >- } > >- Map<String, String> deletedMap = (Map<String, String>) > >get(DELETED); > >- if (deletedMap != null) { > >- revisions.addAll(deletedMap.keySet()); > >- } > >+ revisions.addAll(getCommitRoot().keySet()); > >+ Map<String, String> deletedMap = getDeleted(); > >+ revisions.addAll(deletedMap.keySet()); > > Revision newestRev = null; > > for (String r : revisions) { > > Revision propRev = Revision.fromString(r); > >@@ -304,12 +292,10 @@ public class NodeDocument extends Docume > > if (newestRev == null) { > > return null; > > } > >- if (deletedMap != null) { > >- String value = deletedMap.get(newestRev.toString()); > >- if ("true".equals(value)) { > >- // deleted in the newest revision > >- return null; > >- } > >+ String value = deletedMap.get(newestRev.toString()); > >+ if ("true".equals(value)) { > >+ // deleted in the newest revision > >+ return null; > > } > > return newestRev; > > } > >@@ -444,9 +430,8 @@ public class NodeDocument extends Docume > > public boolean isDeleted(RevisionContext context, > > Revision readRevision, > > Set<Revision> validRevisions) { > >- @SuppressWarnings("unchecked") > >- Map<String, String> valueMap = (Map<String, String>) > >get(NodeDocument.DELETED); > >- if (valueMap == null) { > >+ Map<String, String> valueMap = getDeleted(); > >+ if (valueMap.isEmpty()) { > > return false; > > } > > if (valueMap instanceof NavigableMap) { > >@@ -487,9 +472,8 @@ public class NodeDocument extends Docume > > @CheckForNull > > public Revision getLiveRevision(RevisionContext context, Revision > >maxRev, > > Set<Revision> validRevisions) { > >- @SuppressWarnings("unchecked") > >- Map<String, String> valueMap = (Map<String, String>) > >get(NodeDocument.DELETED); > >- if (valueMap == null) { > >+ Map<String, String> valueMap = getDeleted(); > >+ if (valueMap.isEmpty()) { > > return null; > > } > > // first, search the newest deleted revision > >@@ -552,13 +536,10 @@ public class NodeDocument extends Docume > > @Nonnull Revision baseRevision, > > @Nonnull RevisionContext context) { > > // did existence of node change after baseRevision? > >- @SuppressWarnings("unchecked") > >- Map<String, String> deleted = (Map<String, String>) get(DELETED); > >- if (deleted != null) { > >- for (Map.Entry<String, String> entry : deleted.entrySet()) { > >- if (isRevisionNewer(context, > >Revision.fromString(entry.getKey()), baseRevision)) { > >- return true; > >- } > >+ Map<String, String> deleted = getDeleted(); > >+ for (Map.Entry<String, String> entry : deleted.entrySet()) { > >+ if (isRevisionNewer(context, > >Revision.fromString(entry.getKey()), baseRevision)) { > >+ return true; > > } > > } > > > >@@ -615,7 +596,7 @@ public class NodeDocument extends Docume > > } > > NavigableMap<Revision, String> splitRevs > > = new TreeMap<Revision, > >String>(context.getRevisionComparator()); > >- Map<String, String> revisions = getRevisionsMap(); > >+ Map<String, String> revisions = getLocalRevisions(); > > // only consider if there are enough revisions > > if (revisions.size() > REVISIONS_SPLIT_OFF_SIZE) { > > // collect commits of this cluster node after the > >@@ -690,6 +671,88 @@ public class NodeDocument extends Docume > > return super.transformAndSeal(map, key, level); > > } > > > >+ /** > >+ * Returns previous revision ranges for this document. The revision > >keys are > >+ * sorted descending, newest first! > >+ * > >+ * @return the previous ranges for this document. > >+ */ > >+ @Nonnull > >+ SortedMap<Revision, Range> getPreviousRanges() { > >+ @SuppressWarnings("unchecked") > >+ SortedMap<Revision, Range> previous = (SortedMap<Revision, > >Range>) get(PREVIOUS); > >+ if (previous == null) { > >+ previous = EMPTY_RANGE_MAP; > >+ } > >+ return previous; > >+ } > >+ > >+ /** > >+ * Returns previous {@link NodeDocument}, which include the given > >revision. > >+ * If the <code>revision</code> is <code>null</code>, then all > >previous > >+ * documents are returned. > >+ * > >+ * @param revision the revision to match or <code>null</code>. > >+ * @return previous documents. > >+ */ > >+ Iterable<NodeDocument> getPreviousDocs(final @Nullable Revision > >revision) { > >+ Iterable<NodeDocument> docs = Iterables.transform( > >+ Iterables.filter(getPreviousRanges().entrySet(), > >+ new Predicate<Map.Entry<Revision, Range>>() { > >+ @Override > >+ public boolean apply(Map.Entry<Revision, > >Range> input) { > >+ return revision == null || > >input.getValue().includes(revision); > >+ } > >+ }), new Function<Map.Entry<Revision, Range>, > >NodeDocument>() { > >+ @Nullable > >+ @Override > >+ public NodeDocument apply(Map.Entry<Revision, Range> input) { > >+ Revision r = input.getKey(); > >+ String prevId = Utils.getPreviousIdFor(getId(), r); > >+ NodeDocument prev = store.find(Collection.NODES, prevId); > >+ if (prev == null) { > >+ LOG.warn("Document with previous revisions not > >found: " + prevId); > >+ } > >+ return prev; > >+ } > >+ }); > >+ // filter out null docs and check if the revision is actually in > >there > >+ return Iterables.filter(docs, new Predicate<NodeDocument>() { > >+ @Override > >+ public boolean apply(@Nullable NodeDocument input) { > >+ if (input == null) { > >+ return false; > >+ } > >+ return revision == null || > >input.containsRevision(revision.toString()); > >+ } > >+ }); > >+ } > >+ > >+ /** > >+ * Returns the local value map for the given key. Returns > ><code>null</code> > >+ * if no such value map exists. > >+ * > >+ * @param key the key. > >+ * @return local value map. > >+ */ > >+ @Nonnull > >+ Map<String, String> getLocalMap(String key) { > >+ @SuppressWarnings("unchecked") > >+ Map<String, String> map = (Map<String, String>) get(key); > >+ if (map == null) { > >+ map = Collections.emptyMap(); > >+ } > >+ return map; > >+ } > >+ > >+ /** > >+ * @return the {@link #REVISIONS} stored on this document. > >+ */ > >+ @Nonnull > >+ Map<String, String> getLocalRevisions() { > >+ return getLocalMap(REVISIONS); > >+ } > >+ > > //-------------------------< UpdateOp modifiers > >>--------------------------- > > > > public static void setModified(@Nonnull UpdateOp op, > >@@ -745,15 +808,12 @@ public class NodeDocument extends Docume > > return this; > > } > > // check commit root > >- @SuppressWarnings("unchecked") > >- Map<String, Integer> commitRoot = (Map<String, Integer>) > >get(COMMIT_ROOT); > >+ Map<String, Integer> commitRoot = getCommitRoot(); > > String commitRootPath = null; > >- if (commitRoot != null) { > >- Integer depth = commitRoot.get(rev.toString()); > >- if (depth != null) { > >- String p = Utils.getPathFromId(getId()); > >- commitRootPath = PathUtils.getAncestorPath(p, > >PathUtils.getDepth(p) - depth); > >- } > >+ Integer depth = commitRoot.get(rev.toString()); > >+ if (depth != null) { > >+ String p = Utils.getPathFromId(getId()); > >+ commitRootPath = PathUtils.getAncestorPath(p, > >PathUtils.getDepth(p) - depth); > > } > > if (commitRootPath == null) { > > // shouldn't happen, either node is commit root for a > >revision > >@@ -835,11 +895,11 @@ public class NodeDocument extends Docume > > @CheckForNull > > private String getCommitValue(Revision revision) { > > String r = revision.toString(); > >- String value = getRevisionsMap().get(r); > >+ String value = getLocalRevisions().get(r); > > if (value == null) { > > // check previous > > for (NodeDocument prev : getPreviousDocs(revision)) { > >- value = prev.getRevisionsMap().get(r); > >+ value = prev.getLocalRevisions().get(r); > > if (value != null) { > > break; > > } > >@@ -907,193 +967,23 @@ public class NodeDocument extends Docume > > return value; > > } > > > >- Map<String, String> getRevisions() { > >- final Map<String, String> map = getRevisionsMap(); > >- if (!data.containsKey(PREVIOUS)) { > >- return map; > >- } > >- final Set<Map.Entry<String, String>> revisions > >- = new AbstractSet<Map.Entry<String, String>>() { > >- > >- @Override > >- @Nonnull > >- public Iterator<Map.Entry<String, String>> iterator() { > >- return Iterators.concat(map.entrySet().iterator(), > >- Iterators.concat(new > >Iterator<Iterator<Map.Entry<String, String>>>() { > >- private final Iterator<NodeDocument> previous > >- = getPreviousDocs(null).iterator(); > >- > >- @Override > >- public boolean hasNext() { > >- return previous.hasNext(); > >- } > >- > >- @Override > >- public Iterator<Map.Entry<String, String>> > >next() { > >- return > >previous.next().getRevisions().entrySet().iterator(); > >- } > >- > >- @Override > >- public void remove() { > >- throw new > >UnsupportedOperationException(); > >- } > >- })); > >- } > >- > >- @Override > >- public int size() { > >- int size = map.size(); > >- for (NodeDocument prev : getPreviousDocs(null)) { > >- size += prev.getRevisions().size(); > >- } > >- return size; > >- } > >- }; > >- return new AbstractMap<String, String>() { > >- > >- private final Map<String, String> map = getRevisionsMap(); > >- > >- @Override > >- @Nonnull > >- public Set<Entry<String, String>> entrySet() { > >- return revisions; > >- } > >- > >- @Override > >- public String get(Object key) { > >- // first check revisions map of this document > >- String value = map.get(key); > >- if (value != null) { > >- return value; > >- } > >- Revision r = Revision.fromString(key.toString()); > >- for (NodeDocument prev : getPreviousDocs(r)) { > >- value = prev.getRevisions().get(key); > >- if (value != null) { > >- return value; > >- } > >- } > >- // not found > >- return null; > >- } > >- > >- @Override > >- public boolean containsKey(Object key) { > >- // can use get() > >- // the revisions map does not have null values > >- return get(key) != null; > >- } > >- > >- }; > >- } > >- > > @Nonnull > >- Map<String, String> getRevisionsMap() { > >- @SuppressWarnings("unchecked") > >- Map<String, String> map = (Map<String, String>) get(REVISIONS); > >- if (map == null) { > >- map = Collections.emptyMap(); > >- } > >- return map; > >+ private Map<String, String> getRevisions() { > >+ return ValueMap.create(this, REVISIONS); > > } > > > >- /** > >- * Returns previous {@link NodeDocument}, which include the given > >revision. > >- * If the <code>revision</code> is <code>null</code>, then all > >previous > >- * documents are returned. > >- * > >- * @param revision the revision to match or <code>null</code>. > >- * @return previous documents. > >- */ > >- Iterable<NodeDocument> getPreviousDocs(@Nullable final Revision > >revision) { > >- Iterable<NodeDocument> docs = Iterables.transform( > >- Iterables.filter(getPreviousRanges().entrySet(), > >- new Predicate<Map.Entry<Revision, Range>>() { > >- @Override > >- public boolean apply(Map.Entry<Revision, Range> input) { > >- return revision == null || > >input.getValue().includes(revision); > >- } > >- }), new Function<Map.Entry<Revision, Range>, NodeDocument>() { > >- @Nullable > >- @Override > >- public NodeDocument apply(Map.Entry<Revision, Range> input) { > >- Revision r = input.getKey(); > >- String prevId = Utils.getPreviousIdFor(getId(), r); > >- NodeDocument prev = store.find(Collection.NODES, prevId); > >- if (prev == null) { > >- LOG.warn("Document with previous revisions not > >found: " + prevId); > >- } > >- return prev; > >- } > >- }); > >- // filter out null docs and check if the revision is actually in > >there > >- return Iterables.filter(docs, new Predicate<NodeDocument>() { > >- @Override > >- public boolean apply(@Nullable NodeDocument input) { > >- if (input == null) { > >- return false; > >- } > >- return revision == null || > >input.containsRevision(revision.toString()); > >- } > >- }); > >+ @Nonnull > >+ private Map<String, String> getDeleted() { > >+ return ValueMap.create(this, DELETED); > > } > > > >- /** > >- * Returns previous revision ranges for this document. The revision > >keys are > >- * sorted descending, newest first! > >- * > >- * @return the previous ranges for this document. > >- */ > > @Nonnull > >- private SortedMap<Revision, Range> getPreviousRanges() { > >+ private Map<String, Integer> getCommitRoot() { > > @SuppressWarnings("unchecked") > >- SortedMap<Revision, Range> previous = (SortedMap<Revision, > >Range>) get(PREVIOUS); > >- if (previous == null) { > >- previous = EMPTY_RANGE_MAP; > >- } > >- return previous; > >- } > >- > >- /** > >- * A range of revisions. > >- */ > >- private static final class Range { > >- > >- final Revision high; > >- final Revision low; > >- > >- /** > >- * A range of revisions, with both inclusive bounds. > >- * > >- * @param high the high bound. > >- * @param low the low bound. > >- */ > >- Range(@Nonnull Revision high, @Nonnull Revision low) { > >- this.high = checkNotNull(high); > >- this.low = checkNotNull(low); > >- checkArgument(high.getClusterId() == low.getClusterId(), > >- "Revisions from have the same clusterId"); > >- checkArgument(high.compareRevisionTime(low) > 0, > >- "High Revision must be later than low Revision"); > >- } > >- > >- /** > >- * Returns <code>true</code> if the given revision is within > >this range. > >- * > >- * @param r the revision to check. > >- * @return <code>true</code> if within this range; > ><code>false</code> > >- * otherwise. > >- */ > >- boolean includes(Revision r) { > >- return high.compareRevisionTime(r) >= 0 > >- && low.compareRevisionTime(r) <= 0; > >- } > >- > >- @Override > >- public String toString() { > >- return low.toString(); > >+ Map<String, Integer> commitRoot = (Map<String, Integer>) > >get(COMMIT_ROOT); > >+ if (commitRoot == null) { > >+ commitRoot = Collections.emptyMap(); > > } > >- > >+ return commitRoot; > > } > >- > > } > > > >Added: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java > >URL: > >http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak- > core/src/main/java/o > >rg/apache/jackrabbit/oak/plugins/mongomk/Range.java?rev=1522553&vie > w=auto > >========================================================= > ================= > >==== > >--- > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java (added) > >+++ > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java Thu Sep 12 12:45:19 2013 > >@@ -0,0 +1,63 @@ > >+/* > >+ * Licensed to the Apache Software Foundation (ASF) under one or more > >+ * contributor license agreements. See the NOTICE file distributed with > >+ * this work for additional information regarding copyright ownership. > >+ * The ASF licenses this file to You under the Apache License, Version > >2.0 > >+ * (the "License"); you may not use this file except in compliance with > >+ * the License. You may obtain a copy of the License at > >+ * > >+ * http://www.apache.org/licenses/LICENSE-2.0 > >+ * > >+ * Unless required by applicable law or agreed to in writing, software > >+ * distributed under the License is distributed on an "AS IS" BASIS, > >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express > or > >implied. > >+ * See the License for the specific language governing permissions and > >+ * limitations under the License. > >+ */ > >+package org.apache.jackrabbit.oak.plugins.mongomk; > >+ > >+import javax.annotation.Nonnull; > >+ > >+import static com.google.common.base.Preconditions.checkArgument; > >+import static com.google.common.base.Preconditions.checkNotNull; > >+ > >+/** > >+* A revision range for {@link NodeDocument#PREVIOUS} documents. > >+*/ > >+final class Range { > >+ > >+ final Revision high; > >+ final Revision low; > >+ > >+ /** > >+ * A range of revisions, with both inclusive bounds. > >+ * > >+ * @param high the high bound. > >+ * @param low the low bound. > >+ */ > >+ Range(@Nonnull Revision high, @Nonnull Revision low) { > >+ this.high = checkNotNull(high); > >+ this.low = checkNotNull(low); > >+ checkArgument(high.getClusterId() == low.getClusterId(), > >+ "Revisions from have the same clusterId"); > >+ checkArgument(high.compareRevisionTime(low) > 0, > >+ "High Revision must be later than low Revision"); > >+ } > >+ > >+ /** > >+ * Returns <code>true</code> if the given revision is within this > >range. > >+ * > >+ * @param r the revision to check. > >+ * @return <code>true</code> if within this range; <code>false</code> > >+ * otherwise. > >+ */ > >+ boolean includes(Revision r) { > >+ return high.compareRevisionTime(r) >= 0 > >+ && low.compareRevisionTime(r) <= 0; > >+ } > >+ > >+ @Override > >+ public String toString() { > >+ return low.toString(); > >+ } > >+} > > > >Propchange: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java > >-------------------------------------------------------------------------- > >---- > > svn:eol-style = native > > > >Propchange: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/Range.java > >-------------------------------------------------------------------------- > >---- > > svn:keywords = Author Date Id Revision Rev URL > > > >Added: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java > >URL: > >http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak- > core/src/main/java/o > >rg/apache/jackrabbit/oak/plugins/mongomk/ValueMap.java?rev=1522553 > &view=au > >to > >========================================================= > ================= > >==== > >--- > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java (added) > >+++ > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java Thu Sep 12 12:45:19 2013 > >@@ -0,0 +1,113 @@ > >+/* > >+ * Licensed to the Apache Software Foundation (ASF) under one or more > >+ * contributor license agreements. See the NOTICE file distributed with > >+ * this work for additional information regarding copyright ownership. > >+ * The ASF licenses this file to You under the Apache License, Version > >2.0 > >+ * (the "License"); you may not use this file except in compliance with > >+ * the License. You may obtain a copy of the License at > >+ * > >+ * http://www.apache.org/licenses/LICENSE-2.0 > >+ * > >+ * Unless required by applicable law or agreed to in writing, software > >+ * distributed under the License is distributed on an "AS IS" BASIS, > >+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express > or > >implied. > >+ * See the License for the specific language governing permissions and > >+ * limitations under the License. > >+ */ > >+package org.apache.jackrabbit.oak.plugins.mongomk; > >+ > >+import java.util.AbstractMap; > >+import java.util.AbstractSet; > >+import java.util.Iterator; > >+import java.util.Map; > >+import java.util.Set; > >+ > >+import javax.annotation.Nonnull; > >+ > >+import com.google.common.collect.Iterators; > >+ > >+/** > >+ * A value map contains the versioned values of a property. The key into > >this > >+ * map is the revision when the value was set. > >+ */ > >+class ValueMap { > >+ > >+ @Nonnull > >+ static Map<String, String> create(final @Nonnull NodeDocument doc, > >+ final @Nonnull String property) { > >+ final Map<String, String> map = doc.getLocalMap(property); > >+ if (doc.getPreviousRanges().isEmpty()) { > >+ return map; > >+ } > >+ final Set<Map.Entry<String, String>> values > >+ = new AbstractSet<Map.Entry<String, String>>() { > >+ > >+ @Override > >+ @Nonnull > >+ public Iterator<Map.Entry<String, String>> iterator() { > >+ return Iterators.concat(map.entrySet().iterator(), > >Iterators.concat(new Iterator<Iterator<Map.Entry<String, String>>>() { > >+ private final Iterator<NodeDocument> previous = > >doc.getPreviousDocs(null).iterator(); > >+ > >+ @Override > >+ public boolean hasNext() { > >+ return previous.hasNext(); > >+ } > >+ > >+ @Override > >+ public Iterator<Map.Entry<String, String>> next() { > >+ return > >previous.next().getLocalMap(property).entrySet().iterator(); > >+ } > >+ > >+ @Override > >+ public void remove() { > >+ throw new UnsupportedOperationException(); > >+ } > >+ })); > >+ } > >+ > >+ @Override > >+ public int size() { > >+ int size = map.size(); > >+ for (NodeDocument prev : doc.getPreviousDocs(null)) { > >+ size += prev.getLocalMap(property).size(); > >+ } > >+ return size; > >+ } > >+ }; > >+ return new AbstractMap<String, String>() { > >+ > >+ private final Map<String, String> map = > >doc.getLocalMap(property); > >+ > >+ @Override > >+ @Nonnull > >+ public Set<Entry<String, String>> entrySet() { > >+ return values; > >+ } > >+ > >+ @Override > >+ public String get(Object key) { > >+ // first check values map of this document > >+ String value = map.get(key); > >+ if (value != null) { > >+ return value; > >+ } > >+ Revision r = Revision.fromString(key.toString()); > >+ for (NodeDocument prev : doc.getPreviousDocs(r)) { > >+ value = prev.getLocalMap(property).get(key); > >+ if (value != null) { > >+ return value; > >+ } > >+ } > >+ // not found > >+ return null; > >+ } > >+ > >+ @Override > >+ public boolean containsKey(Object key) { > >+ // can use get() > >+ // the values map does not have null values > >+ return get(key) != null; > >+ } > >+ }; > >+ } > >+} > > > >Propchange: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java > >-------------------------------------------------------------------------- > >---- > > svn:eol-style = native > > > >Propchange: > >jackrabbit/oak/trunk/oak- > core/src/main/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/ValueMap.java > >-------------------------------------------------------------------------- > >---- > > svn:keywords = Author Date Id Revision Rev URL > > > >Modified: > >jackrabbit/oak/trunk/oak- > core/src/test/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/DocumentSplitTest.java > >URL: > >http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak- > core/src/test/java/o > >rg/apache/jackrabbit/oak/plugins/mongomk/DocumentSplitTest.java?rev= > 152255 > >3&r1=1522552&r2=1522553&view=diff > >========================================================= > ================= > >==== > >--- > >jackrabbit/oak/trunk/oak- > core/src/test/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/DocumentSplitTest.java (original) > >+++ > >jackrabbit/oak/trunk/oak- > core/src/test/java/org/apache/jackrabbit/oak/plug > >ins/mongomk/DocumentSplitTest.java Thu Sep 12 12:45:19 2013 > >@@ -39,7 +39,7 @@ public class DocumentSplitTest extends B > > Set<String> revisions = Sets.newHashSet(); > > NodeDocument doc = store.find(Collection.NODES, > >Utils.getIdFromPath("/")); > > assertNotNull(doc); > >- revisions.addAll(doc.getRevisionsMap().keySet()); > >+ revisions.addAll(doc.getLocalRevisions().keySet()); > > > > // MongoMK initializes with a root node with a single revision > > int numRevs = 1; > >@@ -55,7 +55,7 @@ public class DocumentSplitTest extends B > > String head = mk.getHeadRevision(); > > doc = store.find(Collection.NODES, Utils.getIdFromPath("/")); > > assertNotNull(doc); > >- Map<String, String> revs = doc.getRevisionsMap(); > >+ Map<String, String> revs = doc.getLocalRevisions(); > > // one remaining in the local revisions map > > assertEquals(1, revs.size()); > > for (String r : revisions) { > > > >
