You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by md...@apache.org on 2016/05/23 12:59:23 UTC

svn commit: r1745182 [1/3] - in /jackrabbit/oak/trunk: oak-run/src/main/java/org/apache/jackrabbit/oak/run/ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/ oak-segme...

Author: mduerig
Date: Mon May 23 12:59:22 2016
New Revision: 1745182

URL: http://svn.apache.org/viewvc?rev=1745182&view=rev
Log:
OAK-4373: Refactor SegmentTracker
- Put SegmentTracker back to its original purpose: tracking and creating segment ids.
- Introduce a SegmentReader class for reading from segments as a dual to SegmentWriter and move the strings cache there
- Add (temporarily) getters for SegmentReader and SegmentWriter to the SegmentStore interface
- Make the segment cache an implementation detail of the FileStore

Added:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentCache.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReader.java
      - copied, changed from r1745165, jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReaderImpl.java
Modified:
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapEntry.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapRecord.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyser.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentId.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeBuilder.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentParser.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentPropertyState.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStream.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentTracker.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentWriter.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Template.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/FileStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/http/HttpStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/memory/MemoryStore.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompactionAndCleanupIT.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/CompareAgainstBaseStateTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MapRecordTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyserTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentCompactionIT.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentGraphTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdFactoryTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableBenchmark.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentIdTableTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentParserTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/SegmentSizeTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/TemplateTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/TestUtils.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/ExternalBlobReferenceTest.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreIT.java
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java

Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/run/SegmentTarUtils.java Mon May 23 12:59:22 2016
@@ -84,13 +84,13 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStore;
 
-class SegmentTarUtils {
+final class SegmentTarUtils {
 
     private static final boolean TAR_STORAGE_MEMORY_MAPPED = Boolean.getBoolean("tar.memoryMapped");
 
     private static final int TAR_SEGMENT_CACHE_SIZE = Integer.getInteger("cache", 256);
 
-    private final static int MAX_CHAR_DISPLAY = Integer.getInteger("max.char.display", 60);
+    private static final int MAX_CHAR_DISPLAY = Integer.getInteger("max.char.display", 60);
 
     private SegmentTarUtils() {
         // Prevent instantiation
@@ -217,7 +217,7 @@ class SegmentTarUtils {
         long bulkSize = 0;
 
         ((Logger) getLogger(SegmentTracker.class)).setLevel(Level.OFF);
-        RecordUsageAnalyser analyser = new RecordUsageAnalyser();
+        RecordUsageAnalyser analyser = new RecordUsageAnalyser(store);
 
         for (SegmentId id : store.getSegmentIds()) {
             if (id.isDataSegmentId()) {
@@ -433,7 +433,7 @@ class SegmentTarUtils {
                 }
 
                 if (id2 == null) {
-                    NodeState node = new SegmentNodeState(id1);
+                    NodeState node = new SegmentNodeState(store, id1);
                     System.out.println("/ (" + id1 + ") -> " + node);
                     for (String name : PathUtils.elements(path)) {
                         node = node.getChildNode(name);
@@ -445,8 +445,8 @@ class SegmentTarUtils {
                                 + node);
                     }
                 } else {
-                    NodeState node1 = new SegmentNodeState(id1);
-                    NodeState node2 = new SegmentNodeState(id2);
+                    NodeState node1 = new SegmentNodeState(store, id1);
+                    NodeState node2 = new SegmentNodeState(store, id2);
                     for (String name : PathUtils.elements(path)) {
                         node1 = node1.getChildNode(name);
                         node2 = node2.getChildNode(name);

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapEntry.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapEntry.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapEntry.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapEntry.java Mon May 23 12:59:22 2016
@@ -24,11 +24,12 @@ import static org.apache.jackrabbit.oak.
 
 import java.util.Map;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
-
-import org.apache.jackrabbit.oak.spi.state.AbstractChildNodeEntry;
+import javax.annotation.Nullable;
 
 import com.google.common.collect.ComparisonChain;
+import org.apache.jackrabbit.oak.spi.state.AbstractChildNodeEntry;
 
 /**
  * Representation of a single key-value entry in a map.
@@ -36,13 +37,21 @@ import com.google.common.collect.Compari
 class MapEntry extends AbstractChildNodeEntry
         implements Map.Entry<RecordId, RecordId>, Comparable<MapEntry> {
 
+    @Nonnull
+    private final SegmentStore store;
+
+    @Nonnull
     private final String name;
 
+    @Nonnull
     private final RecordId key;
 
+    @CheckForNull
     private final RecordId value;
 
-    MapEntry(String name, RecordId key, RecordId value) {
+    MapEntry(@Nonnull SegmentStore store, @Nonnull String name,
+             @Nonnull RecordId key, @Nullable RecordId value) {
+        this.store = checkNotNull(store);
         this.name = checkNotNull(name);
         this.key = checkNotNull(key);
         this.value = value;
@@ -62,16 +71,18 @@ class MapEntry extends AbstractChildNode
     @Override @Nonnull
     public SegmentNodeState getNodeState() {
         checkState(value != null);
-        return new SegmentNodeState(value);
+        return new SegmentNodeState(store, value);
     }
 
     //---------------------------------------------------------< Map.Entry >--
 
+    @Nonnull
     @Override
     public RecordId getKey() {
         return key;
     }
 
+    @CheckForNull
     @Override
     public RecordId getValue() {
         return value;

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapRecord.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapRecord.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapRecord.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MapRecord.java Mon May 23 12:59:22 2016
@@ -30,6 +30,8 @@ import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.oak.spi.state.DefaultNodeStateDiff;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
 import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
@@ -51,6 +53,9 @@ public class MapRecord extends Record {
     private static final int A = 0xB;
     static final long HASH_MASK = 0xFFFFFFFFL;
 
+    @Nonnull
+    private final SegmentStore store;
+
     /**
      * Generates a hash code for the value, using a random number generator
      * to improve the distribution of the hash values.
@@ -93,8 +98,9 @@ public class MapRecord extends Record {
      */
     protected static final int MAX_SIZE = (1 << SIZE_BITS) - 1; // ~268e6
 
-    protected MapRecord(RecordId id) {
+    protected MapRecord(@Nonnull SegmentStore store, @Nonnull RecordId id) {
         super(id);
+        this.store = checkNotNull(store);
     }
 
     boolean isLeaf() {
@@ -102,7 +108,7 @@ public class MapRecord extends Record {
         int head = segment.readInt(getOffset(0));
         if (isDiff(head)) {
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).isLeaf();
+            return new MapRecord(store, base).isLeaf();
         }
         return !isBranch(head);
     }
@@ -118,8 +124,7 @@ public class MapRecord extends Record {
         int ids = 0;
         for (int i = 0; i < BUCKETS_PER_LEVEL; i++) {
             if ((bitmap & (1 << i)) != 0) {
-                buckets[i] = new MapRecord(
-                        segment.readRecordId(getOffset(8, ids++)));
+                buckets[i] = new MapRecord(store, segment.readRecordId(getOffset(8, ids++)));
             } else {
                 buckets[i] = null;
             }
@@ -134,7 +139,7 @@ public class MapRecord extends Record {
         for (int i = 0; i < BUCKETS_PER_LEVEL; i++) {
             if ((bitmap & (1 << i)) != 0) {
                 RecordId id = segment.readRecordId(getOffset(8, ids++));
-                buckets.add(new MapRecord(id));
+                buckets.add(new MapRecord(store, id));
             }
         }
         return buckets;
@@ -145,7 +150,7 @@ public class MapRecord extends Record {
         int head = segment.readInt(getOffset(0));
         if (isDiff(head)) {
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).size();
+            return new MapRecord(store, base).size();
         }
         return getSize(head);
     }
@@ -159,13 +164,13 @@ public class MapRecord extends Record {
         if (isDiff(head)) {
             if (hash == segment.readInt(getOffset(4))) {
                 RecordId key = segment.readRecordId(getOffset(8));
-                if (name.equals(Segment.readString(key))) {
+                if (name.equals(store.getReader().readString(key))) {
                     RecordId value = segment.readRecordId(getOffset(8, 1));
-                    return new MapEntry(name, key, value);
+                    return new MapEntry(store, name, key, value);
                 }
             }
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).getEntry(name);
+            return new MapRecord(store, base).getEntry(name);
         }
 
         int size = getSize(head);
@@ -185,7 +190,7 @@ public class MapRecord extends Record {
             if ((bitmap & bit) != 0) {
                 int ids = bitCount(bitmap & (bit - 1));
                 RecordId id = segment.readRecordId(getOffset(8, ids));
-                return new MapRecord(id).getEntry(name);
+                return new MapRecord(store, id).getEntry(name);
             } else {
                 return null;
             }
@@ -214,9 +219,9 @@ public class MapRecord extends Record {
                         getOffset(4 + size * 4, i * 2));
                 RecordId valueId = segment.readRecordId(
                         getOffset(4 + size * 4, i * 2 + 1));
-                diff = Segment.readString(keyId).compareTo(name);
+                diff = store.getReader().readString(keyId).compareTo(name);
                 if (diff == 0) {
-                    return new MapEntry(name, keyId, valueId);
+                    return new MapEntry(store, name, keyId, valueId);
                 }
             }
 
@@ -242,7 +247,7 @@ public class MapRecord extends Record {
                 return segment.readRecordId(getOffset(8, 1));
             }
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).getValue(hash, key);
+            return new MapRecord(store, base).getValue(hash, key);
         }
 
         int size = getSize(head);
@@ -262,7 +267,7 @@ public class MapRecord extends Record {
             if ((bitmap & bit) != 0) {
                 int ids = bitCount(bitmap & (bit - 1));
                 RecordId id = segment.readRecordId(getOffset(8, ids));
-                return new MapRecord(id).getValue(hash, key);
+                return new MapRecord(store, id).getValue(hash, key);
             } else {
                 return null;
             }
@@ -292,7 +297,7 @@ public class MapRecord extends Record {
         int head = segment.readInt(getOffset(0));
         if (isDiff(head)) {
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).getKeys();
+            return new MapRecord(store, base).getKeys();
         }
 
         int size = getSize(head);
@@ -318,7 +323,7 @@ public class MapRecord extends Record {
 
         String[] keys = new String[size];
         for (int i = 0; i < size; i++) {
-            keys[i] = Segment.readString(ids[i]);
+            keys[i] = store.getReader().readString(ids[i]);
         }
         return Arrays.asList(keys);
     }
@@ -336,7 +341,7 @@ public class MapRecord extends Record {
             RecordId key = segment.readRecordId(getOffset(8));
             RecordId value = segment.readRecordId(getOffset(8, 1));
             RecordId base = segment.readRecordId(getOffset(8, 2));
-            return new MapRecord(base).getEntries(key, value);
+            return new MapRecord(store, base).getEntries(key, value);
         }
 
         int size = getSize(head);
@@ -369,8 +374,8 @@ public class MapRecord extends Record {
             } else {
                 value = segment.readRecordId(getOffset(4 + size * 4, i * 2 + 1));
             }
-            String name = Segment.readString(key);
-            entries[i] = new MapEntry(name, key, value);
+            String name = store.getReader().readString(key);
+            entries[i] = new MapEntry(store, name, key, value);
         }
         return Arrays.asList(entries);
     }
@@ -385,9 +390,9 @@ public class MapRecord extends Record {
         if (isDiff(head)) {
             int hash = segment.readInt(getOffset(4));
             RecordId keyId = segment.readRecordId(getOffset(8));
-            final String key = Segment.readString(keyId);
+            final String key = store.getReader().readString(keyId);
             final RecordId value = segment.readRecordId(getOffset(8, 1));
-            MapRecord base = new MapRecord(segment.readRecordId(getOffset(8, 2)));
+            MapRecord base = new MapRecord(store, segment.readRecordId(getOffset(8, 2)));
 
             boolean rv = base.compare(before, new DefaultNodeStateDiff() {
                 @Override
@@ -411,12 +416,12 @@ public class MapRecord extends Record {
                 if (beforeEntry == null) {
                     rv = diff.childNodeAdded(
                             key,
-                            new SegmentNodeState(value));
+                            new SegmentNodeState(store, value));
                 } else if (!value.equals(beforeEntry.getValue())) {
                     rv = diff.childNodeChanged(
                             key,
                             beforeEntry.getNodeState(),
-                            new SegmentNodeState(value));
+                            new SegmentNodeState(store, value));
                 }
             }
             return rv;
@@ -427,9 +432,9 @@ public class MapRecord extends Record {
         if (isDiff(beforeHead)) {
             int hash = beforeSegment.readInt(before.getOffset(4));
             RecordId keyId = beforeSegment.readRecordId(before.getOffset(8));
-            final String key = Segment.readString(keyId);
+            final String key = store.getReader().readString(keyId);
             final RecordId value = beforeSegment.readRecordId(before.getOffset(8, 1));
-            MapRecord base = new MapRecord(beforeSegment.readRecordId(before.getOffset(8, 2)));
+            MapRecord base = new MapRecord(store, beforeSegment.readRecordId(before.getOffset(8, 2)));
 
             boolean rv = this.compare(base, new DefaultNodeStateDiff() {
                 @Override
@@ -453,11 +458,11 @@ public class MapRecord extends Record {
                 if (afterEntry == null) {
                     rv = diff.childNodeDeleted(
                             key,
-                            new SegmentNodeState(value));
+                            new SegmentNodeState(store, value));
                 } else if (!value.equals(afterEntry.getValue())) {
                     rv = diff.childNodeChanged(
                             key,
-                            new SegmentNodeState(value),
+                            new SegmentNodeState(store, value),
                             afterEntry.getNodeState());
                 }
             }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Record.java Mon May 23 12:59:22 2016
@@ -62,15 +62,6 @@ class Record {
     }
 
     /**
-     * Returns the tracker of the segment that contains this record.
-     *
-     * @return segment tracker
-     */
-    protected SegmentTracker getTracker() {
-        return segmentId.getTracker();
-    }
-
-    /**
      * Returns the segment that contains this record.
      *
      * @return segment that contains this record

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordId.java Mon May 23 12:59:22 2016
@@ -89,6 +89,7 @@ public final class RecordId implements C
         return segmentId.asUUID();
     }
 
+    @Nonnull
     public Segment getSegment() {
         return segmentId.getSegment();
     }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyser.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyser.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/RecordUsageAnalyser.java Mon May 23 12:59:22 2016
@@ -25,6 +25,8 @@ import static org.apache.commons.io.File
 import java.util.Formatter;
 import java.util.Set;
 
+import javax.annotation.Nonnull;
+
 /**
  * This utility breaks down space usage per record type.
  * It accounts for value sharing. That is, an instance
@@ -56,6 +58,10 @@ public class RecordUsageAnalyser extends
     private long templateCount;
     private long nodeCount;
 
+    public RecordUsageAnalyser(@Nonnull SegmentStore store) {
+        super(store);
+    }
+
     /**
      * @return number of bytes in {@link RecordType#LEAF leaf} and {@link RecordType#BRANCH branch}
      * records.

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/Segment.java Mon May 23 12:59:22 2016
@@ -26,28 +26,25 @@ import static com.google.common.collect.
 import static com.google.common.collect.Maps.newConcurrentMap;
 import static java.lang.Boolean.getBoolean;
 import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly;
+import static org.apache.jackrabbit.oak.segment.SegmentBlob.readBlobId;
 import static org.apache.jackrabbit.oak.segment.SegmentId.isDataSegmentId;
 import static org.apache.jackrabbit.oak.segment.SegmentVersion.LATEST_VERSION;
 import static org.apache.jackrabbit.oak.segment.SegmentVersion.isValid;
 import static org.apache.jackrabbit.oak.segment.SegmentWriter.BLOCK_SIZE;
 
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.nio.ByteBuffer;
-import java.nio.channels.Channels;
-import java.nio.channels.WritableByteChannel;
 import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentMap;
 
 import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
+import javax.annotation.Nonnull;
 
 import com.google.common.base.Charsets;
-import com.google.common.base.Function;
 import org.apache.commons.io.HexDump;
 import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.jackrabbit.oak.api.PropertyState;
@@ -127,7 +124,7 @@ public class Segment {
 
     public static final int GC_GENERATION_OFFSET = 10;
 
-    private final SegmentTracker tracker;
+    private final SegmentStore store;
 
     private final SegmentId id;
 
@@ -144,24 +141,12 @@ public class Segment {
      */
     private final SegmentId[] refids;
 
-    private final Function<Integer, String> loadString = new Function<Integer, String>() {
-        @Nullable
-        @Override
-        public String apply(Integer offset) {
-            return loadString(offset);
-        }
-    };
-
-    /**
-     * Cache for string records
-     */
-    private final StringCache stringCache;
-
     /**
      * Template records read from segment. Used to avoid duplicate
      * copies and repeated parsing of the same templates.
+     * FIXME OAK-4373 move the template cache to the segment reader along side with the string cache
      */
-    private final ConcurrentMap<Integer, Template> templates;
+    final ConcurrentMap<Integer, Template> templates;
 
     private static final boolean DISABLE_TEMPLATE_CACHE = getBoolean("oak.segment.disableTemplateCache");
 
@@ -195,11 +180,12 @@ public class Segment {
         return (address + boundary - 1) & ~(boundary - 1);
     }
 
-    public Segment(SegmentTracker tracker, final SegmentId id, final ByteBuffer data) {
-        this.tracker = checkNotNull(tracker);
+    public Segment(@Nonnull SegmentStore store,
+                   @Nonnull final SegmentId id,
+                   @Nonnull final ByteBuffer data) {
+        this.store = checkNotNull(store);
         this.id = checkNotNull(id);
 
-        stringCache = tracker.getStringCache();
         if (DISABLE_TEMPLATE_CACHE) {
             templates = null;
         } else {
@@ -240,11 +226,10 @@ public class Segment {
         }
     }
 
-    Segment(SegmentTracker tracker, byte[] buffer, String info) {
-        this.tracker = checkNotNull(tracker);
-        this.id = tracker.newDataSegmentId();
-        this.info = info;
-        stringCache = tracker.getStringCache();
+    Segment(@Nonnull SegmentStore store, @Nonnull byte[] buffer, @Nonnull String info) {
+        this.store = checkNotNull(store);
+        this.id = store.getTracker().newDataSegmentId();
+        this.info = checkNotNull(info);
         if (DISABLE_TEMPLATE_CACHE) {
             templates = null;
         } else {
@@ -255,7 +240,7 @@ public class Segment {
         this.refids = new SegmentId[SEGMENT_REFERENCE_LIMIT + 1];
         this.refids[0] = id;
         this.version = SegmentVersion.fromByte(buffer[3]);
-        this.id.setSegment(this);
+        id.loaded(this);
     }
 
     SegmentVersion getSegmentVersion() {
@@ -370,7 +355,7 @@ public class Segment {
                     int refpos = data.position() + index * 16;
                     long msb = data.getLong(refpos);
                     long lsb = data.getLong(refpos + 8);
-                    refid = tracker.getSegmentId(msb, lsb);
+                    refid = store.getTracker().getSegmentId(msb, lsb);
                     refids[index] = refid;
                 }
             }
@@ -391,31 +376,6 @@ public class Segment {
         return data.remaining();
     }
 
-    public long getCacheSize() {
-        int size = 1024;
-        if (!data.isDirect()) {
-            size += size();
-        }
-        if (id.isDataSegmentId()) {
-            size += size();
-        }
-        return size;
-    }
-
-    /**
-     * Writes this segment to the given output stream.
-     *
-     * @param stream stream to which this segment will be written
-     * @throws IOException on an IO error
-     */
-    public void writeTo(OutputStream stream) throws IOException {
-        ByteBuffer buffer = data.duplicate();
-        WritableByteChannel channel = Channels.newChannel(stream);
-        while (buffer.hasRemaining()) {
-            channel.write(buffer);
-        }
-    }
-
     public void collectBlobReferences(ReferenceCollector collector) {
         int refcount = getRefCount();
         int rootcount =
@@ -425,9 +385,8 @@ public class Segment {
         int blobrefpos = data.position() + refcount * 16 + rootcount * 3;
 
         for (int i = 0; i < blobrefcount; i++) {
-            int offset = (data.getShort(blobrefpos + i * 2) & 0xffff) << 2;
-            SegmentBlob blob = new SegmentBlob(new RecordId(id, offset));
-            collector.addReference(blob.getBlobId(), null);
+            int offset = (data.getShort(blobrefpos + i * 2) & 0xffff) << RECORD_ALIGN_BITS;
+            collector.addReference(readBlobId(store, this, offset), null);
         }
     }
 
@@ -475,31 +434,8 @@ public class Segment {
         return new RecordId(refid, offset << RECORD_ALIGN_BITS);
     }
 
-    static String readString(final RecordId id) {
-        final SegmentId segmentId = id.getSegmentId();
-        StringCache cache = segmentId.getTracker().getStringCache();
-        if (cache == null) {
-            return segmentId.getSegment().readString(id.getOffset());
-        } else {
-            long msb = segmentId.getMostSignificantBits();
-            long lsb = segmentId.getLeastSignificantBits();
-            return cache.getString(msb, lsb, id.getOffset(), new Function<Integer, String>() {
-                @Nullable
-                @Override
-                public String apply(Integer offset) {
-                    return segmentId.getSegment().loadString(offset);
-                }
-            });
-        }
-    }
-
-    private String readString(int offset) {
-        long msb = id.getMostSignificantBits();
-        long lsb = id.getLeastSignificantBits();
-        return stringCache.getString(msb, lsb, offset, loadString);
-    }
-
-    private String loadString(int offset) {
+    @Nonnull
+    public String readString(int offset) {
         int pos = pos(offset, 1);
         long length = internalReadLength(pos);
         if (length < SMALL_LIMIT) {
@@ -530,27 +466,8 @@ public class Segment {
         }
     }
 
-    MapRecord readMap(RecordId id) {
-        return new MapRecord(id);
-    }
-
-    Template readTemplate(final RecordId id) {
-        return id.getSegment().readTemplate(id.getOffset());
-    }
-
-    private Template readTemplate(int offset) {
-        if (templates == null) {
-            return loadTemplate(offset);
-        }
-        Template template = templates.get(offset);
-        if (template == null) {
-            template = loadTemplate(offset);
-            templates.putIfAbsent(offset, template); // only keep the first copy
-        }
-        return template;
-    }
-
-    private Template loadTemplate(int offset) {
+    @Nonnull
+    Template readTemplate(int offset) {
         int head = readInt(offset);
         boolean hasPrimaryType = (head & (1 << 31)) != 0;
         boolean hasMixinTypes = (head & (1 << 30)) != 0;
@@ -564,7 +481,7 @@ public class Segment {
         if (hasPrimaryType) {
             RecordId primaryId = readRecordId(offset);
             primaryType = PropertyStates.createProperty(
-                    "jcr:primaryType", readString(primaryId), Type.NAME);
+                    "jcr:primaryType", store.getReader().readString(primaryId), Type.NAME);
             offset += RECORD_ID_BYTES;
         }
 
@@ -573,7 +490,7 @@ public class Segment {
             String[] mixins = new String[mixinCount];
             for (int i = 0; i < mixins.length; i++) {
                 RecordId mixinId = readRecordId(offset);
-                mixins[i] =  readString(mixinId);
+                mixins[i] =  store.getReader().readString(mixinId);
                 offset += RECORD_ID_BYTES;
             }
             mixinTypes = PropertyStates.createProperty(
@@ -585,13 +502,13 @@ public class Segment {
             childName = Template.MANY_CHILD_NODES;
         } else if (!zeroChildNodes) {
             RecordId childNameId = readRecordId(offset);
-            childName = readString(childNameId);
+            childName = store.getReader().readString(childNameId);
             offset += RECORD_ID_BYTES;
         }
 
         PropertyTemplate[] properties;
         properties = readProps(propertyCount, offset);
-        return new Template(primaryType, mixinTypes, properties, childName);
+        return new Template(store, primaryType, mixinTypes, properties, childName);
     }
 
     private PropertyTemplate[] readProps(int propertyCount, int offset) {
@@ -603,7 +520,7 @@ public class Segment {
             for (int i = 0; i < propertyCount; i++) {
                 byte type = readByte(offset++);
                 properties[i] = new PropertyTemplate(i,
-                        readString(propertyNames.getEntry(i)), Type.fromTag(
+                        store.getReader().readString(propertyNames.getEntry(i)), Type.fromTag(
                                 Math.abs(type), type < 0));
             }
         }
@@ -671,11 +588,9 @@ public class Segment {
             pos += rootcount * 3;
             for (int blobrefid = 0; blobrefid < blobrefcount; blobrefid++) {
                 int offset = data.getShort(pos + blobrefid * 2) & 0xffff;
-                SegmentBlob blob = new SegmentBlob(
-                        new RecordId(id, offset << RECORD_ALIGN_BITS));
                 writer.format(
                         "blobref %d: %s at %04x%n", blobrefid,
-                        blob.getBlobId(), offset);
+                        readBlobId(store, this, offset << RECORD_ALIGN_BITS), offset);
             }
         }
         writer.println("--------------------------------------------------------------------------");

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBlob.java Mon May 23 12:59:22 2016
@@ -19,6 +19,7 @@
 package org.apache.jackrabbit.oak.segment;
 
 import static com.google.common.base.Charsets.UTF_8;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Sets.newHashSet;
 import static java.util.Collections.emptySet;
 import static org.apache.jackrabbit.oak.segment.Segment.MEDIUM_LIMIT;
@@ -41,6 +42,9 @@ import org.apache.jackrabbit.oak.spi.blo
  */
 public class SegmentBlob extends Record implements Blob {
 
+    @Nonnull
+    private final SegmentStore store;
+
     public static Iterable<SegmentId> getBulkSegmentIds(Blob blob) {
         if (blob instanceof SegmentBlob) {
             return ((SegmentBlob) blob).getBulkSegmentIds();
@@ -49,8 +53,9 @@ public class SegmentBlob extends Record
         }
     }
 
-    SegmentBlob(RecordId id) {
+    SegmentBlob(@Nonnull SegmentStore store, @Nonnull RecordId id) {
         super(id);
+        this.store = checkNotNull(store);
     }
 
     private InputStream getInlineStream(
@@ -84,7 +89,7 @@ public class SegmentBlob extends Record
             return getNewStream(readShortBlobId(segment, offset, head));
         } else if ((head & 0xf8) == 0xf0) {
             // 1111 0xxx: external value, long blob ID
-            return getNewStream(readLongBlobId(segment, offset));
+            return getNewStream(readLongBlobId(store, segment, offset));
         } else {
             throw new IllegalStateException(String.format(
                     "Unexpected value record type: %02x", head & 0xff));
@@ -110,7 +115,7 @@ public class SegmentBlob extends Record
             return getLength(readShortBlobId(segment, offset, head));
         } else if ((head & 0xf8) == 0xf0) {
             // 1111 0xxx: external value, long blob ID
-            return getLength(readLongBlobId(segment, offset));
+            return getLength(readLongBlobId(store, segment, offset));
         } else {
             throw new IllegalStateException(String.format(
                     "Unexpected value record type: %02x", head & 0xff));
@@ -122,8 +127,7 @@ public class SegmentBlob extends Record
     public String getReference() {
         String blobId = getBlobId();
         if (blobId != null) {
-            BlobStore blobStore = getSegment().getSegmentId().getTracker().
-                    getStore().getBlobStore();
+            BlobStore blobStore = store.getBlobStore();
             if (blobStore != null) {
                 return blobStore.getReference(blobId);
             } else {
@@ -152,16 +156,20 @@ public class SegmentBlob extends Record
         return (head & 0xf0) == 0xe0 || (head & 0xf8) == 0xf0;
     }
 
+    @CheckForNull
     public String getBlobId() {
-        Segment segment = getSegment();
-        int offset = getOffset();
+        return readBlobId(store, getSegment(), getOffset());
+    }
+
+    @CheckForNull
+    static String readBlobId(@Nonnull SegmentStore store, @Nonnull Segment segment, int offset) {
         byte head = segment.readByte(offset);
         if ((head & 0xf0) == 0xe0) {
             // 1110 xxxx: external value, small blob ID
             return readShortBlobId(segment, offset, head);
         } else if ((head & 0xf8) == 0xf0) {
             // 1111 0xxx: external value, long blob ID
-            return readLongBlobId(segment, offset);
+            return readLongBlobId(store, segment, offset);
         } else {
             return null;
         }
@@ -204,9 +212,9 @@ public class SegmentBlob extends Record
         return new String(bytes, UTF_8);
     }
 
-    private static String readLongBlobId(Segment segment, int offset) {
+    private static String readLongBlobId(SegmentStore store, Segment segment, int offset) {
         RecordId blobIdRecordId = segment.readRecordId(offset + 1);
-        return Segment.readString(blobIdRecordId);
+        return store.getReader().readString(blobIdRecordId);
     }
 
     private List<RecordId> getBulkRecordIds() {
@@ -239,7 +247,7 @@ public class SegmentBlob extends Record
     }
 
     private Blob getBlob(String blobId) {
-        return getSegment().getSegmentId().getTracker().getStore().readBlob(blobId);
+        return store.readBlob(blobId);
     }
 
     private InputStream getNewStream(String blobId) {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriter.java Mon May 23 12:59:22 2016
@@ -88,8 +88,6 @@ public class SegmentBufferWriter impleme
      */
     private final String wid;
 
-    private final SegmentTracker tracker;
-
     private final int generation;
 
     /**
@@ -119,15 +117,10 @@ public class SegmentBufferWriter impleme
                 ? "w-" + identityHashCode(this)
                 : wid);
 
-        this.tracker = store.getTracker();
         this.generation = generation;
         newSegment();
     }
 
-    public SegmentBufferWriter(SegmentStore store, SegmentVersion version, String wid) {
-        this(store, version, wid, store.getTracker().getGcGeneration());
-    }
-
     @Override
     public RecordId execute(WriteOperation writeOperation) throws IOException {
         return writeOperation.execute(this);
@@ -169,10 +162,10 @@ public class SegmentBufferWriter impleme
 
         String metaInfo =
             "{\"wid\":\"" + wid + '"' +
-            ",\"sno\":" + tracker.getSegmentCount() +
+            ",\"sno\":" + store.getTracker().getSegmentCount() +
             ",\"t\":" + currentTimeMillis() + "}";
         try {
-            segment = new Segment(tracker, buffer, metaInfo);
+            segment = new Segment(store, buffer, metaInfo);
             byte[] data = metaInfo.getBytes(UTF_8);
             RecordWriters.newValueWriter(data.length, data).write(this);
         } catch (IOException e) {
@@ -328,25 +321,8 @@ public class SegmentBufferWriter impleme
             }
 
             SegmentId segmentId = segment.getSegmentId();
-            int segmentOffset = buffer.length - length;
-
             LOG.debug("Writing data segment {} ({} bytes)", segmentId, length);
-            store.writeSegment(segmentId, buffer, segmentOffset, length);
-
-            // Keep this segment in memory as it's likely to be accessed soon
-            ByteBuffer data;
-            if (segmentOffset > 4096) {
-                data = ByteBuffer.allocate(length);
-                data.put(buffer, segmentOffset, length);
-                data.rewind();
-            } else {
-                data = ByteBuffer.wrap(buffer, segmentOffset, length);
-            }
-
-            // It is important to put the segment into the cache only *after* it has been
-            // written to the store since as soon as it is in the cache it becomes eligible
-            // for eviction, which might lead to SNFEs when it is not yet in the store at that point.
-            tracker.setSegment(segmentId, new Segment(tracker, segmentId, data));
+            store.writeSegment(segmentId, buffer, buffer.length - length, length);
             newSegment();
         }
     }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentBufferWriterPool.java Mon May 23 12:59:22 2016
@@ -19,6 +19,7 @@
 
 package org.apache.jackrabbit.oak.segment;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.newHashMap;
@@ -30,26 +31,52 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import javax.annotation.Nonnull;
+
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+
 /**
  * This {@link WriteOperationHandler} uses a pool of {@link SegmentBufferWriter}s,
  * which it passes to its {@link #execute(WriteOperation) execute} method.
  */
-class SegmentBufferWriterPool implements WriteOperationHandler {
+public class SegmentBufferWriterPool implements WriteOperationHandler {
     private final Map<Object, SegmentBufferWriter> writers = newHashMap();
     private final Set<SegmentBufferWriter> borrowed = newHashSet();
     private final Set<SegmentBufferWriter> disposed = newHashSet();
+
+    @Nonnull
     private final SegmentStore store;
+
+    @Nonnull
+    private final Supplier<Integer> gcGeneration;
+
+    @Nonnull
     private final SegmentVersion version;
+
+    @Nonnull
     private final String wid;
 
     private short writerId = -1;
 
-    SegmentBufferWriterPool(SegmentStore store, SegmentVersion version, String wid) {
-        this.store = store;
-        this.version = version;
-        this.wid = wid;
+    public SegmentBufferWriterPool(
+            @Nonnull SegmentStore store,
+            @Nonnull SegmentVersion version,
+            @Nonnull String wid,
+            @Nonnull Supplier<Integer> gcGeneration) {
+        this.store = checkNotNull(store);
+        this.version = checkNotNull(version);
+        this.wid = checkNotNull(wid);
+        this.gcGeneration = checkNotNull(gcGeneration);
     }
 
+    public SegmentBufferWriterPool(
+            @Nonnull SegmentStore store,
+            @Nonnull SegmentVersion version,
+            @Nonnull  String wid) {
+            this(store, version, wid, Suppliers.ofInstance(0));
+        }
+
     @Override
     public RecordId execute(WriteOperation writeOperation) throws IOException {
         SegmentBufferWriter writer = borrowWriter(currentThread());
@@ -80,10 +107,10 @@ class SegmentBufferWriterPool implements
     private synchronized SegmentBufferWriter borrowWriter(Object key) {
         SegmentBufferWriter writer = writers.remove(key);
         if (writer == null) {
-            writer = new SegmentBufferWriter(store, version, getWriterId(wid));
-        } else if (writer.getGeneration() != store.getTracker().getGcGeneration()) {
+            writer = new SegmentBufferWriter(store, version, getWriterId(wid), gcGeneration.get());
+        } else if (writer.getGeneration() != gcGeneration.get()) {
             disposed.add(writer);
-            writer = new SegmentBufferWriter(store, version, getWriterId(wid));
+            writer = new SegmentBufferWriter(store, version, getWriterId(wid), gcGeneration.get());
         }
         borrowed.add(writer);
         return writer;

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentCache.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentCache.java?rev=1745182&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentCache.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentCache.java Mon May 23 12:59:22 2016
@@ -0,0 +1,96 @@
+/*
+ * 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.segment;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import com.google.common.cache.RemovalCause;
+import org.apache.jackrabbit.oak.cache.CacheLIRS;
+import org.apache.jackrabbit.oak.cache.CacheLIRS.EvictionCallback;
+import org.apache.jackrabbit.oak.cache.CacheStats;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * FIXME OAK-4373 document, add monitoring, management, tests, logging
+ */
+public class SegmentCache {
+    private static final Logger LOG = LoggerFactory.getLogger(SegmentCache.class);
+
+    /**
+     * Cache of recently accessed segments
+     */
+    @Nonnull
+    private final CacheLIRS<SegmentId, Segment> cache;
+
+    public SegmentCache(long cacheSizeMB) {
+        this.cache = CacheLIRS.<SegmentId, Segment>newBuilder()
+            .module("SegmentCache")
+            .maximumWeight(cacheSizeMB * 1024 * 1024)
+            .averageWeight(Segment.MAX_SEGMENT_SIZE/2)
+            .evictionCallback(new EvictionCallback<SegmentId, Segment>() {
+                @Override
+                public void evicted(SegmentId id, Segment segment, RemovalCause cause) {
+                    if (segment != null) {
+                        id.unloaded();
+                    }
+                } })
+            .build();
+    }
+
+    /**
+     * Get a segment from the cache
+     * @param id  segment id
+     * @return  segment with the given {@code id} or {@code null} if not in the cache
+     */
+    @CheckForNull
+    public Segment geSegment(@Nonnull SegmentId id) {
+        try {
+            return cache.get(id);
+        } catch (ExecutionException e) {
+            LOG.error("Error loading segment {} from cache", id, e);
+            return null;
+        }
+    }
+
+    @Nonnull
+    public Segment geSegment(@Nonnull SegmentId id, @Nonnull Callable<Segment> loader)
+    throws ExecutionException {
+        return cache.get(id, loader);
+    }
+
+    public void putSegment(@Nonnull Segment segment) {
+        cache.put(segment.getSegmentId(), segment, segment.size());
+        segment.getSegmentId().loaded(segment);
+    }
+
+    public void clear() {
+        cache.invalidateAll();
+    }
+
+    @Nonnull
+    public CacheStats getCacheStats() {
+        return new CacheStats(cache, "Segment Cache", null, -1);
+    }
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentGraph.java Mon May 23 12:59:22 2016
@@ -166,7 +166,7 @@ public final class SegmentGraph {
                 ? Predicates.<UUID>alwaysTrue()
                 : createRegExpFilter(pattern, fileStore.getTracker());
             Graph<UUID> segmentGraph = parseSegmentGraph(fileStore, filter);
-            Graph<UUID> headGraph = parseHeadGraph(root.getRecordId());
+            Graph<UUID> headGraph = parseHeadGraph(fileStore, root.getRecordId());
 
             writer.write("nodedef>name VARCHAR, label VARCHAR, type VARCHAR, wid VARCHAR, gc INT, t INT, size INT, head BOOLEAN\n");
             for (UUID segment : segmentGraph.vertices()) {
@@ -349,17 +349,18 @@ public final class SegmentGraph {
     }
 
     /**
-     * Parser the head graph. The head graph is the sub graph of the segment
+     * Parser the head graph of a {@code store}. The head graph is the sub graph of the segment
      * graph containing the {@code root}.
+     * @param store
      * @param root
      * @return  the head graph of {@code root}.
      */
     @Nonnull
-    public static Graph<UUID> parseHeadGraph(@Nonnull RecordId root) {
+    public static Graph<UUID> parseHeadGraph(@Nonnull SegmentStore store, @Nonnull RecordId root) {
         final Graph<UUID> graph = new Graph<UUID>();
 
         try {
-            new SegmentParser() {
+            new SegmentParser(store) {
                 private void addEdge(RecordId from, RecordId to) {
                     graph.addVertex(from.asUUID());
                     graph.addVertex(to.asUUID());

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentId.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentId.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentId.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentId.java Mon May 23 12:59:22 2016
@@ -18,11 +18,10 @@
  */
 package org.apache.jackrabbit.oak.segment;
 
-import static java.lang.Integer.getInteger;
-import static java.lang.Integer.rotateLeft;
-
 import java.util.UUID;
 
+import javax.annotation.Nonnull;
+
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,21 +36,6 @@ public class SegmentId implements Compar
     private static final Logger log = LoggerFactory.getLogger(SegmentId.class);
 
     /**
-     * Sample rate bit mask of {@link SegmentTracker#segmentCache}. Lower values
-     * will cause more frequent accesses to that cache instead of the short
-     * circuit through {@link SegmentId#segment}. Access to that cache is slower
-     * but allows tracking access statistics. Should be 2^x - 1 (for example
-     * 1023, 255, 15,...).
-     */
-    private static final int SEGMENT_CACHE_SAMPLE_MASK = getInteger("SegmentCacheSampleRate", 1023);
-
-    /**
-     * The initial random value for the pseudo random number generator. Initial
-     * values of 0 - 0xffff will ensure a long period, but other values don't.
-     */
-    private static volatile int random = (int) (System.currentTimeMillis() & 0xffff);
-    
-    /**
      * Checks whether this is a data segment identifier.
      *
      * @return {@code true} for a data segment, {@code false} otherwise
@@ -60,7 +44,8 @@ public class SegmentId implements Compar
         return (lsb >>> 60) == 0xAL;
     }
 
-    private final SegmentTracker tracker;
+    @Nonnull
+    private final SegmentStore store;
 
     private final long msb;
 
@@ -70,15 +55,12 @@ public class SegmentId implements Compar
 
     /**
      * A reference to the segment object, if it is available in memory. It is
-     * used for fast lookup. The segment tracker will set or reset this field.
-     * <p>
-     * Needs to be volatile so {@link #setSegment(Segment)} doesn't need to
-     * be synchronized as this would lead to deadlocks.
+     * used for fast lookup.
      */
     private volatile Segment segment;
 
-    public SegmentId(SegmentTracker tracker, long msb, long lsb) {
-        this.tracker = tracker;
+    public SegmentId(@Nonnull SegmentStore store, long msb, long lsb) {
+        this.store = store;
         this.msb = msb;
         this.lsb = lsb;
         this.creationTime = System.currentTimeMillis();
@@ -110,47 +92,37 @@ public class SegmentId implements Compar
         return lsb;
     }
 
-    /**
-     * Get a random integer. A fast, but lower quality pseudo random number
-     * generator is used.
-     * 
-     * @return a random value.
-     */
-    private static int randomInt() {
-        // There is a race here on concurrent access. However, given the usage the resulting
-        // bias seems preferable to the performance penalty of synchronization
-        return random = 0xc3e157c1 - rotateLeft(random, 19);
-    }
-
     public Segment getSegment() {
-        // Sample the segment cache once in a while to get some cache hit/miss statistics
-        if ((randomInt() & SEGMENT_CACHE_SAMPLE_MASK) == 0) {
-            Segment segment = tracker.getCachedSegment(this);
-            if (segment != null) {
-                return segment;
-            }
-        }
-
-        // Fall back to short circuit via this.segment if not in the cache
         Segment segment = this.segment;
         if (segment == null) {
             synchronized (this) {
                 segment = this.segment;
                 if (segment == null) {
-                    log.debug("Loading segment {}", this);
-                    segment = tracker.readSegment(this);
+                    try {
+                        log.debug("Loading segment {}", this);
+                        segment = store.readSegment(this);
+                    } catch (SegmentNotFoundException snfe) {
+                        long delta = System.currentTimeMillis() - creationTime;
+                        log.error("Segment not found: {}. Creation date delta is {} ms.",
+                                this, delta, snfe);
+                        throw snfe;
+                    }
                 }
             }
         }
         return segment;
     }
 
-    void setSegment(Segment segment) {
+    void loaded(@Nonnull Segment segment) {
         this.segment = segment;
     }
 
-    public SegmentTracker getTracker() {
-        return tracker;
+    void unloaded() {
+        this.segment = null;
+    }
+
+    public boolean sameStore(@Nonnull SegmentStore store) {
+        return this.store == store;
     }
 
     public long getCreationTime() {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentIdTable.java Mon May 23 12:59:22 2016
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.segment;
 
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
 import static java.util.Collections.nCopies;
@@ -28,6 +29,8 @@ import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
+import javax.annotation.Nonnull;
+
 import com.google.common.base.Predicate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -60,8 +63,9 @@ public class SegmentIdTable {
     private final ArrayList<WeakReference<SegmentId>> references =
             newArrayList(nCopies(1024, (WeakReference<SegmentId>) null));
 
-    private final SegmentTracker tracker;
-    
+    @Nonnull
+    private final SegmentStore store;
+
     private static final Logger LOG = LoggerFactory.getLogger(SegmentIdTable.class);
 
     
@@ -75,8 +79,8 @@ public class SegmentIdTable {
      */
     private int entryCount;
 
-    SegmentIdTable(SegmentTracker tracker) {
-        this.tracker = tracker;
+    SegmentIdTable(@Nonnull SegmentStore store) {
+        this.store = checkNotNull(store);
     }
 
     /**
@@ -106,7 +110,7 @@ public class SegmentIdTable {
             reference = references.get(index);
         }
 
-        SegmentId id = new SegmentId(tracker, msb, lsb);
+        SegmentId id = new SegmentId(store, msb, lsb);
         references.set(index, new WeakReference<SegmentId>(id));
         entryCount++;
         if (entryCount > references.size() * 0.75) {

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeBuilder.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeBuilder.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeBuilder.java Mon May 23 12:59:22 2016
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.segment;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -45,6 +47,7 @@ public class SegmentNodeBuilder extends
     private static final int UPDATE_LIMIT =
             Integer.getInteger("update.limit", 10000);
 
+    @Nonnull
     private final SegmentWriter writer;
 
     /**
@@ -61,20 +64,15 @@ public class SegmentNodeBuilder extends
      */
     private long updateCount;
 
-    SegmentNodeBuilder(SegmentNodeState base) {
-        this(base, base.getTracker().getWriter());
-    }
-
-    SegmentNodeBuilder(SegmentNodeState base, SegmentWriter writer) {
+    SegmentNodeBuilder(@Nonnull SegmentNodeState base, @Nonnull SegmentWriter writer) {
         super(base);
-        this.writer = writer;
+        this.writer = checkNotNull(writer);
         this.updateCount = 0;
     }
 
-    private SegmentNodeBuilder(SegmentNodeBuilder parent, String name,
-            SegmentWriter writer) {
+    private SegmentNodeBuilder(SegmentNodeBuilder parent, String name, @Nonnull SegmentWriter writer) {
         super(parent, name);
-        this.writer = writer;
+        this.writer = checkNotNull(writer);
         this.updateCount = -1;
     }
 
@@ -129,8 +127,7 @@ public class SegmentNodeBuilder extends
 
     @Override
     public Blob createBlob(InputStream stream) throws IOException {
-        SegmentNodeState sns = getNodeState();
-        return sns.getTracker().getWriter().writeStream(stream);
+        return writer.writeStream(stream);
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeState.java Mon May 23 12:59:22 2016
@@ -33,7 +33,6 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.api.Type.STRINGS;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
 import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.MISSING_NODE;
-import static org.apache.jackrabbit.oak.segment.Segment.readString;
 import static org.apache.jackrabbit.oak.segment.Segment.unpack;
 import static org.apache.jackrabbit.oak.spi.state.AbstractNodeState.checkValidName;
 
@@ -58,13 +57,16 @@ import org.apache.jackrabbit.oak.spi.sta
  * currently doesn't cache data (but the template is fully loaded).
  */
 public class SegmentNodeState extends Record implements NodeState {
+    @Nonnull
+    private final SegmentStore store;
 
     private volatile RecordId templateId = null;
 
     private volatile Template template = null;
 
-    public SegmentNodeState(RecordId id) {
+    public SegmentNodeState(@Nonnull SegmentStore store, @Nonnull RecordId id) {
         super(id);
+        this.store = checkNotNull(store);
     }
 
     RecordId getTemplateId() {
@@ -80,14 +82,14 @@ public class SegmentNodeState extends Re
         if (template == null) {
             // no problem if updated concurrently,
             // as each concurrent thread will just get the same value
-            template = getSegment().readTemplate(getTemplateId());
+            template = store.getReader().readTemplate(store, getTemplateId());
         }
         return template;
     }
 
     MapRecord getChildNodeMap() {
         Segment segment = getSegment();
-        return segment.readMap(segment.readRecordId(getOffset(0, 2)));
+        return store.getReader().readMap(store, segment.readRecordId(getOffset(0, 2)));
     }
 
     /**
@@ -161,7 +163,7 @@ public class SegmentNodeState extends Re
         if (propertyTemplate != null) {
             Segment segment = getSegment();
             RecordId id = getRecordId(segment, template, propertyTemplate);
-            return new SegmentPropertyState(id, propertyTemplate);
+            return new SegmentPropertyState(store, id, propertyTemplate);
         } else {
             return null;
         }
@@ -208,8 +210,7 @@ public class SegmentNodeState extends Re
                     propertyTemplates.length);
             for (int i = 0; i < propertyTemplates.length; i++) {
                 RecordId propertyId = pIds.getEntry(i);
-                list.add(new SegmentPropertyState(propertyId,
-                        propertyTemplates[i]));
+                list.add(new SegmentPropertyState(store, propertyId, propertyTemplates[i]));
             }
         }
 
@@ -288,7 +289,7 @@ public class SegmentNodeState extends Re
 
         Segment segment = getSegment();
         RecordId id = getRecordId(segment, template, propertyTemplate);
-        return readString(id);
+        return store.getReader().readString(id);
     }
 
     /**
@@ -334,13 +335,13 @@ public class SegmentNodeState extends Re
 
         id = segment.readRecordId(id.getOffset() + 4);
         if (size == 1) {
-            return singletonList(readString(id));
+            return singletonList(store.getReader().readString(id));
         }
 
         List<String> values = newArrayListWithCapacity(size);
         ListRecord list = new ListRecord(id, size);
         for (RecordId value : list.getEntries()) {
-            values.add(readString(value));
+            values.add(store.getReader().readString(value));
         }
         return values;
     }
@@ -381,7 +382,7 @@ public class SegmentNodeState extends Re
                 && childName.equals(name)) {
             Segment segment = getSegment();
             RecordId childNodeId = segment.readRecordId(getOffset(0, 2));
-            return new SegmentNodeState(childNodeId);
+            return new SegmentNodeState(store, childNodeId);
         }
         checkValidName(name);
         return MISSING_NODE;
@@ -410,13 +411,13 @@ public class SegmentNodeState extends Re
             Segment segment = getSegment();
             RecordId childNodeId = segment.readRecordId(getOffset(0, 2));
             return Collections.singletonList(new MemoryChildNodeEntry(
-                    childName, new SegmentNodeState(childNodeId)));
+                    childName, new SegmentNodeState(store, childNodeId)));
         }
     }
 
     @Override @Nonnull
     public SegmentNodeBuilder builder() {
-        return new SegmentNodeBuilder(this);
+        return new SegmentNodeBuilder(this, store.getWriter());
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStore.java Mon May 23 12:59:22 2016
@@ -291,7 +291,7 @@ public class SegmentNodeStore implements
 
     @Override
     public Blob createBlob(InputStream stream) throws IOException {
-        return store.getTracker().getWriter().writeStream(stream);
+        return store.getWriter().writeStream(stream);
     }
 
     @Override

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java Mon May 23 12:59:22 2016
@@ -360,9 +360,8 @@ public class SegmentNodeStoreService ext
 
         // Expose stats about the segment cache
 
-        CacheStats segmentCacheStats = store.getTracker().getSegmentCacheStats();
-
-        segmentCacheMBean = registerMBean(
+        CacheStats segmentCacheStats = store.getSegmentCacheStats();
+         segmentCacheMBean = registerMBean(
                 whiteboard,
                 CacheStatsMBean.class,
                 segmentCacheStats,
@@ -372,16 +371,13 @@ public class SegmentNodeStoreService ext
 
         // Expose stats about the string cache, if available
 
-        CacheStats stringCacheStats = store.getTracker().getStringCacheStats();
-
-        if (stringCacheStats != null) {
-            stringCacheMBean = registerMBean(
-                    whiteboard,
-                    CacheStatsMBean.class,
-                    stringCacheStats,CacheStats.TYPE,
-                    stringCacheStats.getName()
-            );
-        }
+        CacheStats stringCacheStats = store.getReader().getStringCacheStats();
+        stringCacheMBean = registerMBean(
+                whiteboard,
+                CacheStatsMBean.class,
+                stringCacheStats,CacheStats.TYPE,
+                stringCacheStats.getName()
+        );
 
         // Listen for Executor services on the whiteboard
 

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentParser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentParser.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentParser.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentParser.java Mon May 23 12:59:22 2016
@@ -20,6 +20,7 @@
 package org.apache.jackrabbit.oak.segment;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Lists.newArrayListWithCapacity;
 import static java.util.Collections.singletonList;
@@ -34,6 +35,8 @@ import static org.apache.jackrabbit.oak.
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.blob.BlobStore;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
@@ -254,6 +257,13 @@ public class SegmentParser {
         }
     }
 
+    @Nonnull
+    private final SegmentStore store;
+
+    public SegmentParser(@Nonnull SegmentStore store) {
+        this.store = checkNotNull(store);
+    }
+
     /**
      * Callback called by {@link #parseNode(RecordId)} upon encountering
      * a child node.
@@ -413,22 +423,22 @@ public class SegmentParser {
 
         Segment segment = nodeId.getSegment();
         int offset = nodeId.getOffset();
-        String stableId = new SegmentNodeState(nodeId).getStableId();
+        String stableId = new SegmentNodeState(store, nodeId).getStableId();
         offset += RECORD_ID_BYTES;
         RecordId templateId = segment.readRecordId(offset);
         onTemplate(nodeId, templateId);
 
-        Template template = segment.readTemplate(templateId);
+        Template template = store.getReader().readTemplate(store, templateId);
 
         // Recurses into child nodes in this segment
         if (template.getChildName() == MANY_CHILD_NODES) {
             RecordId childMapId = segment.readRecordId(offset + RECORD_ID_BYTES);
-            MapRecord childMap = segment.readMap(childMapId);
+            MapRecord childMap = store.getReader().readMap(store, childMapId);
             onMap(nodeId, childMapId, childMap);
             for (ChildNodeEntry childNodeEntry : childMap.getEntries()) {
                 NodeState child = childNodeEntry.getNodeState();
                 if (child instanceof SegmentNodeState) {
-                    RecordId childId = ((SegmentNodeState) child).getRecordId();
+                    RecordId childId = ((Record) child).getRecordId();
                     onNode(nodeId, childId);
                     nodeCount++;
                 }
@@ -548,7 +558,7 @@ public class SegmentParser {
 
         RecordId baseId = mapId.getSegment()
                 .readRecordId(mapId.getOffset() + 8 + 2 * RECORD_ID_BYTES);
-        onMap(mapId, baseId, new MapRecord(baseId));
+        onMap(mapId, baseId, new MapRecord(store, baseId));
 
         return new MapInfo(mapId, size);
     }

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentPropertyState.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentPropertyState.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentPropertyState.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentPropertyState.java Mon May 23 12:59:22 2016
@@ -61,18 +61,26 @@ import org.apache.jackrabbit.oak.plugins
  * of type "LIST" (for arrays).
  */
 public class SegmentPropertyState extends Record implements PropertyState {
+    @Nonnull
+    private final SegmentStore store;
 
+    @Nonnull
     private final String name;
+
+    @Nonnull
     private final Type<?> type;
 
-    SegmentPropertyState(RecordId id, String name, Type<?> type) {
+    SegmentPropertyState(@Nonnull SegmentStore store, @Nonnull RecordId id,
+                         @Nonnull String name, @Nonnull Type<?> type) {
         super(id);
+        this.store = checkNotNull(store);
         this.name = checkNotNull(name);
         this.type = checkNotNull(type);
     }
 
-    SegmentPropertyState(RecordId id, PropertyTemplate template) {
-        this(id, template.getName(), template.getType());
+    SegmentPropertyState(@Nonnull SegmentStore store, @Nonnull RecordId id,
+                         @Nonnull PropertyTemplate template) {
+        this(store, id, template.getName(), template.getType());
     }
 
     private ListRecord getValueList(Segment segment) {
@@ -98,7 +106,7 @@ public class SegmentPropertyState extend
         ListRecord values = getValueList(segment);
         for (int i = 0; i < values.size(); i++) {
             RecordId valueId = values.getEntry(i);
-            String value = Segment.readString(valueId);
+            String value = store.getReader().readString(valueId);
             map.put(value, valueId);
         }
 
@@ -110,6 +118,7 @@ public class SegmentPropertyState extend
         return name;
     }
 
+    @Nonnull
     @Override
     public Type<?> getType() {
         return type;
@@ -138,13 +147,12 @@ public class SegmentPropertyState extend
             if (values.size() == 0) {
                 return (T) emptyList();
             } else if (values.size() == 1) {
-                return (T) singletonList(getValue(
-                        segment, values.getEntry(0), type.getBaseType()));
+                return (T) singletonList(getValue(values.getEntry(0), type.getBaseType()));
             } else {
                 Type<?> base = type.getBaseType();
                 List<Object> list = newArrayListWithCapacity(values.size());
                 for (RecordId id : values.getEntries()) {
-                    list.add(getValue(segment, id, base));
+                    list.add(getValue(id, base));
                 }
                 return (T) list;
             }
@@ -152,9 +160,9 @@ public class SegmentPropertyState extend
             RecordId id = getRecordId();
             if (type.isArray()) {
                 return (T) singletonList(
-                        getValue(segment, id, type.getBaseType()));
+                        getValue(id, type.getBaseType()));
             } else {
-                return getValue(segment, id, type);
+                return getValue(id, type);
             }
         }
     }
@@ -172,16 +180,16 @@ public class SegmentPropertyState extend
         Segment segment = getSegment();
         ListRecord values = getValueList(segment);
         checkElementIndex(index, values.size());
-        return getValue(segment, values.getEntry(index), type);
+        return getValue(values.getEntry(index), type);
     }
 
     @SuppressWarnings("unchecked")
-    private <T> T getValue(Segment segment, RecordId id, Type<T> type) {
+    private <T> T getValue(RecordId id, Type<T> type) {
         if (type == BINARY) {
-            return (T) new SegmentBlob(id); // load binaries lazily
+            return (T) new SegmentBlob(store, id); // load binaries lazily
         }
 
-        String value = Segment.readString(id);
+        String value = store.getReader().readString(id);
         if (type == STRING || type == URI || type == DATE
                 || type == NAME || type == PATH
                 || type == REFERENCE || type == WEAKREFERENCE) {
@@ -214,7 +222,7 @@ public class SegmentPropertyState extend
         RecordId entry = values.getEntry(index);
 
         if (getType().equals(BINARY) || getType().equals(BINARIES)) {
-            return new SegmentBlob(entry).length();
+            return new SegmentBlob(store, entry).length();
         }
 
         return getSegment().readLength(entry);

Copied: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReader.java (from r1745165, jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReader.java?p2=jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReader.java&p1=jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java&r1=1745165&r2=1745182&rev=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/FileStoreTest.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReader.java Mon May 23 12:59:22 2016
@@ -17,36 +17,23 @@
  * under the License.
  */
 
-package org.apache.jackrabbit.oak.segment.file;
+package org.apache.jackrabbit.oak.segment;
 
-import java.io.File;
-import java.io.IOException;
+import javax.annotation.Nonnull;
 
-import org.apache.jackrabbit.oak.segment.SegmentId;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-
-public class FileStoreTest {
-
-    @Rule
-    public TemporaryFolder folder = new TemporaryFolder();
-
-    private File getFileStoreFolder() {
-        return folder.getRoot();
-    }
-
-    @Test
-    public void containsSegment() throws IOException {
-        FileStore fileStore = FileStore.builder(getFileStoreFolder()).build();
-        try {
-            SegmentId id = new SegmentId(fileStore.getTracker(), 0, 0);
-            if (fileStore.containsSegment(id)) {
-                fileStore.readSegment(id);
-            }
-        } finally {
-            fileStore.close();
-        }
-    }
+import org.apache.jackrabbit.oak.cache.CacheStats;
 
+public interface SegmentReader {
+    @Nonnull
+    String readString(@Nonnull RecordId id);
+
+    @Nonnull
+    MapRecord readMap(@Nonnull SegmentStore store, @Nonnull RecordId id);
+
+    @Nonnull
+    Template readTemplate(@Nonnull SegmentStore store, @Nonnull RecordId id);
+
+    // FIXME OAK-4373 remove from this interface
+    @Nonnull
+    CacheStats getStringCacheStats();
 }

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReaderImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReaderImpl.java?rev=1745182&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReaderImpl.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReaderImpl.java Mon May 23 12:59:22 2016
@@ -0,0 +1,93 @@
+/*
+ * 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.segment;
+
+import static java.lang.Long.getLong;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.base.Function;
+import org.apache.jackrabbit.oak.cache.CacheStats;
+
+/*
+ * FIXME OAK-4373 implement invalidation through GCMonitor listener
+ * FIXME OAK-4373 implement monitoring, management, logging, tests
+ */
+public class SegmentReaderImpl implements SegmentReader {
+    public static final int DEFAULT_STRING_CACHE_MB = 256;
+
+    public static final String STRING_CACHE_MB = "oak.segment.stringCacheMB";
+
+    /**
+     * Cache for string records
+     */
+    private final StringCache stringCache;
+
+    public SegmentReaderImpl(long stringCacheMB) {
+        stringCache = new StringCache(getLong(STRING_CACHE_MB, stringCacheMB) * 1024 * 1024);
+    }
+
+    public SegmentReaderImpl() {
+        this(DEFAULT_STRING_CACHE_MB);
+    }
+
+    @Nonnull
+    @Override
+    public String readString(@Nonnull RecordId id) {
+        final SegmentId segmentId = id.getSegmentId();
+        long msb = segmentId.getMostSignificantBits();
+        long lsb = segmentId.getLeastSignificantBits();
+        return stringCache.getString(msb, lsb, id.getOffset(), new Function<Integer, String>() {
+            @Nullable
+            @Override
+            public String apply(Integer offset) {
+                return segmentId.getSegment().readString(offset);
+            }
+        });
+    }
+
+    @Nonnull
+    @Override
+    public MapRecord readMap(@Nonnull SegmentStore store, @Nonnull RecordId id) {
+        return new MapRecord(store, id);
+    }
+
+    @Nonnull
+    @Override
+    public Template readTemplate(@Nonnull SegmentStore store, @Nonnull RecordId id) {
+        int offset = id.getOffset();
+        if (id.getSegment().templates == null) {
+            return id.getSegment().readTemplate(offset);
+        }
+        Template template = id.getSegment().templates.get(offset);
+        if (template == null) {
+            template = id.getSegment().readTemplate(offset);
+            id.getSegment().templates.putIfAbsent(offset, template); // only keep the first copy
+        }
+        return template;
+    }
+
+    @Nonnull
+    @Override
+    public CacheStats getStringCacheStats() {
+        return stringCache.getStats();
+    }
+}

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStore.java Mon May 23 12:59:22 2016
@@ -33,6 +33,10 @@ public interface SegmentStore {
 
     SegmentTracker getTracker();
 
+    SegmentWriter getWriter();
+
+    SegmentReader getReader();
+
     /**
      * Returns the head state.
      *

Modified: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStream.java?rev=1745182&r1=1745181&r2=1745182&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStream.java (original)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentStream.java Mon May 23 12:59:22 2016
@@ -44,7 +44,7 @@ public class SegmentStream extends Input
         if (stream instanceof SegmentStream) {
             SegmentStream sstream = (SegmentStream) stream;
             RecordId id = sstream.recordId;
-            if (sstream.position == 0 && store.getTracker().isTracking(id.getSegmentId())) {
+            if (sstream.position == 0 && id.getSegmentId().sameStore(store)) {
                 return id;
             }
         }