This is an automated email from the ASF dual-hosted git repository. stefanegli pushed a commit to branch OAK-10281 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 1d3c1f5fee7751b0c53320c5d8bbeb68d333fdf8 Author: Stefan Egli <[email protected]> AuthorDate: Mon Jan 22 17:39:38 2024 +0100 OAK-10281 : oak.documentMK.recoveryDelaySecs introduced, default 0 --- .../oak/plugins/document/ClusterNodeInfo.java | 23 +++++++++++++++++++ .../plugins/document/ClusterNodeInfoDocument.java | 2 +- .../oak/plugins/document/ClusterNodeInfoTest.java | 26 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java index d53e1822f9..3090732d91 100644 --- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java +++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfo.java @@ -229,6 +229,15 @@ public class ClusterNodeInfo { /** OAK-3399 : max number of times we're doing a 1sec retry loop just before declaring lease failure **/ private static final int MAX_RETRY_SLEEPS_BEFORE_LEASE_FAILURE = 5; + /** OAK-10281 : seconds to delay a recovery after a lease timeout */ + private static final int DEFAULT_RECOVERY_DELAY_SECS = SystemPropertySupplier.create("oak.documentMK.recoveryDelaySecs", 0) + .loggingTo(LOG).validateWith(value -> value >= 0) + .formatSetMessage((name, value) -> String.format("recovery delay set to (secs): %ss (using system property %s)", name, value)).get(); + private static final long DEFAULT_RECOVERY_DELAY_MILLIS = 1000L * (long)DEFAULT_RECOVERY_DELAY_SECS; + + // kept non-final for testing purpose + static long recoveryDelayMillis = DEFAULT_RECOVERY_DELAY_MILLIS; + /** * The Oak version. */ @@ -1180,6 +1189,20 @@ public class ClusterNodeInfo { clock = Clock.SIMPLE; } + static long getRecoveryDelayMillis() { + return recoveryDelayMillis; + } + + /** <b>only used for testing</b> **/ + static void setRecoveryDelayMillis(long recoveryDelayMillis) { + ClusterNodeInfo.recoveryDelayMillis = recoveryDelayMillis; + } + + /** <b>only used for testing</b> **/ + static void resetRecoveryDelayMillisToDefault() { + recoveryDelayMillis = DEFAULT_RECOVERY_DELAY_MILLIS; + } + private static long getProcessId() { try { String name = ManagementFactory.getRuntimeMXBean().getName(); diff --git a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoDocument.java b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoDocument.java index aa7d5ead06..adfb83161d 100644 --- a/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoDocument.java +++ b/oak-store-document/src/main/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoDocument.java @@ -108,7 +108,7 @@ public class ClusterNodeInfoDocument extends Document { */ public boolean isRecoveryNeeded(long currentTimeMillis) { return isActive() && - (currentTimeMillis > getLeaseEndTime() || + (currentTimeMillis - getLeaseEndTime() > ClusterNodeInfo.getRecoveryDelayMillis() || isBeingRecovered()); } diff --git a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java index 5622a3b6ca..7d26d3519a 100644 --- a/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java +++ b/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/ClusterNodeInfoTest.java @@ -78,6 +78,7 @@ public class ClusterNodeInfoTest { @After public void after() { ClusterNodeInfo.resetClockToDefault(); + ClusterNodeInfo.resetRecoveryDelayMillisToDefault(); } @Test @@ -708,6 +709,31 @@ public class ClusterNodeInfoTest { assertFalse(handler.isLeaseFailure()); } + @Test + public void recoveryNeededNoDelay() throws Exception { + ClusterNodeInfo info = newClusterNodeInfo(1); + String key = String.valueOf(info.getId()); + ClusterNodeInfoDocument doc = store.find(Collection.CLUSTER_NODES, key); + assertFalse(doc.isRecoveryNeeded(clock.getTime())); + clock.waitUntil(info.getLeaseEndTime() + 1); + assertTrue(doc.isRecoveryNeeded(clock.getTime())); + } + + @Test + public void recoveryNeededWithDelay() throws Exception { + ClusterNodeInfo.setRecoveryDelayMillis(60000); + ClusterNodeInfo info = newClusterNodeInfo(1); + String key = String.valueOf(info.getId()); + ClusterNodeInfoDocument doc = store.find(Collection.CLUSTER_NODES, key); + assertFalse(doc.isRecoveryNeeded(clock.getTime())); + clock.waitUntil(info.getLeaseEndTime() + 59999); + assertFalse(doc.isRecoveryNeeded(clock.getTime())); + clock.waitUntil(info.getLeaseEndTime() + 1); + assertFalse(doc.isRecoveryNeeded(clock.getTime())); + clock.waitUntil(info.getLeaseEndTime() + 1); + assertTrue(doc.isRecoveryNeeded(clock.getTime())); + } + private void assertLeaseFailure() throws Exception { for (int i = 0; i < 100; i++) { if (handler.isLeaseFailure()) {
