Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit92e1357

Browse files
committed
8371802: Do not let QUIC connection to idle terminate when HTTP/3 is configured with a higher idle timeout
Reviewed-by: dfuchs
1 parent52568bf commit92e1357

File tree

8 files changed

+577
-99
lines changed

8 files changed

+577
-99
lines changed

‎src/java.net.http/share/classes/jdk/internal/net/http/Http3Connection.java‎

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,16 @@ public final class Http3Connection implements AutoCloseable {
126126
// as per spec
127127
// -1 is used to imply no GOAWAY received so far
128128
privatefinalAtomicLonglowestGoAwayReceipt =newAtomicLong(-1);
129+
130+
privatefinalDurationidleTimeoutDuration;
129131
privatevolatileIdleConnectionTimeoutEventidleConnectionTimeoutEvent;
130132
// value of true implies no more streams will be initiated on this connection,
131133
// and the connection will be closed once the in-progress streams complete.
132134
privatevolatilebooleanfinalStream;
133135
privatevolatilebooleanallowOnlyOneStream;
136+
// true if this connection has been placed in the HTTP/3 connection pool of the HttpClient.
137+
// false otherwise.
138+
privatevolatilebooleanpresentInConnPool;
134139
// set to true if we decide to open a new connection
135140
// due to stream limit reached
136141
privatevolatilebooleanstreamLimitReached;
@@ -220,6 +225,17 @@ public final class Http3Connection implements AutoCloseable {
220225
// in case of exception. Throws in the dependent
221226
// action after wrapping the exception if needed.
222227
.exceptionally(this::exceptionallyAndClose);
228+
229+
this.idleTimeoutDuration =client.client().idleConnectionTimeout(HTTP_3).orElse(null);
230+
if (idleTimeoutDuration ==null) {
231+
// The absence of HTTP/3 idle timeout duration is considered to mean
232+
// never idle terminating the connection
233+
quicConnection.connectionTerminator().appLayerMaxIdle(Duration.MAX,
234+
this::isQUICTrafficGenerationRequired);
235+
}else {
236+
quicConnection.connectionTerminator().appLayerMaxIdle(idleTimeoutDuration,
237+
this::isQUICTrafficGenerationRequired);
238+
}
223239
if (Log.http3()) {
224240
Log.logHttp3("HTTP/3 connection created for " +quicConnectionTag() +" - local address: "
225241
+quicConnection.localAddress());
@@ -732,9 +748,8 @@ void onExchangeClose(Http3ExchangeImpl<?> exch, final long streamId) {
732748
try {
733749
varte =idleConnectionTimeoutEvent;
734750
if (te ==null &&exchangeStreams.isEmpty()) {
735-
te =idleConnectionTimeoutEvent =client.client().idleConnectionTimeout(HTTP_3)
736-
.map(IdleConnectionTimeoutEvent::new).orElse(null);
737-
if (te !=null) {
751+
if (idleTimeoutDuration !=null) {
752+
te =idleConnectionTimeoutEvent =newIdleConnectionTimeoutEvent();
738753
client.client().registerTimer(te);
739754
}
740755
}
@@ -873,6 +888,48 @@ boolean tryReserveForPoolCheckout() {
873888
}
874889
}
875890

891+
/**
892+
* Mark this connection as being present or absent from the connection pool.
893+
*/
894+
voidsetPooled(finalbooleanpresent) {
895+
this.presentInConnPool =present;
896+
}
897+
898+
/**
899+
* This callback method is invoked by the QUIC layer when it notices that this
900+
* connection hasn't seen any traffic for certain period of time. QUIC
901+
* invokes this method to ask HTTP/3 whether the QUIC layer
902+
* should generate traffic to keep this connection active.
903+
* This method returns true, indicating that the traffic must be generated,
904+
* if this HTTP/3 connection is in pool and there's no current request/response
905+
* in progress over this connection (i.e. the HTTP/3 connection is idle in the
906+
* pool waiting for any new requests to be issued by the application).
907+
*/
908+
privatebooleanisQUICTrafficGenerationRequired() {
909+
if (!isOpen()) {
910+
returnfalse;
911+
}
912+
lock();
913+
try {
914+
// if there's no HTTP/3 request/responses in progress and the connection is
915+
// in the pool (thus idle), then we instruct QUIC to generate traffic on the
916+
// QUIC connection to prevent it from being idle terminated.
917+
finalbooleangenerateTraffic =this.presentInConnPool
918+
&&this.exchanges.isEmpty()
919+
&&this.reservedStreamCount.get() ==0
920+
// a connection in the pool could be marked as
921+
// finalStream (for example when it receives a GOAWAY). we don't want
922+
// to generate explicit QUIC traffic for such connections too.
923+
&& !this.finalStream;
924+
if (debug.on()) {
925+
debug.log("QUIC traffic generation required = " +generateTraffic);
926+
}
927+
returngenerateTraffic;
928+
}finally {
929+
unlock();
930+
}
931+
}
932+
876933
/**
877934
* Cancels any event that might have been scheduled to shutdown this connection. Must be called
878935
* with the stateLock held.
@@ -893,8 +950,9 @@ final class IdleConnectionTimeoutEvent extends TimeoutEvent {
893950
privatebooleancancelled;
894951
privatebooleanidleShutDownInitiated;
895952

896-
IdleConnectionTimeoutEvent(Durationduration) {
897-
super(duration);
953+
IdleConnectionTimeoutEvent() {
954+
assertidleTimeoutDuration !=null :"idle timeout duration is null";
955+
super(idleTimeoutDuration);
898956
}
899957

900958
@Override

‎src/java.net.http/share/classes/jdk/internal/net/http/Http3ConnectionPool.java‎

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -155,23 +155,34 @@ Http3Connection putIfAbsent(String key, Http3Connection c) {
155155
assertkey.equals(c.key());
156156
varaltService =c.connection().getSourceAltService().orElse(null);
157157
if (altService !=null &&altService.wasAdvertised()) {
158-
returnadvertised.putIfAbsent(key,c);
158+
finalvarprev =advertised.putIfAbsent(key,c);
159+
if (prev ==null) {
160+
c.setPooled(true);// mark the newly pooled connection as pooled
161+
}
162+
returnprev;
159163
}
160164
assertaltService ==null ||altService.originHasSameAuthority();
161-
returnunadvertised.putIfAbsent(key,c);
165+
finalvarprev =unadvertised.putIfAbsent(key,c);
166+
if (prev ==null) {
167+
c.setPooled(true);// mark the newly pooled connection as pooled
168+
}
169+
returnprev;
162170
}
163171

164-
Http3Connectionput(Stringkey,Http3Connectionc) {
172+
voidput(Stringkey,Http3Connectionc) {
165173
Objects.requireNonNull(key);
166174
Objects.requireNonNull(c);
167175
assertkey.equals(c.key()) :"key mismatch %s -> %s"
168176
.formatted(key,c.key());
169177
varaltService =c.connection().getSourceAltService().orElse(null);
170178
if (altService !=null &&altService.wasAdvertised()) {
171-
returnadvertised.put(key,c);
179+
advertised.put(key,c);
180+
c.setPooled(true);
181+
return;
172182
}
173183
assertaltService ==null ||altService.originHasSameAuthority();
174-
returnunadvertised.put(key,c);
184+
unadvertised.put(key,c);
185+
c.setPooled(true);
175186
}
176187

177188
booleanremove(Stringkey,Http3Connectionc) {
@@ -189,11 +200,17 @@ boolean remove(String key, Http3Connection c) {
189200
}
190201

191202
assertaltService ==null ||altService.originHasSameAuthority();
192-
returnunadvertised.remove(key,c);
203+
finalbooleanremoved =unadvertised.remove(key,c);
204+
if (removed) {
205+
c.setPooled(false);
206+
}
207+
returnremoved;
193208
}
194209

195210
voidclear() {
211+
advertised.values().forEach((c) ->c.setPooled(false));
196212
advertised.clear();
213+
unadvertised.values().forEach((c) ->c.setPooled(false));
197214
unadvertised.clear();
198215
}
199216

‎src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminator.java‎

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,77 @@
2424
*/
2525
packagejdk.internal.net.http.quic;
2626

27-
// responsible for managing the connection termination of a QUIC connection
27+
importjava.time.Duration;
28+
importjava.util.function.Supplier;
29+
30+
/**
31+
* Responsible for managing the connection termination of a QUIC connection
32+
*/
2833
publicsealedinterfaceConnectionTerminator permitsConnectionTerminatorImpl {
2934

30-
// lets the terminator know that the connection is still alive and should not be
31-
// idle timed out
32-
voidkeepAlive();
35+
/**
36+
* Instructs the connection terminator to consider the connection as active
37+
* at the present point in time. The connection terminator will then restart its
38+
* idle timeout timer from this point in time.
39+
* <p>
40+
* This method must be called when an incoming packet is processed successfully
41+
* or when an ack-eliciting packet is sent by the local endpoint on the connection.
42+
*/
43+
voidmarkActive();
3344

45+
/**
46+
* Terminates the connection, if not already terminated, with the given cause.
47+
* <p>
48+
* A connection is terminated only once with a {@link TerminationCause}. However, this method
49+
* can be called any number of times. If the connection is not already terminated,
50+
* then this method does the necessary work to terminate the connection. Any subsequent
51+
* invocations of this method, after the connection has been terminated, will not
52+
* change the termination cause of the connection.
53+
*
54+
* @param cause the termination cause
55+
*/
3456
voidterminate(TerminationCausecause);
3557

58+
/**
59+
* Returns {@code true} if the connection is allowed for use, {@code false} otherwise.
60+
* <p>
61+
* This method is typically called when a connection that has been idle, is about to be used
62+
* for handling some request. This method allows for co-ordination between the connection usage
63+
* and the connection terminator to prevent the connection from being idle timed out when it is
64+
* about to be used for some request. The connection must only be used if this method
65+
* returns {@code true}.
66+
*
67+
* @return true if the connection can be used, false otherwise
68+
*/
3669
booleantryReserveForUse();
3770

71+
/**
72+
* Instructs the connection terminator that the application layer allows the
73+
* connection to stay idle for the given {@code maxIdle} duration. If the QUIC
74+
* layer has negotiated an idle timeout for the connection, that's lower than
75+
* the application's {@code maxIdle} duration, then the connection terminator
76+
* upon noticing absence of traffic over the connection for certain duration,
77+
* calls the {@code trafficGenerationCheck} to check if the QUIC layer should
78+
* explicitly generate some traffic to prevent the connection
79+
* from idle terminating.
80+
* <p>
81+
* When the {@code trafficGenerationCheck} is invoked, the application layer
82+
* must return {@code true} only if explicit traffic generation is necessary
83+
* to keep the connection alive.
84+
* <p>
85+
* If the application layer wishes to never idle terminate the connection, then
86+
* a {@code maxIdle} duration of {@linkplain Duration#MAX Duration.MAX} is recommended.
87+
*
88+
* @param maxIdle the maximum idle duration of the connection,
89+
* at the application layer
90+
* @param trafficGenerationCheck the callback that will be invoked by the connection
91+
* terminator to decide if the QUIC layer should generate
92+
* any traffic to prevent the connection from idle terminating
93+
* @throws NullPointerException if either {@code maxIdle} or {@code trafficGenerationCheck}
94+
* is null
95+
* @throws IllegalArgumentException if {@code maxIdle} is
96+
* {@linkplain Duration#isNegative() negative} or
97+
* {@linkplain Duration#isZero() zero}
98+
*/
99+
voidappLayerMaxIdle(DurationmaxIdle,Supplier<Boolean>trafficGenerationCheck);
38100
}

‎src/java.net.http/share/classes/jdk/internal/net/http/quic/ConnectionTerminatorImpl.java‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
packagejdk.internal.net.http.quic;
2626

2727
importjava.nio.ByteBuffer;
28+
importjava.time.Duration;
2829
importjava.util.List;
2930
importjava.util.Objects;
3031
importjava.util.concurrent.CompletableFuture;
3132
importjava.util.concurrent.atomic.AtomicReference;
3233
importjava.util.function.Function;
34+
importjava.util.function.Supplier;
3335

3436
importjdk.internal.net.http.common.Log;
3537
importjdk.internal.net.http.common.Logger;
@@ -52,7 +54,6 @@
5254
importstaticjdk.internal.net.http.quic.TerminationCause.appLayerClose;
5355
importstaticjdk.internal.net.http.quic.TerminationCause.forSilentTermination;
5456
importstaticjdk.internal.net.http.quic.TerminationCause.forTransportError;
55-
importstaticjdk.internal.net.quic.QuicTransportErrors.INTERNAL_ERROR;
5657
importstaticjdk.internal.net.quic.QuicTransportErrors.NO_ERROR;
5758

5859
finalclassConnectionTerminatorImplimplementsConnectionTerminator {
@@ -70,15 +71,20 @@ final class ConnectionTerminatorImpl implements ConnectionTerminator {
7071
}
7172

7273
@Override
73-
publicvoidkeepAlive() {
74-
this.connection.idleTimeoutManager.keepAlive();
74+
publicvoidmarkActive() {
75+
this.connection.idleTimeoutManager.markActive();
7576
}
7677

7778
@Override
7879
publicbooleantryReserveForUse() {
7980
returnthis.connection.idleTimeoutManager.tryReserveForUse();
8081
}
8182

83+
@Override
84+
publicvoidappLayerMaxIdle(finalDurationmaxIdle,finalSupplier<Boolean>trafficGenerationCheck) {
85+
this.connection.idleTimeoutManager.appLayerMaxIdle(maxIdle,trafficGenerationCheck);
86+
}
87+
8288
@Override
8389
publicvoidterminate(finalTerminationCausecause) {
8490
Objects.requireNonNull(cause);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp