GEODE-6164: CacheClientProxy's closeSocket should be called atomically#2972
GEODE-6164: CacheClientProxy's closeSocket should be called atomically#2972gesterzhou merged 1 commit intodevelopfrom
Conversation
85dde7d to
4751056
Compare
| if (!closeSocket()) { | ||
| // other thread who closed the socket will be responsible to | ||
| // releaseResourcesForAddress and clearClientInterestList | ||
| return; |
There was a problem hiding this comment.
The callers of this method will possibly return without doing the rest of the work. As long as the callers are ok/expecting this to occur, then this should be ok...
|
|
||
| CacheServerStats stats = mock(CacheServerStats.class); | ||
| doNothing().when(stats).incCurrentQueueConnections(); | ||
| // InternalCache cache = cacheRule.getCache(); |
| ((CompletableFuture<Void>) result1).join(); | ||
| ((CompletableFuture<Void>) result2).join(); | ||
| ((CompletableFuture<Void>) result3).join(); | ||
| assertThatCode(() -> result1.get(2, SECONDS)).doesNotThrowAnyException(); |
There was a problem hiding this comment.
Should this be bumped up to a higher number? Maybe just have it have a max wait of 60 seconds, that way it won't fail if for some reason the close happens to take longer or maybe the vm we are running on got cpu starved for a bit?
| if (this._socketClosed.compareAndSet(false, true)) { | ||
| private boolean closeSocket() { | ||
| String remoteHostAddress = this._remoteHostAddress; | ||
| if (this._socketClosed.compareAndSet(false, true) && remoteHostAddress != null) { |
There was a problem hiding this comment.
Would it make sense to break the && condition into another if call instead?
if (remoteHostAddress == null) {
return false?
}
There was a problem hiding this comment.
I think it's worth comments above each of closeSocket() and closeTransientFields() explaining that _socketClosed is used to provide one-shot protection around the close logic in both methods.
|
|
||
| private void closeTransientFields() { | ||
| closeSocket(); | ||
| if (!closeSocket()) { |
There was a problem hiding this comment.
What happens if remoteHostAddress is null, we end up returning false from closeSocket and not doing the rest of this method. Is that acceptable?
There was a problem hiding this comment.
remoteHostAddress is null only when closeTransientFields() is called. So it's ok not to do anything else.
4751056 to
e78b493
Compare
Bill
left a comment
There was a problem hiding this comment.
Good stuff @gesterzhou. I made a couple suggestions that might add a little bit to readability/maintainability. Functionally this looks good to me.
| CacheClientProxy proxy = new CacheClientProxy(ccn, socket, proxyID, true, | ||
| Handshake.CONFLATION_DEFAULT, Version.CURRENT, 1L, true, | ||
| null, null); | ||
| Future<Void> result1 = executorServiceRule.runAsync(() -> proxy.close()); |
There was a problem hiding this comment.
runAsync() returns a CompletableFuture<>. Since you'll need a CompletableFuture later (e.g. line 77), why not capture a CompletableFuture<Void> ref here to avoid the cast later?
| ((CompletableFuture<Void>) result3).join(); | ||
| assertThatCode(() -> result1.get(60, SECONDS)).doesNotThrowAnyException(); | ||
| assertThatCode(() -> result2.get(60, SECONDS)).doesNotThrowAnyException(); | ||
| assertThatCode(() -> result3.get(60, SECONDS)).doesNotThrowAnyException(); |
There was a problem hiding this comment.
FYI if you capture CompletableFuture<> refs above, then these three joins can become one statement:
CompletableFuture.allOf(result1,result2,result3).join();
There was a problem hiding this comment.
sounds good. I enhanced the code.
| InetAddress address = mock(InetAddress.class); | ||
| when(socket.getInetAddress()).thenReturn(address); | ||
| when(address.getHostAddress()).thenReturn("localhost"); | ||
| doNothing().when(sc).asyncClose(any(), eq("localhost"), eq(null)); |
There was a problem hiding this comment.
This would read a lot easier for me if:
- variables that could be declared
final(all of them!) were declaredfinal - vertical space was used to separate each mocked object (its construction and configuration via
when(...))
| if (this._socketClosed.compareAndSet(false, true)) { | ||
| private boolean closeSocket() { | ||
| String remoteHostAddress = this._remoteHostAddress; | ||
| if (this._socketClosed.compareAndSet(false, true) && remoteHostAddress != null) { |
There was a problem hiding this comment.
I think it's worth comments above each of closeSocket() and closeTransientFields() explaining that _socketClosed is used to provide one-shot protection around the close logic in both methods.
e78b493 to
2fed76c
Compare
2fed76c to
77b3926
Compare
|
Looks good to me now. |
Thank you for submitting a contribution to Apache Geode.
@jhuynh1 @Bill
In order to streamline the review of the contribution we ask you
to ensure the following steps have been taken:
For all changes:
Is there a JIRA ticket associated with this PR? Is it referenced in the commit message?
Has your PR been rebased against the latest commit within the target branch (typically
develop)?Is your initial contribution a single, squashed commit?
Does
gradlew buildrun cleanly?Have you written or updated unit tests to verify your changes?
If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under ASF 2.0?
Note:
Please ensure that once the PR is submitted, you check travis-ci for build issues and
submit an update to your PR as soon as possible. If you need help, please send an
email to dev@geode.apache.org.