Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -499,22 +499,28 @@ public CompletableFuture<Void> connectAsync(Exchange<?> exchange) {
}, exchange.parentExecutor.safeDelegate());
}

Optional<Duration> timeout = client().connectTimeout();
CompletableFuture<CompletableFuture<Void>> fxi = handshakeCfCf;

// In case of connection timeout, set up a timeout on the handshakeCfCf.
// Note: this is a different timeout than the direct connection timeout.
if (timeout.isPresent()) {
Duration timeout = client().connectTimeout().orElse(null);
if (timeout != null) {
// In case of timeout we need to close the quic connection
debug.log("setting up quic connect timeout: " + timeout.get().toMillis());
debug.log("setting up quic connect timeout: " + timeout);
long timeoutMillis;
try {
timeoutMillis = timeout.toMillis();
} catch (ArithmeticException _) {
timeoutMillis = Long.MAX_VALUE;
}
fxi = handshakeCfCf.completeOnTimeout(
MinimalFuture.failedFuture(new HttpConnectTimeoutException("quic connect timeout")),
timeout.get().toMillis(), TimeUnit.MILLISECONDS);
timeoutMillis, TimeUnit.MILLISECONDS);
}

// If we have set up any timeout, arrange to close the quicConnection
// if one of the timeout expires
if (timeout.isPresent() || directTimeout.isPresent()) {
if (timeout != null || directTimeout.isPresent()) {
fxi = fxi.handleAsync(this::handleTimeout, exchange.parentExecutor.safeDelegate());
}
return fxi.thenCompose(Function.identity());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -28,14 +28,19 @@
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAmount;
import java.time.temporal.TemporalUnit;
import java.time.temporal.UnsupportedTemporalTypeException;

/**
* A Deadline represents an instant on a {@linkplain TimeLine time line}.
* An instantaneous point on the {@linkplain TimeLine time-line}.
* <p>
* This class is immutable and thread-safe.
* <p>
* On <b>numeric overflows</b>, all {@code Deadline} methods will return a
* semantically meaningful extremum instead of throwing. For instance, on a
* numeric overflow, {@link #plus(Duration) plus()} will return
* {@link Deadline#MAX} if the provided duration is positive,
* {@link Deadline#MIN} otherwise.
*/
public final class Deadline implements Comparable<Deadline> {

Expand All @@ -49,17 +54,23 @@ private Deadline(Instant deadline) {


/**
* Returns a copy of this deadline with the specified duration in nanoseconds added.
* {@return a deadline with the specified duration in nanoseconds added}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MAX} if
* the provided duration is positive, {@link Deadline#MIN} otherwise.
*
* @param nanosToAdd the nanoseconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified nanoseconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusNanos(long nanosToAdd) {
return new Deadline(deadline.plusNanos(nanosToAdd));
if (nanosToAdd == 0) return this;
try {
return new Deadline(deadline.plusNanos(nanosToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return nanosToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
Expand Down Expand Up @@ -89,92 +100,111 @@ public Deadline truncatedTo(ChronoUnit unit) {
}

/**
* Returns a copy of this deadline with the specified amount subtracted.
* <p>
* This returns a {@code Deadline}, based on this one, with the specified amount subtracted.
* The amount is typically {@link Duration} but may be any other type implementing
* the {@link TemporalAmount} interface.
* {@return a deadline with the specified amount subtracted from this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MIN} if
* the provided duration is positive, {@link Deadline#MAX} otherwise.
*
* @param amountToSubtract the amount to subtract, not null
* @return a {@code Deadline} based on this deadline with the subtraction made, not null
* @throws DateTimeException if the subtraction cannot be made
* @throws ArithmeticException if numeric overflow occurs
* @param duration the amount to subtract, not null
*/
public Deadline minus(TemporalAmount amountToSubtract) {
return Deadline.of(deadline.minus(amountToSubtract));
public Deadline minus(Duration duration) {
if (duration.isZero()) return this;
try {
return Deadline.of(deadline.minus(duration));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return duration.isPositive() ? Deadline.MIN : Deadline.MAX;
}
}

/**
* Returns a copy of this deadline with the specified amount added.
* {@return a deadline with the specified amount added to this deadline}
* <p>
* This returns a {@code Deadline}, based on this one, with the amount
* in terms of the unit added. If it is not possible to add the amount, because the
* unit is not supported or for some other reason, an exception is thrown.
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MAX} if
* the provided amount is positive, {@link Deadline#MIN} otherwise.
*
* @see Instant#plus(long, TemporalUnit)
*
* @param amountToAdd the amount of the unit to add to the result, may be negative
* @param unit the unit of the amount to add, not null
* @return a {@code Deadline} based on this deadline with the specified amount added, not null
* @throws DateTimeException if the addition cannot be made
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plus(long amountToAdd, TemporalUnit unit) {
if (amountToAdd == 0) return this;
return Deadline.of(deadline.plus(amountToAdd, unit));
try {
return Deadline.of(deadline.plus(amountToAdd, unit));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return amountToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified duration in seconds added.
* {@return a deadline with the specified duration in seconds added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MAX} if
* the provided duration is positive, {@link Deadline#MIN} otherwise.
*
* @param secondsToAdd the seconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified seconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusSeconds(long secondsToAdd) {
if (secondsToAdd == 0) return this;
return Deadline.of(deadline.plusSeconds(secondsToAdd));
try {
return Deadline.of(deadline.plusSeconds(secondsToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return secondsToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified duration in milliseconds added.
* {@return a deadline with the specified duration in milliseconds added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MAX} if
* the provided duration is positive, {@link Deadline#MIN} otherwise.
*
* @param millisToAdd the milliseconds to add, positive or negative
* @return a {@code Deadline} based on this deadline with the specified milliseconds added, not null
* @throws DateTimeException if the result exceeds the maximum or minimum deadline
* @throws ArithmeticException if numeric overflow occurs
*/
public Deadline plusMillis(long millisToAdd) {
if (millisToAdd == 0) return this;
return Deadline.of(deadline.plusMillis(millisToAdd));
try {
return Deadline.of(deadline.plusMillis(millisToAdd));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return millisToAdd > 0 ? Deadline.MAX : Deadline.MIN;
}
}

/**
* Returns a copy of this deadline with the specified amount added.
* <p>
* This returns a {@code Deadline}, based on this one, with the specified amount added.
* The amount is typically {@link Duration} but may be any other type implementing
* the {@link TemporalAmount} interface.
* {@return a deadline with the specified duration added to this deadline}
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Deadline#MAX} if
* the provided duration is positive, {@link Deadline#MIN} otherwise.
*
* @param amountToAdd the amount to add, not null
* @return a {@code Deadline} based on this deadline with the addition made, not null
* @throws DateTimeException if the addition cannot be made
* @throws ArithmeticException if numeric overflow occurs
* @param duration the duration to add, not null
*/
public Deadline plus(TemporalAmount amountToAdd) {
return Deadline.of(deadline.plus(amountToAdd));
public Deadline plus(Duration duration) {
if (duration.isZero()) return this;
try {
return Deadline.of(deadline.plus(duration));
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
return duration.isPositive() ? Deadline.MAX : Deadline.MIN;
}
}

/**
Expand All @@ -188,16 +218,24 @@ public Deadline plus(TemporalAmount amountToAdd) {
* complete units between the two deadlines.
* <p>
* This instance is immutable and unaffected by this method call.
* <p>
* On numeric overflows, this method will return {@link Long#MAX_VALUE} if
* the current deadline is before the provided end deadline,
* {@link Long#MIN_VALUE} otherwise.
*
* @param endExclusive the end deadline, exclusive
* @param unit the unit to measure the amount in, not null
* @return the amount of time between this deadline and the end deadline
* @throws DateTimeException if the amount cannot be calculated
* @throws UnsupportedTemporalTypeException if the unit is not supported
* @throws ArithmeticException if numeric overflow occurs
*/
public long until(Deadline endExclusive, TemporalUnit unit) {
return deadline.until(endExclusive.deadline, unit);
try {
return deadline.until(endExclusive.deadline, unit);
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException _) { // "long overflow"
int delta = compareTo(endExclusive);
return delta < 0 ? Long.MAX_VALUE : Long.MIN_VALUE;
}
}

/**
Expand Down Expand Up @@ -266,10 +304,18 @@ static Deadline of(Instant instant) {
* @param startInclusive the start deadline, inclusive, not null
* @param endExclusive the end deadline, exclusive, not null
* @return a {@code Duration}, not null
* @throws DateTimeException if the seconds between the deadline cannot be obtained
* @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration}
*/
public static Duration between(Deadline startInclusive, Deadline endExclusive) {
return Duration.between(startInclusive.deadline, endExclusive.deadline);
if (startInclusive.equals(endExclusive)) return Duration.ZERO;
try {
return Duration.between(startInclusive.deadline, endExclusive.deadline);
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException exception) { // "long overflow"
// `Deadline` works with `Instant` under the hood.
// Delta between `Instant.MIN` and `Instant.MAX` fits in a `Duration`.
// Hence, we should never receive a numeric overflow while calculating the delta between two deadlines.
throw new IllegalStateException("Unexpected overflow", exception);
}
Comment on lines +309 to +318
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm... DateTimeException and ArithmeticException are both RuntimeException. We know they won't be thrown here, so there's no point in trying to catch them to replace them with another exception, since that would essentially be dead code. Removing the @throws from the API doc is the right call though.
If you want you can add an @apiNote to say this method will never throw DateTimeException or ArithmeticException since duration between two deadlines will never overflow; but this is an internal API so the comment in the code below is probably enough.

Suggested change
if (startInclusive.equals(endExclusive)) return Duration.ZERO;
try {
return Duration.between(startInclusive.deadline, endExclusive.deadline);
} catch (DateTimeException | // "Instant exceeds minimum or maximum instant"
ArithmeticException exception) { // "long overflow"
// `Deadline` works with `Instant` under the hood.
// Delta between `Instant.MIN` and `Instant.MAX` fits in a `Duration`.
// Hence, we should never receive a numeric overflow while calculating the delta between two deadlines.
throw new IllegalStateException("Unexpected overflow", exception);
}
if (startInclusive.equals(endExclusive)) return Duration.ZERO;
// `Deadline` works with `Instant` under the hood.
// Delta between `Instant.MIN` and `Instant.MAX` fits in a `Duration`.
// Hence, we should never receive a numeric overflow while calculating the delta between two deadlines.
return Duration.between(startInclusive.deadline, endExclusive.deadline);

}

Comment on lines +310 to +320
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to change this method? I would just revert them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duration#between(Temporal,Temporal) can throw DateTimeException and ArithmeticException, but not in our case due to the reason I elaborated in the comment. In this change, I've removed these two exceptions from the Javadoc, since they cannot happen.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh - yes we don't take Temporal but Deadline as paramater which eliminates the possibility of overflow.

}
Loading