This is an automated email from the ASF dual-hosted git repository. reschke pushed a commit to branch OAK-11620 in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git
commit 5b75e8673b58c3ab17d5756bab5f5e322d5d83b6 Author: Julian Reschke <[email protected]> AuthorDate: Wed Apr 9 14:02:52 2025 +0100 OAK-11260: Create replacement for Guava Stopwatch --- .../jackrabbit/oak/commons/time/Stopwatch.java | 19 +++-- .../jackrabbit/oak/commons/time/StopwatchTest.java | 90 ++++++++++++++++++++++ 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/time/Stopwatch.java b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/time/Stopwatch.java index bbe8153ce1..bcf8278739 100644 --- a/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/time/Stopwatch.java +++ b/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/time/Stopwatch.java @@ -26,14 +26,14 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** - * A stop watch based either on a {@link Supplier} of nanoseconds, or a {@link java.time.Clock}. + * A stop watch based either on a {@link Supplier} of nanoseconds, or a {@link Clock}. * <p> * The accuracy of measurements depends on the precision of the time source, which likely depends on platform and * configuration. * <p> * Inspired by Guava's. */ -public class Stopwatch { +public final class Stopwatch { private long startTime; private long accumulated; @@ -55,7 +55,7 @@ public class Stopwatch { } /** - * @return a running stop watch, using the supplied provider. + * @return a running stop watch, using the supplied supplier. */ public static Stopwatch createStarted(Supplier<Long> ticker) { return new Stopwatch(ticker).start(); @@ -66,10 +66,17 @@ public class Stopwatch { * <p> * Note that only {@link Clock#millis()} will be used, thus the watch will have ms precision at most. */ - public static Stopwatch createStarted(java.time.Clock clock) { + public static Stopwatch createStarted(Clock clock) { return new Stopwatch(clockAsLongSupplier(clock)).start(); } + /** + * @return a non-running stop watch, using the supplied supplier. + */ + public static Stopwatch createUnstarted(Supplier<Long> ticker) { + return new Stopwatch(ticker); + } + /** * @return a non-running stop watch, using {@link System#nanoTime()}. */ @@ -132,12 +139,12 @@ public class Stopwatch { * @return elapsed time */ public Duration elapsed() { - return Duration.ofMillis(elapsedNanos()); + return Duration.ofNanos(elapsedNanos()); } @Override public String toString() { - return java.time.Duration.ofNanos(elapsedNanos()).toString(); + return Duration.ofNanos(elapsedNanos()).toString(); } // private parts diff --git a/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/time/StopwatchTest.java b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/time/StopwatchTest.java new file mode 100755 index 0000000000..1c7eb8f740 --- /dev/null +++ b/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/time/StopwatchTest.java @@ -0,0 +1,90 @@ +/* + * 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.commons.time; + +import org.junit.Test; + +import java.time.Clock; +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class StopwatchTest { + + private static final long CHECK_INTERVAL_SECONDS = 3; + private static final long CHECK_INTERVAL_MILLIS = TimeUnit.SECONDS.toMillis(CHECK_INTERVAL_SECONDS); + + @Test + public void started() throws InterruptedException { + testStarted(Stopwatch.createStarted()); + } + + @Test + public void stopped() throws InterruptedException { + Stopwatch sw = Stopwatch.createUnstarted(); + assertFalse(sw.isRunning()); + testStarted(sw.start()); + } + + @Test + public void withClock() throws InterruptedException { + testStarted(Stopwatch.createStarted(Clock.systemUTC())); + } + + @Test + public void specialTicker() { + final AtomicLong time = new AtomicLong(0); + Stopwatch sw = Stopwatch.createUnstarted(time::get); + assertEquals(0, sw.elapsed().toNanos()); + sw.start(); + time.set(123); + assertEquals(123, sw.elapsed().toNanos()); + time.set(456); + sw.stop(); + assertEquals(456, sw.elapsed().toNanos()); + + time.set(0); + sw.reset().start(); + + // tests internals + assertEquals(Duration.ofNanos(0).toString(), sw.toString()); + } + + private void testStarted(Stopwatch sw) throws InterruptedException { + letElapse(CHECK_INTERVAL_MILLIS); + sw.stop(); + long millis = sw.elapsed().toMillis(); + assertTrue("elapsed " + millis + "ms, expected ~" + CHECK_INTERVAL_MILLIS, + millis >= CHECK_INTERVAL_MILLIS - 1000 && millis <= CHECK_INTERVAL_MILLIS + 1000); + long seconds = sw.elapsed(TimeUnit.SECONDS); + assertTrue("elapsed " + seconds + "s, expected ~" + CHECK_INTERVAL_SECONDS, + seconds >= CHECK_INTERVAL_SECONDS - 1 && seconds <= CHECK_INTERVAL_SECONDS + 1); + } + + private static void letElapse(long delta) throws InterruptedException { + long start = System.currentTimeMillis(); + while (System.currentTimeMillis() < start + delta) { + Thread.sleep(1); + } + } +}
