Skip to content

Commit 4c61d39

Browse files
stepanchegslandelle
authored andcommitted
Replace AtomicBoolean with AtomicFieldUpdater (AsyncHttpClient#1291)
Avoid unnecessary heap allocations.
1 parent 671378f commit 4c61d39

File tree

6 files changed

+63
-32
lines changed

6 files changed

+63
-32
lines changed

client/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.java

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,9 @@
2222
import java.util.concurrent.CompletableFuture;
2323
import java.util.concurrent.CountDownLatch;
2424
import java.util.concurrent.ExecutionException;
25-
import java.util.concurrent.Executor;
2625
import java.util.concurrent.Future;
2726
import java.util.concurrent.TimeUnit;
2827
import java.util.concurrent.TimeoutException;
29-
import java.util.concurrent.atomic.AtomicBoolean;
3028
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
3129
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3230

@@ -70,13 +68,28 @@ public final class NettyResponseFuture<V> extends AbstractListenableFuture<V> {
7068

7169
// state mutated from outside the event loop
7270
// TODO check if they are indeed mutated outside the event loop
73-
private final AtomicBoolean isDone = new AtomicBoolean(false);
74-
private final AtomicBoolean isCancelled = new AtomicBoolean(false);
75-
private final AtomicBoolean inAuth = new AtomicBoolean(false);
76-
private final AtomicBoolean inProxyAuth = new AtomicBoolean(false);
77-
private final AtomicBoolean statusReceived = new AtomicBoolean(false);
78-
private final AtomicBoolean contentProcessed = new AtomicBoolean(false);
79-
private final AtomicBoolean onThrowableCalled = new AtomicBoolean(false);
71+
private volatile int isDone = 0;
72+
private volatile int isCancelled = 0;
73+
private volatile int inAuth = 0;
74+
private volatile int inProxyAuth = 0;
75+
private volatile int statusReceived = 0;
76+
private volatile int contentProcessed = 0;
77+
private volatile int onThrowableCalled = 0;
78+
79+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> isDoneField =
80+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "isDone");
81+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> isCancelledField =
82+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "isCancelled");
83+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> inAuthField =
84+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "inAuth");
85+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> inProxyAuthField =
86+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "inProxyAuth");
87+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> statusReceivedField =
88+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "statusReceived");
89+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> contentProcessedField =
90+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "contentProcessed");
91+
private static final AtomicIntegerFieldUpdater<NettyResponseFuture> onThrowableCalledField =
92+
AtomicIntegerFieldUpdater.newUpdater(NettyResponseFuture.class, "onThrowableCalled");
8093

8194
// volatile where we need CAS ops
8295
private volatile int redirectCount = 0;
@@ -124,19 +137,19 @@ public NettyResponseFuture(Request originalRequest,//
124137

125138
@Override
126139
public boolean isDone() {
127-
return isDone.get() || isCancelled();
140+
return isDone != 0 || isCancelled();
128141
}
129142

130143
@Override
131144
public boolean isCancelled() {
132-
return isCancelled.get();
145+
return isCancelled != 0;
133146
}
134147

135148
@Override
136149
public boolean cancel(boolean force) {
137150
cancelTimeouts();
138151

139-
if (isCancelled.getAndSet(true))
152+
if (isCancelledField.getAndSet(this, 1) != 0)
140153
return false;
141154

142155
// cancel could happen before channel was attached
@@ -145,7 +158,7 @@ public boolean cancel(boolean force) {
145158
Channels.silentlyCloseChannel(channel);
146159
}
147160

148-
if (!onThrowableCalled.getAndSet(true)) {
161+
if (onThrowableCalledField.getAndSet(this, 1) == 0) {
149162
try {
150163
asyncHandler.onThrowable(new CancellationException());
151164
} catch (Throwable t) {
@@ -183,11 +196,11 @@ private V getContent() throws ExecutionException {
183196
V update = (V) CONTENT_UPDATER.get(this);
184197
// No more retry
185198
CURRENT_RETRY_UPDATER.set(this, maxRetry);
186-
if (!contentProcessed.getAndSet(true)) {
199+
if (contentProcessedField.getAndSet(this, 1) == 0) {
187200
try {
188201
update = asyncHandler.onCompleted();
189202
} catch (Throwable ex) {
190-
if (!onThrowableCalled.getAndSet(true)) {
203+
if (onThrowableCalledField.getAndSet(this, 1) == 0) {
191204
try {
192205
try {
193206
asyncHandler.onThrowable(ex);
@@ -211,7 +224,7 @@ private boolean terminateAndExit() {
211224
cancelTimeouts();
212225
this.channel = null;
213226
this.reuseChannel = false;
214-
return isDone.getAndSet(true) || isCancelled.get();
227+
return isDoneField.getAndSet(this, 1) != 0 || isCancelled != 0;
215228
}
216229

217230
public final void done() {
@@ -241,7 +254,7 @@ public final void abort(final Throwable t) {
241254
if (terminateAndExit())
242255
return;
243256

244-
if (onThrowableCalled.compareAndSet(false, true)) {
257+
if (onThrowableCalledField.compareAndSet(this, 0, 1)) {
245258
try {
246259
asyncHandler.onThrowable(t);
247260
} catch (Throwable te) {
@@ -341,12 +354,28 @@ public TimeoutsHolder getTimeoutsHolder() {
341354
return timeoutsHolder;
342355
}
343356

344-
public AtomicBoolean getInAuth() {
345-
return inAuth;
357+
public boolean getInAuth() {
358+
return inAuth != 0;
346359
}
347360

348-
public AtomicBoolean getInProxyAuth() {
349-
return inProxyAuth;
361+
public void setInAuth(boolean inAuth) {
362+
this.inAuth = inAuth ? 1 : 0;
363+
}
364+
365+
public boolean getAndSetInAuth(boolean set) {
366+
return inAuthField.getAndSet(this, set ? 1 : 0) != 0;
367+
}
368+
369+
public boolean getInProxyAuth() {
370+
return inProxyAuth != 0;
371+
}
372+
373+
public void setInProxyAuth(boolean inProxyAuth) {
374+
this.inProxyAuth = inProxyAuth ? 1 : 0;
375+
}
376+
377+
public boolean getAndSetInProxyAuth(boolean inProxyAuth) {
378+
return inProxyAuthField.getAndSet(this, inProxyAuth ? 1 : 0) != 0;
350379
}
351380

352381
public ChannelState getChannelState() {
@@ -358,7 +387,7 @@ public void setChannelState(ChannelState channelState) {
358387
}
359388

360389
public boolean getAndSetStatusReceived(boolean sr) {
361-
return statusReceived.getAndSet(sr);
390+
return statusReceivedField.getAndSet(this, sr ? 1 : 0) != 0;
362391
}
363392

364393
public boolean isStreamWasAlreadyConsumed() {
@@ -439,7 +468,9 @@ public void setCurrentRequest(Request currentRequest) {
439468
* @return true if that {@link Future} cannot be recovered.
440469
*/
441470
public boolean canBeReplayed() {
442-
return !isDone() && !(Channels.isChannelValid(channel) && !getUri().getScheme().equalsIgnoreCase("https")) && !inAuth.get() && !inProxyAuth.get();
471+
return !isDone() && !(Channels.isChannelValid(channel) && !getUri().getScheme().equalsIgnoreCase("https"))
472+
&& inAuth == 0
473+
&& inProxyAuth == 0;
443474
}
444475

445476
public long getStart() {

client/src/main/java/org/asynchttpclient/netty/handler/intercept/ProxyUnauthorized407Interceptor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public boolean exitAfterHandling407(//
6060
ProxyServer proxyServer,//
6161
HttpRequest httpRequest) {
6262

63-
if (future.getInProxyAuth().getAndSet(true)) {
63+
if (future.getAndSetInProxyAuth(true)) {
6464
LOGGER.info("Can't handle 407 as auth was already performed");
6565
return false;
6666
}
@@ -210,7 +210,7 @@ private void ntlmProxyChallenge(String authenticateHeader,//
210210
// FIXME we might want to filter current NTLM and add (leave other
211211
// Authorization headers untouched)
212212
requestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader);
213-
future.getInProxyAuth().set(false);
213+
future.setInProxyAuth(false);
214214

215215
} else {
216216
String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim();

client/src/main/java/org/asynchttpclient/netty/handler/intercept/Redirect30xInterceptor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ public boolean exitAfterHandlingRedirect(//
7979

8080
} else {
8181
// We must allow auth handling again.
82-
future.getInAuth().set(false);
83-
future.getInProxyAuth().set(false);
82+
future.setInAuth(false);
83+
future.setInProxyAuth(false);
8484

8585
String originalMethod = request.getMethod();
8686
boolean switchToGet = !originalMethod.equals(GET)

client/src/main/java/org/asynchttpclient/netty/handler/intercept/Unauthorized401Interceptor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public boolean exitAfterHandling401(//
6868
return false;
6969
}
7070

71-
if (future.getInAuth().getAndSet(true)) {
71+
if (future.getAndSetInAuth(true)) {
7272
LOGGER.info("Can't handle 401 as auth was already performed");
7373
return false;
7474
}
@@ -195,7 +195,7 @@ private void ntlmChallenge(String authenticateHeader,//
195195
// FIXME we might want to filter current NTLM and add (leave other
196196
// Authorization headers untouched)
197197
requestHeaders.set(AUTHORIZATION, "NTLM " + challengeHeader);
198-
future.getInAuth().set(false);
198+
future.setInAuth(false);
199199

200200
} else {
201201
String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim();

client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ private <T> ListenableFuture<T> sendRequestWithNewChannel(//
253253
requestFactory.addAuthorizationHeader(headers, perConnectionAuthorizationHeader(request, proxy, realm));
254254
requestFactory.setProxyAuthorizationHeader(headers, perConnectionProxyAuthorizationHeader(request, proxyRealm));
255255

256-
future.getInAuth().set(realm != null && realm.isUsePreemptiveAuth() && realm.getScheme() != AuthScheme.NTLM);
257-
future.getInProxyAuth().set(proxyRealm != null && proxyRealm.isUsePreemptiveAuth() && proxyRealm.getScheme() != AuthScheme.NTLM);
256+
future.setInAuth(realm != null && realm.isUsePreemptiveAuth() && realm.getScheme() != AuthScheme.NTLM);
257+
future.setInProxyAuth(proxyRealm != null && proxyRealm.isUsePreemptiveAuth() && proxyRealm.getScheme() != AuthScheme.NTLM);
258258

259259
// Do not throw an exception when we need an extra connection for a redirect
260260
// FIXME why? This violate the max connection per host handling, right?

client/src/main/java/org/asynchttpclient/netty/request/WriteListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ protected void operationComplete(Channel channel, Throwable cause) {
6767
* We need to make sure we aren't in the middle of an authorization process before publishing events as we will re-publish again the same event after the authorization,
6868
* causing unpredictable behavior.
6969
*/
70-
boolean startPublishing = !future.getInAuth().get() && !future.getInProxyAuth().get();
70+
boolean startPublishing = !future.getInAuth() && !future.getInProxyAuth();
7171
if (startPublishing) {
7272

7373
if (notifyHeaders) {

0 commit comments

Comments
 (0)