Skip to content

Commit e433fe2

Browse files
rishabhdaimRishabh Kumar
andauthored
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 <diam@adobe.com>
1 parent 0bfdde4 commit e433fe2

File tree

15 files changed

+533
-21
lines changed

15 files changed

+533
-21
lines changed

oak-run-commons/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreHelper.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ public static VersionGarbageCollector createVersionGC(final DocumentNodeStore no
7474
boolean isFullGCDryRun, final DocumentNodeStoreBuilder<?> builder) {
7575
return new VersionGarbageCollector(nodeStore, gcSupport, isFullGCEnabled(builder), isFullGCDryRun,
7676
isEmbeddedVerificationEnabled(builder), builder.getFullGCMode(), builder.getFullGCDelayFactor(),
77-
builder.getFullGCBatchSize(), builder.getFullGCProgressSize(), builder.getFullGcMaxAgeMillis());
77+
builder.getFullGCBatchSize(), builder.getFullGCProgressSize(), builder.getFullGcMaxAgeMillis(),
78+
builder.getFullGCGeneration());
7879
}
7980

8081
public static DocumentNodeState readNode(DocumentNodeStore documentNodeStore, Path path, RevisionVector rootRevision) {

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/Configuration.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreBuilder.DEFAULT_UPDATE_LIMIT;
3737
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_ENABLED;
3838
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
39+
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
3940
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_PERFLOGGER_INFO_MILLIS;
4041
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_ENABLED;
4142
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
@@ -376,6 +377,17 @@
376377
"is set to true, the fullGCMode will be ignored.")
377378
int fullGCMode() default DEFAULT_FULL_GC_MODE;
378379

380+
@AttributeDefinition(
381+
name = "Document Node Store Full GC Generation",
382+
description = "Long value indicating which Full GC generation is currently running on " +
383+
"document node store. The Default value is " + DEFAULT_FULL_GC_GENERATION +
384+
". Note that this value can be overridden via framework " +
385+
"property 'oak.documentstore.fullGCGeneration'. " +
386+
"FullGC can be reset to run from beginning after incrementing this value. " +
387+
"Any value change must be a increment from previous value to reset the FullGC, " +
388+
"in case we set to a value smaller or equal to exiting generation, it would simply be ignored.")
389+
long fullGCGeneration() default DEFAULT_FULL_GC_GENERATION;
390+
379391
@AttributeDefinition(
380392
name = "Delay factor for a Full GC run",
381393
description = "A Full GC run has a gap of this delay factor to reduce continuous load on system." +

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStore.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,8 @@ public DocumentNodeStore(DocumentNodeStoreBuilder<?> builder) {
653653
this.versionGarbageCollector = new VersionGarbageCollector(
654654
this, builder.createVersionGCSupport(), isFullGCEnabled(builder), false,
655655
isEmbeddedVerificationEnabled(builder), builder.getFullGCMode(), builder.getFullGCDelayFactor(),
656-
builder.getFullGCBatchSize(), builder.getFullGCProgressSize(), builder.getFullGcMaxAgeMillis());
656+
builder.getFullGCBatchSize(), builder.getFullGCProgressSize(), builder.getFullGcMaxAgeMillis(),
657+
builder.getFullGCGeneration());
657658
this.versionGarbageCollector.setStatisticsProvider(builder.getStatisticsProvider());
658659
this.versionGarbageCollector.setGCMonitor(builder.getGCMonitor());
659660
this.versionGarbageCollector.setFullGCPaths(builder.getFullGCIncludePaths(), builder.getFullGCExcludePaths());

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ public class DocumentNodeStoreBuilder<T extends DocumentNodeStoreBuilder<T>> {
181181
private Set<String> fullGCExcludePaths = Set.of();
182182
private boolean embeddedVerificationEnabled = DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
183183
private int fullGCMode = DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
184+
private long fullGCGeneration = DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
184185
private long fullGcMaxAgeMillis = TimeUnit.SECONDS.toMillis(DocumentNodeStoreService.DEFAULT_FULL_GC_MAX_AGE);
185186
private int fullGCBatchSize = DocumentNodeStoreService.DEFAULT_FGC_BATCH_SIZE;
186187
private int fullGCProgressSize = DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
@@ -371,6 +372,15 @@ public int getFullGCMode() {
371372
return this.fullGCMode;
372373
}
373374

375+
public T setFullGCGeneration(long v) {
376+
this.fullGCGeneration = v;
377+
return thisBuilder();
378+
}
379+
380+
public long getFullGCGeneration() {
381+
return this.fullGCGeneration;
382+
}
383+
374384
/**
375385
* The maximum age for nodes in milliseconds. Older entries are candidates for full gc
376386
* @param v max age in millis

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ public class DocumentNodeStoreService {
141141
static final boolean DEFAULT_FULL_GC_ENABLED = false;
142142
static final boolean DEFAULT_EMBEDDED_VERIFICATION_ENABLED = true;
143143
static final int DEFAULT_FULL_GC_MODE = 0;
144+
static final int DEFAULT_FULL_GC_GENERATION = 0;
144145
static final int DEFAULT_MONGO_LEASE_SO_TIMEOUT_MILLIS = 30000;
145146
static final String DEFAULT_PERSISTENT_CACHE = "cache";
146147
static final String DEFAULT_JOURNAL_CACHE = "diff-cache";
@@ -530,6 +531,7 @@ private void configureBuilder(DocumentNodeStoreBuilder<?> builder) {
530531
setFullGCExcludePaths(config.fullGCExcludePaths()).
531532
setEmbeddedVerificationEnabled(config.embeddedVerificationEnabled()).
532533
setFullGCMode(config.fullGCMode()).
534+
setFullGCGeneration(config.fullGCGeneration()).
533535
setFullGcMaxAgeMillis(TimeUnit.SECONDS.toMillis(config.fullGcMaxAgeInSecs())).
534536
setFullGCBatchSize(config.fullGCBatchSize()).
535537
setFullGCProgressSize(config.fullGCProgressSize()).

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/VersionGarbageCollector.java

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,13 @@
8383
import static org.apache.jackrabbit.oak.plugins.document.Document.ID;
8484
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_BATCH_SIZE;
8585
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
86+
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
8687
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MAX_AGE;
8788
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
8889
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.BRANCH_COMMITS;
8990
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.COLLISIONS;
9091
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.COMMIT_ROOT;
92+
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.LOG;
9193
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MIN_ID_VALUE;
9294
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.MODIFIED_IN_SECS;
9395
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.REVISIONS;
@@ -153,6 +155,11 @@ public class VersionGarbageCollector {
153155
*/
154156
static final String SETTINGS_COLLECTION_FULL_GC_DRY_RUN_TIMESTAMP_PROP = "fullGCDryRunTimeStamp";
155157

158+
/**
159+
* Property name to fullGcGeneration which is currently running
160+
*/
161+
static final String SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP = "fullGCGeneration";
162+
156163
/**
157164
* Property name to _id till when last full-GC run happened in dryRun mode only
158165
*/
@@ -174,6 +181,78 @@ static void setFullGcMode(int fullGcMode) {
174181
VersionGarbageCollector.fullGcMode = FullGCMode.getMode(fullGcMode);
175182
}
176183

184+
/**
185+
* Sets the full GC generation for this document store and performs a reset if needed.
186+
* <p>
187+
* This method checks the existing full GC generation stored in the settings document:
188+
* <ul>
189+
* <li>If no document exists, the new generation value is persisted</li>
190+
* <li>If the previous generation isn't a number or null, resets full GC and persists the new value</li>
191+
* <li>If the new generation is higher than the previous one, resets full GC and updates the value</li>
192+
* <li>If the new generation is less than or equal to the previous one, only logs the information</li>
193+
* </ul>
194+
*
195+
* @param fullGcGen The new full GC generation value to set
196+
* @return the generation with which the full GC has started
197+
*/
198+
long resetFullGcIfGenChange(final long fullGcGen) {
199+
200+
if (fullGcGen == DEFAULT_FULL_GC_GENERATION) {
201+
// generation hasn't been set yet, no need to make any change to make this backward compatible
202+
LOG.info("Full GC generation is set to default value {}. No action needed.", fullGcGen);
203+
return fullGcGen;
204+
}
205+
206+
final Document doc = ds.find(SETTINGS, SETTINGS_COLLECTION_ID);
207+
208+
if (doc == null) {
209+
// No version gc document exists, must be a new environment
210+
persistFullGcGen(fullGcGen);
211+
return fullGcGen;
212+
}
213+
214+
final Object prevFullGcGenObj = doc.get(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP);
215+
216+
// If no previous generation or not a Number, just persist the new value
217+
if (!(prevFullGcGenObj instanceof Number)) {
218+
// this could happen if the previous value was set to a non-numeric value i.e. (not present)
219+
LOG.info("Full GC generation {} is not a valid number or null, resetting to {}.", prevFullGcGenObj, fullGcGen);
220+
resetFullGC();
221+
persistFullGcGen(fullGcGen);
222+
return fullGcGen;
223+
}
224+
225+
// Compare with the previous generation
226+
long prevFullGcGen = ((Number) prevFullGcGenObj).longValue();
227+
if (prevFullGcGen >= fullGcGen) {
228+
LOG.info("Full GC generation {} is less than or equal to the previously saved value {}.", fullGcGen, prevFullGcGen);
229+
return prevFullGcGen;
230+
} else {
231+
LOG.info("Found a new generation of FullGC {}, resetting the Old gen {} values.", fullGcGen, prevFullGcGen);
232+
resetFullGC();
233+
persistFullGcGen(fullGcGen);
234+
return fullGcGen;
235+
}
236+
}
237+
238+
/**
239+
* Persists the full garbage collection generation value to the settings document.
240+
* <p>
241+
* This method creates or updates a document in the settings collection with the
242+
* specified full GC generation number. The generation value is used to track major
243+
* changes in the garbage collection process across restarts or different cluster nodes.
244+
* <p>
245+
* When the system detects a higher generation number than previously stored, it will
246+
* reset the full GC state before persisting the new generation value.
247+
*
248+
* @param fullGcGeneration The full garbage collection generation value to persist
249+
*/
250+
private void persistFullGcGen(long fullGcGeneration) {
251+
UpdateOp op = new UpdateOp(SETTINGS_COLLECTION_ID, true);
252+
op.set(SETTINGS_COLLECTION_FULL_GC_GENERATION_PROP, fullGcGeneration);
253+
ds.createOrUpdate(SETTINGS, op);
254+
}
255+
177256
private final DocumentNodeStore nodeStore;
178257
private final DocumentStore ds;
179258
private final boolean fullGCEnabled;
@@ -198,7 +277,7 @@ static void setFullGcMode(int fullGcMode) {
198277
final boolean isFullGCDryRun,
199278
final boolean embeddedVerification) {
200279
this(nodeStore, gcSupport, fullGCEnabled, isFullGCDryRun, embeddedVerification, DEFAULT_FULL_GC_MODE,
201-
0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE, SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE));
280+
0, DEFAULT_FGC_BATCH_SIZE, DEFAULT_FGC_PROGRESS_SIZE, SECONDS.toMillis(DEFAULT_FULL_GC_MAX_AGE), 0);
202281
}
203282

204283
VersionGarbageCollector(DocumentNodeStore nodeStore,
@@ -210,7 +289,8 @@ static void setFullGcMode(int fullGcMode) {
210289
final double fullGCDelayFactor,
211290
final int fullGCBatchSize,
212291
final int fullGCProgressSize,
213-
final long fullGcMaxAgeInMillis) {
292+
final long fullGcMaxAgeInMillis,
293+
final long fullGcGeneration) {
214294
this.nodeStore = nodeStore;
215295
this.versionStore = gcSupport;
216296
this.ds = gcSupport.getDocumentStore();
@@ -224,8 +304,9 @@ static void setFullGcMode(int fullGcMode) {
224304
this.options = new VersionGCOptions();
225305

226306
setFullGcMode(fullGCMode);
227-
AUDIT_LOG.info("<init> VersionGarbageCollector created with fullGcMode: {}, maxFullGcAgeInMillis: {}, batchSize: {}, progressSize: {}, delayFactor: {}",
228-
fullGcMode, fullGcMaxAgeInMillis, fullGCBatchSize, fullGCProgressSize, fullGCDelayFactor);
307+
long fullGcGen = fullGCEnabled ? resetFullGcIfGenChange(fullGcGeneration) : fullGcGeneration;
308+
AUDIT_LOG.info("<init> VersionGarbageCollector created with fullGcMode: {}, maxFullGcAgeInMillis: {}, batchSize: {}, progressSize: {}, delayFactor: {}, fullGcGeneration: {}",
309+
fullGcMode, fullGcMaxAgeInMillis, fullGCBatchSize, fullGCProgressSize, fullGCDelayFactor, fullGcGen);
229310
}
230311

231312
/**

oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentNodeStoreBuilder.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ public int getFullGCMode() {
183183
return 0;
184184
}
185185

186+
@Override
187+
public RDBDocumentNodeStoreBuilder setFullGCGeneration(long v) {
188+
// fullGC modes are not supported for RDB
189+
log.warn("FullGC generation are not supported for RDB");
190+
return thisBuilder();
191+
}
192+
193+
@Override
194+
public long getFullGCGeneration() {
195+
// fullGC modes are not supported for RDB
196+
return 0;
197+
}
198+
186199
@Override
187200
public RDBDocumentNodeStoreBuilder setFullGcMaxAgeMillis(long v) {
188201
// fullGC modes are not supported for RDB

oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentNodeStoreServiceConfigurationTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FGC_PROGRESS_SIZE;
4040
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_ENABLED;
4141
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_EMBEDDED_VERIFICATION_ENABLED;
42+
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_GENERATION;
4243
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_FULL_GC_MODE;
4344
import static org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_ENABLED;
4445
import static org.junit.Assert.assertArrayEquals;
@@ -97,6 +98,7 @@ public void defaultValues() throws Exception {
9798
assertEquals(DEFAULT_THROTTLING_ENABLED, config.throttlingEnabled());
9899
assertEquals(DEFAULT_FULL_GC_ENABLED, config.fullGCEnabled());
99100
assertEquals(DEFAULT_FULL_GC_MODE, config.fullGCMode());
101+
assertEquals(DEFAULT_FULL_GC_GENERATION, config.fullGCGeneration());
100102
assertEquals(DEFAULT_FGC_DELAY_FACTOR, config.fullGCDelayFactor(), 0.01);
101103
assertEquals(DEFAULT_FGC_BATCH_SIZE, config.fullGCBatchSize());
102104
assertEquals(DEFAULT_FGC_PROGRESS_SIZE, config.fullGCProgressSize());
@@ -139,6 +141,14 @@ public void fullGCModeValueSet() throws Exception {
139141
assertEquals(fullGCModeValue, config.fullGCMode());
140142
}
141143

144+
@Test
145+
public void fullGCGenerationValueSet() throws Exception {
146+
long fullGCGenerationValue = 2;
147+
addConfigurationEntry(preset, "fullGCGeneration", fullGCGenerationValue);
148+
Configuration config = createConfiguration();
149+
assertEquals(fullGCGenerationValue, config.fullGCGeneration());
150+
}
151+
142152
@Test
143153
public void fullGCIncludePaths() throws Exception {
144154
final String[] includesPath = new String[]{"/foo", "/bar"};

0 commit comments

Comments
 (0)