This is an automated email from the ASF dual-hosted git repository.
daim pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
The following commit(s) were added to refs/heads/trunk by this push:
new e433fe28f2 OAK-11634 : provided support for generations in FullGC
(#2206)
e433fe28f2 is described below
commit e433fe28f2f19f07ec1287137fd71799269890c1
Author: Rishabh Kumar <[email protected]>
AuthorDate: Mon Apr 14 13:26:35 2025 +0530
OAK-11634 : provided support for generations in FullGC (#2206)
* OAK-11634 : provided support for generations in FullGC
* OAK-11634 : avoid reset operation if full gc is not enabled
* OAK-11634 : changed log level to info
---------
Co-authored-by: Rishabh Kumar <[email protected]>
---
.../plugins/document/DocumentNodeStoreHelper.java | 3 +-
.../oak/plugins/document/Configuration.java | 12 ++
.../oak/plugins/document/DocumentNodeStore.java | 3 +-
.../plugins/document/DocumentNodeStoreBuilder.java | 10 ++
.../plugins/document/DocumentNodeStoreService.java | 2 +
.../plugins/document/VersionGarbageCollector.java | 89 ++++++++++-
.../document/rdb/RDBDocumentNodeStoreBuilder.java | 13 ++
.../DocumentNodeStoreServiceConfigurationTest.java | 10 ++
.../oak/plugins/document/VersionGCInitTest.java | 56 +++++++
.../oak/plugins/document/VersionGCTest.java | 137 +++++++++++++++--
.../document/VersionGarbageCollectorIT.java | 2 +-
.../document/VersionGarbageCollectorTest.java | 162 +++++++++++++++++++++
.../mongo/MongoDocumentNodeStoreBuilderTest.java | 17 ++-
.../rdb/RDBDocumentNodeStoreBuilderTest.java | 7 +
.../oak/plugins/document/util/UtilsTest.java | 31 +++-
15 files changed, 533 insertions(+), 21 deletions(-)
diff --git
a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
index b46b3880dd..1ef9956b6b 100644
---
a/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
+++
b/oak-run-commons/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java
@@ -74,7 +74,8 @@ public class DocumentNodeStoreHelper {
boolean
isFullGCDryRun, final DocumentNodeStoreBuilder<?> builder) {
return new VersionGarbageCollector(nodeStore, gcSupport,
isFullGCEnabled(builder), isFullGCDryRun,
isEmbeddedVerificationEnabled(builder),
builder.getFullGCMode(), builder.getFullGCDelayFactor(),
- builder.getFullGCBatchSize(), builder.getFullGCProgressSize(),
builder.getFullGcMaxAgeMillis());
+ builder.getFullGCBatchSize(), builder.getFullGCProgressSize(),
builder.getFullGcMaxAgeMillis(),
+ builder.getFullGCGeneration());
}
public static DocumentNodeState readNode(DocumentNodeStore
documentNodeStore, Path path, RevisionVector rootRevision) {
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
index eb5e9e1f51..48be6afe0e 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java
@@ -36,6 +36,7 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilde
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder.DEFAULT_UPDATE_LIMIT;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_ENABLED;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_PERFLOGGER_INFO_MILLIS;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_ENABLED;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
@@ -376,6 +377,17 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServic
"is set to true, the fullGCMode will be ignored.")
int fullGCMode() default DEFAULT_FULL_GC_MODE;
+ @AttributeDefinition(
+ name = "Document Node Store Full GC Generation",
+ description = "Long value indicating which Full GC generation is
currently running on " +
+ "document node store. The Default value is " +
DEFAULT_FULL_GC_GENERATION +
+ ". Note that this value can be overridden via framework " +
+ "property 'oak.documentstore.fullGCGeneration'. " +
+ "FullGC can be reset to run from beginning after
incrementing this value. " +
+ "Any value change must be a increment from previous value
to reset the FullGC, " +
+ "in case we set to a value smaller or equal to exiting
generation, it would simply be ignored.")
+ long fullGCGeneration() default DEFAULT_FULL_GC_GENERATION;
+
@AttributeDefinition(
name = "Delay factor for a Full GC run",
description = "A Full GC run has a gap of this delay factor to
reduce continuous load on system." +
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
index 0f7109ada8..4ec7871024 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java
@@ -653,7 +653,8 @@ public final class DocumentNodeStore
this.versionGarbageCollector = new VersionGarbageCollector(
this, builder.createVersionGCSupport(),
isFullGCEnabled(builder), false,
isEmbeddedVerificationEnabled(builder),
builder.getFullGCMode(), builder.getFullGCDelayFactor(),
- builder.getFullGCBatchSize(), builder.getFullGCProgressSize(),
builder.getFullGcMaxAgeMillis());
+ builder.getFullGCBatchSize(), builder.getFullGCProgressSize(),
builder.getFullGcMaxAgeMillis(),
+ builder.getFullGCGeneration());
this.versionGarbageCollector.setStatisticsProvider(builder.getStatisticsProvider());
this.versionGarbageCollector.setGCMonitor(builder.getGCMonitor());
this.versionGarbageCollector.setFullGCPaths(builder.getFullGCIncludePaths(),
builder.getFullGCExcludePaths());
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
index 702cdca0bc..05b5e721f3 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java
@@ -181,6 +181,7 @@ public class DocumentNodeStoreBuilder<T extends
DocumentNodeStoreBuilder<T>> {
private Set<String> fullGCExcludePaths = Set.of();
private boolean embeddedVerificationEnabled =
DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
private int fullGCMode = DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
+ private long fullGCGeneration =
DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
private long fullGcMaxAgeMillis =
TimeUnit.SECONDS.toMillis(DocumentNodeStoreService.DEFAULT_FULL_GC_MAX_AGE);
private int fullGCBatchSize =
DocumentNodeStoreService.DEFAULT_FGC_BATCH_SIZE;
private int fullGCProgressSize =
DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
@@ -371,6 +372,15 @@ public class DocumentNodeStoreBuilder<T extends
DocumentNodeStoreBuilder<T>> {
return this.fullGCMode;
}
+ public T setFullGCGeneration(long v) {
+ this.fullGCGeneration = v;
+ return thisBuilder();
+ }
+
+ public long getFullGCGeneration() {
+ return this.fullGCGeneration;
+ }
+
/**
* The maximum age for nodes in milliseconds. Older entries are candidates
for full gc
* @param v max age in millis
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
index 9790267abd..27ce481cb7 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java
@@ -141,6 +141,7 @@ public class DocumentNodeStoreService {
static final boolean DEFAULT_FULL_GC_ENABLED = false;
static final boolean DEFAULT_EMBEDDED_VERIFICATION_ENABLED = true;
static final int DEFAULT_FULL_GC_MODE = 0;
+ static final int DEFAULT_FULL_GC_GENERATION = 0;
static final int DEFAULT_MONGO_LEASE_SO_TIMEOUT_MILLIS = 30000;
static final String DEFAULT_PERSISTENT_CACHE = "cache";
static final String DEFAULT_JOURNAL_CACHE = "diff-cache";
@@ -530,6 +531,7 @@ public class DocumentNodeStoreService {
setFullGCExcludePaths(config.fullGCExcludePaths()).
setEmbeddedVerificationEnabled(config.embeddedVerificationEnabled()).
setFullGCMode(config.fullGCMode()).
+ setFullGCGeneration(config.fullGCGeneration()).
setFullGcMaxAgeMillis(TimeUnit.SECONDS.toMillis(config.fullGcMaxAgeInSecs())).
setFullGCBatchSize(config.fullGCBatchSize()).
setFullGCProgressSize(config.fullGCProgressSize()).
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
index 386f623da5..86291d8def 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java
@@ -83,11 +83,13 @@ import static
org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
import static org.apache.jackrabbit.oak.plugins.document.Document.ID;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_BATCH_SIZE;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MAX_AGE;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.BRANCH_COMMITS;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.COLLISIONS;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.COMMIT_ROOT;
+import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.LOG;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.MIN_ID_VALUE;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.REVISIONS;
@@ -153,6 +155,11 @@ public class VersionGarbageCollector {
*/
static final String SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP =
"fullGCDryRunTimeStamp";
+ /**
+ * Property name to fullGcGeneration which is currently running
+ */
+ static final String SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP =
"fullGCGeneration";
+
/**
* Property name to _id till when last full-GC run happened in dryRun mode
only
*/
@@ -174,6 +181,78 @@ public class VersionGarbageCollector {
VersionGarbageCollector.fullGcMode = FullGCMode.getMode(fullGcMode);
}
+ /**
+ * Sets the full GC generation for this document store and performs a
reset if needed.
+ * <p>
+ * This method checks the existing full GC generation stored in the
settings document:
+ * <ul>
+ * <li>If no document exists, the new generation value is persisted</li>
+ * <li>If the previous generation isn't a number or null, resets full GC
and persists the new value</li>
+ * <li>If the new generation is higher than the previous one, resets
full GC and updates the value</li>
+ * <li>If the new generation is less than or equal to the previous one,
only logs the information</li>
+ * </ul>
+ *
+ * @param fullGcGen The new full GC generation value to set
+ * @return the generation with which the full GC has started
+ */
+ long resetFullGcIfGenChange(final long fullGcGen) {
+
+ if (fullGcGen == DEFAULT_FULL_GC_GENERATION) {
+ // generation hasn't been set yet, no need to make any change to
make this backward compatible
+ LOG.info("Full GC generation is set to default value {}. No action
needed.", fullGcGen);
+ return fullGcGen;
+ }
+
+ final Document doc = ds.find(SETTINGS, SETTINGS_COLLECTION_ID);
+
+ if (doc == null) {
+ // No version gc document exists, must be a new environment
+ persistFullGcGen(fullGcGen);
+ return fullGcGen;
+ }
+
+ final Object prevFullGcGenObj =
doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP);
+
+ // If no previous generation or not a Number, just persist the new
value
+ if (!(prevFullGcGenObj instanceof Number)) {
+ // this could happen if the previous value was set to a
non-numeric value i.e. (not present)
+ LOG.info("Full GC generation {} is not a valid number or null,
resetting to {}.", prevFullGcGenObj, fullGcGen);
+ resetFullGC();
+ persistFullGcGen(fullGcGen);
+ return fullGcGen;
+ }
+
+ // Compare with the previous generation
+ long prevFullGcGen = ((Number) prevFullGcGenObj).longValue();
+ if (prevFullGcGen >= fullGcGen) {
+ LOG.info("Full GC generation {} is less than or equal to the
previously saved value {}.", fullGcGen, prevFullGcGen);
+ return prevFullGcGen;
+ } else {
+ LOG.info("Found a new generation of FullGC {}, resetting the Old
gen {} values.", fullGcGen, prevFullGcGen);
+ resetFullGC();
+ persistFullGcGen(fullGcGen);
+ return fullGcGen;
+ }
+ }
+
+ /**
+ * Persists the full garbage collection generation value to the settings
document.
+ * <p>
+ * This method creates or updates a document in the settings collection
with the
+ * specified full GC generation number. The generation value is used to
track major
+ * changes in the garbage collection process across restarts or different
cluster nodes.
+ * <p>
+ * When the system detects a higher generation number than previously
stored, it will
+ * reset the full GC state before persisting the new generation value.
+ *
+ * @param fullGcGeneration The full garbage collection generation value to
persist
+ */
+ private void persistFullGcGen(long fullGcGeneration) {
+ UpdateOp op = new UpdateOp(SETTINGS_COLLECTION_ID, true);
+ op.set(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP, fullGcGeneration);
+ ds.createOrUpdate(SETTINGS, op);
+ }
+
private final DocumentNodeStore nodeStore;
private final DocumentStore ds;
private final boolean fullGCEnabled;
@@ -198,7 +277,7 @@ public class VersionGarbageCollector {
final boolean isFullGCDryRun,
final boolean embeddedVerification) {
this(nodeStore, gcSupport, fullGCEnabled, isFullGCDryRun,
embeddedVerification, DEFAULT_FULL_GC_MODE,
- 0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ 0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
}
VersionGarbageCollector(DocumentNodeStore nodeStore,
@@ -210,7 +289,8 @@ public class VersionGarbageCollector {
final double fullGCDelayFactor,
final int fullGCBatchSize,
final int fullGCProgressSize,
- final long fullGcMaxAgeInMillis) {
+ final long fullGcMaxAgeInMillis,
+ final long fullGcGeneration) {
this.nodeStore = nodeStore;
this.versionStore = gcSupport;
this.ds = gcSupport.getDocumentStore();
@@ -224,8 +304,9 @@ public class VersionGarbageCollector {
this.options = new VersionGCOptions();
setFullGcMode(fullGCMode);
- AUDIT_LOG.info("<init> VersionGarbageCollector created with
fullGcMode: {}, maxFullGcAgeInMillis: {}, batchSize: {}, progressSize: {},
delayFactor: {}",
- fullGcMode, fullGcMaxAgeInMillis, fullGCBatchSize,
fullGCProgressSize, fullGCDelayFactor);
+ long fullGcGen = fullGCEnabled ?
resetFullGcIfGenChange(fullGcGeneration) : fullGcGeneration;
+ AUDIT_LOG.info("<init> VersionGarbageCollector created with
fullGcMode: {}, maxFullGcAgeInMillis: {}, batchSize: {}, progressSize: {},
delayFactor: {}, fullGcGeneration: {}",
+ fullGcMode, fullGcMaxAgeInMillis, fullGCBatchSize,
fullGCProgressSize, fullGCDelayFactor, fullGcGen);
}
/**
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilder.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilder.java
index bff7f0ff17..b8223fd599 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilder.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilder.java
@@ -183,6 +183,19 @@ public class RDBDocumentNodeStoreBuilder
return 0;
}
+ @Override
+ public RDBDocumentNodeStoreBuilder setFullGCGeneration(long v) {
+ // fullGC modes are not supported for RDB
+ log.warn("FullGC generation are not supported for RDB");
+ return thisBuilder();
+ }
+
+ @Override
+ public long getFullGCGeneration() {
+ // fullGC modes are not supported for RDB
+ return 0;
+ }
+
@Override
public RDBDocumentNodeStoreBuilder setFullGcMaxAgeMillis(long v) {
// fullGC modes are not supported for RDB
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
index 2e9429a9ad..1516626a85 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java
@@ -39,6 +39,7 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServic
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_ENABLED;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_ENABLED;
import static org.junit.Assert.assertArrayEquals;
@@ -97,6 +98,7 @@ public class DocumentNodeStoreServiceConfigurationTest {
assertEquals(DEFAULT_THROTTLING_ENABLED, config.throttlingEnabled());
assertEquals(DEFAULT_FULL_GC_ENABLED, config.fullGCEnabled());
assertEquals(DEFAULT_FULL_GC_MODE, config.fullGCMode());
+ assertEquals(DEFAULT_FULL_GC_GENERATION, config.fullGCGeneration());
assertEquals(DEFAULT_FGC_DELAY_FACTOR, config.fullGCDelayFactor(),
0.01);
assertEquals(DEFAULT_FGC_BATCH_SIZE, config.fullGCBatchSize());
assertEquals(DEFAULT_FGC_PROGRESS_SIZE, config.fullGCProgressSize());
@@ -139,6 +141,14 @@ public class DocumentNodeStoreServiceConfigurationTest {
assertEquals(fullGCModeValue, config.fullGCMode());
}
+ @Test
+ public void fullGCGenerationValueSet() throws Exception {
+ long fullGCGenerationValue = 2;
+ addConfigurationEntry(preset, "fullGCGeneration",
fullGCGenerationValue);
+ Configuration config = createConfiguration();
+ assertEquals(fullGCGenerationValue, config.fullGCGeneration());
+ }
+
@Test
public void fullGCIncludePaths() throws Exception {
final String[] includesPath = new String[]{"/foo", "/bar"};
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCInitTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCInitTest.java
index 47afbf2b7e..dad613d6d0 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCInitTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCInitTest.java
@@ -33,6 +33,7 @@ import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.MIN_ID_VAL
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DRY_RUN_DOCUMENT_ID_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP;
+import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_ID;
import static
org.apache.jackrabbit.oak.plugins.document.util.Utils.getIdFromPath;
@@ -66,6 +67,7 @@ public class VersionGCInitTest {
// fullGC values shouldn't have been updated without fullGC enabled
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
}
@Test
@@ -88,6 +90,57 @@ public class VersionGCInitTest {
assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
assertEquals(stats.oldestModifiedDocId,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
assertEquals(MIN_ID_VALUE,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
+ @Test
+ public void lazyInitializeWithFullGCWithGenerationWithFullGCDisabled()
throws Exception {
+ ns =
builderProvider.newBuilder().setFullGCGeneration(1).getNodeStore();
+ DocumentStore store = ns.getDocumentStore();
+ Document vgc = store.find(SETTINGS, SETTINGS_COLLECTION_ID);
+ assertNull(vgc);
+
+ enableFullGC(ns.getVersionGarbageCollector());
+ long offset = SECONDS.toMillis(42);
+ String id = getIdFromPath("/node");
+ Revision r = new Revision(offset, 0, 1);
+ UpdateOp op = new UpdateOp(id, true);
+ NodeDocument.setModified(op, r);
+ store.createOrUpdate(NODES, op);
+ VersionGCStats stats = ns.getVersionGarbageCollector().gc(1, DAYS);
+
+ vgc = store.find(SETTINGS, SETTINGS_COLLECTION_ID);
+ assertNotNull(vgc);
+ assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(stats.oldestModifiedDocId,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertEquals(MIN_ID_VALUE,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
+ @Test
+ public void lazyInitializeWithFullGCWithGeneration() throws Exception {
+ ns =
builderProvider.newBuilder().setFullGCGeneration(1).setFullGCEnabled(true).getNodeStore();
+ DocumentStore store = ns.getDocumentStore();
+ Document vgc = store.find(SETTINGS, SETTINGS_COLLECTION_ID);
+ assertNotNull(vgc);
+ assertEquals(1L, vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ enableFullGC(ns.getVersionGarbageCollector());
+ ns.getVersionGarbageCollector().resetFullGcIfGenChange(1);
+ long offset = SECONDS.toMillis(42);
+ String id = getIdFromPath("/node");
+ Revision r = new Revision(offset, 0, 1);
+ UpdateOp op = new UpdateOp(id, true);
+ NodeDocument.setModified(op, r);
+ store.createOrUpdate(NODES, op);
+ VersionGCStats stats = ns.getVersionGarbageCollector().gc(1, DAYS);
+
+ vgc = store.find(SETTINGS, SETTINGS_COLLECTION_ID);
+ assertNotNull(vgc);
+ assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(stats.oldestModifiedDocId,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertEquals(MIN_ID_VALUE,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertEquals(1L, vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
}
@Test
@@ -104,6 +157,7 @@ public class VersionGCInitTest {
assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
assertEquals(stats.oldestModifiedDocId,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
assertEquals(MIN_ID_VALUE,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
}
@Test
@@ -128,6 +182,7 @@ public class VersionGCInitTest {
// fullGC values shouldn't have been updated in dryRun mode
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
// dryRun mode values should have been updated
assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP));
@@ -149,6 +204,7 @@ public class VersionGCInitTest {
// fullGC values shouldn't have been updated in dryRun mode
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+ assertNull(vgc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
// dryRun mode values should have been updated
assertEquals(stats.oldestModifiedDocTimeStamp,
vgc.get(SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP));
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java
index e57c9b3950..5876e78177 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGCTest.java
@@ -62,6 +62,7 @@ import static
org.apache.jackrabbit.oak.plugins.document.FullGCHelper.enableFull
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DRY_RUN_DOCUMENT_ID_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP;
+import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP;
import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_ID;
import static org.junit.Assert.assertEquals;
@@ -535,12 +536,128 @@ public class VersionGCTest {
// OAK-10370 END
+ @Test
+ public void testResetWithFullGCGeneration() throws Exception {
+ enableFullGC(gc);
+ VersionGCStats stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ final Document settingsBefore = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsBefore);
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+
assertNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ gc.resetFullGcIfGenChange(1);
+ final Document settingsAfter = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter);
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(1L,
settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
+ @Test
+ public void testResetWithFullGCGenerationIncrement() throws Exception {
+ enableFullGC(gc);
+ VersionGCStats stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ final Document settingsBefore = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsBefore);
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+
assertNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ gc.resetFullGcIfGenChange(1);
+ final Document settingsAfter = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter);
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(1L,
settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ // run full gc and set fullgc variables again in db
+ stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ // change generation to a higher value
+ gc.resetFullGcIfGenChange(2);
+ final Document settingsAfter2 = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter2);
+
assertNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(2L,
settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
+ @Test
+ public void testResetWithFullGCGenerationDecrement() throws Exception {
+ enableFullGC(gc);
+ VersionGCStats stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ final Document settingsBefore = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsBefore);
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+
assertNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ gc.resetFullGcIfGenChange(2);
+ final Document settingsAfter = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter);
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(2L,
settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ // run full gc and set fullgc variables again in db
+ stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ // change generation to a lower value
+ gc.resetFullGcIfGenChange(1);
+ final Document settingsAfter2 = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter2);
+
assertNotNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(2L,
settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
+ @Test
+ public void testResetWithFullGCGenerationSameValue() throws Exception {
+ enableFullGC(gc);
+ VersionGCStats stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ final Document settingsBefore = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsBefore);
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+
assertNull(settingsBefore.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ gc.resetFullGcIfGenChange(2);
+ final Document settingsAfter = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter);
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNull(settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(2L,
settingsAfter.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+
+ // run full gc and set fullgc variables again in db
+ stats = FullGCHelper.gc(gc, 30, TimeUnit.MINUTES);
+ assertNotNull(stats);
+
+ // change generation to a same value
+ gc.resetFullGcIfGenChange(2);
+ final Document settingsAfter2 = store.find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ assertNotNull(settingsAfter2);
+
assertNotNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_DOCUMENT_ID_PROP));
+
assertNotNull(settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_TIMESTAMP_PROP));
+ assertEquals(2L,
settingsAfter2.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP));
+ }
+
// OAK-10745
@Test
public void testVGCWithBatchSizeSmallerThanProgressSize() throws
IllegalAccessException {
VersionGarbageCollector vgc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- 0, 0, 1000, 5000,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ 0, 0, 1000, 5000,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(1000, readDeclaredField(vgc, "fullGCBatchSize", true));
assertEquals(5000, readDeclaredField(vgc, "fullGCProgressSize", true));
@@ -550,7 +667,7 @@ public class VersionGCTest {
public void testVGCWithBatchSizeGreaterThanProgressSize() throws
IllegalAccessException {
VersionGarbageCollector vgc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- 0, 0, 20000, 15000,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ 0, 0, 20000, 15000,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(15000, readDeclaredField(vgc, "fullGCBatchSize", true));
assertEquals(15000, readDeclaredField(vgc, "fullGCProgressSize",
true));
@@ -571,7 +688,7 @@ public class VersionGCTest {
// reinitialize VersionGarbageCollector with not allowed value
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeNotAllowedValue, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeNotAllowedValue, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE),
0);
assertEquals("Starting VersionGarbageCollector with not applicable /
not allowed value" +
"will set fullGcMode to default NONE", FullGCMode.NONE,
VersionGarbageCollector.getFullGcMode());
@@ -582,7 +699,7 @@ public class VersionGCTest {
int fullGcModeNone = 0;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeNone, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeNone, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE),
0);
assertEquals(FullGCMode.NONE, VersionGarbageCollector.getFullGcMode());
}
@@ -592,7 +709,7 @@ public class VersionGCTest {
int fullGcModeGapOrphans = 2;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeGapOrphans, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeGapOrphans, 0, DEFAULT_FGC_BATCH_SIZE,
DEFAULT_FGC_PROGRESS_SIZE, TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE),
0);
assertEquals(FullGCMode.GAP_ORPHANS,
VersionGarbageCollector.getFullGcMode());
}
@@ -602,7 +719,7 @@ public class VersionGCTest {
int fullGcModeGapOrphansEmptyProperties = 3;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeGapOrphansEmptyProperties, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeGapOrphansEmptyProperties, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(FullGCMode.GAP_ORPHANS_EMPTYPROPS,
VersionGarbageCollector.getFullGcMode());
}
@@ -616,7 +733,7 @@ public class VersionGCTest {
int fullGcModeAllOrphansEmptyProperties = 4;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeAllOrphansEmptyProperties, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeAllOrphansEmptyProperties, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(FullGCMode.ALL_ORPHANS_EMPTYPROPS,
VersionGarbageCollector.getFullGcMode());
}
@@ -626,7 +743,7 @@ public class VersionGCTest {
int fullGcModeAllOrphansEmptyPropertiesKeepOneUserProps = 5;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeAllOrphansEmptyPropertiesKeepOneUserProps, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeAllOrphansEmptyPropertiesKeepOneUserProps, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(FullGCMode.ORPHANS_EMPTYPROPS_KEEP_ONE_USER_PROPS,
VersionGarbageCollector.getFullGcMode());
}
@@ -636,7 +753,7 @@ public class VersionGCTest {
int fullGcModeAllOrphansEmptyPropertiesKeepOneAllProps = 6;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeAllOrphansEmptyPropertiesKeepOneAllProps, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeAllOrphansEmptyPropertiesKeepOneAllProps, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(FullGCMode.ORPHANS_EMPTYPROPS_KEEP_ONE_ALL_PROPS,
VersionGarbageCollector.getFullGcMode());
}
@@ -646,7 +763,7 @@ public class VersionGCTest {
int fullGcModeAllOrphansEmptyPropertiesUnmergedBC = 7;
VersionGarbageCollector gc = new VersionGarbageCollector(
ns, new VersionGCSupport(store), true, false, false,
- fullGcModeAllOrphansEmptyPropertiesUnmergedBC, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
+ fullGcModeAllOrphansEmptyPropertiesUnmergedBC, 0,
DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
assertEquals(FullGCMode.ORPHANS_EMPTYPROPS_UNMERGED_BC,
VersionGarbageCollector.getFullGcMode());
}
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
index 7342cd7d43..f80076ee6b 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorIT.java
@@ -1789,7 +1789,7 @@ public class VersionGarbageCollectorIT {
}
};
- gcRef.set(new VersionGarbageCollector(store1, gcSupport, true, false,
false, 3, 0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE)));
+ gcRef.set(new VersionGarbageCollector(store1, gcSupport, true, false,
false, 3, 0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE,
TimeUnit.SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0));
//3. Check that deleted property does get collected post maxAge
clock.waitUntil(clock.getTime() + HOURS.toMillis(maxAge*2) + delta);
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
new file mode 100644
index 0000000000..f63824f5f6
--- /dev/null
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollectorTest.java
@@ -0,0 +1,162 @@
+/*
+ * 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.plugins.document;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.apache.jackrabbit.oak.plugins.document.Collection.SETTINGS;
+import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP;
+import static
org.apache.jackrabbit.oak.plugins.document.VersionGarbageCollector.SETTINGS_COLLECTION_ID;
+
+/**
+ * Unit tests for {@link VersionGarbageCollector}
+ */
+public class VersionGarbageCollectorTest {
+
+ final DocumentStore ds = Mockito.mock(DocumentStore.class);
+ final DocumentNodeStore ns = Mockito.mock(DocumentNodeStore.class);
+ final VersionGCSupport gcSupport = Mockito.mock(VersionGCSupport.class);
+ final int fullGcGen = 2;
+ VersionGarbageCollector vgc;
+
+ @Before
+ public void before() {
+ Mockito.when(gcSupport.getDocumentStore()).thenReturn(ds);
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithFullGcDisabled() {
+ // Setup: ensure no settings document exists
+ final Document doc = Mockito.mock(Document.class);
+
Mockito.when(doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP)).thenReturn(5);
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(doc);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, false, false, true,
3, 0.0, 100, 1000, 86400, 2);
+
+ // no database query if generation is default value.
+ Mockito.verifyNoInteractions(ds);
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithDefaultValue() {
+ // Setup: ensure no settings document exists
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(null);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, 0);
+
+ // no database query if generation is default value.
+ Mockito.verifyNoInteractions(ds);
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithNoDocument() {
+ // Setup: ensure no settings document exists
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(null);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, fullGcGen);
+
+ Mockito.verify(ds, Mockito.times(1)).find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ Mockito.verify(ds,
Mockito.times(1)).createOrUpdate(Mockito.eq(SETTINGS), (UpdateOp)
Mockito.any());
+ // verify no calls to specific methods
+ Mockito.verify(ds, Mockito.never()).remove(Mockito.any(), (String)
Mockito.any());
+ Mockito.verify(ds, Mockito.never()).findAndUpdate(Mockito.any(),
(UpdateOp) Mockito.any());
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithEmptyGeneration() {
+ // Setup: document exists but has non-numeric generation value
+ final Document doc = Mockito.mock(Document.class);
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(doc);
+
Mockito.when(doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP)).thenReturn(null);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, fullGcGen);
+
+ // Verify: logs warning and persists new value
+ Mockito.verify(ds).find(SETTINGS, SETTINGS_COLLECTION_ID);
+ Mockito.verify(ds, Mockito.times(1)).findAndUpdate(Mockito.any(),
(UpdateOp) Mockito.any());
+ Mockito.verify(ds).createOrUpdate(Mockito.eq(SETTINGS), (UpdateOp)
Mockito.any());
+
+ // verify no calls to specific methods
+ Mockito.verify(ds, Mockito.never()).remove(Mockito.any(), (String)
Mockito.any());
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithNonNumberGeneration() {
+ // Setup: document exists but has non-numeric generation value
+ final Document doc = Mockito.mock(Document.class);
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(doc);
+
Mockito.when(doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP)).thenReturn("not-a-number");
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, fullGcGen);
+
+ // Verify: logs warning and persists new value
+ Mockito.verify(ds).find(SETTINGS, SETTINGS_COLLECTION_ID);
+ Mockito.verify(ds, Mockito.times(1)).findAndUpdate(Mockito.any(),
(UpdateOp) Mockito.any());
+ Mockito.verify(ds).createOrUpdate(Mockito.eq(SETTINGS), (UpdateOp)
Mockito.any());
+
+ // verify no calls to specific methods
+ Mockito.verify(ds, Mockito.never()).remove(Mockito.any(), (String)
Mockito.any());
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithLowerGeneration() {
+ // Setup: document exists with higher generation
+ final Document doc = Mockito.mock(Document.class);
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(doc);
+
Mockito.when(doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP)).thenReturn(5);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, fullGcGen);
+
+ // Verify: logs warning and persists new value
+ Mockito.verify(ds).find(SETTINGS, SETTINGS_COLLECTION_ID);
+ Mockito.verify(ds,
Mockito.never()).createOrUpdate(Mockito.eq(SETTINGS), (UpdateOp) Mockito.any());
+
+ // verify no calls to specific methods
+ Mockito.verify(ds, Mockito.never()).remove(Mockito.any(), (String)
Mockito.any());
+ Mockito.verify(ds, Mockito.never()).findAndUpdate(Mockito.any(),
(UpdateOp) Mockito.any());
+ }
+
+ @Test
+ public void testResetFullGcIfGenChangeWithHigherGeneration() {
+ // Setup: document exists with lower generation
+ final Document doc = Mockito.mock(Document.class);
+ Mockito.when(ds.find(SETTINGS,
SETTINGS_COLLECTION_ID)).thenReturn(doc);
+
Mockito.when(doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP)).thenReturn(1);
+
+ // Execute
+ vgc = new VersionGarbageCollector(ns, gcSupport, true, false, true, 3,
0.0, 100, 1000, 86400, fullGcGen);
+
+ // Verify: logs warning and persists new value
+ Mockito.verify(ds, Mockito.times(1)).find(SETTINGS,
SETTINGS_COLLECTION_ID);
+ Mockito.verify(ds,
Mockito.times(1)).findAndUpdate(Mockito.eq(SETTINGS), (UpdateOp) Mockito.any());
+ Mockito.verify(ds,
Mockito.times(1)).createOrUpdate(Mockito.eq(SETTINGS), (UpdateOp)
Mockito.any());
+
+ // verify no calls to specific methods
+ Mockito.verify(ds, Mockito.never()).remove(Mockito.any(), (String)
Mockito.any());
+ }
+
+}
\ No newline at end of file
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentNodeStoreBuilderTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentNodeStoreBuilderTest.java
index d900d10f71..340d62ca6b 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentNodeStoreBuilderTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentNodeStoreBuilderTest.java
@@ -130,7 +130,22 @@ public class MongoDocumentNodeStoreBuilderTest {
public void fullGCModeDefaultValue() {
MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
final int fullGcModeNone = 0;
- assertEquals(builder.getFullGCMode(), fullGcModeNone);
+ assertEquals(fullGcModeNone, builder.getFullGCMode());
+ }
+
+ @Test
+ public void fullGCGenerationDefaultValue() {
+ MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
+ final long fullGcGeneration = 0;
+ assertEquals(fullGcGeneration, builder.getFullGCGeneration());
+ }
+
+ @Test
+ public void fullGCGenerationSetValue() {
+ MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
+ final long fullGcGeneration = 3;
+ builder.setFullGCGeneration(fullGcGeneration);
+ assertEquals(fullGcGeneration, builder.getFullGCGeneration());
}
@Test
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilderTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilderTest.java
index 642b05e20e..fa0f2479e9 100755
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilderTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilderTest.java
@@ -115,6 +115,13 @@ public class RDBDocumentNodeStoreBuilderTest {
assertEquals(0, builder.getFullGCMode());
}
+ @Test
+ public void fullGCGenerationHasDefaultValue() {
+ RDBDocumentNodeStoreBuilder builder = new
RDBDocumentNodeStoreBuilder();
+ builder.setFullGCGeneration(3);
+ assertEquals(0, builder.getFullGCGeneration());
+ }
+
@Test
public void fullGcMaxAgeInSecsHasDefaultValue() {
RDBDocumentNodeStoreBuilder builder = new
RDBDocumentNodeStoreBuilder();
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
index 71ba70e2ad..2ec1de9e3d 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/util/UtilsTest.java
@@ -241,7 +241,15 @@ public class UtilsTest {
DocumentNodeStoreBuilder<?> builder = newDocumentNodeStoreBuilder();
int fullGCModeDefaultValue = builder.getFullGCMode();
final int fullGcModeNone = 0;
- assertEquals("Full GC mode has NONE value by default",
fullGCModeDefaultValue, fullGcModeNone);
+ assertEquals("Full GC mode has NONE value by default", fullGcModeNone,
fullGCModeDefaultValue);
+ }
+
+ @Test
+ public void fullGCGenerationDefaultValue() {
+ DocumentNodeStoreBuilder<?> builder = newDocumentNodeStoreBuilder();
+ long fullGCGenerationDefaultValue = builder.getFullGCGeneration();
+ final long fullGcgeneration = 0;
+ assertEquals("Full GC generation has 0 value by default",
fullGcgeneration, fullGCGenerationDefaultValue);
}
@Test
@@ -250,7 +258,16 @@ public class UtilsTest {
final int fullGcModeGapOrphans = 2;
builder.setFullGCMode(fullGcModeGapOrphans);
int fullGCModeValue = builder.getFullGCMode();
- assertEquals("Full GC mode set correctly via configuration",
fullGCModeValue, fullGcModeGapOrphans);
+ assertEquals("Full GC mode set correctly via configuration",
fullGcModeGapOrphans, fullGCModeValue);
+ }
+
+ @Test
+ public void fullGCGenerationSetViaConfiguration() {
+ DocumentNodeStoreBuilder<?> builder = newDocumentNodeStoreBuilder();
+ final long fullGcGeneration = 2;
+ builder.setFullGCGeneration(fullGcGeneration);
+ long fullGCGenerationValue = builder.getFullGCGeneration();
+ assertEquals("Full GC generation set correctly via configuration",
fullGcGeneration, fullGCGenerationValue);
}
@Test
@@ -258,7 +275,15 @@ public class UtilsTest {
DocumentNodeStoreBuilder<?> builder = newRDBDocumentNodeStoreBuilder();
builder.setFullGCMode(3);
int fullGCModeValue = builder.getFullGCMode();
- assertEquals("Full GC mode has default value 0 for RDB Document
Store", fullGCModeValue, 0);
+ assertEquals("Full GC mode has default value 0 for RDB Document
Store", 0, fullGCModeValue);
+ }
+
+ @Test
+ public void fullGCGenerationHasDefaultValueForRDB() {
+ DocumentNodeStoreBuilder<?> builder = newRDBDocumentNodeStoreBuilder();
+ builder.setFullGCGeneration(3);
+ long fullGCGenerationValue = builder.getFullGCGeneration();
+ assertEquals("Full GC generation has default value 0 for RDB Document
Store", 0, fullGCGenerationValue);
}
@Test