This is an automated email from the ASF dual-hosted git repository.
joscorbe 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 9b73ce1a6f OAK-11839 : added throttler to throttle the document store
based on external factor set inside settings collection (#2429)
9b73ce1a6f is described below
commit 9b73ce1a6f5bd6475199f261c40ff8dc8a4b97ed
Author: Rishabh Kumar <[email protected]>
AuthorDate: Tue Aug 5 19:26:30 2025 +0530
OAK-11839 : added throttler to throttle the document store based on
external factor set inside settings collection (#2429)
---
.../oak/plugins/document/Configuration.java | 19 +++
.../plugins/document/DocumentNodeStoreBuilder.java | 20 ++++
.../plugins/document/DocumentNodeStoreService.java | 4 +
.../plugins/document/mongo/MongoDocumentStore.java | 22 ++--
.../MongoDocumentStoreThrottlingFactorUpdater.java | 101 ++++++++++++++++
.../document/mongo/MongoThrottlerFactory.java | 39 +++++++
.../DocumentNodeStoreServiceConfigurationTest.java | 20 ++++
.../mongo/MongoDocumentNodeStoreBuilderTest.java | 16 +++
...goDocumentStoreThrottlingFactorUpdaterTest.java | 127 +++++++++++++++++++++
.../document/mongo/MongoThrottlerFactoryTest.java | 34 ++++++
10 files changed, 388 insertions(+), 14 deletions(-)
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 508cc05598..434aa738ef 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
@@ -41,6 +41,8 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServic
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;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_TIME_MILLIS;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS;
@ObjectClassDefinition(
pid = {PID},
@@ -381,6 +383,23 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServic
"property 'oak.documentstore.throttlingEnabled'")
boolean throttlingEnabled() default DEFAULT_THROTTLING_ENABLED;
+
+ @AttributeDefinition(
+ name = "Document Node Store throttling time in millis",
+ description = "Time (in millis) for which we need to throttle the
document store in case system is under heavy load. " +
+ "The Default value is " + DEFAULT_THROTTLING_TIME_MILLIS +
"ms" +
+ ". Note that this value can be overridden via framework " +
+ "property 'oak.documentstore.throttlingTimeMillis'")
+ int throttlingTimeMillis() default DEFAULT_THROTTLING_TIME_MILLIS;
+
+ @AttributeDefinition(
+ name = "Document Node Store throttling job period in secs",
+ description = "Time (in secs) after which the throttling
background job would run (in cycles) to keep updating the throttling values." +
+ "The Default value is " +
DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS + "secs" +
+ ". Note that this value can be overridden via framework " +
+ "property
'oak.documentstore.throttlingJobSchedulePeriodSecs'")
+ int throttlingJobSchedulePeriodSecs() default
DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS;
+
@AttributeDefinition(
name = "Document Node Store Compression",
description = "Select compressor type for collections. 'Snappy' is
the default supported compression.")
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 18c0503c16..c221769e21 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
@@ -177,6 +177,8 @@ public class DocumentNodeStoreBuilder<T extends
DocumentNodeStoreBuilder<T>> {
private Predicate<Path> nodeCachePredicate = x -> true;
private boolean clusterInvisible;
private boolean throttlingEnabled;
+ private int throttlingTimeMillis =
DocumentNodeStoreService.DEFAULT_THROTTLING_TIME_MILLIS;
+ private int throttlingJobSchedulePeriodSecs =
DocumentNodeStoreService.DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS;
private boolean avoidMergeLock;
private boolean fullGCEnabled;
private Set<String> fullGCIncludePaths = Set.of();
@@ -312,6 +314,24 @@ public class DocumentNodeStoreBuilder<T extends
DocumentNodeStoreBuilder<T>> {
return this.throttlingEnabled;
}
+ public T setThrottlingTimeMillis(int v) {
+ this.throttlingTimeMillis = v;
+ return thisBuilder();
+ }
+
+ public int getThrottlingTimeMillis() {
+ return this.throttlingTimeMillis;
+ }
+
+ public T setThrottlingJobSchedulePeriodSecs(int v) {
+ this.throttlingJobSchedulePeriodSecs = v;
+ return thisBuilder();
+ }
+
+ public int getThrottlingJobSchedulePeriodSecs() {
+ return this.throttlingJobSchedulePeriodSecs;
+ }
+
public T setAvoidMergeLock(boolean b) {
this.avoidMergeLock = b;
return thisBuilder();
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 9480d94634..c263934da5 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
@@ -138,6 +138,8 @@ public class DocumentNodeStoreService {
@Deprecated
static final boolean DEFAULT_SO_KEEP_ALIVE = true;
static final boolean DEFAULT_THROTTLING_ENABLED = false;
+ static final int DEFAULT_THROTTLING_TIME_MILLIS = 10;
+ static final int DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS = 20;
static final boolean DEFAULT_FULL_GC_ENABLED = false;
static final boolean DEFAULT_EMBEDDED_VERIFICATION_ENABLED = true;
static final int DEFAULT_FULL_GC_MODE = 0;
@@ -555,6 +557,8 @@ public class DocumentNodeStoreService {
setDocStoreAvoidMergeLockFeature(docStoreAvoidMergeLockFeature).
setPrevNoPropCacheFeature(prevNoPropCacheFeature).
setThrottlingEnabled(config.throttlingEnabled()).
+ setThrottlingTimeMillis(config.throttlingTimeMillis()).
+
setThrottlingJobSchedulePeriodSecs(config.throttlingJobSchedulePeriodSecs()).
setAvoidMergeLock(config.avoidExclusiveMergeLock()).
setFullGCEnabled(config.fullGCEnabled()).
setFullGCIncludePaths(config.fullGCIncludePaths()).
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
index 1d3aaaa549..a1a315ebed 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStore.java
@@ -133,7 +133,6 @@ import static
org.apache.jackrabbit.oak.plugins.document.NodeDocument.SD_MAX_REV
import static org.apache.jackrabbit.oak.plugins.document.NodeDocument.SD_TYPE;
import static
org.apache.jackrabbit.oak.plugins.document.Throttler.NO_THROTTLING;
import static
org.apache.jackrabbit.oak.plugins.document.UpdateOp.Condition.newEqualsCondition;
-import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoThrottlerFactory.exponentialThrottler;
import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.createIndex;
import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.createPartialIndex;
import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoUtils.getDocumentStoreExceptionTypeFor;
@@ -161,11 +160,6 @@ public class MongoDocumentStore implements DocumentStore {
* For mongo based document store this value is threshold for the oplog
replication window.
*/
public static final int DEFAULT_THROTTLING_THRESHOLD =
Integer.getInteger("oak.mongo.throttlingThreshold", 2);
- /**
- * The default throttling time (in millis) when throttling is enabled.
This is the time for
- * which we block any data modification operation when system has been
throttled.
- */
- public static final long DEFAULT_THROTTLING_TIME_MS =
Long.getLong("oak.mongo.throttlingTime", 20);
private static final @NotNull String BIN_COLLECTION = "bin";
/**
@@ -297,7 +291,7 @@ public class MongoDocumentStore implements DocumentStore {
/**
* An updater instance to periodically updates mongo oplog window
*/
- private MongoDocumentStoreThrottlingMetricsUpdater
throttlingMetricsUpdater;
+ private MongoDocumentStoreThrottlingFactorUpdater throttlingFactorUpdater;
private boolean hasModifiedIdCompoundIndex = true;
@@ -367,12 +361,12 @@ public class MongoDocumentStore implements DocumentStore {
if (ol.isPresent()) {
// oplog window based on current oplog filling rate
- final AtomicReference<Double> oplogWindow = new
AtomicReference<>((double) MAX_VALUE);
- throttler = exponentialThrottler(DEFAULT_THROTTLING_THRESHOLD,
oplogWindow, DEFAULT_THROTTLING_TIME_MS);
- throttlingMetricsUpdater = new
MongoDocumentStoreThrottlingMetricsUpdater(localDb, oplogWindow);
- throttlingMetricsUpdater.scheduleUpdateMetrics();
- LOG.info("Started MongoDB throttling metrics with threshold
{}, throttling time {}",
- DEFAULT_THROTTLING_THRESHOLD,
DEFAULT_THROTTLING_TIME_MS);
+ final AtomicReference<Integer> factor = new
AtomicReference<>(0);
+ throttler = MongoThrottlerFactory.extFactorThrottler(factor,
builder.getThrottlingTimeMillis());
+ throttlingFactorUpdater = new
MongoDocumentStoreThrottlingFactorUpdater(localDb, factor,
builder.getThrottlingJobSchedulePeriodSecs());
+ throttlingFactorUpdater.scheduleFactorUpdates();
+ LOG.info("Started MongoDB throttling with factor {},
throttling time {}, schedule period {}",
+ factor.get(), builder.getThrottlingTimeMillis(),
builder.getThrottlingJobSchedulePeriodSecs());
} else {
LOG.warn("Connected to MongoDB with replication not detected
and hence oplog based throttling is not supported");
}
@@ -2046,7 +2040,7 @@ public class MongoDocumentStore implements DocumentStore {
clusterNodesConnection.close();
}
try {
- IOUtils.close(throttlingMetricsUpdater);
+ IOUtils.close(throttlingFactorUpdater);
} catch (IOException e) {
LOG.warn("Error occurred while closing throttlingMetricsUpdater",
e);
}
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdater.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdater.java
new file mode 100644
index 0000000000..4d13c61394
--- /dev/null
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdater.java
@@ -0,0 +1,101 @@
+/*
+ * 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.mongo;
+
+import com.mongodb.client.MongoDatabase;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import org.bson.Document;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+/**
+ * Reads throttling values from the MongoDB settings collection.
+ * <p>
+ * This class provides methods to fetch the throttling factor and related
settings
+ * from the MongoDB database for use in throttling logic.
+ */
+public class MongoDocumentStoreThrottlingFactorUpdater implements Closeable {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(MongoDocumentStoreThrottlingFactorUpdater.class);
+ private static final String SETTINGS = "settings";
+ private static final String ENABLE = "enable";
+ private static final String FACTOR = "factor";
+ private static final String TS_TIME = "ts";
+ public static final String SIZE = "size";
+ private final ScheduledExecutorService throttlingFactorExecutor;
+ private final AtomicReference<Integer> factor;
+ private final MongoDatabase localDb;
+ private final int period;
+
+ public MongoDocumentStoreThrottlingFactorUpdater(final @NotNull
MongoDatabase localDb,
+ final @NotNull
AtomicReference<Integer> factor,
+ int period) {
+ this.throttlingFactorExecutor =
Executors.newSingleThreadScheduledExecutor();
+ this.factor = factor;
+ this.localDb = localDb;
+ this.period = period;
+ }
+
+ public void scheduleFactorUpdates() {
+ throttlingFactorExecutor.scheduleAtFixedRate(() ->
factor.set(updateFactor()), 10, period, SECONDS);
+ }
+
+ // visible for testing only
+ public int updateFactor() {
+ final Document document = localDb.runCommand(new
Document("throttling", SETTINGS));
+
+ if (!document.containsKey(ENABLE) || !document.containsKey(FACTOR) ||
!document.containsKey(TS_TIME)) {
+ LOG.warn("Could not get values for settings.{} collection.
Document returned: {}. Setting throttling factor to 0", "throttling", document);
+ return 0;
+ }
+ if (!document.getBoolean(ENABLE)) {
+ LOG.debug("Throttling has been disabled. Setting throttling factor
to 0.");
+ return 0;
+ }
+
+ long ts = document.getLong(TS_TIME);
+ long now = System.currentTimeMillis();
+ if (now - ts > 3600000) { // 1 hour in ms
+ LOG.warn("Throttling timestamp is older than 1 hour. Setting
throttling factor to 0");
+ return 0;
+ }
+
+ int factor = document.getInteger(FACTOR, 0);
+ if (factor <= 0) {
+ LOG.warn("Throttling factor is less than or equal to 0. Setting
throttling factor to 0");
+ return 0;
+ }
+ return factor;
+ }
+
+
+ @Override
+ public void close() throws IOException {
+ new ExecutorCloser(this.throttlingFactorExecutor).close();
+ }
+}
diff --git
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactory.java
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactory.java
index 091fed9b3f..409526de82 100644
---
a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactory.java
+++
b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactory.java
@@ -47,6 +47,18 @@ public final class MongoThrottlerFactory {
return new ExponentialThrottler(threshold, oplogWindow,
throttlingTime);
}
+ /**
+ * Returns an instance of @{@link Throttler} which throttles the system
based on throttling factor set externally
+ *
+ * @param factor current oplog window for mongo
+ * @param time time duration for throttling
+ * @return an external factor throttler to throttle the system if required
+ */
+ public static Throttler extFactorThrottler(final AtomicReference<Integer>
factor, final long time) {
+ requireNonNull(factor);
+ return new ExtFactorThrottler(factor, time);
+ }
+
/**
* A {@link Throttler} which doesn't do any throttling, no matter how much
system is under load
* @return No throttler
@@ -93,4 +105,31 @@ public final class MongoThrottlerFactory {
return throttleTime;
}
}
+
+ private static class ExtFactorThrottler implements Throttler {
+
+ @NotNull
+ private final AtomicReference<Integer> factor;
+ private final long time;
+
+ public ExtFactorThrottler(final @NotNull AtomicReference<Integer>
factor, final long time) {
+ this.factor = factor;
+ this.time = time;
+ }
+
+ /**
+ * The time duration (in Millis) for which we need to throttle the
system.
+ *
+ * @return the throttling time duration (in Millis)
+ */
+ @Override
+ public long throttlingTime() {
+
+ if (factor.get() <= 0) {
+ return 0;
+ }
+
+ return time * factor.get();
+ }
+ }
}
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 af14bce034..2dc014678e 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
@@ -43,6 +43,8 @@ import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreServic
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.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS;
+import static
org.apache.jackrabbit.oak.plugins.document.DocumentNodeStoreService.DEFAULT_THROTTLING_TIME_MILLIS;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -98,6 +100,8 @@ public class DocumentNodeStoreServiceConfigurationTest {
assertEquals("STRICT", config.leaseCheckMode());
assertEquals(DEFAULT_AVOID_EXCLUSIVE_MERGE_LOCK,
config.avoidExclusiveMergeLock());
assertEquals(DEFAULT_THROTTLING_ENABLED, config.throttlingEnabled());
+ assertEquals(DEFAULT_THROTTLING_TIME_MILLIS,
config.throttlingTimeMillis());
+ assertEquals(DEFAULT_THROTTLING_JOB_SCHEDULE_PERIOD_SECS,
config.throttlingJobSchedulePeriodSecs());
assertEquals(DEFAULT_FULL_GC_ENABLED, config.fullGCEnabled());
assertEquals(DEFAULT_FULL_GC_MODE, config.fullGCMode());
assertEquals(DEFAULT_FULL_GC_GENERATION, config.fullGCGeneration());
@@ -127,6 +131,22 @@ public class DocumentNodeStoreServiceConfigurationTest {
assertEquals(throttleDocStore, config.throttlingEnabled());
}
+ @Test
+ public void throttleTimeMillis() throws Exception {
+ int throttlingTimeMillis = 20;
+ addConfigurationEntry(preset, "throttlingTimeMillis",
throttlingTimeMillis);
+ Configuration config = createConfiguration();
+ assertEquals(throttlingTimeMillis, config.throttlingTimeMillis());
+ }
+
+ @Test
+ public void throttlingJobSchedulePeriodSecs() throws Exception {
+ int throttlingJobSchedulePeriodSecs = 200;
+ addConfigurationEntry(preset, "throttlingJobSchedulePeriodSecs",
throttlingJobSchedulePeriodSecs);
+ Configuration config = createConfiguration();
+ assertEquals(throttlingJobSchedulePeriodSecs,
config.throttlingJobSchedulePeriodSecs());
+ }
+
@Test
public void avoidMergeLockEnabled() throws Exception {
boolean avoidMergeLock = true;
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 16736f3880..b43dd0f64c 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
@@ -160,6 +160,22 @@ public class MongoDocumentNodeStoreBuilderTest {
assertEquals(fullGcGeneration, builder.getFullGCGeneration());
}
+ @Test
+ public void throttlingTimeMillisSetValue() {
+ MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
+ final int throttlingTimeMillis = 30;
+ builder.setThrottlingTimeMillis(throttlingTimeMillis);
+ assertEquals(throttlingTimeMillis, builder.getThrottlingTimeMillis());
+ }
+
+ @Test
+ public void throttlingJobSchedulePeriodSecs() {
+ MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
+ final int throttlingJobSchedulePeriodSecs = 30;
+
builder.setThrottlingJobSchedulePeriodSecs(throttlingJobSchedulePeriodSecs);
+ assertEquals(throttlingJobSchedulePeriodSecs,
builder.getThrottlingJobSchedulePeriodSecs());
+ }
+
@Test
public void isFullGCAuditLoggingEnabled() {
MongoDocumentNodeStoreBuilder builder = new
MongoDocumentNodeStoreBuilder();
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdaterTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdaterTest.java
new file mode 100644
index 0000000000..2e098a013a
--- /dev/null
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDocumentStoreThrottlingFactorUpdaterTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.mongo;
+
+import com.mongodb.client.MongoDatabase;
+import org.bson.Document;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Unit cases for {@link MongoDocumentStoreThrottlingFactorUpdater}
+ */
+public class MongoDocumentStoreThrottlingFactorUpdaterTest {
+
+ private MongoDatabase mockDb;
+ private MongoDocumentStoreThrottlingFactorUpdater reader;
+
+ @Before
+ public void setUp() {
+ mockDb = Mockito.mock(MongoDatabase.class);
+ AtomicReference<Integer> factor = new AtomicReference<>(0);
+ reader = new MongoDocumentStoreThrottlingFactorUpdater(mockDb, factor,
20);
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ reader.close();
+ }
+
+ @Test
+ public void testReadThrottlingFactorValid() {
+ Document doc = new Document("enable", true)
+ .append("factor", 5)
+ .append("ts", System.currentTimeMillis());
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(5, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorMissing() {
+ Document doc = new Document();
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorMissingEnable() {
+ Document doc = new Document("factor", 5)
+ .append("ts", System.currentTimeMillis());
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorWhenThrottlingDisabled() {
+ Document doc = new Document("enable", false)
+ .append("factor", 5)
+ .append("ts", System.currentTimeMillis());
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorMissingFactor() {
+ Document doc = new Document("enable", true)
+ .append("ts", System.currentTimeMillis());
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorMissingTS() {
+ Document doc = new Document("enable", true)
+ .append("factor", 5);
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testThrottlingFactorTimestampOlderThanOneHour() {
+ long oldTs = System.currentTimeMillis() - 3600001; // 1 hour + 1 ms ago
+ Document doc = new Document("enable", true)
+ .append("factor", 5)
+ .append("ts", oldTs);
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+
+ @Test
+ public void testReadThrottlingFactorNegative() {
+ Document doc = new Document("enable", true)
+ .append("factor", -2)
+ .append("ts", System.currentTimeMillis());
+
Mockito.when(mockDb.runCommand(Mockito.any(Document.class))).thenReturn(doc);
+
+ Assert.assertEquals(0, reader.updateFactor());
+ }
+}
\ No newline at end of file
diff --git
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactoryTest.java
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactoryTest.java
index 6d7180d6ac..e9fb3905bf 100644
---
a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactoryTest.java
+++
b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoThrottlerFactoryTest.java
@@ -24,6 +24,7 @@ import org.junit.Test;
import java.util.concurrent.atomic.AtomicReference;
import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoThrottlerFactory.exponentialThrottler;
+import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoThrottlerFactory.extFactorThrottler;
import static
org.apache.jackrabbit.oak.plugins.document.mongo.MongoThrottlerFactory.noThrottler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@@ -111,4 +112,37 @@ public class MongoThrottlerFactoryTest {
assertEquals(80L, throttler.throttlingTime());
}
+ @Test
+ public void testThrottlingTimeWithFactorZero() {
+ Throttler throttler = extFactorThrottler(new AtomicReference<>(0),
100L);
+ assertEquals(0L, throttler.throttlingTime());
+ }
+
+ @Test
+ public void testThrottlingTimeWithFactorOne() {
+ Throttler throttler = extFactorThrottler(new AtomicReference<>(1),
100L);
+ assertEquals(100L, throttler.throttlingTime());
+ }
+
+ @Test
+ public void testThrottlingTimeWithFactorFive() {
+ Throttler throttler = extFactorThrottler(new AtomicReference<>(5),
200L);
+ assertEquals(1000L, throttler.throttlingTime());
+ }
+
+ @Test
+ public void testThrottlingTimeWithNegativeFactor() {
+ Throttler throttler = extFactorThrottler(new AtomicReference<>(-2),
100L);
+ assertEquals(0, throttler.throttlingTime());
+ }
+
+ @Test
+ public void testThrottlingTimeWithFactorChange() {
+ AtomicReference<Integer> factor = new AtomicReference<>(2);
+ Throttler throttler = extFactorThrottler(factor, 50L);
+ assertEquals(100L, throttler.throttlingTime());
+ factor.set(4);
+ assertEquals(200L, throttler.throttlingTime());
+ }
+
}