Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweeper.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweeper.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweeper.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/NodeDocumentSweeper.java
 Wed Apr 10 11:13:19 2019
@@ -137,10 +137,10 @@ final class NodeDocumentSweeper {
             return null;
         }
 
-        Iterable<Map.Entry<String, UpdateOp>> ops = sweepOperations(documents);
-        for (List<Map.Entry<String, UpdateOp>> batch : partition(ops, 
INVALIDATE_BATCH_SIZE)) {
-            Map<String, UpdateOp> updates = newHashMap();
-            for (Map.Entry<String, UpdateOp> entry : batch) {
+        Iterable<Map.Entry<Path, UpdateOp>> ops = sweepOperations(documents);
+        for (List<Map.Entry<Path, UpdateOp>> batch : partition(ops, 
INVALIDATE_BATCH_SIZE)) {
+            Map<Path, UpdateOp> updates = newHashMap();
+            for (Map.Entry<Path, UpdateOp> entry : batch) {
                 updates.put(entry.getKey(), entry.getValue());
             }
             listener.sweepUpdate(updates);
@@ -149,17 +149,17 @@ final class NodeDocumentSweeper {
         return head;
     }
 
-    private Iterable<Map.Entry<String, UpdateOp>> sweepOperations(
+    private Iterable<Map.Entry<Path, UpdateOp>> sweepOperations(
             final Iterable<NodeDocument> docs) {
         return filter(transform(docs,
-                new Function<NodeDocument, Map.Entry<String, UpdateOp>>() {
+                new Function<NodeDocument, Map.Entry<Path, UpdateOp>>() {
             @Override
-            public Map.Entry<String, UpdateOp> apply(NodeDocument doc) {
+            public Map.Entry<Path, UpdateOp> apply(NodeDocument doc) {
                 return immutableEntry(doc.getPath(), sweepOne(doc));
             }
-        }), new Predicate<Map.Entry<String, UpdateOp>>() {
+        }), new Predicate<Map.Entry<Path, UpdateOp>>() {
             @Override
-            public boolean apply(Map.Entry<String, UpdateOp> input) {
+            public boolean apply(Map.Entry<Path, UpdateOp> input) {
                 return input.getValue() != null;
             }
         });

Added: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Path.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Path.java?rev=1857240&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Path.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Path.java
 Wed Apr 10 11:13:19 2019
@@ -0,0 +1,368 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Objects;
+
+import org.apache.jackrabbit.oak.cache.CacheValue;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.commons.StringUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.collect.Iterables.elementsEqual;
+
+/**
+ * The {@code Path} class is closely modeled after the semantics of
+ * {@code PathUtils} in oak-commons. Corresponding methods in this class can
+ * be used as a replacement for the methods in {@code PathUtils} on {@code 
Path}
+ * objects.
+ */
+public final class Path implements CacheValue, Comparable<Path> {
+
+    public static final Path ROOT = new Path(null, "", "".hashCode());
+
+    @Nullable
+    private final Path parent;
+
+    @NotNull
+    private final String name;
+
+    private int hash;
+
+    private Path(@Nullable Path parent,
+                 @NotNull String name,
+                 int hash) {
+        this.parent = parent;
+        this.name = name;
+        this.hash = hash;
+    }
+
+    /**
+     * Creates a new {@code Path} from the given parent {@code Path}. The name
+     * of the new {@code Path} cannot be the empty {@code String}.
+     *
+     * @param parent the parent {@code Path}.
+     * @param name the name of the new {@code Path}.
+     * @throws IllegalArgumentException if the {@code name} is empty.
+     */
+    public Path(@NotNull Path parent, @NotNull String name) {
+        this(checkNotNull(parent), checkNotNull(name), -1);
+        checkArgument(!name.isEmpty(), "name cannot be the empty String");
+    }
+
+    /**
+     * Creates a relative path with a single name element. The name cannot be
+     * the empty {@code String}.
+     *
+     * @param name the name of the first path element.
+     * @throws IllegalArgumentException if the {@code name} is empty.
+     */
+    public Path(@NotNull String name) {
+        this(null, checkNotNull(name), -1);
+        checkArgument(!name.isEmpty(), "name cannot be the empty String");
+    }
+
+    /**
+     * Returns the name of this path. The {@link #ROOT} is the only path with
+     * an empty name. That is a String with length zero.
+     *
+     * @return the name of this path.
+     */
+    @NotNull
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns the names of the path elements with increasing {@link 
#getDepth()}
+     * starting at depth 1.
+     * 
+     * @return the names of the path elements.
+     */
+    @NotNull
+    public Iterable<String> elements() {
+        return elements(false);
+    }
+
+    /**
+     * Returns {@code true} if this is the {@link #ROOT} path; {@code false}
+     * otherwise.
+     *
+     * @return whether this is the {@link #ROOT} path.
+     */
+    public boolean isRoot() {
+        return name.isEmpty();
+    }
+
+    /**
+     * The parent of this path or {@code null} if this path does not have a
+     * parent. The {@link #ROOT} path and the first path element of a relative
+     * path do not have a parent.
+     *
+     * @return the parent of this path or {@code null} if this path does not
+     *      have a parent.
+     */
+    @Nullable
+    public Path getParent() {
+        return parent;
+    }
+
+    /**
+     * @return the number of characters of the {@code String} representation of
+     *  this path.
+     */
+    public int length() {
+        if (isRoot()) {
+            return 1;
+        }
+        int length = 0;
+        Path p = this;
+        while (p != null) {
+            length += p.name.length();
+            if (p.parent != null) {
+                length++;
+            }
+            p = p.parent;
+        }
+        return length;
+    }
+
+    /**
+     * The depth of this path. The {@link #ROOT} has a depth of 0. The path
+     * {@code /foo/bar} as well as {@code bar/baz} have depth 2.
+     *
+     * @return the depth of the path.
+     */
+    public int getDepth() {
+        return getNumberOfPathElements(false);
+    }
+
+    /**
+     * Get the nth ancestor of a path. The 1st ancestor is the parent path,
+     * 2nd ancestor the grandparent path, and so on...
+     * <p>
+     * If {@code nth <= 0}, then this path is returned.
+     *
+     * @param nth  indicates the ancestor level for which the path should be
+     *             calculated.
+     * @return the ancestor path
+     */
+    @NotNull
+    public Path getAncestor(int nth) {
+        Path p = this;
+        while (nth-- > 0 && p.parent != null) {
+            p = p.parent;
+        }
+        return p;
+    }
+
+    /**
+     * Return {@code true} if {@code this} path is an ancestor of the
+     * {@code other} path, otherwise {@code false}.
+     *
+     * @param other the other path.
+     * @return whether this path is an ancestor of the other path.
+     */
+    public boolean isAncestorOf(@NotNull Path other) {
+        checkNotNull(other);
+        int depthDiff = other.getDepth() - getDepth();
+        return depthDiff > 0
+                && elementsEqual(elements(true), 
other.getAncestor(depthDiff).elements(true));
+    }
+
+    /**
+     * @return {@code true} if this is an absolute path; {@code false} 
otherwise.
+     */
+    public boolean isAbsolute() {
+        Path p = this;
+        while (p.parent != null) {
+            p = p.parent;
+        }
+        return p.isRoot();
+    }
+
+    /**
+     * Creates a {@code Path} from a {@code String}.
+     *
+     * @param path the {@code String} to parse.
+     * @return the {@code Path} from the {@code String}.
+     * @throws IllegalArgumentException if the {@code path} is the empty
+     *      {@code String}.
+     */
+    @NotNull
+    public static Path fromString(@NotNull String path) throws 
IllegalArgumentException {
+        checkNotNull(path);
+        Path p = null;
+        if (PathUtils.isAbsolute(path)) {
+            p = ROOT;
+        }
+        for (String name : PathUtils.elements(path)) {
+            name = StringCache.get(name);
+            if (p == null) {
+                p = new Path(name);
+            } else {
+                p = new Path(p, StringCache.get(name));
+            }
+        }
+        if (p == null) {
+            throw new IllegalArgumentException("path must not be empty");
+        }
+        return p;
+    }
+
+    /**
+     * Appends the {@code String} representation of this {@code Path} to the
+     * passed {@code StringBuilder}. See also {@link #toString()}.
+     *
+     * @param sb the {@code StringBuilder} this {@code Path} is appended to.
+     * @return the passed {@code StringBuilder}.
+     */
+    @NotNull
+    public StringBuilder toStringBuilder(@NotNull StringBuilder sb) {
+        if (isRoot()) {
+            sb.append('/');
+        } else {
+            buildPath(sb);
+        }
+        return sb;
+    }
+
+    @Override
+    public int getMemory() {
+        int memory = 0;
+        Path p = this;
+        while (p.parent != null) {
+            memory += 24; // shallow size
+            memory += StringUtils.estimateMemoryUsage(name);
+            p = p.parent;
+        }
+        return memory;
+    }
+
+    @Override
+    public int compareTo(@NotNull Path other) {
+        if (this == other) {
+            return 0;
+        }
+        Path t = this;
+        int off = t.getNumberOfPathElements(true) -
+                checkNotNull(other).getNumberOfPathElements(true);
+        int corrected = off;
+        while (corrected > 0) {
+            t = t.parent;
+            corrected--;
+        }
+        while (corrected < 0) {
+            other = other.parent;
+            corrected++;
+        }
+        int cp = comparePath(t, other);
+        if (cp != 0) {
+            return cp;
+        }
+        return Integer.signum(off);
+    }
+
+    @Override
+    public String toString() {
+        if (isRoot()) {
+            return "/";
+        } else {
+            return buildPath(new StringBuilder(length())).toString();
+        }
+    }
+
+    @Override
+    public int hashCode() {
+        int h = hash;
+        if (h == -1 && parent != null) {
+            h = 17;
+            h = 37 * h + parent.hashCode();
+            h = 37 * h + name.hashCode();
+            hash = h;
+        }
+        return h;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        } else if (obj instanceof Path) {
+            Path other = (Path) obj;
+            return this.name.equals(other.name)
+                    && Objects.equals(this.parent, other.parent);
+        }
+        return false;
+    }
+
+    //-------------------------< internal 
>-------------------------------------
+
+    private Iterable<String> elements(boolean withRoot) {
+        int size = getNumberOfPathElements(withRoot);
+        String[] elements = new String[size];
+        Path p = this;
+        for (int i = size - 1; p != null; i--) {
+            if (withRoot || !p.isRoot()) {
+                elements[i] = p.name;
+            }
+            p = p.parent;
+        }
+        return Arrays.asList(elements);
+    }
+
+    private StringBuilder buildPath(StringBuilder sb) {
+        if (parent != null) {
+            parent.buildPath(sb).append("/");
+        }
+        sb.append(name);
+        return sb;
+    }
+
+    /**
+     * Returns the number of path elements. Depending on {@code withRoot} the
+     * root of an absolute path is also taken into account.
+     *
+     * @param withRoot whether the root of an absolute path is also counted.
+     * @return the number of path elements.
+     */
+    private int getNumberOfPathElements(boolean withRoot) {
+        int depth = 0;
+        for (Path p = this; p != null; p = p.parent) {
+            if (withRoot || !p.isRoot()) {
+                depth++;
+            }
+        }
+        return depth;
+    }
+
+    private static int comparePath(Path a, Path b) {
+        if (a.parent != b.parent) {
+            int cp = comparePath(a.parent, b.parent);
+            if (cp != 0) {
+                return cp;
+            }
+        }
+        return a.name.compareTo(b.name);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Path.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathComparator.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathComparator.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathComparator.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathComparator.java
 Wed Apr 10 11:13:19 2019
@@ -24,25 +24,25 @@ import java.util.Comparator;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 
 /**
- * Implements a comparator, which sorts path string according to 1) their
- * depth (highest first) and 2) the path string itself.
+ * Implements a comparator, which sorts paths according to 1) their depth
+ * (highest first) and 2) the paths natural ordering.
  */
-public class PathComparator implements Comparator<String>, Serializable {
+public class PathComparator implements Comparator<Path>, Serializable {
 
     private static final long serialVersionUID = -1523171906146067782L;
 
-    public static final Comparator<String> INSTANCE = new PathComparator();
+    public static final Comparator<Path> INSTANCE = new PathComparator();
 
     private PathComparator() {
     }
 
     @Override
-    public int compare(String o1, String o2) {
-        int d1 = Utils.pathDepth(o1);
-        int d2 = Utils.pathDepth(o2);
+    public int compare(Path p1, Path p2) {
+        int d1 = p1.getDepth();
+        int d2 = p2.getDepth();
         if (d1 != d2) {
             return Integer.signum(d2 - d1);
         }
-        return o1.compareTo(o2);
+        return p1.compareTo(p2);
     }
 }

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PathRev.java
 Wed Apr 10 11:13:19 2019
@@ -19,7 +19,6 @@
 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;
@@ -27,31 +26,37 @@ import org.slf4j.LoggerFactory;
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
- * A cache key implementation, which is a combination of a path string and a
- * revision.
+ * A cache key implementation, which is a combination of a path and a revision
+ * vector.
  */
-public final class PathRev implements CacheValue {
+public final class PathRev implements CacheValue, Comparable<PathRev> {
 
     private static final Logger LOG = LoggerFactory.getLogger(PathRev.class);
 
-    private final String path;
+    private final Path path;
 
     private final RevisionVector revision;
 
-    public PathRev(@NotNull String path, @NotNull RevisionVector revision) {
+    private int hash;
+
+    public PathRev(@NotNull Path path, @NotNull RevisionVector revision) {
         this.path = checkNotNull(path);
         this.revision = checkNotNull(revision);
     }
 
-    public String getPath() {
+    public Path getPath() {
         return path;
     }
 
+    public RevisionVector getRevision() {
+        return revision;
+    }
+
     @Override
     public int getMemory() {
-        long size =  24                                               // 
shallow size
-                       + (long)StringUtils.estimateMemoryUsage(path)  // path
-                       + revision.getMemory();                        // 
revision
+        long size =  24L                          // shallow size
+                       + path.getMemory()         // path
+                       + revision.getMemory();    // revision
         if (size > Integer.MAX_VALUE) {
             LOG.debug("Estimated memory footprint larger than 
Integer.MAX_VALUE: {}.", size);
             size = Integer.MAX_VALUE;
@@ -59,12 +64,31 @@ public final class PathRev implements Ca
         return (int) size;
     }
 
-    //----------------------------< Object 
>------------------------------------
+    //---------------------------< Comparable 
>---------------------------------
+
+    public int compareTo(@NotNull PathRev other) {
+        if (this == other) {
+            return 0;
+        }
+        int compare = this.path.compareTo(other.path);
+        if (compare != 0) {
+            return compare;
+        }
+        return this.revision.compareTo(other.revision);
+    }
 
+    //----------------------------< Object 
>------------------------------------
 
     @Override
     public int hashCode() {
-        return path.hashCode() ^ revision.hashCode();
+        int h = this.hash;
+        if (h == 0) {
+            h = 17;
+            h = 37 * h + path.hashCode();
+            h = 37 * h + revision.hashCode();
+            this.hash = h;
+        }
+        return h;
     }
 
     @Override
@@ -88,25 +112,4 @@ public final class PathRev implements Ca
         return sb.toString();
     }
 
-    public String asString() {
-        return toString();
-    }
-
-    public static PathRev fromString(String s) {
-        int index = s.lastIndexOf('@');
-        return new PathRev(s.substring(0, index),
-                RevisionVector.fromString(s.substring(index + 1)));
-    }
-
-    public int compareTo(PathRev b) {
-        if (this == b) {
-            return 0;
-        }
-        int compare = path.compareTo(b.path);
-        if (compare == 0) {
-            compare = revision.compareTo(b.revision);
-        }
-        return compare;
-    }
-    
 }

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PropertyHistory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PropertyHistory.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PropertyHistory.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/PropertyHistory.java
 Wed Apr 10 11:13:19 2019
@@ -47,7 +47,7 @@ class PropertyHistory implements Iterabl
     private final NodeDocument doc;
     private final String property;
     // path of the main document
-    private final String mainPath;
+    private final Path mainPath;
 
     public PropertyHistory(@NotNull NodeDocument doc,
                            @NotNull String property) {

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ResetDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ResetDiff.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ResetDiff.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ResetDiff.java
 Wed Apr 10 11:13:19 2019
@@ -19,7 +19,6 @@ package org.apache.jackrabbit.oak.plugin
 import java.util.Map;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
@@ -38,19 +37,19 @@ class ResetDiff implements NodeStateDiff
 
     private final ResetDiff parent;
     private final Revision revision;
-    private final String path;
-    private final Map<String, UpdateOp> operations;
+    private final Path path;
+    private final Map<Path, UpdateOp> operations;
     private UpdateOp update;
 
     ResetDiff(@NotNull Revision revision,
-              @NotNull Map<String, UpdateOp> operations) {
-        this(null, revision, "/", operations);
+              @NotNull Map<Path, UpdateOp> operations) {
+        this(null, revision, Path.ROOT, operations);
     }
 
     private ResetDiff(@Nullable ResetDiff parent,
                       @NotNull Revision revision,
-                      @NotNull String path,
-                      @NotNull Map<String, UpdateOp> operations) {
+                      @NotNull Path path,
+                      @NotNull Map<Path, UpdateOp> operations) {
         this.parent = parent;
         this.revision = checkNotNull(revision);
         this.path = checkNotNull(path);
@@ -78,7 +77,7 @@ class ResetDiff implements NodeStateDiff
     @Override
     public boolean childNodeAdded(String name, NodeState after) {
         NodeDocument.removeCommitRoot(getUpdateOp(), revision);
-        String p = PathUtils.concat(path, name);
+        Path p = new Path(path, name);
         ResetDiff diff = new ResetDiff(this, revision, p, operations);
         UpdateOp op = diff.getUpdateOp();
         NodeDocument.removeDeleted(op, revision);
@@ -94,20 +93,20 @@ class ResetDiff implements NodeStateDiff
     public boolean childNodeChanged(String name,
                                     NodeState before,
                                     NodeState after) {
-        String p = PathUtils.concat(path, name);
+        Path p = new Path(path, name);
         return after.compareAgainstBaseState(before,
                 new ResetDiff(this, revision, p, operations));
     }
 
     @Override
     public boolean childNodeDeleted(String name, NodeState before) {
-        String p = PathUtils.concat(path, name);
+        Path p = new Path(path, name);
         ResetDiff diff = new ResetDiff(this, revision, p, operations);
         NodeDocument.removeDeleted(diff.getUpdateOp(), revision);
         return MISSING_NODE.compareAgainstBaseState(before, diff);
     }
 
-    Map<String, UpdateOp> getOperations() {
+    Map<Path, UpdateOp> getOperations() {
         return operations;
     }
 

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitDocumentCleanUp.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitDocumentCleanUp.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitDocumentCleanUp.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitDocumentCleanUp.java
 Wed Apr 10 11:13:19 2019
@@ -114,11 +114,9 @@ public class SplitDocumentCleanUp implem
             return;
         }
 
-        String splitDocPath = splitDoc.getPath();
-        int slashIdx = splitDocPath.lastIndexOf('/');
-        int height = Integer.parseInt(splitDocPath.substring(slashIdx + 1));
-        Revision rev = Revision.fromString(
-                splitDocPath.substring(splitDocPath.lastIndexOf('/', slashIdx 
- 1) + 1, slashIdx));
+        Path splitDocPath = splitDoc.getPath();
+        int height = Integer.parseInt(splitDocPath.getName());
+        Revision rev = Revision.fromString(splitDocPath.getParent().getName());
         doc = doc.findPrevReferencingDoc(rev, height);
         if (doc == null) {
             LOG.warn("Split document {} for path {} not referenced anymore. 
Main document is {}",

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitOperations.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitOperations.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitOperations.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/SplitOperations.java
 Wed Apr 10 11:13:19 2019
@@ -77,7 +77,7 @@ class SplitOperations {
     private static final DocumentStore STORE = new MemoryDocumentStore();
 
     private final NodeDocument doc;
-    private final String path;
+    private final Path path;
     private final String id;
     private final Revision headRevision;
     private final RevisionContext context;
@@ -314,11 +314,11 @@ class SplitOperations {
                 if (h == null || l == null) {
                     throw new IllegalStateException();
                 }
-                String prevPath = Utils.getPreviousPathFor(path, h, 
entry.getKey() + 1);
+                Path prevPath = Utils.getPreviousPathFor(path, h, 
entry.getKey() + 1);
                 String prevId = Utils.getIdFromPath(prevPath);
                 UpdateOp intermediate = new UpdateOp(prevId, true);
-                if (Utils.isLongPath(prevPath)) {
-                    intermediate.set(NodeDocument.PATH, prevPath);
+                if (Utils.isIdFromLongPath(prevId)) {
+                    intermediate.set(NodeDocument.PATH, prevPath.toString());
                 }
                 setPrevious(main, new Range(h, l, entry.getKey() + 1));
                 for (Range r : entry.getValue()) {
@@ -351,10 +351,11 @@ class SplitOperations {
             // move to another document
             main = new UpdateOp(id, false);
             setPrevious(main, new Range(high, low, 0));
-            String oldPath = Utils.getPreviousPathFor(path, high, 0);
-            UpdateOp old = new UpdateOp(Utils.getIdFromPath(oldPath), true);
-            if (Utils.isLongPath(oldPath)) {
-                old.set(NodeDocument.PATH, oldPath);
+            Path oldPath = Utils.getPreviousPathFor(path, high, 0);
+            String oldId = Utils.getIdFromPath(oldPath);
+            UpdateOp old = new UpdateOp(oldId, true);
+            if (Utils.isIdFromLongPath(oldId)) {
+                old.set(NodeDocument.PATH, oldPath.toString());
             }
             for (String property : committedChanges.keySet()) {
                 NavigableMap<Revision, String> splitMap = 
committedChanges.get(property);

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/StringCache.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/StringCache.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/StringCache.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/StringCache.java
 Wed Apr 10 11:13:19 2019
@@ -16,13 +16,13 @@
  */
 package org.apache.jackrabbit.oak.plugins.document;
 
+import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
 import org.apache.jackrabbit.oak.spi.version.VersionConstants;
 
-import com.google.common.collect.ImmutableMap;
 import org.apache.jackrabbit.oak.spi.state.ConflictType;
 
 /**
@@ -139,11 +139,11 @@ public final class StringCache {
     }
 
     private static Map<String, String> createStringMap(String... strings) {
-        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+        Map<String, String> map = new HashMap<>();
         for (String string : strings) {
-            builder.put(string, string);
+            map.put(string, string);
         }
-        return builder.build();
+        return map;
     }
 
     // must be a power of 2

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/TieredDiffCache.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/TieredDiffCache.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/TieredDiffCache.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/TieredDiffCache.java
 Wed Apr 10 11:13:19 2019
@@ -53,7 +53,7 @@ class TieredDiffCache extends DiffCache
     @Override
     public String getChanges(@NotNull RevisionVector from,
                              @NotNull RevisionVector to,
-                             @NotNull String path,
+                             @NotNull Path path,
                              @Nullable Loader loader) {
         // do not check local cache when changes are external
         if (isLocalChange(from, to, clusterId)) {

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnmergedBranches.java
 Wed Apr 10 11:13:19 2019
@@ -71,7 +71,7 @@ class UnmergedBranches {
         if (!initialized.compareAndSet(false, true)) {
             throw new IllegalStateException("already initialized");
         }
-        NodeDocument doc = store.find(Collection.NODES, 
Utils.getIdFromPath("/"));
+        NodeDocument doc = store.find(Collection.NODES, 
Utils.getIdFromPath(Path.ROOT));
         if (doc == null) {
             return;
         }

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/UnsavedModifications.java
 Wed Apr 10 11:13:19 2019
@@ -24,7 +24,6 @@ import java.util.concurrent.ConcurrentMa
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.locks.Lock;
 
-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.jetbrains.annotations.NotNull;
@@ -41,7 +40,6 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
 import static 
org.apache.jackrabbit.oak.plugins.document.Collection.CLUSTER_NODES;
 import static org.apache.jackrabbit.oak.plugins.document.Collection.NODES;
 import static org.apache.jackrabbit.oak.plugins.document.Commit.createUpdateOp;
@@ -59,7 +57,7 @@ class UnsavedModifications {
      */
     static final int BACKGROUND_MULTI_UPDATE_LIMIT = 100;
 
-    private final ConcurrentMap<String, Revision> map = 
MapFactory.getInstance().create();
+    private final ConcurrentMap<Path, Revision> map = 
MapFactory.getInstance().create();
 
     /**
      * Puts a revision for the given path. The revision for the given path is
@@ -72,7 +70,7 @@ class UnsavedModifications {
      *          was none or the current revision is newer.
      */
     @Nullable
-    public Revision put(@NotNull String path, @NotNull Revision revision) {
+    public Revision put(@NotNull Path path, @NotNull Revision revision) {
         checkNotNull(path);
         checkNotNull(revision);
         for (;;) {
@@ -95,12 +93,12 @@ class UnsavedModifications {
     }
 
     @Nullable
-    public Revision get(String path) {
+    public Revision get(Path path) {
         return map.get(path);
     }
 
     @NotNull
-    public Collection<String> getPaths() {
+    public Collection<Path> getPaths() {
         return map.keySet();
     }
 
@@ -112,19 +110,19 @@ class UnsavedModifications {
      * @return matching paths with pending modifications.
      */
     @NotNull
-    public Iterable<String> getPaths(@NotNull final Revision start) {
+    public Iterable<Path> getPaths(@NotNull final Revision start) {
         if (map.isEmpty()) {
             return Collections.emptyList();
         } else {
             return Iterables.transform(Iterables.filter(map.entrySet(),
-                    new Predicate<Map.Entry<String, Revision>>() {
+                    new Predicate<Map.Entry<Path, Revision>>() {
                 @Override
-                public boolean apply(Map.Entry<String, Revision> input) {
+                public boolean apply(Map.Entry<Path, Revision> input) {
                     return start.compareRevisionTime(input.getValue()) < 1;
                 }
-            }), new Function<Map.Entry<String, Revision>, String>() {
+            }), new Function<Map.Entry<Path, Revision>, Path>() {
                 @Override
-                public String apply(Map.Entry<String, Revision> input) {
+                public Path apply(Map.Entry<Path, Revision> input) {
                     return input.getKey();
                 }
             });
@@ -163,7 +161,7 @@ class UnsavedModifications {
         stats.lock = sw.elapsed(TimeUnit.MILLISECONDS);
         sw.reset().start();
         Revision sweepRev;
-        Map<String, Revision> pending;
+        Map<Path, Revision> pending;
         try {
             snapshot.acquiring(getMostRecentRevision());
             pending = Maps.newTreeMap(PathComparator.INSTANCE);
@@ -174,23 +172,23 @@ class UnsavedModifications {
         }
         stats.num = pending.size();
         List<UpdateOp> updates = Lists.newArrayList();
-        Map<String, Revision> pathToRevision = Maps.newHashMap();
-        for (Iterable<Map.Entry<String, Revision>> batch : Iterables.partition(
+        Map<Path, Revision> pathToRevision = Maps.newHashMap();
+        for (Iterable<Map.Entry<Path, Revision>> batch : Iterables.partition(
                 pending.entrySet(), BACKGROUND_MULTI_UPDATE_LIMIT)) {
-            for (Map.Entry<String, Revision> entry : batch) {
-                String p = entry.getKey();
+            for (Map.Entry<Path, Revision> entry : batch) {
+                Path p = entry.getKey();
                 Revision r = entry.getValue();
-                if (PathUtils.denotesRoot(entry.getKey())) {
+                if (p.isRoot()) {
                     // update root individually at the end
                     continue;
                 }
                 updates.add(newUpdateOp(p, r));
-                pathToRevision.put(p, r);
+                pathToRevision.put(entry.getKey(), r);
             }
             if (!updates.isEmpty()) {
                 store.createOrUpdate(NODES, updates);
                 stats.calls++;
-                for (Map.Entry<String, Revision> entry : 
pathToRevision.entrySet()) {
+                for (Map.Entry<Path, Revision> entry : 
pathToRevision.entrySet()) {
                     map.remove(entry.getKey(), entry.getValue());
                     LOG.debug("Updated _lastRev to {} on {}", 
entry.getValue(), entry.getKey());
                 }
@@ -200,9 +198,9 @@ class UnsavedModifications {
             }
         }
         // finally update remaining root document
-        Revision rootRev = pending.get(ROOT_PATH);
+        Revision rootRev = pending.get(Path.ROOT);
         if (rootRev != null) {
-            UpdateOp rootUpdate = newUpdateOp(ROOT_PATH, rootRev);
+            UpdateOp rootUpdate = newUpdateOp(Path.ROOT, rootRev);
             // also update to most recent sweep revision
             if (sweepRev != null) {
                 NodeDocument.setSweepRevision(rootUpdate, sweepRev);
@@ -210,8 +208,8 @@ class UnsavedModifications {
             }
             store.findAndUpdate(NODES, rootUpdate);
             stats.calls++;
-            map.remove(ROOT_PATH, rootRev);
-            LOG.debug("Updated _lastRev to {} on {}", rootRev, ROOT_PATH);
+            map.remove(Path.ROOT, rootRev);
+            LOG.debug("Updated _lastRev to {} on {}", rootRev, Path.ROOT);
 
             int cid = rootRev.getClusterId();
             UpdateOp update = new UpdateOp(String.valueOf(cid), false);
@@ -228,7 +226,7 @@ class UnsavedModifications {
         return map.toString();
     }
 
-    private static UpdateOp newUpdateOp(String path, Revision r) {
+    private static UpdateOp newUpdateOp(Path path, Revision r) {
         UpdateOp updateOp = createUpdateOp(path, r, false);
         NodeDocument.setLastRev(updateOp, r);
         return updateOp;
@@ -236,7 +234,7 @@ class UnsavedModifications {
 
     private Revision getMostRecentRevision() {
         // use revision of root document
-        Revision rev = map.get(ROOT_PATH);
+        Revision rev = map.get(Path.ROOT);
         // otherwise find most recent
         if (rev == null) {
             for (Revision r : map.values()) {

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
 Wed Apr 10 11:13:19 2019
@@ -764,7 +764,7 @@ public class VersionGarbageCollector {
                 // all previous document ids can be constructed from the
                 // previous ranges map. this works for first level previous
                 // documents only.
-                final String path = doc.getPath();
+                final Path path = doc.getPath();
                 return Iterators.transform(prevRanges.entrySet().iterator(),
                         new Function<Map.Entry<Revision, Range>, String>() {
                     @Override

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundledDocumentDiffer.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundledDocumentDiffer.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundledDocumentDiffer.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundledDocumentDiffer.java
 Wed Apr 10 11:13:19 2019
@@ -26,6 +26,7 @@ import org.apache.jackrabbit.oak.commons
 import org.apache.jackrabbit.oak.plugins.document.AbstractDocumentNodeState;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.spi.state.NodeStateUtils;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -103,7 +104,7 @@ public class BundledDocumentDiffer {
             //and from there traverse down to the actual child node
             checkState(BundlorUtils.isBundledChild(state));
             String bundlingPath = 
state.getString(DocumentBundlor.META_PROP_BUNDLING_PATH);
-            String bundlingRootPath = 
PathUtils.getAncestorPath(state.getPath(), PathUtils.getDepth(bundlingPath));
+            Path bundlingRootPath = 
state.getPath().getAncestor(PathUtils.getDepth(bundlingPath));
             DocumentNodeState bundlingRoot = 
nodeStore.getNode(bundlingRootPath, state.getLastRevision());
             result = (DocumentNodeState) NodeStateUtils.getNode(bundlingRoot, 
bundlingPath);
         } else {

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundlingHandler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundlingHandler.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundlingHandler.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/bundlor/BundlingHandler.java
 Wed Apr 10 11:13:19 2019
@@ -24,25 +24,25 @@ import java.util.Set;
 import com.google.common.collect.Sets;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.apache.jackrabbit.oak.commons.PathUtils.ROOT_PATH;
 import static 
org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
 
 public class BundlingHandler {
 
     private final BundledTypesRegistry registry;
-    private final String path;
+    private final Path path;
     private final BundlingContext ctx;
     private final NodeState nodeState;
 
     public BundlingHandler(BundledTypesRegistry registry) {
-        this(checkNotNull(registry), BundlingContext.NULL, ROOT_PATH, 
EMPTY_NODE);
+        this(checkNotNull(registry), BundlingContext.NULL, Path.ROOT, 
EMPTY_NODE);
     }
 
-    private BundlingHandler(BundledTypesRegistry registry, BundlingContext 
ctx, String path, NodeState nodeState) {
+    private BundlingHandler(BundledTypesRegistry registry, BundlingContext 
ctx, Path path, NodeState nodeState) {
         this.registry = registry;
         this.path = path;
         this.ctx = ctx;
@@ -67,7 +67,7 @@ public class BundlingHandler {
     /**
      * Returns absolute path of the current node
      */
-    public String getNodeFullPath() {
+    public Path getNodeFullPath() {
         return path;
     }
 
@@ -86,12 +86,12 @@ public class BundlingHandler {
         return ctx.removedProps;
     }
 
-    public String getRootBundlePath() {
+    public Path getRootBundlePath() {
         return ctx.isBundling() ? ctx.bundlingPath : path;
     }
 
     public BundlingHandler childAdded(String name, NodeState state){
-        String childPath = childPath(name);
+        Path childPath = childPath(name);
         BundlingContext childContext;
         Matcher childMatcher = ctx.matcher.next(name);
         if (childMatcher.isMatch()) {
@@ -111,7 +111,7 @@ public class BundlingHandler {
     }
 
     public BundlingHandler childDeleted(String name, NodeState state){
-        String childPath = childPath(name);
+        Path childPath = childPath(name);
         BundlingContext childContext;
         Matcher childMatcher = ctx.matcher.next(name);
         if (childMatcher.isMatch()) {
@@ -127,7 +127,7 @@ public class BundlingHandler {
     }
 
     public BundlingHandler childChanged(String name, NodeState before, 
NodeState after){
-        String childPath = childPath(name);
+        Path childPath = childPath(name);
         BundlingContext childContext;
         Matcher childMatcher = ctx.matcher.next(name);
         if (childMatcher.isMatch()) {
@@ -151,22 +151,22 @@ public class BundlingHandler {
 
     @Override
     public String toString() {
-        String result = path;
+        String result = path.toString();
         if (isBundledNode()){
             result = path + "( Bundling root - " + getRootBundlePath() + ")";
         }
         return result;
     }
 
-    private String childPath(String name){
-        return PathUtils.concat(path, name);
+    private Path childPath(String name){
+        return new Path(path, name);
     }
 
     private BundlingContext createChildContext(Matcher childMatcher) {
         return ctx.child(childMatcher);
     }
 
-    private static BundlingContext getBundlorContext(String path, NodeState 
state) {
+    private static BundlingContext getBundlorContext(Path path, NodeState 
state) {
         BundlingContext result = BundlingContext.NULL;
         PropertyState bundlorConfig = 
state.getProperty(DocumentBundlor.META_PROP_PATTERN);
         if (bundlorConfig != null){
@@ -199,13 +199,13 @@ public class BundlingHandler {
     }
 
     private static class BundlingContext {
-        static final BundlingContext NULL = new BundlingContext("", 
Matcher.NON_MATCHING);
-        final String bundlingPath;
+        static final BundlingContext NULL = new BundlingContext(Path.ROOT, 
Matcher.NON_MATCHING);
+        final Path bundlingPath;
         final Matcher matcher;
         final Set<PropertyState> metaProps = Sets.newHashSet();
         final Set<String> removedProps = Sets.newHashSet();
 
-        public BundlingContext(String bundlingPath, Matcher matcher) {
+        public BundlingContext(Path bundlingPath, Matcher matcher) {
             this.bundlingPath = bundlingPath;
             this.matcher = matcher;
         }

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/locks/StripedNodeDocumentLocks.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/locks/StripedNodeDocumentLocks.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/locks/StripedNodeDocumentLocks.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/locks/StripedNodeDocumentLocks.java
 Wed Apr 10 11:13:19 2019
@@ -18,13 +18,14 @@ package org.apache.jackrabbit.oak.plugin
 
 import java.util.concurrent.locks.Lock;
 
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.plugins.document.util.Utils;
 
 import com.google.common.util.concurrent.Striped;
 
 public class StripedNodeDocumentLocks implements NodeDocumentLocks {
 
-    private static final String ROOT = Utils.getIdFromPath("/");
+    private static final String ROOT = Utils.getIdFromPath(Path.ROOT);
 
     /**
      * Locks to ensure cache consistency on reads, writes and invalidation.

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoVersionGCSupport.java
 Wed Apr 10 11:13:19 2019
@@ -38,6 +38,7 @@ import com.mongodb.client.model.Filters;
 
 import org.apache.jackrabbit.oak.plugins.document.Document;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.plugins.document.Revision;
 import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
 import org.apache.jackrabbit.oak.plugins.document.SplitDocumentCleanUp;
@@ -189,7 +190,7 @@ public class MongoVersionGCSupport exten
         // only remove those older than sweep rev
         List<Bson> queries = Lists.newArrayList();
         for (Revision r : sweepRevs) {
-            String idSuffix = Utils.getPreviousIdFor("/", r, 0);
+            String idSuffix = Utils.getPreviousIdFor(Path.ROOT, r, 0);
             idSuffix = idSuffix.substring(idSuffix.lastIndexOf('-'));
 
             // id/path constraint for previous documents

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/CacheType.java
 Wed Apr 10 11:13:19 2019
@@ -16,44 +16,60 @@
  */
 package org.apache.jackrabbit.oak.plugins.document.persistentCache;
 
+import java.nio.ByteBuffer;
+
 import org.apache.jackrabbit.oak.plugins.document.LocalDiffCache;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState;
 import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
 import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.MemoryDiffCache;
+import org.apache.jackrabbit.oak.plugins.document.NamePathRev;
 import org.apache.jackrabbit.oak.plugins.document.NodeDocument;
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.plugins.document.PathRev;
+import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
 import org.apache.jackrabbit.oak.plugins.document.util.RevisionsKey;
 import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
+import org.h2.mvstore.WriteBuffer;
+import org.h2.mvstore.type.StringDataType;
 
 public enum CacheType {
     
     NODE {
+
         @Override
-        public <K> String keyToString(K key) {
-            return ((PathRev) key).asString();
+        public <K> void writeKey(WriteBuffer buffer, K key) {
+            PathRev pr = (PathRev) key;
+            DataTypeUtil.pathRevToBuffer(pr, buffer);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <K> K keyFromString(String key) {
-            return (K) PathRev.fromString(key);
+        public <K> K readKey(ByteBuffer buffer) {
+            return (K) DataTypeUtil.pathRevFromBuffer(buffer);
         }
+
         @Override
         public <K> int compareKeys(K a, K b) {
             return ((PathRev) a).compareTo((PathRev) b);
         }
+
         @Override
-        public <V> String valueToString(V value) {
-            return ((DocumentNodeState) value).asString();
+        public <V> void writeValue(WriteBuffer buffer, V value) {
+            DataTypeUtil.stateToBuffer((DocumentNodeState) value, buffer);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
-            return (V) DocumentNodeState.fromString(store, value);
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
+            return (V) DataTypeUtil.stateFromBuffer(store, buffer);
         }
+
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
-            String path = ((PathRev) key).getPath();
+            Path path = ((PathRev) key).getPath();
             if (!store.getNodeCachePredicate().apply(path)){
                 return false;
             }
@@ -62,33 +78,40 @@ public enum CacheType {
     },
     
     CHILDREN {
+
         @Override
-        public <K> String keyToString(K key) {
-            return ((PathRev) key).asString();
+        public <K> void writeKey(WriteBuffer buffer, K key) {
+            DataTypeUtil.namePathRevToBuffer((NamePathRev) key, buffer);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <K> K keyFromString(String key) {
-            return (K) PathRev.fromString(key);
+        public <K> K readKey(ByteBuffer buffer) {
+            return (K) DataTypeUtil.namePathRevFromBuffer(buffer);
         }
+
         @Override
         public <K> int compareKeys(K a, K b) {
-            return ((PathRev) a).compareTo((PathRev) b);
+            return ((NamePathRev) a).compareTo((NamePathRev) b);
         }
+
         @Override
-        public <V> String valueToString(V value) {
-            return ((DocumentNodeState.Children) value).asString();
+        public <V> void writeValue(WriteBuffer buffer, V value) {
+            String s = ((DocumentNodeState.Children) value).asString();
+            StringDataType.INSTANCE.write(buffer, s);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
-            return (V) DocumentNodeState.Children.fromString(value);
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
+            return (V) 
DocumentNodeState.Children.fromString(readString(buffer));
         }
 
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
-            String path = ((PathRev) key).getPath();
+            Path path = ((NamePathRev) key).getPath();
             if (!store.getNodeCachePredicate().apply(path)){
                 return false;
             }
@@ -97,29 +120,44 @@ public enum CacheType {
     }, 
     
     DIFF {
+
         @Override
-        public <K> String keyToString(K key) {
-            return ((PathRev) key).asString();
+        public <K> void writeKey(WriteBuffer buffer, K key) {
+            MemoryDiffCache.Key k = ((MemoryDiffCache.Key) key);
+            DataTypeUtil.pathToBuffer(k.getPath(), buffer);
+            DataTypeUtil.revisionVectorToBuffer(k.getFromRevision(), buffer);
+            DataTypeUtil.revisionVectorToBuffer(k.getToRevision(), buffer);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <K> K keyFromString(String key) {
-            return (K) PathRev.fromString(key);
+        public <K> K readKey(ByteBuffer buffer) {
+            Path p = DataTypeUtil.pathFromBuffer(buffer);
+            RevisionVector from = 
DataTypeUtil.revisionVectorFromBuffer(buffer);
+            RevisionVector to = DataTypeUtil.revisionVectorFromBuffer(buffer);
+            return (K) new MemoryDiffCache.Key(p, from, to);
         }
+
+
         @Override
         public <K> int compareKeys(K a, K b) {
-            return ((PathRev) a).compareTo((PathRev) b);
-        }            
+            return ((MemoryDiffCache.Key) a).compareTo((MemoryDiffCache.Key) 
b);
+        }
+
         @Override
-        public <V> String valueToString(V value) {
-            return ((StringValue) value).asString();
+        public <V> void writeValue(WriteBuffer buffer, V value) {
+            String s = ((StringValue) value).asString();
+            StringDataType.INSTANCE.write(buffer, s);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
-            return (V) StringValue.fromString(value);
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
+            return (V) StringValue.fromString(readString(buffer));
         }
+
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
             return true;
@@ -127,27 +165,34 @@ public enum CacheType {
     },
 
     DOCUMENT {
+
         @Override
-        public <K> String keyToString(K key) {
+        public <K> void writeKey(WriteBuffer buffer, K key) {
             throw new UnsupportedOperationException();
         }
+
         @Override
-        public <K> K keyFromString(String key) {
+        public <K> K readKey(ByteBuffer buffer) {
             throw new UnsupportedOperationException();
         }
+
         @Override
         public <K> int compareKeys(K a, K b) {
             throw new UnsupportedOperationException();
-        }            
+        }
+
         @Override
-        public <V> String valueToString(V value) {
+        public <V> void writeValue(WriteBuffer buffer, V value) {
             throw new UnsupportedOperationException();
         }
+
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
             throw new UnsupportedOperationException();
         }
+
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
             return false;
@@ -155,29 +200,38 @@ public enum CacheType {
     },
 
     PREV_DOCUMENT {
+
         @Override
-        public <K> String keyToString(K key) {
-            return ((StringValue) key).asString();
+        public <K> void writeKey(WriteBuffer buffer, K key) {
+            String s = ((StringValue) key).asString();
+            StringDataType.INSTANCE.write(buffer, s);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <K> K keyFromString(String key) {
-            return (K) StringValue.fromString(key);
+        public <K> K readKey(ByteBuffer buffer) {
+            return (K) StringValue.fromString(readString(buffer));
         }
+
         @Override
         public <K> int compareKeys(K a, K b) {
             return ((StringValue) a).asString().compareTo(((StringValue) 
b).asString());
         }
+
         @Override
-        public <V> String valueToString(V value) {
-            return ((NodeDocument) value).asString();
+        public <V> void writeValue(WriteBuffer buffer, V value) {
+            String s = ((NodeDocument) value).asString();
+            StringDataType.INSTANCE.write(buffer, s);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
-            return (V) NodeDocument.fromString(docStore, value);
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
+            return (V) NodeDocument.fromString(docStore, readString(buffer));
         }
+
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
             return true;
@@ -185,29 +239,41 @@ public enum CacheType {
     },
 
     LOCAL_DIFF {
+
         @Override
-        public <K> String keyToString(K key) {
-            return ((RevisionsKey) key).asString();
+        public <K> void writeKey(WriteBuffer buffer, K key) {
+            RevisionsKey revisionsKey = ((RevisionsKey) key);
+            DataTypeUtil.revisionVectorToBuffer(revisionsKey.getRev1(), 
buffer);
+            DataTypeUtil.revisionVectorToBuffer(revisionsKey.getRev2(), 
buffer);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <K> K keyFromString(String key) {
-            return (K) RevisionsKey.fromString(key);
+        public <K> K readKey(ByteBuffer buffer) {
+            RevisionVector rv1 = DataTypeUtil.revisionVectorFromBuffer(buffer);
+            RevisionVector rv2 = DataTypeUtil.revisionVectorFromBuffer(buffer);
+            return (K) new RevisionsKey(rv1, rv2);
         }
+
         @Override
         public <K> int compareKeys(K a, K b) {
             return ((RevisionsKey) a).compareTo((RevisionsKey) b);
         }
+
         @Override
-        public <V> String valueToString(V value) {
-            return ((LocalDiffCache.Diff) value).asString();
+        public <V> void writeValue(WriteBuffer buffer, V value) {
+            String s = ((LocalDiffCache.Diff) value).asString();
+            StringDataType.INSTANCE.write(buffer, s);
         }
+
         @SuppressWarnings("unchecked")
         @Override
-        public <V> V valueFromString(
-                DocumentNodeStore store, DocumentStore docStore, String value) 
{
-            return (V) LocalDiffCache.Diff.fromString(value);
+        public <V> V readValue(DocumentNodeStore store,
+                               DocumentStore docStore,
+                               ByteBuffer buffer) {
+            return (V) LocalDiffCache.Diff.fromString(readString(buffer));
         }
+
         @Override
         public <K> boolean shouldCache(DocumentNodeStore store, K key) {
             return true;
@@ -216,13 +282,22 @@ public enum CacheType {
     
     public static final CacheType[] VALUES = CacheType.values();
 
-    public abstract <K> String keyToString(K key);
-    public abstract <K> K keyFromString(String key);
+    public String getMapName() {
+        // add a version suffix to the name and increment the version
+        // whenever the serialization for a key or value changes
+        return name() + "-v1";
+    }
+
+    public abstract <K> void writeKey(WriteBuffer buffer, K key);
+    public abstract <K> K readKey(ByteBuffer buffer);
     public abstract <K> int compareKeys(K a, K b);
-    public abstract <V> String valueToString(V value);
-    public abstract <V> V valueFromString(
-            DocumentNodeStore store, DocumentStore docStore, String value);
+    public abstract <V> void writeValue(WriteBuffer buffer, V value);
+    public abstract <V> V readValue(
+            DocumentNodeStore store, DocumentStore docStore, ByteBuffer 
buffer);
     public abstract <K> boolean shouldCache(DocumentNodeStore store, K key);
 
+    private static String readString(ByteBuffer buffer) {
+        return StringDataType.INSTANCE.read(buffer);
+    }
 }
 

Added: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/DataTypeUtil.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/DataTypeUtil.java?rev=1857240&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/DataTypeUtil.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/DataTypeUtil.java
 Wed Apr 10 11:13:19 2019
@@ -0,0 +1,169 @@
+/*
+ * 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.persistentCache;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeState;
+import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore;
+import org.apache.jackrabbit.oak.plugins.document.NamePathRev;
+import org.apache.jackrabbit.oak.plugins.document.Path;
+import org.apache.jackrabbit.oak.plugins.document.PathRev;
+import org.apache.jackrabbit.oak.plugins.document.Revision;
+import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
+import org.h2.mvstore.DataUtils;
+import org.h2.mvstore.WriteBuffer;
+import org.h2.mvstore.type.StringDataType;
+
+/**
+ * Utility class to write various types to a buffer and read it back again.
+ */
+class DataTypeUtil {
+
+    static void booleanToBuffer(boolean b, WriteBuffer buffer) {
+        buffer.put((byte) (b ? 1 : 0));
+    }
+
+    static boolean booleanFromBuffer(ByteBuffer buffer) {
+        return buffer.get() != 0;
+    }
+
+    static void revisionVectorToBuffer(RevisionVector rv, WriteBuffer buffer) {
+        buffer.putVarInt(rv.getDimensions());
+        for (Revision r : rv) {
+            buffer.putLong(r.getTimestamp());
+            buffer.putVarInt(r.getCounter());
+            buffer.putVarInt(r.getClusterId());
+            booleanToBuffer(r.isBranch(), buffer);
+        }
+    }
+
+    static RevisionVector revisionVectorFromBuffer(ByteBuffer buffer) {
+        int dim  = DataUtils.readVarInt(buffer);
+        List<Revision> revisions = new ArrayList<>();
+        for (int i = 0; i < dim; i++) {
+            revisions.add(new Revision(
+                    buffer.getLong(),
+                    DataUtils.readVarInt(buffer),
+                    DataUtils.readVarInt(buffer),
+                    booleanFromBuffer(buffer))
+            );
+        }
+        return new RevisionVector(revisions);
+    }
+
+    static void pathToBuffer(Path p, WriteBuffer buffer) {
+        int len = p.getDepth() + (p.isAbsolute() ? 1 : 0);
+        buffer.putVarInt(len);
+        // write path elements backwards
+        while (p != null) {
+            StringDataType.INSTANCE.write(buffer, p.getName());
+            p = p.getParent();
+        }
+    }
+
+    static Path pathFromBuffer(ByteBuffer buffer) {
+        int numElements = DataUtils.readVarInt(buffer);
+        List<String> elements = new ArrayList<>(numElements);
+        for (int i = 0; i < numElements; i++) {
+            elements.add(StringDataType.INSTANCE.read(buffer));
+        }
+        // elements are written backwards
+        String firstElement = elements.get(elements.size() - 1);
+        Path p;
+        if (firstElement.isEmpty()) {
+            p = Path.ROOT;
+        } else {
+            p = new Path(firstElement);
+        }
+        // construct path with remaining elements
+        for (int i = elements.size() - 2; i >= 0; i--) {
+            p = new Path(p, elements.get(i));
+        }
+        return p;
+    }
+
+    static void pathRevToBuffer(PathRev pr, WriteBuffer buffer) {
+        pathToBuffer(pr.getPath(), buffer);
+        revisionVectorToBuffer(pr.getRevision(), buffer);
+    }
+
+    static PathRev pathRevFromBuffer(ByteBuffer buffer) {
+        return new PathRev(
+                pathFromBuffer(buffer),
+                revisionVectorFromBuffer(buffer)
+        );
+    }
+
+    static void namePathRevToBuffer(NamePathRev pnr, WriteBuffer buffer) {
+        StringDataType.INSTANCE.write(buffer, pnr.getName());
+        pathToBuffer(pnr.getPath(), buffer);
+        revisionVectorToBuffer(pnr.getRevision(), buffer);
+    }
+
+    static NamePathRev namePathRevFromBuffer(ByteBuffer buffer) {
+        return new NamePathRev(
+                StringDataType.INSTANCE.read(buffer),
+                pathFromBuffer(buffer),
+                revisionVectorFromBuffer(buffer)
+        );
+    }
+
+    static void stateToBuffer(DocumentNodeState state, WriteBuffer buffer) {
+        pathToBuffer(state.getPath(), buffer);
+        revisionVectorToBuffer(state.getRootRevision(), buffer);
+        RevisionVector lastRevision = state.getLastRevision();
+        if (lastRevision == null) {
+            lastRevision = RevisionVector.fromString("");
+        }
+        revisionVectorToBuffer(lastRevision, buffer);
+        buffer.putVarInt(state.getMemory());
+        booleanToBuffer(state.hasNoChildren(), buffer);
+        Map<String, String> props = state.getAllBundledProperties();
+        buffer.putVarInt(props.size());
+        for (Map.Entry<String, String> e : props.entrySet()) {
+            StringDataType.INSTANCE.write(buffer, e.getKey());
+            StringDataType.INSTANCE.write(buffer, e.getValue());
+        }
+    }
+
+    static DocumentNodeState stateFromBuffer(DocumentNodeStore store,
+                                             ByteBuffer buffer) {
+        Path p = pathFromBuffer(buffer);
+        RevisionVector rootRevision = revisionVectorFromBuffer(buffer);
+        RevisionVector lastRevision = revisionVectorFromBuffer(buffer);
+        if (lastRevision.getDimensions() == 0) {
+            lastRevision = null;
+        }
+        int mem = DataUtils.readVarInt(buffer);
+        boolean noChildren = booleanFromBuffer(buffer);
+        int numProps = DataUtils.readVarInt(buffer);
+        Map<String, PropertyState> props = new HashMap<>(numProps);
+        for (int i = 0; i < numProps; i++) {
+            String name = StringDataType.INSTANCE.read(buffer);
+            String value = StringDataType.INSTANCE.read(buffer);
+            props.put(name, store.createPropertyState(name, value));
+        }
+        return new DocumentNodeState(store, p, rootRevision, props,
+                !noChildren, mem, lastRevision, false);
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/DataTypeUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/KeyDataType.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/KeyDataType.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/KeyDataType.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/KeyDataType.java
 Wed Apr 10 11:13:19 2019
@@ -21,7 +21,6 @@ import java.nio.ByteBuffer;
 import org.apache.jackrabbit.oak.cache.CacheValue;
 import org.h2.mvstore.WriteBuffer;
 import org.h2.mvstore.type.DataType;
-import org.h2.mvstore.type.StringDataType;
 
 public class KeyDataType implements DataType {
     
@@ -43,14 +42,12 @@ public class KeyDataType implements Data
 
     @Override
     public void write(WriteBuffer buff, Object obj) {
-        String s = type.keyToString(obj);
-        StringDataType.INSTANCE.write(buff, s);
+        type.writeKey(buff, obj);
     }
 
     @Override
     public Object read(ByteBuffer buff) {
-        String s = StringDataType.INSTANCE.read(buff);
-        return type.keyFromString(s);
+        return type.readKey(buff);
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/NodeCache.java
 Wed Apr 10 11:13:19 2019
@@ -112,8 +112,7 @@ class NodeCache<K extends CacheValue, V
     public void addGeneration(int generation, boolean readOnly) {
         MVMap.Builder<K, V> b = new MVMap.Builder<K, V>().
                 keyType(keyType).valueType(valueType);
-        String mapName = type.name();
-        CacheMap<K, V> m = cache.openMap(generation, mapName, b);
+        CacheMap<K, V> m = cache.openMap(generation, type.getMapName(), b);
         map.addReadMap(generation, m);
         if (!readOnly) {
             map.setWriteMap(m);

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/ValueDataType.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/ValueDataType.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/ValueDataType.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/persistentCache/ValueDataType.java
 Wed Apr 10 11:13:19 2019
@@ -23,7 +23,9 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
 import org.h2.mvstore.WriteBuffer;
 import org.h2.mvstore.type.DataType;
-import org.h2.mvstore.type.StringDataType;
+import org.jetbrains.annotations.NotNull;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 public class ValueDataType implements DataType {
     
@@ -31,9 +33,9 @@ public class ValueDataType implements Da
     private final DocumentStore docStore;
     private final CacheType type;
     
-    public ValueDataType(
-            DocumentNodeStore docNodeStore,
-            DocumentStore docStore, CacheType type) {
+    ValueDataType(DocumentNodeStore docNodeStore,
+                  DocumentStore docStore,
+                  CacheType type) {
         this.docNodeStore = docNodeStore;
         this.docStore = docStore;
         this.type = type;
@@ -51,14 +53,12 @@ public class ValueDataType implements Da
 
     @Override
     public void write(WriteBuffer buff, Object obj) {
-        String s = type.valueToString(obj);
-        StringDataType.INSTANCE.write(buff, s);
+        type.writeValue(buff, obj);
     }
 
     @Override
     public Object read(ByteBuffer buff) {
-        String s = StringDataType.INSTANCE.read(buff);
-        return type.valueFromString(docNodeStore, docStore, s);
+        return type.readValue(docNodeStore, docStore, buff);
     }
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/DelegatingDocumentNodeState.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/DelegatingDocumentNodeState.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/DelegatingDocumentNodeState.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/DelegatingDocumentNodeState.java
 Wed Apr 10 11:13:19 2019
@@ -25,6 +25,7 @@ import com.google.common.collect.Iterabl
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.plugins.document.AbstractDocumentNodeState;
 import org.apache.jackrabbit.oak.plugins.document.NodeStateDiffer;
+import org.apache.jackrabbit.oak.plugins.document.Path;
 import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeBuilder;
@@ -36,9 +37,6 @@ import org.jetbrains.annotations.Nullabl
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-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.commons.PathUtils.denotesRoot;
 
 /**
  * NodeState wrapper which wraps another NodeState (mostly SegmentNodeState)
@@ -61,7 +59,7 @@ public class DelegatingDocumentNodeState
     private final NodeState delegate;
     private final RevisionVector rootRevision;
     private final boolean fromExternalChange;
-    private final String path;
+    private final Path path;
     private RevisionVector lastRevision;
 
 
@@ -75,7 +73,7 @@ public class DelegatingDocumentNodeState
     public static NodeState wrapIfPossible(NodeState delegate, NodeStateDiffer 
differ) {
         if (hasMetaProps(delegate)) {
             String revVector = getRequiredProp(delegate, PROP_REVISION);
-            return new DelegatingDocumentNodeState(delegate, ROOT_PATH, 
RevisionVector.fromString(revVector), false, differ);
+            return new DelegatingDocumentNodeState(delegate, Path.ROOT, 
RevisionVector.fromString(revVector), false, differ);
         }
         return delegate;
     }
@@ -86,10 +84,10 @@ public class DelegatingDocumentNodeState
 
     public static AbstractDocumentNodeState wrap(NodeState delegate, 
NodeStateDiffer differ) {
         String revVector = getRequiredProp(delegate, PROP_REVISION);
-        return new DelegatingDocumentNodeState(delegate, ROOT_PATH, 
RevisionVector.fromString(revVector), false, differ);
+        return new DelegatingDocumentNodeState(delegate, Path.ROOT, 
RevisionVector.fromString(revVector), false, differ);
     }
 
-    private DelegatingDocumentNodeState(NodeState delegate, String path, 
RevisionVector rootRevision,
+    private DelegatingDocumentNodeState(NodeState delegate, Path path, 
RevisionVector rootRevision,
                                        boolean fromExternalChange, 
NodeStateDiffer differ) {
         this.differ = differ;
         this.delegate = delegate;
@@ -111,7 +109,7 @@ public class DelegatingDocumentNodeState
     //~----------------------------------< AbstractDocumentNodeState >
 
     @Override
-    public String getPath() {
+    public Path getPath() {
         return path;
     }
 
@@ -192,7 +190,7 @@ public class DelegatingDocumentNodeState
     @NotNull
     @Override
     public NodeBuilder builder() {
-        checkState(!denotesRoot(getPath()), "Builder cannot be opened for root 
" +
+        checkState(!getPath().isRoot(), "Builder cannot be opened for root " +
                 "path for state of type [%s]", delegate.getClass());
         return new MemoryNodeBuilder(this);
     }
@@ -261,7 +259,7 @@ public class DelegatingDocumentNodeState
 
     private NodeState decorate(String nodeName, NodeState childNode) {
         if (childNode.exists()) {
-            return new DelegatingDocumentNodeState(childNode, concat(path, 
nodeName), rootRevision,
+            return new DelegatingDocumentNodeState(childNode, new Path(path, 
nodeName), rootRevision,
                     fromExternalChange, differ);
         }
         return childNode;

Modified: 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/PathFilteringDiff.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/PathFilteringDiff.java?rev=1857240&r1=1857239&r2=1857240&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/PathFilteringDiff.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/secondary/PathFilteringDiff.java
 Wed Apr 10 11:13:19 2019
@@ -22,7 +22,6 @@ package org.apache.jackrabbit.oak.plugin
 import java.util.List;
 
 import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.document.AbstractDocumentNodeState;
 import org.apache.jackrabbit.oak.plugins.document.RevisionVector;
 import org.apache.jackrabbit.oak.spi.filter.PathFilter;
@@ -56,7 +55,7 @@ class PathFilteringDiff extends ApplyDif
     @Override
     public boolean childNodeAdded(String name, NodeState after) {
         AbstractDocumentNodeState afterDoc = asDocumentState(after, name);
-        String nextPath = afterDoc.getPath();
+        String nextPath = afterDoc.getPath().toString();
         PathFilter.Result result = ctx.pathFilter.filter(nextPath);
         if (result == PathFilter.Result.EXCLUDE){
             return true;
@@ -75,7 +74,7 @@ class PathFilteringDiff extends ApplyDif
     @Override
     public boolean childNodeChanged(String name, NodeState before, NodeState 
after) {
         AbstractDocumentNodeState afterDoc = asDocumentState(after, name);
-        String nextPath = afterDoc.getPath();
+        String nextPath = afterDoc.getPath().toString();
         if (ctx.pathFilter.filter(nextPath) != PathFilter.Result.EXCLUDE) {
             ctx.traversingNode(nextPath);
             NodeBuilder childBuilder = builder.getChildNode(name);
@@ -88,7 +87,7 @@ class PathFilteringDiff extends ApplyDif
 
     @Override
     public boolean childNodeDeleted(String name, NodeState before) {
-        String path = asDocumentState(before, name).getPath();
+        String path = asDocumentState(before, name).getPath().toString();
         if (ctx.pathFilter.filter(path) != PathFilter.Result.EXCLUDE) {
             return super.childNodeDeleted(name, before);
         }
@@ -104,7 +103,7 @@ class PathFilteringDiff extends ApplyDif
 
     static void copyMetaProperties(AbstractDocumentNodeState state, 
NodeBuilder builder, List<String> metaPropNames) {
         //Only set root revision on root node
-        if (PathUtils.denotesRoot(state.getPath())) {
+        if (state.getPath().isRoot()) {
             builder.setProperty(asPropertyState(PROP_REVISION, 
state.getRootRevision()));
         }
 


Reply via email to