diff --git oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PropertiesUtil.java oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PropertiesUtil.java index 0990f91..50599db 100644 --- oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PropertiesUtil.java +++ oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PropertiesUtil.java @@ -127,6 +127,30 @@ public final class PropertiesUtil { return defaultValue; } + + /** + * Returns the parameter as a byte or the + * {@code defaultValue} if the parameter is {@code null} or if + * the parameter is not a {@code Byte} and cannot be converted to + * a {@code Byte} from the parameter's string value. + * + * @param propValue the property value or {@code null} + * @param defaultValue the default byte value + */ + public static byte toByte(Object propValue, byte defaultValue) { + propValue = toObject(propValue); + if (propValue instanceof Byte) { + return (Byte) propValue; + } else if (propValue != null) { + try { + return Byte.parseByte(String.valueOf(propValue)); + } catch (NumberFormatException nfe) { + // don't care, fall through to default value + } + } + + return defaultValue; + } /** * Returns the parameter as a double or the diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java index 0ad4cb8..5e77adf 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/SegmentNodeStoreService.java @@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState; import static java.util.Collections.emptyMap; import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toBoolean; import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toInteger; +import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toByte; import static org.apache.jackrabbit.oak.commons.PropertiesUtil.toLong; import static org.apache.jackrabbit.oak.osgi.OsgiUtil.lookupConfigurationThenFramework; import static org.apache.jackrabbit.oak.segment.SegmentNotFoundExceptionListener.IGNORE_SNFE; @@ -31,6 +32,7 @@ import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.PAUS import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.RETAINED_GENERATIONS_DEFAULT; import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.RETRY_COUNT_DEFAULT; import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.SIZE_DELTA_ESTIMATION_DEFAULT; +import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.SIZE_PERCENTAGE_ESTIMATION_DEFAULT; import static org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions.DISABLE_ESTIMATION_DEFAULT; import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; import static org.apache.jackrabbit.oak.spi.blob.osgi.SplitBlobStoreService.ONLY_STANDALONE_TARGET; @@ -218,6 +220,14 @@ public class SegmentNodeStoreService extends ProxyNodeStore description = "Amount of increase in repository size that will trigger compaction (bytes)" ) public static final String COMPACTION_SIZE_DELTA_ESTIMATION = "compaction.sizeDeltaEstimation"; + + @Property( + byteValue = SIZE_PERCENTAGE_ESTIMATION_DEFAULT, + label = "Compaction Repository Size Percentage", + description = "Percentage of increase in repository size that will trigger compaction. " + + "Value represents a percentage, so an input between 0 and 100 is expected." + ) + public static final String COMPACTION_SIZE_PERCENTAGE_ESTIMATION = "compaction.sizePercentageEstimation"; @Property( boolValue = DISABLE_ESTIMATION_DEFAULT, @@ -650,6 +660,7 @@ public class SegmentNodeStoreService extends ProxyNodeStore int retainedGenerations = toInteger(property(RETAINED_GENERATIONS), RETAINED_GENERATIONS_DEFAULT); long sizeDeltaEstimation = toLong(property(COMPACTION_SIZE_DELTA_ESTIMATION), SIZE_DELTA_ESTIMATION_DEFAULT); + byte sizePercentageEstimation = toByte(property(COMPACTION_SIZE_PERCENTAGE_ESTIMATION), SIZE_PERCENTAGE_ESTIMATION_DEFAULT); int memoryThreshold = toInteger(property(MEMORY_THRESHOLD), MEMORY_THRESHOLD_DEFAULT); boolean disableEstimation = toBoolean(property(COMPACTION_DISABLE_ESTIMATION), DISABLE_ESTIMATION_DEFAULT); @@ -661,6 +672,7 @@ public class SegmentNodeStoreService extends ProxyNodeStore return new SegmentGCOptions(pauseCompaction, retryCount, forceTimeout) .setRetainedGenerations(retainedGenerations) .setGcSizeDeltaEstimation(sizeDeltaEstimation) + .setGcSizePercentageEstimation(sizePercentageEstimation) .setMemoryThreshold(memoryThreshold) .setEstimationDisabled(disableEstimation); } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentGCOptions.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentGCOptions.java index b980c35..0e66929 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentGCOptions.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentGCOptions.java @@ -55,6 +55,11 @@ public class SegmentGCOptions { * Default value for {@link #getGcSizeDeltaEstimation()} set to 10GB */ public static final long SIZE_DELTA_ESTIMATION_DEFAULT = 10737418240L; + + /** + * Default value for {@link #getGcSizePercentageEstimation()} set to 50% + */ + public static final byte SIZE_PERCENTAGE_ESTIMATION_DEFAULT = 50; /** * Default value for {@link #getMemoryThreshold()} @@ -88,6 +93,8 @@ public class SegmentGCOptions { private long gcSizeDeltaEstimation = Long.getLong( "oak.segment.compaction.gcSizeDeltaEstimation", SIZE_DELTA_ESTIMATION_DEFAULT); + + private int gcSizePercentageEstimation = SIZE_PERCENTAGE_ESTIMATION_DEFAULT; public SegmentGCOptions(boolean paused, int retryCount, int forceTimeout) { this.paused = paused; @@ -206,10 +213,10 @@ public class SegmentGCOptions { "paused=" + paused + ", estimationDisabled=" + estimationDisabled + ", gcSizeDeltaEstimation=" + gcSizeDeltaEstimation + + ", gcSizePercentageEstimation:=" + gcSizePercentageEstimation + ", retryCount=" + retryCount + ", forceTimeout=" + forceTimeout + - ", retainedGenerations=" + retainedGenerations + - ", gcSizeDeltaEstimation=" + gcSizeDeltaEstimation + "}"; + ", retainedGenerations=" + retainedGenerations + "}"; } } @@ -281,6 +288,16 @@ public class SegmentGCOptions { this.gcSizeDeltaEstimation = gcSizeDeltaEstimation; return this; } + + public int getGcSizePercentageEstimation() { + return gcSizePercentageEstimation; + } + + public SegmentGCOptions setGcSizePercentageEstimation(int gcSizePercentageEstimation) { + this.gcSizePercentageEstimation = gcSizePercentageEstimation; + + return this; + } /** * Get the available memory threshold beyond which revision gc will be diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGC.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGC.java index f18993d..a350ff5 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGC.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGC.java @@ -94,6 +94,10 @@ public interface SegmentRevisionGC { long getGcSizeDeltaEstimation(); void setGcSizeDeltaEstimation(long gcSizeDeltaEstimation); + + int getGcSizePercentageEstimation(); + + void setGcSizePercentageEstimation(int gcSizePercentageEstimation); boolean isEstimationDisabled(); diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGCMBean.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGCMBean.java index 0a24682..2b9a82b 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGCMBean.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/compaction/SegmentRevisionGCMBean.java @@ -104,6 +104,16 @@ public class SegmentRevisionGCMBean } @Override + public int getGcSizePercentageEstimation() { + return gcOptions.getGcSizePercentageEstimation(); + } + + @Override + public void setGcSizePercentageEstimation(int gcSizePercentageEstimation) { + gcOptions.setGcSizePercentageEstimation(gcSizePercentageEstimation); + } + + @Override public boolean isEstimationDisabled() { return gcOptions.isEstimationDisabled(); } diff --git oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java index 74e9743..0403bc3 100644 --- oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java +++ oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/SizeDeltaGcEstimation.java @@ -30,6 +30,8 @@ import org.apache.jackrabbit.oak.segment.compaction.SegmentGCOptions; public class SizeDeltaGcEstimation implements GCEstimation { private final long delta; + + private final int deltaP; private final GCJournal gcJournal; @@ -44,6 +46,7 @@ public class SizeDeltaGcEstimation implements GCEstimation { public SizeDeltaGcEstimation(@Nonnull SegmentGCOptions opts, @Nonnull GCJournal gcJournal, long totalSize) { this.delta = checkNotNull(opts).getGcSizeDeltaEstimation(); + this.deltaP = checkNotNull(opts).getGcSizePercentageEstimation(); this.gcJournal = checkNotNull(gcJournal); this.totalSize = totalSize; } @@ -80,7 +83,7 @@ public class SizeDeltaGcEstimation implements GCEstimation { long lastGc = getPreviousCleanupSize(); long gain = totalSize - lastGc; long gainP = 100 * (totalSize - lastGc) / totalSize; - gcNeeded = gain > delta; + gcNeeded = (gain > delta) || (gainP > deltaP); gcInfo = format( "Segmentstore size has increased since the last compaction from %s (%s bytes) to %s (%s bytes), " + "an increase of %s (%s bytes) or %s%%. ", @@ -89,12 +92,12 @@ public class SizeDeltaGcEstimation implements GCEstimation { humanReadableByteCount(gain), gain, gainP); if (gcNeeded) { gcInfo = gcInfo + format( - "This is greater than sizeDeltaEstimation=%s (%s bytes), so running compaction", - humanReadableByteCount(delta), delta); + "This is greater than sizeDeltaEstimation=%s (%s bytes) or sizePercentageEstimation=%s%%, so running compaction", + humanReadableByteCount(delta), delta, deltaP); } else { gcInfo = gcInfo + format( - "This is less than sizeDeltaEstimation=%s (%s bytes), so skipping compaction", - humanReadableByteCount(delta), delta); + "This is less than both sizeDeltaEstimation=%s (%s bytes) and sizePercentageEstimation=%s%%, so skipping compaction", + humanReadableByteCount(delta), delta, deltaP); } } finished = true;