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 fr...@apache.org on 2016/09/30 14:38:52 UTC

svn commit: r1762918 - in /jackrabbit/oak/trunk/oak-segment-tar/src: main/java/org/apache/jackrabbit/oak/segment/ test/java/org/apache/jackrabbit/oak/segment/

Author: frm
Date: Fri Sep 30 14:38:52 2016
New Revision: 1762918

URL: http://svn.apache.org/viewvc?rev=1762918&view=rev
Log:
OAK-4872 - Extract segment references into a separate set of classes

Added:
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java   (with props)
    jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java   (with props)
Modified:
    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/SegmentBufferWriter.java

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,40 @@
+/*
+ * 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.Iterator;
+
+/**
+ * An implementation of {@link SegmentReferences} that throws {@link
+ * IllegalStateException}s every time it's used. This instance is used in
+ * context where accessing a {@link SegmentReferences} is considered a
+ * programmer's error.
+ */
+class IllegalSegmentReferences implements SegmentReferences {
+
+    @Override
+    public SegmentId getSegmentId(int reference) {
+        throw new IllegalStateException("invalid use");
+    }
+
+    @Override
+    public Iterator<SegmentId> iterator() {
+        throw new IllegalStateException("invalid use");
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferences.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,47 @@
+/*
+ * 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.Iterator;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+/**
+ * An immutable and trivially thread-safe implementation of {@link
+ * SegmentReferences}.
+ */
+class ImmutableSegmentReferences implements SegmentReferences {
+
+    private final List<SegmentId> ids;
+
+    ImmutableSegmentReferences(List<SegmentId> ids) {
+        this.ids = Lists.newArrayList(ids);
+    }
+
+    @Override
+    public SegmentId getSegmentId(int reference) {
+        return ids.get(reference - 1);
+    }
+
+    @Override
+    public Iterator<SegmentId> iterator() {
+        return ids.iterator();
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferences.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,120 @@
+/*
+ * 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 com.google.common.collect.Lists.newArrayList;
+import static com.google.common.collect.Maps.newHashMap;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A mutable, thread-safe implementation of {@link SegmentReferences}.
+ */
+class MutableSegmentReferences implements SegmentReferences {
+
+    private final Object lock = new Object();
+
+    private final List<SegmentId> ids = newArrayList();
+
+    private final Map<SegmentId, Integer> numbers = newHashMap();
+
+    @Override
+    public SegmentId getSegmentId(int reference) {
+        SegmentId id = ids.get(reference - 1);
+
+        if (id != null) {
+            return id;
+        }
+
+        synchronized (lock) {
+            return ids.get(reference - 1);
+        }
+    }
+
+    /**
+     * Generate a reference or return the existing reference for the provided
+     * segment ID.
+     *
+     * @param id an instance of {@link SegmentId}. It should not be {@code
+     *           null}.
+     * @return a reference to the provided segment ID. The reference number is
+     * strictly greater than zero.
+     */
+    int addOrReference(SegmentId id) {
+        Integer number = numbers.get(id);
+
+        if (number != null) {
+            return number;
+        }
+
+        synchronized (lock) {
+            number = numbers.get(id);
+
+            if (number != null) {
+                return number;
+            }
+
+            ids.add(id);
+            number = ids.size();
+            numbers.put(id, number);
+            return number;
+        }
+    }
+
+    /**
+     * Return the number of references (segment IDs) accessible from this
+     * instance.
+     *
+     * @return the number of references (segment IDs) accessible from this
+     * instance.
+     */
+    int size() {
+        synchronized (lock) {
+            return numbers.size();
+        }
+    }
+
+    /**
+     * Check if a reference exists for a provided segment ID.
+     *
+     * @param id The segment ID to check for a reference.
+     * @return {@code true} if a reference exists for the provided segment ID,
+     * {@code false} otherwise.
+     */
+    boolean contains(SegmentId id) {
+        boolean contains = numbers.containsKey(id);
+
+        if (contains) {
+            return true;
+        }
+
+        synchronized (lock) {
+            return numbers.containsKey(id);
+        }
+    }
+
+    @Override
+    public Iterator<SegmentId> iterator() {
+        synchronized (lock) {
+            return ids.iterator();
+        }
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferences.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1762918&r1=1762917&r2=1762918&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 Fri Sep 30 14:38:52 2016
@@ -22,7 +22,7 @@ import static com.google.common.base.Pre
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkPositionIndexes;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Maps.newHashMap;
+import static com.google.common.collect.Lists.newArrayListWithCapacity;
 import static com.google.common.collect.Maps.newHashMapWithExpectedSize;
 import static org.apache.jackrabbit.oak.commons.IOUtils.closeQuietly;
 import static org.apache.jackrabbit.oak.segment.SegmentId.isDataSegmentId;
@@ -38,6 +38,7 @@ 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.Map;
 import java.util.UUID;
 
@@ -144,14 +145,17 @@ public class Segment {
     @Nonnull
     private final SegmentVersion version;
 
-    private final Map<Integer, SegmentId> segmentIdCache = newHashMap();
-
     /**
      * The table translating record numbers to offsets.
      */
     private final RecordNumbers recordNumbers;
 
     /**
+     * The table translating references to segment IDs.
+     */
+    private final SegmentReferences segmentReferences;
+
+    /**
      * Align an {@code address} on the given {@code boundary}
      *
      * @param address     address to align
@@ -186,9 +190,11 @@ public class Segment {
             });
             this.version = SegmentVersion.fromByte(segmentVersion);
             this.recordNumbers = readRecordNumberOffsets();
+            this.segmentReferences = readReferencedSegments();
         } else {
             this.version = LATEST_VERSION;
             this.recordNumbers = new IdentityRecordNumbers();
+            this.segmentReferences = new IllegalSegmentReferences();
         }
     }
 
@@ -228,11 +234,31 @@ public class Segment {
         return new ImmutableRecordNumbers(recordNumberOffsets);
     }
 
+    private SegmentReferences readReferencedSegments() {
+        List<SegmentId> referencedSegments = newArrayListWithCapacity(getReferencedSegmentIdCount());
+
+        int position = data.position();
+
+        position += HEADER_SIZE;
+
+        for (int i = 0; i < getReferencedSegmentIdCount(); i++) {
+            long msb = data.getLong(position);
+            position += 8;
+            long lsb = data.getLong(position);
+            position += 8;
+            referencedSegments.add(store.newSegmentId(msb, lsb));
+        }
+
+        return new ImmutableSegmentReferences(referencedSegments);
+    }
+
     Segment(@Nonnull SegmentStore store,
             @Nonnull SegmentReader reader,
             @Nonnull byte[] buffer,
             @Nonnull RecordNumbers recordNumbers,
-            @Nonnull String info) {
+            @Nonnull SegmentReferences segmentReferences,
+            @Nonnull String info
+    ) {
         this.store = checkNotNull(store);
         this.reader = checkNotNull(reader);
         this.id = store.newDataSegmentId();
@@ -240,6 +266,7 @@ public class Segment {
         this.data = ByteBuffer.wrap(checkNotNull(buffer));
         this.version = SegmentVersion.fromByte(buffer[3]);
         this.recordNumbers = recordNumbers;
+        this.segmentReferences = segmentReferences;
         id.loaded(this);
     }
 
@@ -298,17 +325,7 @@ public class Segment {
     }
 
     public UUID getReferencedSegmentId(int index) {
-        checkArgument(index < getReferencedSegmentIdCount());
-
-        int position = data.position();
-
-        position += HEADER_SIZE;
-        position += index * 16;
-
-        long msb = data.getLong(position);
-        long lsb = data.getLong(position + 8);
-
-        return new UUID(msb, lsb);
+        return segmentReferences.getSegmentId(index + 1).asUUID();
     }
 
     /**
@@ -457,30 +474,13 @@ public class Segment {
             return id;
         }
 
-        SegmentId id = segmentIdCache.get(reference);
+        SegmentId id = segmentReferences.getSegmentId(reference);
 
-        if (id != null) {
-            return id;
+        if (id == null) {
+            throw new IllegalStateException("Referenced segment not found");
         }
 
-        synchronized (segmentIdCache) {
-            id = segmentIdCache.get(reference);
-
-            if (id != null) {
-                return id;
-            }
-
-            int position = data.position() + HEADER_SIZE + (reference - 1) * 16;
-
-            long msb = data.getLong(position);
-            long lsb = data.getLong(position + 8);
-
-            id = store.newSegmentId(msb, lsb);
-
-            segmentIdCache.put(reference, id);
-
-            return id;
-        }
+        return id;
     }
 
     @Nonnull
@@ -617,15 +617,17 @@ public class Segment {
             if (id.isDataSegmentId()) {
                 writer.println("--------------------------------------------------------------------------");
 
-                for (int i = 0; i < getReferencedSegmentIdCount(); i++) {
-                    writer.format("reference %02x: %s%n", i, getReferencedSegmentId(i));
+                int i = 1;
+
+                for (SegmentId segmentId : segmentReferences) {
+                    writer.format("reference %02x: %s%n", i++, segmentId);
                 }
 
                 for (Entry entry : recordNumbers) {
                     writer.format("record number %08x: %08x", entry.getRecordNumber(), entry.getOffset());
                 }
 
-                for (int i = 0; i < getRootCount(); i++) {
+                for (i = 0; i < getRootCount(); i++) {
                     writer.format("root %d: %s at %04x%n", i, getRootType(i), getRootOffset(i));
                 }
             }

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=1762918&r1=1762917&r2=1762918&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 Fri Sep 30 14:38:52 2016
@@ -23,7 +23,6 @@ import static com.google.common.base.Cha
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.collect.Maps.newHashMap;
 import static com.google.common.collect.Maps.newLinkedHashMap;
 import static com.google.common.collect.Sets.newHashSet;
 import static java.lang.System.arraycopy;
@@ -114,10 +113,10 @@ public class SegmentBufferWriter impleme
      */
     private final Map<RecordId, RecordType> roots = newLinkedHashMap();
 
-    private final Map<SegmentId, Integer> referencedSegmentIds = newHashMap();
-
     private MutableRecordNumbers recordNumbers = new MutableRecordNumbers();
 
+    private MutableSegmentReferences segmentReferences = new MutableSegmentReferences();
+
     @Nonnull
     private final SegmentStore store;
 
@@ -217,15 +216,15 @@ public class SegmentBufferWriter impleme
         length = 0;
         position = buffer.length;
         roots.clear();
-        referencedSegmentIds.clear();
         recordNumbers = new MutableRecordNumbers();
+        segmentReferences = new MutableSegmentReferences();
 
         String metaInfo =
             "{\"wid\":\"" + wid + '"' +
             ",\"sno\":" + tracker.getSegmentCount() +
             ",\"t\":" + currentTimeMillis() + "}";
         try {
-            segment = new Segment(store, reader, buffer, recordNumbers, metaInfo);
+            segment = new Segment(store, reader, buffer, recordNumbers, segmentReferences, metaInfo);
 
             statistics = new Statistics();
             statistics.id = segment.getSegmentId();
@@ -300,20 +299,7 @@ public class SegmentBufferWriter impleme
             return 0;
         }
 
-        Integer reference = referencedSegmentIds.get(id);
-
-        if (reference != null) {
-            return reference;
-        }
-
-        reference = referencedSegmentIds.size() + 1;
-        referencedSegmentIds.put(id, reference);
-
-        BinaryUtils.writeInt(buffer, Segment.REFERENCED_SEGMENT_ID_COUNT_OFFSET, reference);
-        BinaryUtils.writeLong(buffer, HEADER_SIZE + reference * 16 - 16, id.getMostSignificantBits());
-        BinaryUtils.writeLong(buffer, HEADER_SIZE + reference * 16 - 8, id.getLeastSignificantBits());
-
-        return reference;
+        return segmentReferences.addOrReference(id);
     }
 
     /**
@@ -364,7 +350,9 @@ public class SegmentBufferWriter impleme
             int rootcount = roots.size();
             BinaryUtils.writeShort(buffer, Segment.ROOT_COUNT_OFFSET, (short) rootcount);
 
-            int referencedSegmentIdCount = referencedSegmentIds.size();
+            int referencedSegmentIdCount = segmentReferences.size();
+            BinaryUtils.writeInt(buffer, Segment.REFERENCED_SEGMENT_ID_COUNT_OFFSET, referencedSegmentIdCount);
+
             statistics.segmentIdCount = referencedSegmentIdCount;
 
             int recordNumberCount = recordNumbers.size();
@@ -378,7 +366,7 @@ public class SegmentBufferWriter impleme
 
             statistics.size = length = totalLength;
 
-            int pos = HEADER_SIZE + referencedSegmentIdCount * 16;
+            int pos = HEADER_SIZE;
             if (pos + length <= buffer.length) {
                 // the whole segment fits to the space *after* the referenced
                 // segment identifiers we've already written, so we can safely
@@ -394,6 +382,11 @@ public class SegmentBufferWriter impleme
                 length = buffer.length;
             }
 
+            for (SegmentId segmentId : segmentReferences) {
+                pos = BinaryUtils.writeLong(buffer, pos, segmentId.getMostSignificantBits());
+                pos = BinaryUtils.writeLong(buffer, pos, segmentId.getLeastSignificantBits());
+            }
+
             for (Entry entry : recordNumbers) {
                 pos = BinaryUtils.writeInt(buffer, pos, entry.getRecordNumber());
                 pos = BinaryUtils.writeInt(buffer, pos, entry.getOffset());
@@ -441,7 +434,7 @@ public class SegmentBufferWriter impleme
 
         int rootCount = roots.size() + 1;
         int recordNumbersCount = recordNumbers.size() + 1;
-        int referencedIdCount = referencedSegmentIds.size() + ids.size();
+        int referencedIdCount = segmentReferences.size() + ids.size();
         int headerSize = HEADER_SIZE + rootCount * 5 + referencedIdCount * 16 + recordNumbersCount * 8;
         int segmentSize = align(headerSize + recordSize + length, 16);
 
@@ -473,7 +466,7 @@ public class SegmentBufferWriter impleme
             // Adjust the estimation of the new referenced segment ID count.
 
             for (SegmentId segmentId : segmentIds) {
-                if (referencedSegmentIds.containsKey(segmentId)) {
+                if (segmentReferences.contains(segmentId)) {
                     referencedIdCount--;
                 }
             }

Added: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Represents a list of segment IDs referenced from a segment.
+ */
+interface SegmentReferences extends Iterable<SegmentId> {
+
+    /**
+     * Fetch the referenced segment ID associated to the provided reference.
+     *
+     * @param reference The reference to a segment ID.
+     * @return The segment ID associated to the reference of {@code null} if
+     * none is found.
+     */
+    SegmentId getSegmentId(int reference);
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentReferences.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,34 @@
+/*
+ * 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 org.junit.Test;
+
+public class IllegalSegmentReferencesTest {
+
+    @Test(expected = IllegalStateException.class)
+    public void getSegmentIdShouldBeIllegal() throws Exception {
+        new IllegalSegmentReferences().getSegmentId(1);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void iteratorShouldBeIllegal() throws Exception {
+        new IllegalSegmentReferences().iterator();
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/IllegalSegmentReferencesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,59 @@
+/*
+ * 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 com.google.common.collect.Iterables.elementsEqual;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.jackrabbit.oak.segment.memory.MemoryStore;
+import org.junit.Test;
+
+public class ImmutableSegmentReferencesTest {
+
+    @Test
+    public void shouldNotBeIndirectlyModifiable() throws Exception {
+        SegmentStore store = new MemoryStore();
+        List<SegmentId> list = newArrayList(store.newDataSegmentId());
+        ImmutableSegmentReferences table = new ImmutableSegmentReferences(list);
+        list.add(store.newDataSegmentId());
+        assertFalse(elementsEqual(list, table));
+    }
+
+    @Test
+    public void shouldMaintainIterationOrder() throws Exception {
+        SegmentStore store = new MemoryStore();
+        List<SegmentId> list = newArrayList(store.newDataSegmentId());
+        ImmutableSegmentReferences table = new ImmutableSegmentReferences(list);
+        assertTrue(elementsEqual(list, table));
+    }
+
+    @Test
+    public void shouldRetrieveSegmentIdByReference() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+        List<SegmentId> list = newArrayList(id);
+        ImmutableSegmentReferences table = new ImmutableSegmentReferences(list);
+        assertEquals(id, table.getSegmentId(1));
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/ImmutableSegmentReferencesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java?rev=1762918&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java (added)
+++ jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java Fri Sep 30 14:38:52 2016
@@ -0,0 +1,111 @@
+/*
+ * 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 com.google.common.collect.Iterables.elementsEqual;
+import static com.google.common.collect.Lists.newArrayList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.apache.jackrabbit.oak.segment.memory.MemoryStore;
+import org.junit.Test;
+
+public class MutableSegmentReferencesTest {
+
+    @Test
+    public void referencesShouldBeGreaterThanZero() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        int reference = table.addOrReference(id);
+        assertEquals(1, reference);
+    }
+
+    @Test
+    public void referencesShouldBeIncrementing() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId first = store.newDataSegmentId();
+        SegmentId second = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        int firstReference = table.addOrReference(first);
+        int secondReference = table.addOrReference(second);
+        assertEquals(firstReference + 1, secondReference);
+    }
+
+    @Test
+    public void shouldAddNewSegmentReference() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        int reference = table.addOrReference(id);
+        assertEquals(id, table.getSegmentId(reference));
+    }
+
+    @Test
+    public void shouldNotAddSameSegmentIdTwice() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        int first = table.addOrReference(id);
+        int second = table.addOrReference(id);
+        assertEquals(first, second);
+    }
+
+    @Test
+    public void shouldMaintainSize() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        assertEquals(0, table.size());
+        table.addOrReference(id);
+        assertEquals(1, table.size());
+    }
+
+    @Test
+    public void shouldContainAddedSegment() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId id = store.newDataSegmentId();
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        assertFalse(table.contains(id));
+        table.addOrReference(id);
+        assertTrue(table.contains(id));
+    }
+
+    @Test
+    public void shouldIterateInInsertionOrder() throws Exception {
+        SegmentStore store = new MemoryStore();
+        SegmentId first = store.newDataSegmentId();
+        SegmentId second = store.newDataSegmentId();
+        List<SegmentId> ids = newArrayList(first, second);
+
+        MutableSegmentReferences table = new MutableSegmentReferences();
+        table.addOrReference(first);
+        table.addOrReference(second);
+        assertTrue(elementsEqual(ids, table));
+    }
+
+}

Propchange: jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/MutableSegmentReferencesTest.java
------------------------------------------------------------------------------
    svn:eol-style = native