Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java Wed Apr 10 11:13:19 2019 @@ -21,19 +21,17 @@ import static com.google.common.base.Pre import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; -import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.reverse; import static java.util.Collections.singletonList; import static java.util.concurrent.TimeUnit.MICROSECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; import static org.apache.jackrabbit.oak.api.CommitFailedException.OAK; -import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH; -import static org.apache.jackrabbit.oak.commons.PathUtils.concat; import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder.MANY_CHILDREN_THRESHOLD; import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS_RESOLUTION; +import static org.apache.jackrabbit.oak.plugins.document.Path.ROOT; import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key; import static org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation; import static org.apache.jackrabbit.oak.plugins.document.util.Utils.alignWithExternalRevisions; @@ -100,7 +98,6 @@ import org.apache.jackrabbit.oak.commons import org.apache.jackrabbit.oak.api.Blob; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.cache.CacheStats; -import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.json.BlobSerializer; import org.apache.jackrabbit.oak.plugins.document.util.LeaseCheckDocumentStoreWrapper; import org.apache.jackrabbit.oak.plugins.document.util.LoggingDocumentStoreWrapper; @@ -386,7 +383,7 @@ public final class DocumentNodeStore * * Key: PathRev, value: Children */ - private final Cache<PathRev, DocumentNodeState.Children> nodeChildrenCache; + private final Cache<NamePathRev, DocumentNodeState.Children> nodeChildrenCache; private final CacheStats nodeChildrenCacheStats; /** @@ -515,10 +512,10 @@ public final class DocumentNodeStore */ private final Set<Revision> inDoubtTrunkCommits = Sets.newConcurrentHashSet(); - private final Predicate<String> nodeCachePredicate; + private final Predicate<Path> nodeCachePredicate; public DocumentNodeStore(DocumentNodeStoreBuilder<?> builder) { - this.nodeCachePredicate = builder.getNodeCachePredicate(); + this.nodeCachePredicate = builder.getNodeCachePathPredicate(); this.updateLimit = builder.getUpdateLimit(); this.commitValueResolver = new CachingCommitValueResolver( builder.getCommitValueCacheSize(), this::getSweepRevisions); @@ -591,7 +588,7 @@ public final class DocumentNodeStore this.lastRevRecoveryAgent = new LastRevRecoveryAgent(store, this, lastRevSeeker, clusterId -> this.signalClusterStateChange()); this.disableBranches = builder.isDisableBranches(); - this.missing = new DocumentNodeState(this, "MISSING", + this.missing = new DocumentNodeState(this, new Path("missing"), new RevisionVector(new Revision(0, 0, 0))) { @Override public int getMemory() { @@ -612,7 +609,7 @@ public final class DocumentNodeStore diffCache = builder.getDiffCache(this.clusterId); // check if root node exists - NodeDocument rootDoc = store.find(NODES, Utils.getIdFromPath("/")); + NodeDocument rootDoc = store.find(NODES, Utils.getIdFromPath(ROOT)); if (rootDoc == null) { if (readOnlyMode) { throw new DocumentStoreException("Unable to initialize a " + @@ -623,7 +620,7 @@ public final class DocumentNodeStore Revision commitRev = newRevision(); RevisionVector head = new RevisionVector(commitRev); Commit commit = new CommitBuilder(this, commitRev, null) - .addNode("/") + .addNode(ROOT) .build(); try { commit.applyToDocumentStore(); @@ -631,12 +628,12 @@ public final class DocumentNodeStore commit.rollback(); throw new IllegalStateException("Conflict while creating root document", e); } - unsavedLastRevisions.put("/", commitRev); + unsavedLastRevisions.put(ROOT, commitRev); sweepRevisions = sweepRevisions.pmax(head); setRoot(head); // make sure _lastRev is written back to store backgroundWrite(); - rootDoc = store.find(NODES, Utils.getIdFromPath("/")); + rootDoc = store.find(NODES, Utils.getIdFromPath(ROOT)); // at this point the root document must exist if (rootDoc == null) { throw new IllegalStateException("Root document does not exist"); @@ -653,7 +650,7 @@ public final class DocumentNodeStore "missing revision for clusterId " + clusterId + ": " + rootRev); } - unsavedLastRevisions.put("/", initialRev); + unsavedLastRevisions.put(ROOT, initialRev); // set initial sweep revision sweepRevisions = sweepRevisions.pmax(new RevisionVector(initialRev)); if (!readOnlyMode) { @@ -752,7 +749,7 @@ public final class DocumentNodeStore @Override public void headOfQueue(@NotNull Revision revision) { setRoot(getHeadRevision().update(revision)); - unsavedLastRevisions.put(ROOT_PATH, revision); + unsavedLastRevisions.put(ROOT, revision); } }); } catch (DocumentStoreException e) { @@ -1074,11 +1071,11 @@ public final class DocumentNodeStore return nodeCache; } - public Cache<PathRev, DocumentNodeState.Children> getNodeChildrenCache() { + public Cache<NamePathRev, DocumentNodeState.Children> getNodeChildrenCache() { return nodeChildrenCache; } - public Predicate<String> getNodeCachePredicate() { + public Predicate<Path> getNodeCachePredicate() { return nodeCachePredicate; } @@ -1097,7 +1094,7 @@ public final class DocumentNodeStore } void invalidateNodeCache(String path, RevisionVector revision){ - nodeCache.invalidate(new PathRev(path, revision)); + nodeCache.invalidate(new PathRev(Path.fromString(path), revision)); } public int getPendingWriteCount() { @@ -1118,14 +1115,15 @@ public final class DocumentNodeStore } @Nullable - AbstractDocumentNodeState getSecondaryNodeState(@NotNull final String path, + AbstractDocumentNodeState getSecondaryNodeState(@NotNull final Path path, @NotNull final RevisionVector rootRevision, @NotNull final RevisionVector rev) { //Check secondary cache first return nodeStateCache.getDocumentNodeState(path, rootRevision, rev); } - PropertyState createPropertyState(String name, String value){ + @NotNull + public PropertyState createPropertyState(String name, String value){ return new DocumentPropertyState(this, name, checkNotNull(value)); } @@ -1139,8 +1137,8 @@ public final class DocumentNodeStore * given revision. */ @Nullable - public DocumentNodeState getNode(@NotNull final String path, - @NotNull final RevisionVector rev) { + public DocumentNodeState getNode(@NotNull final Path path, + @NotNull final RevisionVector rev) { checkNotNull(rev); checkNotNull(path); final long start = PERFLOG.start(); @@ -1173,16 +1171,16 @@ public final class DocumentNodeStore @NotNull DocumentNodeState.Children getChildren(@NotNull final AbstractDocumentNodeState parent, - @Nullable final String name, - final int limit) + @NotNull final String name, + final int limit) throws DocumentStoreException { if (checkNotNull(parent).hasNoChildren()) { return DocumentNodeState.NO_CHILDREN; } - final String path = checkNotNull(parent).getPath(); + final Path path = checkNotNull(parent).getPath(); final RevisionVector readRevision = parent.getLastRevision(); try { - PathRev key = childNodeCacheKey(path, readRevision, name); + NamePathRev key = childNodeCacheKey(path, readRevision, name); DocumentNodeState.Children children = nodeChildrenCache.get(key, new Callable<DocumentNodeState.Children>() { @Override public DocumentNodeState.Children call() throws Exception { @@ -1216,15 +1214,15 @@ public final class DocumentNodeStore * ascending order. * * @param parent the parent node. - * @param name the name of the lower bound child node (exclusive) or - * {@code null} if no lower bound is given. + * @param name the name of the lower bound child node (exclusive) or the + * empty {@code String} if no lower bound is given. * @param limit the maximum number of child nodes to return. * @return the children of {@code parent}. */ - DocumentNodeState.Children readChildren(AbstractDocumentNodeState parent, - String name, int limit) { + DocumentNodeState.Children readChildren(@NotNull AbstractDocumentNodeState parent, + @NotNull String name, int limit) { String queriedName = name; - String path = parent.getPath(); + Path path = parent.getPath(); RevisionVector rev = parent.getLastRevision(); LOG.trace("Reading children for [{}] at rev [{}]", path, rev); Iterable<NodeDocument> docs; @@ -1238,10 +1236,10 @@ public final class DocumentNodeStore int numReturned = 0; for (NodeDocument doc : docs) { numReturned++; - String p = doc.getPath(); + Path p = doc.getPath(); // remember name of last returned document for // potential next round of readChildDocs() - name = PathUtils.getName(p); + name = p.getName(); // filter out deleted children DocumentNodeState child = getNode(p, rev); if (child == null) { @@ -1249,7 +1247,7 @@ public final class DocumentNodeStore } if (c.children.size() < limit) { // add to children until limit is reached - c.children.add(PathUtils.getName(p)); + c.children.add(p.getName()); } else { // enough collected and we know there are more c.hasMore = true; @@ -1261,7 +1259,7 @@ public final class DocumentNodeStore // fewer documents returned than requested // -> no more documents c.hasMore = false; - if (queriedName == null) { + if (queriedName.isEmpty()) { //we've got to the end of list and we started from the top //This list is complete and can be sorted Collections.sort(c.children); @@ -1279,20 +1277,21 @@ public final class DocumentNodeStore * lower exclusive bound. * * @param path the path of the parent document. - * @param name the lower exclusive bound or {@code null}. + * @param name the name of the lower bound child node (exclusive) or the + * empty {@code String} if no lower bound is given. * @param limit the maximum number of child documents to return. * @return the child documents. */ @NotNull - private Iterable<NodeDocument> readChildDocs(@NotNull final String path, - @Nullable String name, + private Iterable<NodeDocument> readChildDocs(@NotNull final Path path, + @NotNull String name, final int limit) { final String to = Utils.getKeyUpperLimit(checkNotNull(path)); final String from; - if (name != null) { - from = Utils.getIdFromPath(concat(path, name)); - } else { + if (name.isEmpty()) { from = Utils.getKeyLowerLimit(path); + } else { + from = Utils.getIdFromPath(new Path(path, name)); } return store.query(Collection.NODES, from, to, limit); } @@ -1302,15 +1301,15 @@ public final class DocumentNodeStore * {@code name} (exclusive). * * @param parent the parent node. - * @param name the name of the lower bound child node (exclusive) or - * {@code null}, if the method should start with the first known - * child node. + * @param name the name of the lower bound child node (exclusive) or the + * empty {@code String}, if the method should start with the + * first known child node. * @param limit the maximum number of child nodes to return. * @return the child nodes. */ @NotNull Iterable<DocumentNodeState> getChildNodes(@NotNull final DocumentNodeState parent, - @Nullable final String name, + @NotNull final String name, final int limit) { // Preemptive check. If we know there are no children then // return straight away @@ -1322,7 +1321,7 @@ public final class DocumentNodeStore return transform(getChildren(parent, name, limit).children, new Function<String, DocumentNodeState>() { @Override public DocumentNodeState apply(String input) { - String p = concat(parent.getPath(), input); + Path p = new Path(parent.getPath(), input); DocumentNodeState result = getNode(p, readRevision); if (result == null) { // This is very unexpected situation - parent's child list @@ -1366,7 +1365,7 @@ public final class DocumentNodeStore } @Nullable - DocumentNodeState readNode(String path, RevisionVector readRevision) { + private DocumentNodeState readNode(Path path, RevisionVector readRevision) { final long start = PERFLOG.start(); String id = Utils.getIdFromPath(path); Revision lastRevision = getPendingModifications().get(path); @@ -1400,9 +1399,9 @@ public final class DocumentNodeStore * */ void applyChanges(RevisionVector before, RevisionVector after, - Revision rev, String path, - boolean isNew, List<String> added, - List<String> removed, List<String> changed) { + Revision rev, Path path, + boolean isNew, List<Path> added, + List<Path> removed, List<Path> changed) { if (isNew) { // determine the revision for the nodeChildrenCache entry when // the node is new. Fallback to after revision in case document @@ -1417,18 +1416,18 @@ public final class DocumentNodeStore // this is a leaf node. // check if it has the children flag set if (doc != null && doc.hasChildren()) { - PathRev key = childNodeCacheKey(path, afterLastRev, null); + NamePathRev key = childNodeCacheKey(path, afterLastRev, ""); LOG.debug("nodeChildrenCache.put({},{})", key, "NO_CHILDREN"); nodeChildrenCache.put(key, DocumentNodeState.NO_CHILDREN); } } else { DocumentNodeState.Children c = new DocumentNodeState.Children(); Set<String> set = Sets.newTreeSet(); - for (String p : added) { - set.add(PathUtils.getName(p)); + for (Path p : added) { + set.add(p.getName()); } c.children.addAll(set); - PathRev key = childNodeCacheKey(path, afterLastRev, null); + NamePathRev key = childNodeCacheKey(path, afterLastRev, ""); LOG.debug("nodeChildrenCache.put({},{})", key, c); nodeChildrenCache.put(key, c); } @@ -1437,9 +1436,9 @@ public final class DocumentNodeStore DocumentNodeState beforeState = getRoot(before); // do we have a cached before state that can be used // to calculate the new children? - int depth = PathUtils.getDepth(path); + int depth = path.getDepth(); for (int i = 1; i <= depth && beforeState != null; i++) { - String p = PathUtils.getAncestorPath(path, depth - i); + Path p = path.getAncestor(depth - i); RevisionVector lastRev = beforeState.getLastRevision(); PathRev key = new PathRev(p, lastRev); beforeState = nodeCache.getIfPresent(key); @@ -1447,10 +1446,10 @@ public final class DocumentNodeStore // This is unexpected. The before state should exist. // Invalidate the relevant cache entries. (OAK-6294) LOG.warn("Before state is missing {}. Invalidating " + - "affected cache entries.", key.asString()); + "affected cache entries.", key); store.invalidateCache(NODES, Utils.getIdFromPath(p)); nodeCache.invalidate(key); - nodeChildrenCache.invalidate(childNodeCacheKey(path, lastRev, null)); + nodeChildrenCache.invalidate(childNodeCacheKey(path, lastRev, "")); beforeState = null; } } @@ -1459,12 +1458,12 @@ public final class DocumentNodeStore if (beforeState.hasNoChildren()) { children = DocumentNodeState.NO_CHILDREN; } else { - PathRev key = childNodeCacheKey(path, beforeState.getLastRevision(), null); + NamePathRev key = childNodeCacheKey(path, beforeState.getLastRevision(), ""); children = nodeChildrenCache.getIfPresent(key); } } if (children != null) { - PathRev afterKey = new PathRev(path, beforeState.getLastRevision().update(rev)); + NamePathRev afterKey = childNodeCacheKey(path, beforeState.getLastRevision().update(rev), ""); // are there any added or removed children? if (added.isEmpty() && removed.isEmpty()) { // simply use the same list @@ -1473,11 +1472,11 @@ public final class DocumentNodeStore } else if (!children.hasMore){ // list is complete. use before children as basis Set<String> afterChildren = Sets.newTreeSet(children.children); - for (String p : added) { - afterChildren.add(PathUtils.getName(p)); + for (Path p : added) { + afterChildren.add(p.getName()); } - for (String p : removed) { - afterChildren.remove(PathUtils.getName(p)); + for (Path p : removed) { + afterChildren.remove(p.getName()); } DocumentNodeState.Children c = new DocumentNodeState.Children(); c.children.addAll(afterChildren); @@ -1492,8 +1491,8 @@ public final class DocumentNodeStore // incomplete list, but we only removed nodes // use linked hash set to retain order Set<String> afterChildren = Sets.newLinkedHashSet(children.children); - for (String p : removed) { - afterChildren.remove(PathUtils.getName(p)); + for (Path p : removed) { + afterChildren.remove(p.getName()); } DocumentNodeState.Children c = new DocumentNodeState.Children(); c.children.addAll(afterChildren); @@ -1617,7 +1616,7 @@ public final class DocumentNodeStore */ @NotNull DocumentNodeState getRoot(@NotNull RevisionVector revision) { - DocumentNodeState root = getNode("/", revision); + DocumentNodeState root = getNode(ROOT, revision); if (root == null) { throw new IllegalStateException( "root node does not exist at revision " + revision); @@ -1681,9 +1680,9 @@ public final class DocumentNodeStore revs.add(ancestorRev); } revs.addAll(b.getCommits().tailSet(ancestorRev)); - UpdateOp rootOp = new UpdateOp(Utils.getIdFromPath("/"), false); + UpdateOp rootOp = new UpdateOp(Utils.getIdFromPath(ROOT), false); // reset each branch commit in reverse order - Map<String, UpdateOp> operations = Maps.newHashMap(); + Map<Path, UpdateOp> operations = Maps.newHashMap(); AtomicReference<Revision> currentRev = new AtomicReference<>(); for (Revision r : reverse(revs)) { operations.clear(); @@ -1733,7 +1732,7 @@ public final class DocumentNodeStore MergeCommit commit = newMergeCommit(base, numBranchCommits); try { // make branch commits visible - UpdateOp op = new UpdateOp(Utils.getIdFromPath("/"), false); + UpdateOp op = new UpdateOp(Utils.getIdFromPath(ROOT), false); NodeDocument.setModified(op, commit.getRevision()); if (b != null) { // check the branch age and fail the commit @@ -1817,7 +1816,7 @@ public final class DocumentNodeStore } else { return new LastRevTracker() { @Override - public void track(String path) { + public void track(Path path) { unsavedLastRevisions.put(path, r); } }; @@ -2278,7 +2277,7 @@ public final class DocumentNodeStore // was successful -> apply them to the diff cache try { JournalEntry.applyTo(changedPaths, diffCache, - PathUtils.ROOT_PATH, oldHead, newHead); + ROOT, oldHead, newHead); } catch (Exception e1) { LOG.error("backgroundRead: Exception while processing external changes from journal: " + e1, e1); } @@ -2323,7 +2322,7 @@ public final class DocumentNodeStore while ((b = branches.pollOrphanedBranch()) != null) { LOG.debug("Cleaning up orphaned branch with base revision: {}, " + "commits: {}", b.getBase(), b.getCommits()); - UpdateOp op = new UpdateOp(Utils.getIdFromPath("/"), false); + UpdateOp op = new UpdateOp(Utils.getIdFromPath(ROOT), false); for (Revision r : b.getCommits()) { r = r.asTrunkRevision(); NodeDocument.removeRevision(op, r); @@ -2334,7 +2333,7 @@ public final class DocumentNodeStore } private void cleanRootCollisions() { - String id = Utils.getIdFromPath("/"); + String id = Utils.getIdFromPath(ROOT); NodeDocument root = store.find(NODES, id); if (root != null) { cleanCollisions(root, Integer.MAX_VALUE); @@ -2496,7 +2495,7 @@ public final class DocumentNodeStore Revision newSweepRev = sweeper.sweep(docs, new NodeDocumentSweepListener() { @Override - public void sweepUpdate(final Map<String, UpdateOp> updates) + public void sweepUpdate(final Map<Path, UpdateOp> updates) throws DocumentStoreException { // create a synthetic commit. this commit does not have any // changes, we just use it to create a journal entry for @@ -2523,7 +2522,7 @@ public final class DocumentNodeStore } } - private void writeUpdates(Map<String, UpdateOp> updates, + private void writeUpdates(Map<Path, UpdateOp> updates, Revision revision) throws DocumentStoreException { // create journal entry @@ -2537,7 +2536,7 @@ public final class DocumentNodeStore throw new DocumentStoreException(msg); } changes.invalidate(Collections.singleton(r)); - unsavedLastRevisions.put(ROOT_PATH, revision); + unsavedLastRevisions.put(ROOT, revision); RevisionVector newHead = getHeadRevision().update(revision); setRoot(newHead); commitQueue.headRevisionChanged(); @@ -2774,22 +2773,22 @@ public final class DocumentNodeStore /** * Search for presence of child node as denoted by path in the children cache of parent * - * @param path + * @param path the path of the child node * @param rev revision at which check is performed * @return <code>true</code> if and only if the children cache entry for parent path is complete * and that list does not have the given child node. A <code>false</code> indicates that node <i>might</i> * exist */ - private boolean checkNodeNotExistsFromChildrenCache(String path, + private boolean checkNodeNotExistsFromChildrenCache(Path path, RevisionVector rev) { - if (PathUtils.denotesRoot(path)) { + final Path parentPath = path.getParent(); + if (parentPath == null) { return false; } - final String parentPath = PathUtils.getParentPath(path); - PathRev key = childNodeCacheKey(parentPath, rev, null);//read first child cache entry + NamePathRev key = childNodeCacheKey(parentPath, rev, "");//read first child cache entry DocumentNodeState.Children children = nodeChildrenCache.getIfPresent(key); - String lookupChildName = PathUtils.getName(path); + String lookupChildName = path.getName(); //Does not know about children so cannot say for sure if (children == null) { @@ -2855,8 +2854,8 @@ public final class DocumentNodeStore if (continueDiff) { DocumentNodeState.Children fromChildren, toChildren; - fromChildren = getChildren(from, null, max); - toChildren = getChildren(to, null, max); + fromChildren = getChildren(from, "", max); + toChildren = getChildren(to, "", max); getChildrenDoneIn = debug ? now() : 0; if (!fromChildren.hasMore && !toChildren.hasMore) { @@ -2872,8 +2871,8 @@ public final class DocumentNodeStore } else { diffAlgo = "diffAllChildren"; max = Integer.MAX_VALUE; - fromChildren = getChildren(from, null, max); - toChildren = getChildren(to, null, max); + fromChildren = getChildren(from, "", max); + toChildren = getChildren(to, "", max); diffFewChildren(w, from.getPath(), fromChildren, fromRev, toChildren, toRev); } @@ -2894,7 +2893,7 @@ public final class DocumentNodeStore return diff; } - private void diffManyChildren(JsopWriter w, String path, + private void diffManyChildren(JsopWriter w, Path path, RevisionVector fromRev, RevisionVector toRev) { long minTimestamp = Utils.getMinTimestampForDiff( @@ -2910,7 +2909,7 @@ public final class DocumentNodeStore long minValue = NodeDocument.getModifiedInSecs(minTimestamp); String fromKey = Utils.getKeyLowerLimit(path); String toKey = Utils.getKeyUpperLimit(path); - Set<String> paths = Sets.newHashSet(); + Set<Path> paths = Sets.newHashSet(); LOG.debug("diffManyChildren: path: {}, fromRev: {}, toRev: {}", path, fromRev, toRev); @@ -2932,10 +2931,10 @@ public final class DocumentNodeStore } } } - for (String p : paths) { + for (Path p : paths) { DocumentNodeState fromNode = getNode(p, fromRev); DocumentNodeState toNode = getNode(p, toRev); - String name = PathUtils.getName(p); + String name = p.getName(); LOG.trace("diffManyChildren: Changed Path {}", path); @@ -2968,21 +2967,21 @@ public final class DocumentNodeStore } } - private static void addPathsForDiff(String path, - Set<String> paths, - Iterable<String> modified) { - for (String p : modified) { - if (PathUtils.denotesRoot(p)) { + private static void addPathsForDiff(Path path, + Set<Path> paths, + Iterable<Path> modified) { + for (Path p : modified) { + if (p.isRoot()) { continue; } - String parent = PathUtils.getParentPath(p); + Path parent = p.getParent(); if (path.equals(parent)) { paths.add(p); } } } - private void diffFewChildren(JsopWriter w, String parentPath, + private void diffFewChildren(JsopWriter w, Path parentPath, DocumentNodeState.Children fromChildren, RevisionVector fromRev, DocumentNodeState.Children toChildren, @@ -2992,7 +2991,7 @@ public final class DocumentNodeStore if (!childrenSet.contains(n)) { w.tag('-').value(n); } else { - String path = concat(parentPath, n); + Path path = new Path(parentPath, n); DocumentNodeState n1 = getNode(path, fromRev); DocumentNodeState n2 = getNode(path, toRev); // this is not fully correct: @@ -3014,11 +3013,10 @@ public final class DocumentNodeStore } } - private static PathRev childNodeCacheKey(@NotNull String path, - @NotNull RevisionVector readRevision, - @Nullable String name) { - String p = (name == null ? "" : name) + path; - return new PathRev(p, readRevision); + private static NamePathRev childNodeCacheKey(@NotNull Path path, + @NotNull RevisionVector readRevision, + @NotNull String name) { + return new NamePathRev(name, path, readRevision); } private static DocumentRootBuilder asDocumentRootBuilder(NodeBuilder builder)
Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java Wed Apr 10 11:13:19 2019 @@ -16,7 +16,7 @@ */ package org.apache.jackrabbit.oak.plugins.document; -import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -151,8 +151,7 @@ public class DocumentNodeStoreBuilder<T private CacheStats blobStoreCacheStats; private DocumentStoreStatsCollector documentStoreStatsCollector; private DocumentNodeStoreStatsCollector nodeStoreStatsCollector; - private Map<CacheType, PersistentCacheStats> persistentCacheStats = - new EnumMap<CacheType, PersistentCacheStats>(CacheType.class); + private Map<String, PersistentCacheStats> persistentCacheStats = new HashMap<>(); private boolean bundlingDisabled; private JournalPropertyHandlerFactory journalPropertyHandlerFactory = new JournalPropertyHandlerFactory(); @@ -161,7 +160,7 @@ public class DocumentNodeStoreBuilder<T private long maxRevisionAgeMillis = DEFAULT_JOURNAL_GC_MAX_AGE_MILLIS; private GCMonitor gcMonitor = new LoggingGCMonitor( LoggerFactory.getLogger(VersionGarbageCollector.class)); - private Predicate<String> nodeCachePredicate = Predicates.alwaysTrue(); + private Predicate<Path> nodeCachePredicate = Predicates.alwaysTrue(); /** * @return a new {@link DocumentNodeStoreBuilder}. @@ -479,7 +478,7 @@ public class DocumentNodeStoreBuilder<T } @NotNull - public Map<CacheType, PersistentCacheStats> getPersistenceCacheStats() { + public Map<String, PersistentCacheStats> getPersistenceCacheStats() { return persistentCacheStats; } @@ -591,11 +590,11 @@ public class DocumentNodeStoreBuilder<T return buildCache(CacheType.NODE, getNodeCacheSize(), store, null); } - public Cache<PathRev, DocumentNodeState.Children> buildChildrenCache(DocumentNodeStore store) { + public Cache<NamePathRev, DocumentNodeState.Children> buildChildrenCache(DocumentNodeStore store) { return buildCache(CacheType.CHILDREN, getChildrenCacheSize(), store, null); } - public Cache<PathRev, StringValue> buildMemoryDiffCache() { + public Cache<CacheValue, StringValue> buildMemoryDiffCache() { return buildCache(CacheType.DIFF, getMemoryDiffCacheSize(), null, null); } @@ -621,12 +620,29 @@ public class DocumentNodeStoreBuilder<T return new NodeDocumentCache(nodeDocumentsCache, nodeDocumentsCacheStats, prevDocumentsCache, prevDocumentsCacheStats, locks); } + /** + * @deprecated Use {@link #setNodeCachePathPredicate(Predicate)} instead. + */ + @Deprecated public T setNodeCachePredicate(Predicate<String> p){ - this.nodeCachePredicate = p; + this.nodeCachePredicate = input -> input != null && p.apply(input.toString()); return thisBuilder(); } + /** + * @deprecated Use {@link #getNodeCachePathPredicate()} instead. + */ + @Deprecated public Predicate<String> getNodeCachePredicate() { + return input -> input != null && nodeCachePredicate.apply(Path.fromString(input)); + } + + public T setNodeCachePathPredicate(Predicate<Path> p){ + this.nodeCachePredicate = p; + return thisBuilder(); + } + + public Predicate<Path> getNodeCachePathPredicate() { return nodeCachePredicate; } @@ -654,7 +670,7 @@ public class DocumentNodeStoreBuilder<T } PersistentCacheStats stats = PersistentCache.getPersistentCacheStats(cache); if (stats != null) { - persistentCacheStats.put(cacheType, stats); + persistentCacheStats.put(cacheType.name(), stats); } } return cache; Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java Wed Apr 10 11:13:19 2019 @@ -20,7 +20,6 @@ package org.apache.jackrabbit.oak.plugin import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.Lists.newArrayList; -import static java.util.Collections.emptyList; import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly; import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toLong; import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder.DEFAULT_MEMORY_CACHE_SIZE; @@ -79,7 +78,6 @@ import org.apache.jackrabbit.oak.plugins import org.apache.jackrabbit.oak.plugins.blob.SharedDataStore; import org.apache.jackrabbit.oak.plugins.blob.datastore.BlobIdTracker; import org.apache.jackrabbit.oak.plugins.blob.datastore.SharedDataStoreUtils; -import org.apache.jackrabbit.oak.plugins.document.persistentCache.CacheType; import org.apache.jackrabbit.oak.plugins.document.persistentCache.PersistentCacheStats; import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection; import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo; @@ -88,7 +86,6 @@ import org.apache.jackrabbit.oak.spi.blo import org.apache.jackrabbit.oak.spi.blob.GarbageCollectableBlobStore; import org.apache.jackrabbit.oak.spi.blob.stats.BlobStoreStatsMBean; import org.apache.jackrabbit.oak.spi.commit.BackgroundObserverMBean; -import org.apache.jackrabbit.oak.spi.filter.PathFilter; import org.apache.jackrabbit.oak.spi.gc.DelegatingGCMonitor; import org.apache.jackrabbit.oak.spi.gc.GCMonitor; import org.apache.jackrabbit.oak.spi.gc.GCMonitorTracker; @@ -460,7 +457,7 @@ public class DocumentNodeStoreService { setPrefetchExternalChanges(config.prefetchExternalChanges()). setUpdateLimit(config.updateLimit()). setJournalGCMaxAge(config.journalGCMaxAge()). - setNodeCachePredicate(createCachePredicate()); + setNodeCachePathPredicate(createCachePredicate()); if (!Strings.isNullOrEmpty(persistentCache)) { builder.setPersistentCache(persistentCache); @@ -481,7 +478,7 @@ public class DocumentNodeStoreService { return customBlobStore && blobStore instanceof BlobStoreWrapper; } - private Predicate<String> createCachePredicate() { + private Predicate<Path> createCachePredicate() { if (config.persistentCacheIncludes().length == 0) { return Predicates.alwaysTrue(); } @@ -489,16 +486,24 @@ public class DocumentNodeStoreService { return Predicates.alwaysTrue(); } - Set<String> paths = new HashSet<>(); + Set<Path> paths = new HashSet<>(); for (String p : config.persistentCacheIncludes()) { p = p != null ? Strings.emptyToNull(p.trim()) : null; if (p != null) { - paths.add(p); + paths.add(Path.fromString(p)); } } - PathFilter pf = new PathFilter(paths, emptyList()); log.info("Configuring persistent cache to only cache nodes under paths {}", paths); - return path -> path != null && pf.filter(path) == PathFilter.Result.INCLUDE; + return input -> { + if (input != null) { + for (Path p : paths) { + if (p.isAncestorOf(input)) { + return true; + } + } + } + return false; + }; } private boolean isNodeStoreProvider() { @@ -731,7 +736,7 @@ public class DocumentNodeStoreService { } // register persistent cache stats - Map<CacheType, PersistentCacheStats> persistenceCacheStats = mkBuilder.getPersistenceCacheStats(); + Map<String, PersistentCacheStats> persistenceCacheStats = mkBuilder.getPersistenceCacheStats(); for (PersistentCacheStats pcs: persistenceCacheStats.values()) { addRegistration( registerMBean(whiteboard, Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ExternalChange.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ExternalChange.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ExternalChange.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ExternalChange.java Wed Apr 10 11:13:19 2019 @@ -97,7 +97,7 @@ abstract class ExternalChange { Clock clock = store.getClock(); int clusterId = store.getClusterId(); long time = clock.getTime(); - String id = Utils.getIdFromPath("/"); + String id = Utils.getIdFromPath(Path.ROOT); NodeDocument doc = store.getDocumentStore().find(NODES, id, store.getAsyncDelay()); if (doc == null) { return stats; @@ -145,7 +145,7 @@ abstract class ExternalChange { // add changes for this particular clusterId to the externalSort try { fillExternalChanges(externalSort, invalidate, - PathUtils.ROOT_PATH, last, r, + Path.ROOT, last, r, store.getDocumentStore(), journalEntryConsumer, changeSetBuilder, journalPropertyHandler); } catch (Exception e1) { Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalDiffLoader.java Wed Apr 10 11:13:19 2019 @@ -65,13 +65,13 @@ class JournalDiffLoader implements DiffC @Override public String call() { - String path = node.getPath(); RevisionVector afterRev = node.getRootRevision(); RevisionVector beforeRev = base.getRootRevision(); - stats = new Stats(path, beforeRev, afterRev); + stats = new Stats(node.getPath(), beforeRev, afterRev); StringSort changes = JournalEntry.newSorter(); try { + Path path = node.getPath(); readTrunkChanges(path, beforeRev, afterRev, changes); readBranchChanges(path, beforeRev, changes); @@ -80,7 +80,7 @@ class JournalDiffLoader implements DiffC changes.sort(); DiffCache df = ns.getDiffCache(); WrappedDiffCache wrappedCache = new WrappedDiffCache(node.getPath(), df, stats); - JournalEntry.applyTo(changes, wrappedCache, path, beforeRev, afterRev); + JournalEntry.applyTo(changes, wrappedCache, node.getPath(), beforeRev, afterRev); return wrappedCache.changes; } catch (IOException e) { @@ -91,7 +91,7 @@ class JournalDiffLoader implements DiffC } } - private void readBranchChanges(String path, + private void readBranchChanges(Path path, RevisionVector rv, StringSort changes) throws IOException { if (!rv.isBranch() || ns.isDisableBranches()) { @@ -119,7 +119,7 @@ class JournalDiffLoader implements DiffC } } - private void readTrunkChanges(String path, + private void readTrunkChanges(Path path, RevisionVector beforeRev, RevisionVector afterRev, StringSort changes) throws IOException { @@ -214,14 +214,14 @@ class JournalDiffLoader implements DiffC private static class Stats { private final Stopwatch sw = Stopwatch.createStarted(); - private final String path; + private final Path path; private final RevisionVector from, to; private long numJournalEntries; private long numDiffEntries; private long keyMemory; private long valueMemory; - Stats(String path, RevisionVector from, RevisionVector to) { + Stats(Path path, RevisionVector from, RevisionVector to) { this.path = path; this.from = from; this.to = to; @@ -241,12 +241,12 @@ class JournalDiffLoader implements DiffC private static class WrappedDiffCache extends DiffCache { - private final String path; + private final Path path; private String changes = ""; private final DiffCache cache; private Stats stats; - WrappedDiffCache(String path, + WrappedDiffCache(Path path, DiffCache cache, Stats stats) { this.path = path; @@ -262,7 +262,7 @@ class JournalDiffLoader implements DiffC @Override String getChanges(@NotNull RevisionVector from, @NotNull RevisionVector to, - @NotNull String path, + @NotNull Path path, @Nullable Loader loader) { return cache.getChanges(from, to, path, loader); } @@ -275,7 +275,7 @@ class JournalDiffLoader implements DiffC final Entry entry = cache.newEntry(from, to, local); return new Entry() { @Override - public void append(@NotNull String path, + public void append(@NotNull Path path, @NotNull String changes) { trackStats(path, from, to, changes); entry.append(path, changes); @@ -291,12 +291,12 @@ class JournalDiffLoader implements DiffC }; } - private void trackStats(String path, + private void trackStats(Path path, RevisionVector from, RevisionVector to, String changes) { stats.numDiffEntries++; - stats.keyMemory += new StringValue(path).getMemory(); + stats.keyMemory += path.getMemory(); stats.keyMemory += from.getMemory(); stats.keyMemory += to.getMemory(); stats.valueMemory += new StringValue(changes).getMemory(); Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/JournalEntry.java Wed Apr 10 11:13:19 2019 @@ -26,6 +26,7 @@ import java.util.Set; import java.util.function.Consumer; import com.google.common.collect.AbstractIterator; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -45,8 +46,6 @@ import org.slf4j.LoggerFactory; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH; -import static org.apache.jackrabbit.oak.commons.PathUtils.concat; import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL; /** @@ -128,7 +127,7 @@ public final class JournalEntry extends static void applyTo(@NotNull Iterable<String> changedPaths, @NotNull DiffCache diffCache, - @NotNull String path, + @NotNull Path path, @NotNull RevisionVector from, @NotNull RevisionVector to) throws IOException { LOG.debug("applyTo: starting for {} from {} to {}", path, from, to); @@ -206,12 +205,14 @@ public final class JournalEntry extends LOG.debug("applyTo: done. totalCnt: {}, deDuplicatedCnt: {}", totalCnt, deDuplicatedCnt); } - private static boolean inScope(TreeNode node, String path) { - if (PathUtils.denotesRoot(path)) { + private static boolean inScope(TreeNode node, Path path) { + if (path.isRoot()) { return true; } - String p = node.getPath(); - return p.startsWith(path) && (p.length() == path.length() || p.charAt(path.length()) == '/'); + Path p = node.getPath(); + int depthDiff = p.getDepth() - path.getDepth(); + return depthDiff >= 0 + && Iterables.elementsEqual(path.elements(), p.getAncestor(depthDiff).elements()); } /** @@ -238,7 +239,7 @@ public final class JournalEntry extends @NotNull Revision to, @NotNull DocumentStore store) throws IOException { - return fillExternalChanges(externalChanges, invalidate, ROOT_PATH, + return fillExternalChanges(externalChanges, invalidate, Path.ROOT, from, to, store, entry -> {}, null, null); } @@ -270,7 +271,7 @@ public final class JournalEntry extends */ static int fillExternalChanges(@NotNull StringSort externalChanges, @NotNull StringSort invalidate, - @NotNull String path, + @NotNull Path path, @NotNull Revision from, @NotNull Revision to, @NotNull DocumentStore store, @@ -343,7 +344,7 @@ public final class JournalEntry extends private static void fillFromJournalEntry(@NotNull StringSort externalChanges, @NotNull StringSort invalidate, - @NotNull String path, + @NotNull Path path, @Nullable ChangeSetBuilder changeSetBuilder, @Nullable JournalPropertyHandler journalPropertyHandler, @NotNull JournalEntry d, @@ -365,9 +366,9 @@ public final class JournalEntry extends return Long.parseLong(parts[1], 16); } - void modified(String path) { + void modified(Path path) { TreeNode node = getChanges(); - for (String name : PathUtils.elements(path)) { + for (String name : path.elements()) { if (node.get(name) == null) { numChangedNodes++; } @@ -375,8 +376,8 @@ public final class JournalEntry extends } } - void modified(Iterable<String> paths) { - for (String p : paths) { + void modified(Iterable<Path> paths) { + for (Path p : paths) { modified(p); } } @@ -489,11 +490,11 @@ public final class JournalEntry extends * @throws IOException if an exception occurs while adding a path to * {@code sort}. In this case only some paths may have been added. */ - void addTo(final StringSort sort, String path) throws IOException { + void addTo(final StringSort sort, Path path) throws IOException { TraversingVisitor v = new TraversingVisitor() { @Override - public void node(TreeNode node, String p) throws IOException { - sort.add(p); + public void node(TreeNode node, Path p) throws IOException { + sort.add(p.toString()); } }; TreeNode n = getNode(path); @@ -538,12 +539,12 @@ public final class JournalEntry extends TraversingVisitor v = new TraversingVisitor() { @Override - public void node(TreeNode node, String path) throws IOException { - sort.add(path); + public void node(TreeNode node, Path path) throws IOException { + sort.add(path.toString()); } }; for (JournalEntry e : getInvalidateOnly()) { - e.getChanges().accept(v, "/"); + e.getChanges().accept(v, Path.ROOT); } } @@ -613,9 +614,9 @@ public final class JournalEntry extends } @Nullable - private TreeNode getNode(String path) { + private TreeNode getNode(Path path) { TreeNode node = getChanges(); - for (String name : PathUtils.elements(path)) { + for (String name : path.elements()) { node = node.get(name); if (node == null) { return null; @@ -692,23 +693,15 @@ public final class JournalEntry extends return n; } - private String getPath() { - return buildPath(new StringBuilder()).toString(); - } - - private StringBuilder buildPath(StringBuilder sb) { + private Path getPath() { + Path p; if (parent != null) { - parent.buildPath(sb); - if (parent.parent != null) { - // only add slash if parent is not the root - sb.append("/"); - } + p = new Path(parent.getPath(), name); } else { // this is the root - sb.append("/"); + p = Path.ROOT; } - sb.append(name); - return sb; + return p; } void parse(JsopReader reader) { @@ -741,10 +734,10 @@ public final class JournalEntry extends return children.get(name); } - void accept(TraversingVisitor visitor, String path) throws IOException { + void accept(TraversingVisitor visitor, Path path) throws IOException { visitor.node(this, path); for (Map.Entry<String, TreeNode> entry : children.entrySet()) { - entry.getValue().accept(visitor, concat(path, entry.getKey())); + entry.getValue().accept(visitor, new Path(path, entry.getKey())); } } @@ -773,7 +766,7 @@ public final class JournalEntry extends private interface TraversingVisitor { - void node(TreeNode node, String path) throws IOException; + void node(TreeNode node, Path path) throws IOException; } private interface MapFactory { Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevRecoveryAgent.java Wed Apr 10 11:13:19 2019 @@ -22,7 +22,6 @@ import static com.google.common.collect. import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.filterKeys; import static java.util.Collections.singletonList; -import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH; import static org.apache.jackrabbit.oak.plugins.document.Collection.JOURNAL; import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES; import static org.apache.jackrabbit.oak.plugins.document.util.Utils.PROPERTY_OR_DELETED; @@ -40,7 +39,6 @@ import com.google.common.base.Supplier; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; -import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.plugins.document.util.MapFactory; import org.apache.jackrabbit.oak.plugins.document.util.Utils; import org.apache.jackrabbit.oak.stats.Clock; @@ -239,7 +237,7 @@ public class LastRevRecoveryAgent { final NodeDocumentSweeper sweeper = new NodeDocumentSweeper(context, true); sweeper.sweep(suspects, new NodeDocumentSweepListener() { @Override - public void sweepUpdate(Map<String, UpdateOp> updates) + public void sweepUpdate(Map<Path, UpdateOp> updates) throws DocumentStoreException { if (dryRun) { log.info("Dry run of sweeper identified [{}] documents for " + @@ -276,7 +274,7 @@ public class LastRevRecoveryAgent { UnsavedModifications unsavedParents = new UnsavedModifications(); //Map of known last rev of checked paths - Map<String, Revision> knownLastRevOrModification = MapFactory.getInstance().create(); + Map<Path, Revision> knownLastRevOrModification = MapFactory.getInstance().create(); final JournalEntry changes = JOURNAL.newDocument(store); long count = 0; @@ -308,19 +306,19 @@ public class LastRevRecoveryAgent { //2. Update lastRev for parent paths aka rollup if (lastRevForParents != null) { - String path = doc.getPath(); + Path path = doc.getPath(); changes.modified(path); // track all changes while (true) { - if (PathUtils.denotesRoot(path)) { + path = path.getParent(); + if (path == null) { break; } - path = PathUtils.getParentPath(path); unsavedParents.put(path, lastRevForParents); } } } - for (String parentPath : unsavedParents.getPaths()) { + for (Path parentPath : unsavedParents.getPaths()) { Revision calcLastRev = unsavedParents.get(parentPath); Revision knownLastRev = knownLastRevOrModification.get(parentPath); if (knownLastRev == null) { @@ -348,11 +346,11 @@ public class LastRevRecoveryAgent { } if (sweepRev.get() != null) { - unsaved.put(ROOT_PATH, sweepRev.get()); + unsaved.put(Path.ROOT, sweepRev.get()); } // take the root's lastRev - final Revision lastRootRev = unsaved.get(ROOT_PATH); + final Revision lastRootRev = unsaved.get(Path.ROOT); //Note the size before persist as persist operation //would empty the internal state Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LastRevTracker.java Wed Apr 10 11:13:19 2019 @@ -27,5 +27,5 @@ public interface LastRevTracker { * * @param path the path of the document to update. */ - public void track(String path); + public void track(Path path); } Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LocalDiffCache.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LocalDiffCache.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LocalDiffCache.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/LocalDiffCache.java Wed Apr 10 11:13:19 2019 @@ -58,7 +58,7 @@ public class LocalDiffCache extends Diff @Override public String getChanges(@NotNull RevisionVector from, @NotNull RevisionVector to, - @NotNull String path, + @NotNull Path path, @Nullable Loader loader) { RevisionsKey key = new RevisionsKey(from, to); Diff diff = diffCache.getIfPresent(key); @@ -78,14 +78,14 @@ public class LocalDiffCache extends Diff final @NotNull RevisionVector to, boolean local /*ignored*/) { return new Entry() { - private final Map<String, String> changesPerPath = Maps.newHashMap(); + private final Map<Path, String> changesPerPath = Maps.newHashMap(); private long size; @Override - public void append(@NotNull String path, @NotNull String changes) { + public void append(@NotNull Path path, @NotNull String changes) { if (exceedsSize()){ return; } - size += size(path) + size(changes); + size += path.getMemory() + size(changes); changesPerPath.put(path, changes); } @@ -117,16 +117,16 @@ public class LocalDiffCache extends Diff public static final class Diff implements CacheValue { - private final Map<String, String> changes; + private final Map<Path, String> changes; private long memory; - public Diff(Map<String, String> changes, long memory) { + public Diff(Map<Path, String> changes, long memory) { this.changes = changes; this.memory = memory; } public static Diff fromString(String value) { - Map<String, String> map = Maps.newHashMap(); + Map<Path, String> map = Maps.newHashMap(); JsopReader reader = new JsopTokenizer(value); while (true) { if (reader.matches(JsopReader.END)) { @@ -135,7 +135,7 @@ public class LocalDiffCache extends Diff String k = reader.readString(); reader.read(':'); String v = reader.readString(); - map.put(k, v); + map.put(Path.fromString(k), v); if (reader.matches(JsopReader.END)) { break; } @@ -146,14 +146,14 @@ public class LocalDiffCache extends Diff public String asString(){ JsopBuilder builder = new JsopBuilder(); - for (Map.Entry<String, String> entry : changes.entrySet()) { - builder.key(entry.getKey()); + for (Map.Entry<Path, String> entry : changes.entrySet()) { + builder.key(entry.getKey().toString()); builder.value(entry.getValue()); } return builder.toString(); } - public Map<String, String> getChanges() { + public Map<Path, String> getChanges() { return Collections.unmodifiableMap(changes); } @@ -161,8 +161,8 @@ public class LocalDiffCache extends Diff public int getMemory() { if (memory == 0) { long m = 0; - for (Map.Entry<String, String> e : changes.entrySet()){ - m += size(e.getKey()) + size(e.getValue()); + for (Map.Entry<Path, String> e : changes.entrySet()){ + m += e.getKey().getMemory() + size(e.getValue()); } memory = m; } @@ -174,7 +174,7 @@ public class LocalDiffCache extends Diff } } - String get(String path) { + String get(Path path) { return changes.get(path); } Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MemoryDiffCache.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MemoryDiffCache.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MemoryDiffCache.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MemoryDiffCache.java Wed Apr 10 11:13:19 2019 @@ -21,6 +21,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import org.apache.jackrabbit.oak.cache.CacheStats; +import org.apache.jackrabbit.oak.cache.CacheValue; import org.apache.jackrabbit.oak.plugins.document.util.StringValue; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -30,9 +31,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.google.common.base.Preconditions.checkNotNull; -import static org.apache.jackrabbit.oak.commons.PathUtils.denotesRoot; -import static org.apache.jackrabbit.oak.commons.PathUtils.getName; -import static org.apache.jackrabbit.oak.commons.PathUtils.getParentPath; /** * An in-memory diff cache implementation. @@ -53,7 +51,7 @@ public class MemoryDiffCache extends Dif * * Key: PathRev, value: StringValue */ - protected final Cache<PathRev, StringValue> diffCache; + protected final Cache<CacheValue, StringValue> diffCache; protected final CacheStats diffCacheStats; @@ -67,9 +65,9 @@ public class MemoryDiffCache extends Dif @Override public String getChanges(@NotNull final RevisionVector from, @NotNull final RevisionVector to, - @NotNull final String path, + @NotNull final Path path, @Nullable final Loader loader) { - PathRev key = diffCacheKey(path, from, to); + Key key = new Key(path, from, to); StringValue diff; if (loader == null) { diff = diffCache.getIfPresent(key); @@ -121,8 +119,8 @@ public class MemoryDiffCache extends Dif } @Override - public void append(@NotNull String path, @NotNull String changes) { - PathRev key = diffCacheKey(path, from, to); + public void append(@NotNull Path path, @NotNull String changes) { + Key key = new Key(path, from, to); if (changes.length() > CACHE_VALUE_LIMIT) { LOG.warn("Not caching entry for {} from {} to {}. Length of changes is {}.", path, from, to, changes.length()); @@ -138,12 +136,6 @@ public class MemoryDiffCache extends Dif } } - private static PathRev diffCacheKey(@NotNull String path, - @NotNull RevisionVector from, - @NotNull RevisionVector to) { - return new PathRev(from + path, to); - } - /** * Returns {@code true} if it can be inferred from cache entries on * ancestors of the given {@code path} that the node was not changed between @@ -159,27 +151,28 @@ public class MemoryDiffCache extends Dif */ private boolean isUnchanged(@NotNull final RevisionVector from, @NotNull final RevisionVector to, - @NotNull final String path) { - return !denotesRoot(path) - && isChildUnchanged(from, to, getParentPath(path), getName(path)); + @NotNull final Path path) { + Path parent = path.getParent(); + return parent != null + && isChildUnchanged(from, to, parent, path.getName()); } private boolean isChildUnchanged(@NotNull final RevisionVector from, @NotNull final RevisionVector to, - @NotNull final String parent, + @NotNull final Path parent, @NotNull final String name) { - PathRev parentKey = diffCacheKey(parent, from, to); + Key parentKey = new Key(parent, from, to); StringValue parentCachedEntry = diffCache.getIfPresent(parentKey); boolean unchanged; if (parentCachedEntry == null) { - if (denotesRoot(parent)) { + if (parent.getParent() == null) { // reached root and we don't know whether name // changed between from and to unchanged = false; } else { // recurse down unchanged = isChildUnchanged(from, to, - getParentPath(parent), getName(parent)); + parent.getParent(), parent.getName()); } } else { unchanged = parseJsopDiff(parentCachedEntry.asString(), new Diff() { @@ -201,4 +194,107 @@ public class MemoryDiffCache extends Dif } return unchanged; } + + public static final class Key implements CacheValue, Comparable<Key> { + + private final Path path; + + private final RevisionVector from; + + private final RevisionVector to; + + public Key(@NotNull Path path, + @NotNull RevisionVector from, + @NotNull RevisionVector to) { + this.path = checkNotNull(path); + this.from = checkNotNull(from); + this.to = checkNotNull(to); + } + + @NotNull + public Path getPath() { + return path; + } + + @NotNull + public RevisionVector getFromRevision() { + return from; + } + + @NotNull + public RevisionVector getToRevision() { + return to; + } + + public String asString() { + return toString(); + } + + public static Key fromString(@NotNull String s) { + int idx1 = s.indexOf('/'); + int idx2 = s.lastIndexOf('@'); + if (idx1 == -1 || idx2 == -1) { + throw new IllegalArgumentException("Malformed " + + MemoryDiffCache.Key.class.getSimpleName() + ": " + s); + } + return new Key( + Path.fromString(s.substring(idx1, idx2)), + RevisionVector.fromString(s.substring(0, idx1)), + RevisionVector.fromString(s.substring(idx2 + 1)) + ); + } + + @Override + public int getMemory() { + return 32 + path.getMemory() + from.getMemory() + to.getMemory(); + } + + @Override + public int compareTo(@NotNull MemoryDiffCache.Key other) { + if (this == other) { + return 0; + } + int compare = this.from.compareTo(other.from); + if (compare != 0) { + return compare; + } + compare = this.path.compareTo(other.path); + if (compare != 0) { + return compare; + } + return this.to.compareTo(other.to); + } + + @Override + public String toString() { + int dim = from.getDimensions() + to.getDimensions(); + StringBuilder sb = new StringBuilder(path.length() + (Revision.REV_STRING_APPROX_SIZE + 1) * dim); + from.toStringBuilder(sb); + path.toStringBuilder(sb).append('@'); + to.toStringBuilder(sb); + return sb.toString(); + } + + @Override + public int hashCode() { + int h = 17; + h = 37 * h + path.hashCode(); + h = 37 * h + from.hashCode(); + h = 37 * h + to.hashCode(); + return h; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } else if (obj instanceof Key) { + Key other = (Key) obj; + return from.equals(other.from) + && to.equals(other.to) + && path.equals(other.path); + } + return false; + } + } } Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/MissingLastRevSeeker.java Wed Apr 10 11:13:19 2019 @@ -39,8 +39,6 @@ import static org.apache.jackrabbit.oak. */ public class MissingLastRevSeeker { - protected final String ROOT_PATH = "/"; - private final DocumentStore store; protected final Clock clock; @@ -125,7 +123,7 @@ public class MissingLastRevSeeker { } public NodeDocument getRoot() { - return store.find(Collection.NODES, Utils.getIdFromPath(ROOT_PATH)); + return store.find(Collection.NODES, Utils.getIdFromPath(Path.ROOT)); } /** Added: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NamePathRev.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NamePathRev.java?rev=1857240&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NamePathRev.java (added) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NamePathRev.java Wed Apr 10 11:13:19 2019 @@ -0,0 +1,131 @@ +/* + * 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.document; + +import org.apache.jackrabbit.oak.cache.CacheValue; +import org.apache.jackrabbit.oak.commons.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * A cache key implementation, which is a combination of a name, path and a + * revision vector. + */ +public final class NamePathRev implements CacheValue, Comparable<NamePathRev> { + + private static final Logger LOG = LoggerFactory.getLogger(NamePathRev.class); + + @NotNull + private final String name; + + @NotNull + private final Path path; + + @NotNull + private final RevisionVector revision; + + public NamePathRev(@NotNull String name, + @NotNull Path path, + @NotNull RevisionVector revision) { + this.name = checkNotNull(name); + this.path = checkNotNull(path); + this.revision = checkNotNull(revision); + } + + @NotNull + public Path getPath() { + return path; + } + + @NotNull + public String getName() { + return name; + } + + @NotNull + public RevisionVector getRevision() { + return revision; + } + + @Override + public int getMemory() { + long size = 24L // shallow size + + path.getMemory() + + StringUtils.estimateMemoryUsage(name) + + revision.getMemory(); + if (size > Integer.MAX_VALUE) { + LOG.debug("Estimated memory footprint larger than Integer.MAX_VALUE: {}.", size); + size = Integer.MAX_VALUE; + } + return (int) size; + } + + //---------------------------< Comparable >--------------------------------- + + public int compareTo(@NotNull NamePathRev other) { + if (this == other) { + return 0; + } + int compare = this.name.compareTo(other.name); + if (compare != 0) { + return compare; + } + compare = this.path.compareTo(other.path); + if (compare != 0) { + return compare; + } + return this.revision.compareTo(other.revision); + } + + //----------------------------< Object >------------------------------------ + + @Override + public int hashCode() { + int h = 17; + h = 37 * h + name.hashCode(); + h = 37 * h + path.hashCode(); + h = 37 * h + revision.hashCode(); + return h; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } else if (obj instanceof NamePathRev) { + NamePathRev other = (NamePathRev) obj; + return revision.equals(other.revision) + && name.equals(other.name) + && path.equals(other.path); + } + return false; + } + + @Override + public String toString() { + int dim = revision.getDimensions(); + int len = path.length() + name.length(); + StringBuilder sb = new StringBuilder(len + (Revision.REV_STRING_APPROX_SIZE + 1) * dim); + sb.append(name); + path.toStringBuilder(sb).append('@'); + revision.toStringBuilder(sb); + return sb.toString(); + } +} Propchange: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NamePathRev.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocument.java Wed Apr 10 11:13:19 2019 @@ -249,6 +249,11 @@ public final class NodeDocument extends public static final String SD_MAX_REV_TIME_IN_SECS = "_sdMaxRevTime"; /** + * The path prefix for previous documents. + */ + private static final Path PREVIOUS_PREFIX = new Path("p"); + + /** * Return time in seconds with 5 second resolution * * @param timestamp time in millis to convert @@ -496,18 +501,17 @@ public final class NodeDocument extends * @return the path of the main document. */ @NotNull - public String getMainPath() { - String p = getPath(); + public Path getMainPath() { + String p = getPathString(); if (p.startsWith("p")) { p = PathUtils.getAncestorPath(p, 2); if (p.length() == 1) { - return "/"; + return Path.ROOT; } else { - return p.substring(1); + p = p.substring(1); } - } else { - return p; } + return Path.fromString(p); } /** @@ -647,7 +651,7 @@ public final class NodeDocument extends * @return the commit root path or <code>null</code>. */ @Nullable - public String getCommitRootPath(Revision revision) { + public Path getCommitRootPath(Revision revision) { String depth = getCommitRootDepth(revision); if (depth != null) { return getPathAtDepth(depth); @@ -917,7 +921,7 @@ public final class NodeDocument extends // deleted return null; } - String path = getPath(); + Path path = getPath(); List<PropertyState> props = Lists.newArrayList(); for (String key : keySet()) { if (!Utils.isPropertyName(key)) { @@ -1119,7 +1123,7 @@ public final class NodeDocument extends * @return if conflicting change in {@link #DELETED} property is allowed */ private boolean allowConflictingDeleteChange(UpdateOp op) { - String path = getPath(); + String path = getPathString(); if (!Utils.isHiddenPath(path)) { return false; } @@ -1255,7 +1259,7 @@ public final class NodeDocument extends if (revision == null) { return new PropertyHistory(this, property); } else { - final String mainPath = getMainPath(); + final Path mainPath = getMainPath(); // first try to lookup revision directly Map.Entry<Revision, Range> entry = getPreviousRanges().floorEntry(revision); if (entry != null) { @@ -1863,7 +1867,7 @@ public final class NodeDocument extends // main document may be stale, evict it from the cache if it is // older than one minute. We don't want to invalidate a document // too frequently if the document structure is really broken. - String path = getMainPath(); + Path path = getMainPath(); String id = Utils.getIdFromPath(path); NodeDocument doc = store.getIfCached(NODES, id); long now = Revision.getCurrentTimestamp(); @@ -1974,7 +1978,7 @@ public final class NodeDocument extends if (getLocalRevisions().containsKey(rev)) { return this; } - String commitRootPath; + Path commitRootPath; String depth = getLocalCommitRoot().get(rev); if (depth != null) { commitRootPath = getPathAtDepth(depth); @@ -2004,12 +2008,12 @@ public final class NodeDocument extends * integer. */ @NotNull - private String getPathAtDepth(@NotNull String depth) { + private Path getPathAtDepth(@NotNull String depth) { if (checkNotNull(depth).equals("0")) { - return "/"; + return Path.ROOT; } - String p = getPath(); - return PathUtils.getAncestorPath(p, PathUtils.getDepth(p) - Integer.parseInt(depth)); + Path p = getPath(); + return p.getAncestor(p.getDepth() - Integer.parseInt(depth)); } /** @@ -2173,7 +2177,13 @@ public final class NodeDocument extends return null; } - public String getPath() { + @NotNull + public Path getPath() { + return Path.fromString(getPathString()); + } + + @NotNull + private String getPathString() { String p = (String) get(PATH); if (p != null) { return p; Modified: jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweepListener.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweepListener.java?rev=1857240&r1=1857239&r2=1857240&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweepListener.java (original) +++ jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweepListener.java Wed Apr 10 11:13:19 2019 @@ -32,6 +32,6 @@ interface NodeDocumentSweepListener { * of the documents to update. * @throws DocumentStoreException if the operation fails. */ - void sweepUpdate(Map<String, UpdateOp> updates) throws DocumentStoreException; + void sweepUpdate(Map<Path, UpdateOp> updates) throws DocumentStoreException; }
