Author: mduerig
Date: Mon Jun  8 20:49:26 2015
New Revision: 1684274

URL: http://svn.apache.org/r1684274
Log:
OAK-2967: Merge OAK-2800, OAK-2801, OAK-2692, OAK-2713
Merged revisions 1673738, 1673787, 1673791, 1674780, 1679958

Added:
    
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java
      - copied, changed from r1673787, 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java
    
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionMBean.java
      - copied unchanged from r1673787, 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionMBean.java
Modified:
    jackrabbit/oak/branches/1.2/   (props changed)
    
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/CompactionMap.java
    
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/compaction/DefaultCompactionStrategyMBean.java
    
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
    
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreGCMonitor.java
    
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/TarReader.java

Propchange: jackrabbit/oak/branches/1.2/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Jun  8 20:49:26 2015
@@ -1,3 +1,3 @@
 /jackrabbit/oak/branches/1.0:1665962
-/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414,1673436,1673644,1673662-1673664,1673669,1673695,1674046,1674065,1674075,1674107,1674228,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677939,1677991,1678173,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679235,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680805-1680806,1680903,1681282,1681767,1681918,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683089,1683213,1683249,1683278,1683323,1683687,1684174-1684175
+/jackrabbit/oak/trunk:1672350,1672468,1672537,1672603,1672642,1672644,1672834-1672835,1673351,1673410,1673414,1673436,1673644,1673662-1673664,1673669,1673695,1673738,1673787,1673791,1674046,1674065,1674075,1674107,1674228,1674780,1674880,1675054-1675055,1675319,1675332,1675354,1675357,1675382,1675555,1675566,1675593,1676198,1676237,1676407,1676458,1676539,1676670,1676693,1676703,1676725,1677579,1677581,1677609,1677611,1677774,1677788,1677797,1677939,1677991,1678173,1678323,1678758,1678938,1678954,1679144,1679165,1679191,1679235,1679958,1680182,1680222,1680232,1680236,1680461,1680633,1680643,1680805-1680806,1680903,1681282,1681767,1681918,1682218,1682235,1682437,1682494,1682555,1682855,1682904,1683089,1683213,1683249,1683278,1683323,1683687,1684174-1684175
 /jackrabbit/trunk:1345480

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/CompactionMap.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/CompactionMap.java?rev=1684274&r1=1684273&r2=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/CompactionMap.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/CompactionMap.java
 Mon Jun  8 20:49:26 2015
@@ -22,6 +22,8 @@ import static com.google.common.collect.
 import static org.apache.jackrabbit.oak.commons.IOUtils.humanReadableByteCount;
 import static 
org.apache.jackrabbit.oak.plugins.segment.Segment.RECORD_ALIGN_BITS;
 
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -80,8 +82,8 @@ public class CompactionMap {
     private short[] afterOffsets = new short[0];
 
     private int[] afterSegmentIds = new int[0];
-    private long[] amsbs = new long[0];
-    private long[] alsbs = new long[0];
+    private long[] afterMsbs = new long[0];
+    private long[] afterLsbs = new long[0];
 
     private CompactionMap prev;
 
@@ -112,13 +114,8 @@ public class CompactionMap {
     private boolean recursiveWasCompactedTo(RecordId before,
             RecordId after) {
         RecordId potentialAfter = recursiveGet(this, before);
-        if (potentialAfter == null) {
-            return false;
-        }
-        if (after.equals(potentialAfter)) {
-            return true;
-        }
-        return recursiveWasCompactedTo(potentialAfter, after);
+        return potentialAfter != null &&
+                (after.equals(potentialAfter) || 
recursiveWasCompactedTo(potentialAfter, after));
     }
 
     private static RecordId recursiveGet(CompactionMap map, RecordId before) {
@@ -146,14 +143,8 @@ public class CompactionMap {
     }
 
     private static boolean wasCompacted(CompactionMap map, long msb, long lsb) 
{
-        int find = map.findEntry(msb, lsb);
-        if (find != -1) {
-            return true;
-        }
-        if (map.prev != null) {
-            return wasCompacted(map.prev, msb, lsb);
-        }
-        return false;
+        return map.findEntry(msb, lsb) != -1 ||
+                map.prev != null && wasCompacted(map.prev, msb, lsb);
     }
 
     public RecordId get(RecordId before) {
@@ -200,7 +191,7 @@ public class CompactionMap {
 
     private SegmentId asSegmentId(int index) {
         int idx = afterSegmentIds[index];
-        return new SegmentId(tracker, amsbs[idx], alsbs[idx]);
+        return new SegmentId(tracker, afterMsbs[idx], afterLsbs[idx]);
     }
 
     private static UUID asUUID(SegmentId id) {
@@ -222,13 +213,34 @@ public class CompactionMap {
         }
     }
 
-    void compress() {
-        if (recent.isEmpty()) {
-            // noop
+    public void compress(Set<UUID> removed) {
+        CompactionMap cm = this;
+        while (cm != null) {
+            cm.compressInternal(removed);
+            cm = cm.prev;
+        }
+
+        cm = this;
+        while (cm != null) {
+            while (cm.prev != null && cm.prev.msbs.length == 0) {
+                cm.prev = cm.prev.prev;
+            }
+            cm = cm.prev;
+        }
+    }
+
+    public void compress() {
+        compressInternal(Collections.<UUID>emptySet());
+    }
+
+    private void compressInternal(Set<UUID> removed) {
+        if (recent.isEmpty() && removed.isEmpty()) {
+            // no-op
             return;
         }
-        Set<UUID> uuids = newTreeSet();
 
+        Set<UUID> uuids = newTreeSet();
+        int newSize = 0;
         Map<UUID, Map<Integer, RecordId>> mapping = newTreeMap();
         for (Entry<RecordId, RecordId> entry : recent.entrySet()) {
             RecordId before = entry.getKey();
@@ -237,7 +249,9 @@ public class CompactionMap {
             UUID uuid = new UUID(
                     id.getMostSignificantBits(),
                     id.getLeastSignificantBits());
-            uuids.add(uuid);
+            if (uuids.add(uuid) && !removed.contains(uuid)) {
+                newSize++;
+            }
 
             Map<Integer, RecordId> map = mapping.get(uuid);
             if (map == null) {
@@ -248,12 +262,15 @@ public class CompactionMap {
         }
 
         for (int i = 0; i < msbs.length; i++) {
-            uuids.add(new UUID(msbs[i], lsbs[i]));
+            UUID uuid = new UUID(msbs[i], lsbs[i]);
+            if (uuids.add(uuid) && !removed.contains(uuid)) {
+                newSize++;
+            }
         }
 
-        long[] newmsbs = new long[uuids.size()];
-        long[] newlsbs = new long[uuids.size()];
-        int[] newEntryIndex = new int[uuids.size() + 1];
+        long[] newMsbs = new long[newSize];
+        long[] newLsbs = new long[newSize];
+        int[] newEntryIndex = new int[newSize + 1];
 
         int newEntries = beforeOffsets.length + recent.size();
         short[] newBeforeOffsets = new short[newEntries];
@@ -266,36 +283,47 @@ public class CompactionMap {
         int newEntry = 0;
         int oldEntry = 0;
         for (UUID uuid : uuids) {
-            newmsbs[newEntry] = uuid.getMostSignificantBits();
-            newlsbs[newEntry] = uuid.getLeastSignificantBits();
+            long msb = uuid.getMostSignificantBits();
+            long lsb = uuid.getLeastSignificantBits();
+
+            if (removed.contains(uuid)) {
+                if (oldEntry < msbs.length
+                        && msbs[oldEntry] == msb
+                        && lsbs[oldEntry] == lsb) {
+                    oldEntry++;
+                }
+                continue;
+            }
 
             // offset -> record
-            Map<Integer, RecordId> newsegment = mapping.get(uuid);
-            if (newsegment == null) {
-                newsegment = newTreeMap();
+            Map<Integer, RecordId> newSegment = mapping.get(uuid);
+            if (newSegment == null) {
+                newSegment = newTreeMap();
             }
 
             if (oldEntry < msbs.length
-                    && msbs[oldEntry] == newmsbs[newEntry]
-                    && lsbs[oldEntry] == newlsbs[newEntry]) {
+                    && msbs[oldEntry] == msb
+                    && lsbs[oldEntry] == lsb) {
                 int index = entryIndex[oldEntry];
                 int limit = entryIndex[oldEntry + 1];
                 for (int i = index; i < limit; i++) {
-                    newsegment.put(decode(beforeOffsets[i]), new RecordId(
+                    newSegment.put(decode(beforeOffsets[i]), new RecordId(
                             asSegmentId(i), decode(afterOffsets[i])));
                 }
                 oldEntry++;
             }
 
+            newMsbs[newEntry] = msb;
+            newLsbs[newEntry] = lsb;
             newEntryIndex[newEntry++] = newIndex;
-            for (Entry<Integer, RecordId> entry : newsegment.entrySet()) {
+            for (Entry<Integer, RecordId> entry : newSegment.entrySet()) {
                 int key = entry.getKey();
                 RecordId id = entry.getValue();
                 newBeforeOffsets[newIndex] = encode(key);
                 newAfterOffsets[newIndex] = encode(id.getOffset());
 
                 UUID aUUID = asUUID(id.getSegmentId());
-                int aSIdx = -1;
+                int aSIdx;
                 if (newAfterSegments.containsKey(aUUID)) {
                     aSIdx = newAfterSegments.get(aUUID);
                 } else {
@@ -310,20 +338,26 @@ public class CompactionMap {
 
         newEntryIndex[newEntry] = newIndex;
 
-        this.msbs = newmsbs;
-        this.lsbs = newlsbs;
+        this.msbs = newMsbs;
+        this.lsbs = newLsbs;
         this.entryIndex = newEntryIndex;
 
-        this.beforeOffsets = newBeforeOffsets;
-        this.afterOffsets = newAfterOffsets;
+        if (newIndex < newBeforeOffsets.length) {
+            this.beforeOffsets = Arrays.copyOf(newBeforeOffsets, newIndex);
+            this.afterOffsets = Arrays.copyOf(newAfterOffsets, newIndex);
+            this.afterSegmentIds = Arrays.copyOf(newAfterSegmentIds, newIndex);
+        } else {
+            this.beforeOffsets = newBeforeOffsets;
+            this.afterOffsets = newAfterOffsets;
+            this.afterSegmentIds = newAfterSegmentIds;
+        }
 
-        this.afterSegmentIds = newAfterSegmentIds;
-        this.amsbs = new long[newAfterSegments.size()];
-        this.alsbs = new long[newAfterSegments.size()];
+        this.afterMsbs = new long[newAfterSegments.size()];
+        this.afterLsbs = new long[newAfterSegments.size()];
         for (Entry<UUID, Integer> entry : newAfterSegments.entrySet()) {
-            this.amsbs[entry.getValue()] = entry.getKey()
+            this.afterMsbs[entry.getValue()] = entry.getKey()
                     .getMostSignificantBits();
-            this.alsbs[entry.getValue()] = entry.getKey()
+            this.afterLsbs[entry.getValue()] = entry.getKey()
                     .getLeastSignificantBits();
         }
 
@@ -404,7 +438,7 @@ public class CompactionMap {
         StringBuilder sb = new StringBuilder();
         CompactionMap cm = this;
         while (cm != null) {
-            sb.append("[");
+            sb.append('[');
             sb.append(getCompactionStats(cm));
             sb.append("], ");
             cm = cm.prev;
@@ -413,16 +447,18 @@ public class CompactionMap {
     }
 
     private static String getCompactionStats(CompactionMap cm) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Estimated Weight: ");
-        sb.append(humanReadableByteCount(getEstimatedWeight(cm)));
-        sb.append(", Records: ");
-        sb.append(cm.afterOffsets.length);
-        sb.append(", Segments: ");
-        sb.append(cm.amsbs.length);
-        return sb.toString();
+        return "Estimated Weight: " +
+                humanReadableByteCount(getEstimatedWeight(cm)) +
+                ", Records: " +
+                cm.afterOffsets.length +
+                ", Segments: " +
+                cm.afterMsbs.length;
     }
 
+    /**
+     * The weight of the compaction map is its  memory consumption bytes
+     * @return  Estimated weight of the compaction map
+     */
     public long getEstimatedWeight() {
         long total = 0;
         CompactionMap cm = this;
@@ -434,6 +470,20 @@ public class CompactionMap {
     }
 
     /**
+     * The depth of the compaction map is the total number of generations
+     * kept. That is this instance plus the number of all previous instances.
+     * @return  Depth of the compaction map
+     */
+    public int getDepth() {
+        if (prev == null) {
+            return 1;
+        } else {
+            return 1 + prev.getDepth();
+        }
+
+    }
+
+    /**
      * The weight of the last generation of the compaction map.
      * @return  Estimated weight of the last generation of the compaction map.
      */
@@ -459,10 +509,10 @@ public class CompactionMap {
 
         // afterSegmentIds
         total += 24 + cm.afterSegmentIds.length * 4;
-        // amsbs
-        total += 24 + cm.amsbs.length * 8;
-        // alsbs
-        total += 24 + cm.alsbs.length * 8;
+        // afterMsbs
+        total += 24 + cm.afterMsbs.length * 8;
+        // afterLsbs
+        total += 24 + cm.afterLsbs.length * 8;
 
         return total;
     }

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/compaction/DefaultCompactionStrategyMBean.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/compaction/DefaultCompactionStrategyMBean.java?rev=1684274&r1=1684273&r2=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/compaction/DefaultCompactionStrategyMBean.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/compaction/DefaultCompactionStrategyMBean.java
 Mon Jun  8 20:49:26 2015
@@ -19,14 +19,18 @@
 
 package org.apache.jackrabbit.oak.plugins.segment.compaction;
 
+import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean;
 import org.apache.jackrabbit.oak.plugins.segment.CompactionMap;
 import 
org.apache.jackrabbit.oak.plugins.segment.compaction.CompactionStrategy.CleanupType;
 
-public class DefaultCompactionStrategyMBean implements CompactionStrategyMBean 
{
+public class DefaultCompactionStrategyMBean
+        extends AnnotatedStandardMBean
+        implements CompactionStrategyMBean {
 
     private final CompactionStrategy strategy;
 
     public DefaultCompactionStrategyMBean(CompactionStrategy strategy) {
+        super(CompactionStrategyMBean.class);
         this.strategy = strategy;
     }
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java?rev=1684274&r1=1684273&r2=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStore.java
 Mon Jun  8 20:49:26 2015
@@ -658,8 +658,9 @@ public class FileStore implements Segmen
 
         CompactionMap cm = tracker.getCompactionMap();
         List<TarReader> list = newArrayListWithCapacity(readers.size());
+        Set<UUID> cleanedIds = newHashSet();
         for (TarReader reader : readers) {
-            TarReader cleaned = reader.cleanup(ids, cm);
+            TarReader cleaned = reader.cleanup(ids, cm, cleanedIds);
             if (cleaned == reader) {
                 list.add(reader);
             } else {
@@ -671,13 +672,15 @@ public class FileStore implements Segmen
                 toBeRemoved.addLast(file);
             }
         }
+        cm.compress(cleanedIds);
         readers = list;
         long finalSize = size();
         gcMonitor.cleaned(initialSize - finalSize, finalSize);
         gcMonitor.info("TarMK revision cleanup completed in {}. Post cleanup 
size is {} " +
-                "and space reclaimed {}", watch,
+                "and space reclaimed {}. Compaction map weight/depth is 
{}/{}.", watch,
                 humanReadableByteCount(finalSize),
-                humanReadableByteCount(initialSize - finalSize));
+                humanReadableByteCount(initialSize - finalSize),
+                humanReadableByteCount(cm.getEstimatedWeight()), 
cm.getDepth());
     }
 
     /**

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreGCMonitor.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreGCMonitor.java?rev=1684274&r1=1684273&r2=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreGCMonitor.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/FileStoreGCMonitor.java
 Mon Jun  8 20:49:26 2015
@@ -31,6 +31,7 @@ import java.util.Date;
 import javax.annotation.Nonnull;
 import javax.management.openmbean.CompositeData;
 
+import org.apache.jackrabbit.oak.commons.jmx.AnnotatedStandardMBean;
 import org.apache.jackrabbit.oak.spi.gc.GCMonitor;
 import org.apache.jackrabbit.oak.stats.Clock;
 import org.apache.jackrabbit.stats.TimeSeriesRecorder;
@@ -43,7 +44,8 @@ import org.apache.jackrabbit.stats.TimeS
  * second to ensure the various time series maintained by this implementation
  * are correctly aggregated.
  */
-public class FileStoreGCMonitor implements GCMonitor, GCMonitorMBean, Runnable 
{
+public class FileStoreGCMonitor extends AnnotatedStandardMBean
+        implements GCMonitor, GCMonitorMBean, Runnable {
     private final TimeSeriesRecorder gcCount = new TimeSeriesRecorder(true);
     private final TimeSeriesRecorder repositorySize = new 
TimeSeriesRecorder(false);
     private final TimeSeriesRecorder reclaimedSize = new 
TimeSeriesRecorder(true);
@@ -56,6 +58,7 @@ public class FileStoreGCMonitor implemen
     private String status = "NA";
 
     public FileStoreGCMonitor(@Nonnull Clock clock) {
+        super(GCMonitorMBean.class);
         this.clock = checkNotNull(clock);
     }
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/TarReader.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/TarReader.java?rev=1684274&r1=1684273&r2=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/TarReader.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/segment/file/TarReader.java
 Mon Jun  8 20:49:26 2015
@@ -568,10 +568,14 @@ class TarReader {
      * for memory mapped files).
      * 
      * @param referencedIds the referenced segment ids (input and output).
+     * @param cm the compaction map
+     * @param removed a set which will receive the uuids of all segments that
+     *                have been cleaned.
      * @return this (if the file is kept as is), or the new generation file, or
      *         null if the file is fully garbage
      */
-    synchronized TarReader cleanup(Set<UUID> referencedIds, CompactionMap cm) 
throws IOException {
+    synchronized TarReader cleanup(Set<UUID> referencedIds, CompactionMap cm, 
Set<UUID> removed)
+            throws IOException {
         Set<UUID> cleaned = newHashSet();
         Map<UUID, List<UUID>> graph = getGraph();
 
@@ -629,6 +633,7 @@ class TarReader {
 
         if (count == 0) {
             // none of the entries within this tar file are referenceable
+            removed.addAll(cleaned);
             logCleanedSegments(cleaned);
             return null;
         } else if (size >= access.length() * 3 / 4 && graph != null) {
@@ -666,6 +671,7 @@ class TarReader {
                 singletonList(newFile), access.isMemoryMapped());
         if (reader != null) {
             logCleanedSegments(cleaned);
+            removed.addAll(cleaned);
             return reader;
         } else {
             log.warn("Failed to open cleaned up tar file {}", file);

Copied: 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java
 (from r1673787, 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java?p2=jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java&r1=1673787&r2=1684274&rev=1684274&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/segment/SegmentCompactionIT.java
 Mon Jun  8 20:49:26 2015
@@ -374,29 +374,62 @@ public class SegmentCompactionIT {
                 throws IOException {
             int k = rnd.nextInt(100);
             if (k < 10) {
-                if (!nodeBuilder.remove()) {
-                    descent(nodeStore, nodeBuilder, deleteOnly);
-                }
-            } else if (k < 40 && !deleteOnly)  {
-                nodeBuilder.setChildNode('N' + itemPrefix + rnd.nextInt(1000));
+                chooseRandomNode(nodeBuilder).remove();
+            } else if (k < 20) {
+                removeRandomProperty(chooseRandomNode(nodeBuilder));
+            } else if (k < 60 && !deleteOnly)  {
+                addRandomNode(nodeBuilder);
             } else if (k < 80 && !deleteOnly) {
-                nodeBuilder.setProperty('P' + itemPrefix + rnd.nextInt(1000),
-                        randomAlphabetic(rnd.nextInt(10000)));
-            } else if (k < 90 && !deleteOnly) {
-                nodeBuilder.setProperty('B' + itemPrefix + rnd.nextInt(1000),
-                        createBlob(nodeStore, rnd.nextInt(maxBlobSize)));
+                addRandomValue(nodeBuilder);
+            } else if (!deleteOnly) {
+                addRandomBlob(nodeStore, nodeBuilder);
+            }
+        }
+
+        private NodeBuilder chooseRandomNode(NodeBuilder nodeBuilder) {
+            NodeBuilder childBuilder = nodeBuilder;
+            for (int k = 0; k < rnd.nextInt(1000); k++) {
+                childBuilder = randomStep(nodeBuilder, nodeBuilder = 
childBuilder);
+            }
+            return childBuilder;
+        }
+
+        private NodeBuilder randomStep(NodeBuilder parent, NodeBuilder node) {
+            int count = (int) node.getChildNodeCount(Long.MAX_VALUE);
+            int k = rnd.nextInt(count + 1);
+            if (k == 0) {
+                return parent;
             } else {
-                descent(nodeStore, nodeBuilder, deleteOnly);
+                String name = get(node.getChildNodeNames(), k - 1);
+                return node.getChildNode(name);
             }
         }
 
-        private void descent(NodeStore nodeStore, NodeBuilder nodeBuilder, 
boolean deleteOnly)
-                throws IOException {
-            long count = nodeBuilder.getChildNodeCount(Long.MAX_VALUE);
+        private void removeRandomProperty(NodeBuilder nodeBuilder) {
+            int count = (int) nodeBuilder.getPropertyCount();
             if (count > 0) {
-                int c = rnd.nextInt((int) count);
-                String name = get(nodeBuilder.getChildNodeNames(), c);
-                modify(nodeStore, nodeBuilder.getChildNode(name), deleteOnly);
+                PropertyState property = get(nodeBuilder.getProperties(), 
rnd.nextInt(count));
+                nodeBuilder.removeProperty(property.getName());
+            }
+        }
+
+        private void addRandomNode(NodeBuilder nodeBuilder) {
+            if (nodeBuilder.getChildNodeCount(1000) < 1000) {
+                chooseRandomNode(nodeBuilder).setChildNode('N' + itemPrefix + 
rnd.nextInt(1000));
+            }
+        }
+
+        private void addRandomValue(NodeBuilder nodeBuilder) {
+            if (nodeBuilder.getPropertyCount() < 1000) {
+                chooseRandomNode(nodeBuilder).setProperty('P' + itemPrefix + 
rnd.nextInt(1000),
+                        randomAlphabetic(rnd.nextInt(10000)));
+            }
+        }
+
+        private void addRandomBlob(NodeStore nodeStore, NodeBuilder 
nodeBuilder) throws IOException {
+            if (nodeBuilder.getPropertyCount() < 1000) {
+                chooseRandomNode(nodeBuilder).setProperty('B' + itemPrefix + 
rnd.nextInt(1000),
+                        createBlob(nodeStore, rnd.nextInt(maxBlobSize)));
             }
         }
 
@@ -416,16 +449,26 @@ public class SegmentCompactionIT {
             this.nodeStore = nodeStore;
         }
 
-        protected final NodeState readRandomTree(NodeState node) {
-            int i = rnd.nextInt(1 + (int) 
node.getChildNodeCount(Long.MAX_VALUE));
-            if (i != 0) {
-                return readRandomTree(get(node.getChildNodeEntries(), i - 
1).getNodeState());
+        private NodeState randomStep(NodeState parent, NodeState node) {
+            int count = (int) node.getChildNodeCount(Long.MAX_VALUE);
+            int k = rnd.nextInt(count + 1);
+            if (k == 0) {
+                return parent;
             } else {
-                return node;
+                String name = get(node.getChildNodeNames(), k - 1);
+                return node.getChildNode(name);
+            }
+        }
+
+        protected final NodeState chooseRandomNode(NodeState parent) {
+            NodeState child = parent;
+            for (int k = 0; k < rnd.nextInt(1000); k++) {
+                child = randomStep(parent, parent = child);
             }
+            return child;
         }
 
-        protected final PropertyState readRandomProperty(NodeState node) 
throws Exception {
+        protected final PropertyState chooseRandomProperty(NodeState node) 
throws Exception {
             int count = (int) node.getPropertyCount();
             if (count > 0) {
                 return get(node.getProperties(), rnd.nextInt(count));
@@ -442,7 +485,7 @@ public class SegmentCompactionIT {
 
         @Override
         public NodeState call() throws Exception {
-            return readRandomTree(nodeStore.getRoot());
+            return chooseRandomNode(nodeStore.getRoot());
         }
     }
 
@@ -453,7 +496,7 @@ public class SegmentCompactionIT {
 
         @Override
         public PropertyState call() throws Exception {
-            return readRandomProperty(readRandomTree(nodeStore.getRoot()));
+            return chooseRandomProperty(chooseRandomNode(nodeStore.getRoot()));
         }
     }
 


Reply via email to