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 1a66f4d087 OAK-12076 : added sleepUninterruptibly() in oak-commons
(#2705)
1a66f4d087 is described below
commit 1a66f4d087fded053dbd93bce3a86fbd8118b4a1
Author: Rishabh Kumar <[email protected]>
AuthorDate: Thu Jan 29 10:35:04 2026 +0530
OAK-12076 : added sleepUninterruptibly() in oak-commons (#2705)
---
.../internal/concurrent/UninterruptibleUtils.java | 46 +++++++++++
.../concurrent/UninterruptibleUtilsTest.java | 88 ++++++++++++++++++++++
2 files changed, 134 insertions(+)
diff --git
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtils.java
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtils.java
index dfd908469e..6dcb24125b 100644
---
a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtils.java
+++
b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtils.java
@@ -20,6 +20,7 @@ package org.apache.jackrabbit.oak.commons.internal.concurrent;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Utility methods for waiting on synchronization primitives without
@@ -64,4 +65,49 @@ public class UninterruptibleUtils {
}
}
}
+
+ /**
+ * Causes the current thread to sleep for the specified duration,
+ * ignoring {@link InterruptedException} until the full sleep time
+ * has elapsed, then restores the interrupted status before returning.
+ * <p>
+ * This behaves like Guava's
+ * {@code Uninterruptibles.sleepUninterruptibly(long, TimeUnit)}:
+ * it repeatedly invokes {@link TimeUnit#sleep(long)} until the
+ * requested time has passed, catching and recording interruptions
+ * and recomputing the remaining time from a fixed deadline.
+ *
+ * @param sleep the time to sleep; must be non-negative
+ * @param unit the time unit of the {@code sleep} argument; must not
be {@code null}
+ * @throws NullPointerException if {@code unit} is {@code null}
+ * @throws IllegalArgumentException if {@code sleep} is negative
+ */
+ public static void sleepUninterruptibly(final long sleep, final TimeUnit
unit) {
+
+ Objects.requireNonNull(unit, "timeunit is null");
+
+ if (sleep < 0L) {
+ throw new IllegalArgumentException("sleep must be >= 0");
+ }
+
+ boolean interrupted = false;
+ try {
+ long remainingNanos = unit.toNanos(sleep);
+ long end = System.nanoTime() + remainingNanos;
+ for (;;) {
+ try {
+ // TimeUnit.sleep() treats negative timeouts just like
zero.
+ TimeUnit.NANOSECONDS.sleep(remainingNanos);
+ return;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ remainingNanos = end - System.nanoTime();
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
}
diff --git
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtilsTest.java
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtilsTest.java
index 45f945c9a1..1029a34a96 100644
---
a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtilsTest.java
+++
b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/internal/concurrent/UninterruptibleUtilsTest.java
@@ -22,6 +22,7 @@ import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Unit cases for {@link UninterruptibleUtils}
@@ -74,4 +75,91 @@ public class UninterruptibleUtilsTest {
Assert.assertFalse(t.isAlive());
}
+ @Test
+ public void testNullTimeUnit() {
+ Assert.assertThrows(NullPointerException.class, () ->
UninterruptibleUtils.sleepUninterruptibly(1L, null));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void sleepUninterruptibly_negativeSleepThrowsIae() {
+ UninterruptibleUtils.sleepUninterruptibly(-1L, TimeUnit.MILLISECONDS);
+ }
+
+ @Test
+ public void testSleepsForAtLeastRequestedTime() {
+ long sleepMillis = 20L;
+ long start = System.nanoTime();
+
+ UninterruptibleUtils.sleepUninterruptibly(sleepMillis,
TimeUnit.MILLISECONDS);
+
+ long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() -
start);
+
+ Assert.assertTrue("Elapsed should be at least requested sleep",
+ elapsedMillis >= sleepMillis - 10); // small margin
+ }
+
+ @Test
+ public void testIgnoresInterruptsButRestoresFlag() throws Exception {
+ final long sleepMillis = 20L;
+
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ UninterruptibleUtils.sleepUninterruptibly(sleepMillis,
TimeUnit.MILLISECONDS);
+ // After returning, interrupted flag should be set
+ Assert.assertTrue("Interrupt flag should be restored",
+ Thread.currentThread().isInterrupted());
+ }
+ });
+
+ t.start();
+
+ // Let the thread enter sleep
+ Thread.sleep(5);
+
+ // Interrupt during sleep
+ t.interrupt();
+
+ t.join(20);
+
+ Assert.assertFalse("Thread should have completed sleep", t.isAlive());
+ }
+
+ @Test
+ public void testMultipleInterruptsStillCompleteAndRestoreFlag() throws
Exception {
+ final long sleepMillis = 20L;
+
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ UninterruptibleUtils.sleepUninterruptibly(sleepMillis,
TimeUnit.MILLISECONDS);
+ Assert.assertTrue("Interrupt flag should be restored after
multiple interrupts",
+ Thread.currentThread().isInterrupted());
+ }
+ });
+
+ t.start();
+
+ // Interrupt the thread multiple times while it is sleeping
+ for (int i = 0; i < 3; i++) {
+ Thread.sleep(5);
+ t.interrupt();
+ }
+
+ t.join(20);
+
+ Assert.assertFalse("Thread should have completed sleep", t.isAlive());
+ }
+
+ @Test
+ public void testZeroSleepReturnsQuickly() {
+ long start = System.nanoTime();
+
+ UninterruptibleUtils.sleepUninterruptibly(0L, TimeUnit.MILLISECONDS);
+
+ long elapsedMillis = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() -
start);
+
+ Assert.assertTrue("Zero sleep should return quickly", elapsedMillis <
50L);
+ }
+
}
\ No newline at end of file