Skip to content

Commit d4f1e58

Browse files
authored
Cookiejar optimization, close AsyncHttpClient#1580 (AsyncHttpClient#1708)
Changes: Segmented map based on domain names. So instead of traversing all the domains it traverses the domains that are of interest. Use NettyTimer to clean up the expired cookies asynchronously. The timer task that provides this functionality is CookieEvictionTask.
1 parent 7a1a190 commit d4f1e58

File tree

12 files changed

+326
-48
lines changed

12 files changed

+326
-48
lines changed

client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java

+7
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,13 @@ public interface AsyncHttpClientConfig {
198198
*/
199199
CookieStore getCookieStore();
200200

201+
/**
202+
* Return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
203+
*
204+
* @return the delay in milliseconds to evict expired cookies from {@linkplain CookieStore}
205+
*/
206+
int expiredCookieEvictionDelay();
207+
201208
/**
202209
* Return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server
203210
*

client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClient.java

+17
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.netty.util.Timer;
2323
import io.netty.util.concurrent.DefaultThreadFactory;
2424
import org.asynchttpclient.channel.ChannelPool;
25+
import org.asynchttpclient.cookie.CookieEvictionTask;
2526
import org.asynchttpclient.filter.FilterContext;
2627
import org.asynchttpclient.filter.FilterException;
2728
import org.asynchttpclient.filter.RequestFilter;
@@ -90,6 +91,22 @@ public DefaultAsyncHttpClient(AsyncHttpClientConfig config) {
9091
channelManager = new ChannelManager(config, nettyTimer);
9192
requestSender = new NettyRequestSender(config, channelManager, nettyTimer, new AsyncHttpClientState(closed));
9293
channelManager.configureBootstraps(requestSender);
94+
boolean scheduleCookieEviction = false;
95+
96+
final int cookieStoreCount = config.getCookieStore().incrementAndGet();
97+
if (!allowStopNettyTimer) {
98+
if (cookieStoreCount == 1) {
99+
// If this is the first AHC instance for the shared (user-provided) netty timer.
100+
scheduleCookieEviction = true;
101+
}
102+
} else {
103+
// If Timer is not shared.
104+
scheduleCookieEviction = true;
105+
}
106+
if (scheduleCookieEviction) {
107+
nettyTimer.newTimeout(new CookieEvictionTask(config.expiredCookieEvictionDelay(), config.getCookieStore()),
108+
config.expiredCookieEvictionDelay(), TimeUnit.MILLISECONDS);
109+
}
93110
}
94111

95112
private Timer newNettyTimer(AsyncHttpClientConfig config) {

client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java

+15
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public class DefaultAsyncHttpClientConfig implements AsyncHttpClientConfig {
109109

110110
// cookie store
111111
private final CookieStore cookieStore;
112+
private final int expiredCookieEvictionDelay;
112113

113114
// internals
114115
private final String threadPoolName;
@@ -192,6 +193,7 @@ private DefaultAsyncHttpClientConfig(// http
192193

193194
// cookie store
194195
CookieStore cookieStore,
196+
int expiredCookieEvictionDelay,
195197

196198
// tuning
197199
boolean tcpNoDelay,
@@ -283,6 +285,7 @@ private DefaultAsyncHttpClientConfig(// http
283285

284286
// cookie store
285287
this.cookieStore = cookieStore;
288+
this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
286289

287290
// tuning
288291
this.tcpNoDelay = tcpNoDelay;
@@ -558,6 +561,11 @@ public CookieStore getCookieStore() {
558561
return cookieStore;
559562
}
560563

564+
@Override
565+
public int expiredCookieEvictionDelay() {
566+
return expiredCookieEvictionDelay;
567+
}
568+
561569
// tuning
562570
@Override
563571
public boolean isTcpNoDelay() {
@@ -746,6 +754,7 @@ public static class Builder {
746754

747755
// cookie store
748756
private CookieStore cookieStore = new ThreadSafeCookieStore();
757+
private int expiredCookieEvictionDelay = defaultExpiredCookieEvictionDelay();
749758

750759
// tuning
751760
private boolean tcpNoDelay = defaultTcpNoDelay();
@@ -1146,6 +1155,11 @@ public Builder setCookieStore(CookieStore cookieStore) {
11461155
return this;
11471156
}
11481157

1158+
public Builder setExpiredCookieEvictionDelay(int expiredCookieEvictionDelay) {
1159+
this.expiredCookieEvictionDelay = expiredCookieEvictionDelay;
1160+
return this;
1161+
}
1162+
11491163
// tuning
11501164
public Builder setTcpNoDelay(boolean tcpNoDelay) {
11511165
this.tcpNoDelay = tcpNoDelay;
@@ -1330,6 +1344,7 @@ public DefaultAsyncHttpClientConfig build() {
13301344
responseFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(responseFilters),
13311345
ioExceptionFilters.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(ioExceptionFilters),
13321346
cookieStore,
1347+
expiredCookieEvictionDelay,
13331348
tcpNoDelay,
13341349
soReuseAddress,
13351350
soKeepAlive,

client/src/main/java/org/asynchttpclient/config/AsyncHttpClientConfigDefaults.java

+5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public final class AsyncHttpClientConfigDefaults {
7373
public static final String IO_THREADS_COUNT_CONFIG = "ioThreadsCount";
7474
public static final String HASHED_WHEEL_TIMER_TICK_DURATION = "hashedWheelTimerTickDuration";
7575
public static final String HASHED_WHEEL_TIMER_SIZE = "hashedWheelTimerSize";
76+
public static final String EXPIRED_COOKIE_EVICTION_DELAY = "expiredCookieEvictionDelay";
7677

7778
public static final String AHC_VERSION;
7879

@@ -304,4 +305,8 @@ public static int defaultHashedWheelTimerTickDuration() {
304305
public static int defaultHashedWheelTimerSize() {
305306
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + HASHED_WHEEL_TIMER_SIZE);
306307
}
308+
309+
public static int defaultExpiredCookieEvictionDelay() {
310+
return AsyncHttpClientConfigHelper.getAsyncHttpClientConfig().getInt(ASYNC_CLIENT_CONFIG_ROOT + EXPIRED_COOKIE_EVICTION_DELAY);
311+
}
307312
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package org.asynchttpclient.cookie;
2+
3+
import java.util.concurrent.TimeUnit;
4+
5+
import org.asynchttpclient.AsyncHttpClientConfig;
6+
7+
import io.netty.util.Timeout;
8+
import io.netty.util.TimerTask;
9+
10+
/**
11+
* Evicts expired cookies from the {@linkplain CookieStore} periodically.
12+
* The default delay is 30 seconds. You may override the default using
13+
* {@linkplain AsyncHttpClientConfig#expiredCookieEvictionDelay()}.
14+
*/
15+
public class CookieEvictionTask implements TimerTask {
16+
17+
private final long evictDelayInMs;
18+
private final CookieStore cookieStore;
19+
20+
public CookieEvictionTask(long evictDelayInMs, CookieStore cookieStore) {
21+
this.evictDelayInMs = evictDelayInMs;
22+
this.cookieStore = cookieStore;
23+
}
24+
25+
@Override
26+
public void run(Timeout timeout) throws Exception {
27+
cookieStore.evictExpired();
28+
timeout.timer().newTimeout(this, evictDelayInMs, TimeUnit.MILLISECONDS);
29+
}
30+
}

client/src/main/java/org/asynchttpclient/cookie/CookieStore.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import io.netty.handler.codec.http.cookie.Cookie;
1818
import org.asynchttpclient.uri.Uri;
19+
import org.asynchttpclient.util.Counted;
1920

2021
import java.net.CookieManager;
2122
import java.util.List;
@@ -31,10 +32,10 @@
3132
*
3233
* @since 2.1
3334
*/
34-
public interface CookieStore {
35+
public interface CookieStore extends Counted {
3536
/**
3637
* Adds one {@link Cookie} to the store. This is called for every incoming HTTP response.
37-
* If the given cookie has already expired it will not be added, but existing values will still be removed.
38+
* If the given cookie has already expired it will not be added.
3839
*
3940
* <p>A cookie to store may or may not be associated with an URI. If it
4041
* is not associated with an URI, the cookie's domain and path attribute
@@ -82,4 +83,9 @@ public interface CookieStore {
8283
* @return true if any cookies were purged.
8384
*/
8485
boolean clear();
86+
87+
/**
88+
* Evicts all the cookies that expired as of the time this method is run.
89+
*/
90+
void evictExpired();
8591
}

0 commit comments

Comments
 (0)