Skip to content

Add TimePoint and use it in Timeout #1164

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 21, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.mongodb.MongoTimeoutException;
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.internal.VisibleForTesting;
import com.mongodb.internal.time.TimePoint;
import com.mongodb.internal.time.Timeout;
import com.mongodb.lang.Nullable;

import java.util.Deque;
Expand Down Expand Up @@ -142,7 +144,7 @@ public T get() {
* Gets an object from the pool. Blocks until an object is available, or the specified {@code timeout} expires,
* or the pool is {@linkplain #close() closed}/{@linkplain #pause(Supplier) paused}.
*
* @param timeout See {@link com.mongodb.internal.Timeout#startNow(long, TimeUnit)}.
* @param timeout See {@link Timeout#started(long, TimeUnit, TimePoint)}.
* @param timeUnit the time unit of the timeout
* @return An object from the pool, or null if can't get one in the given waitTime
* @throws MongoTimeoutException if the timeout has been exceeded
Expand Down Expand Up @@ -226,7 +228,7 @@ private T createNewAndReleasePermitIfFailure() {
}

/**
* @param timeout See {@link com.mongodb.internal.Timeout#startNow(long, TimeUnit)}.
* @param timeout See {@link Timeout#started(long, TimeUnit, TimePoint)}.
*/
@VisibleForTesting(otherwise = PRIVATE)
boolean acquirePermit(final long timeout, final TimeUnit timeUnit) {
Expand Down Expand Up @@ -386,7 +388,7 @@ boolean acquirePermitImmediateUnfair() {
* This method also emulates the eager {@link InterruptedException} behavior of
* {@link java.util.concurrent.Semaphore#tryAcquire(long, TimeUnit)}.
*
* @param timeout See {@link com.mongodb.internal.Timeout#startNow(long, TimeUnit)}.
* @param timeout See {@link Timeout#started(long, TimeUnit, TimePoint)}.
*/
boolean acquirePermit(final long timeout, final TimeUnit unit) throws MongoInterruptedException {
long remainingNanos = unit.toNanos(timeout);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.mongodb.annotations.ThreadSafe;
import com.mongodb.connection.ConnectionPoolSettings;
import com.mongodb.internal.async.SingleResultCallback;
import com.mongodb.internal.time.Timeout;
import com.mongodb.internal.time.TimePoint;
import org.bson.types.ObjectId;
import com.mongodb.lang.Nullable;

Expand All @@ -38,7 +40,7 @@ interface ConnectionPool extends Closeable {

/**
* @param operationContext operation context
* @param timeout See {@link com.mongodb.internal.Timeout#startNow(long, TimeUnit)}.
* @param timeout See {@link Timeout#started(long, TimeUnit, TimePoint)}.
* @throws MongoConnectionPoolClearedException If detects that the pool is {@linkplain #invalidate(Throwable) paused}.
*/
InternalConnection get(OperationContext operationContext, long timeout, TimeUnit timeUnit) throws MongoConnectionPoolClearedException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
import com.mongodb.event.ConnectionPoolListener;
import com.mongodb.event.ConnectionPoolReadyEvent;
import com.mongodb.event.ConnectionReadyEvent;
import com.mongodb.internal.Timeout;
import com.mongodb.internal.time.TimePoint;
import com.mongodb.internal.time.Timeout;
import com.mongodb.internal.VisibleForTesting;
import com.mongodb.internal.async.SingleResultCallback;
import com.mongodb.internal.connection.SdamServerDescriptionManager.SdamIssue;
Expand Down Expand Up @@ -1123,7 +1124,7 @@ void signalClosedOrPaused() {
}

/**
* @param timeoutNanos See {@link Timeout#startNow(long)}.
* @param timeoutNanos See {@link Timeout#started(long, TimePoint)}.
* @return The remaining duration as per {@link Timeout#remainingOrInfinite(TimeUnit)} if waiting ended early either
* spuriously or because of receiving a signal.
*/
Expand Down
123 changes: 123 additions & 0 deletions driver-core/src/main/com/mongodb/internal/time/TimePoint.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2008-present MongoDB, Inc.
*
* Licensed 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 com.mongodb.internal.time;

import com.mongodb.annotations.Immutable;
import com.mongodb.internal.VisibleForTesting;

import java.time.Clock;
import java.time.Duration;

import static com.mongodb.internal.VisibleForTesting.AccessModifier.PRIVATE;

/**
* A <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html">value-based</a> class
* representing a point on a timeline. The origin of this timeline has no known relation to the
* {@linkplain Clock#systemUTC() system clock}. The same timeline is used by all {@link TimePoint}s within the same process.
* <p>
* Methods operating on a pair of {@link TimePoint}s,
* for example, {@link #durationSince(TimePoint)}, {@link #compareTo(TimePoint)},
* or producing a point from another one, for example, {@link #add(Duration)},
* work correctly only if the duration between the points is not greater than {@link Long#MAX_VALUE} nanoseconds,
* which is more than 292 years.</p>
* <p>
* This class is not part of the public API and may be removed or changed at any time.</p>
*/
@Immutable
public final class TimePoint implements Comparable<TimePoint> {
private final long nanos;

private TimePoint(final long nanos) {
this.nanos = nanos;
}

/**
* Returns the current {@link TimePoint}.
*/
public static TimePoint now() {
return at(System.nanoTime());
}

@VisibleForTesting(otherwise = PRIVATE)
static TimePoint at(final long nanos) {
return new TimePoint(nanos);
}

/**
* The {@link Duration} between this {@link TimePoint} and {@code t}.
* A {@linkplain Duration#isNegative() negative} {@link Duration} means that
* this {@link TimePoint} is {@linkplain #compareTo(TimePoint) before} {@code t}.
*
* @see #elapsed()
*/
public Duration durationSince(final TimePoint t) {
return Duration.ofNanos(nanos - t.nanos);
}

/**
* The {@link Duration} between {@link TimePoint#now()} and this {@link TimePoint}.
* This method is functionally equivalent to {@code TimePoint.now().durationSince(this)}.
*
* @see #durationSince(TimePoint)
*/
public Duration elapsed() {
return Duration.ofNanos(System.nanoTime() - nanos);
}

/**
* Returns a {@link TimePoint} that is {@code duration} away from this one.
*
* @param duration A duration that may also be {@linkplain Duration#isNegative() negative}.
*/
public TimePoint add(final Duration duration) {
long durationNanos = duration.toNanos();
return TimePoint.at(nanos + durationNanos);
}

/**
* If this {@link TimePoint} is less/greater than {@code t}, then it is before/after {@code t}.
* <p>
* {@inheritDoc}</p>
*/
@Override
public int compareTo(final TimePoint t) {
return Long.signum(nanos - t.nanos);
}

@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final TimePoint timePoint = (TimePoint) o;
return nanos == timePoint.nanos;
}

@Override
public int hashCode() {
return Long.hashCode(nanos);
}

@Override
public String toString() {
return "TimePoint{"
+ "nanos=" + nanos
+ '}';
}
}
Loading