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()));
}
}