Skip to content

Commit 3ef3747

Browse files
authored
Replace synchronized with ReentrantLock (#984)
JAVA-4642
1 parent 6693493 commit 3ef3747

File tree

9 files changed

+171
-50
lines changed

9 files changed

+171
-50
lines changed

driver-core/src/main/com/mongodb/KerberosSubjectProvider.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,10 @@
2626
import javax.security.auth.kerberos.KerberosTicket;
2727
import javax.security.auth.login.LoginContext;
2828
import javax.security.auth.login.LoginException;
29+
import java.util.concurrent.locks.ReentrantLock;
2930

3031
import static com.mongodb.assertions.Assertions.notNull;
32+
import static com.mongodb.internal.Locks.checkedWithLock;
3133
import static java.lang.String.format;
3234
import static java.util.concurrent.TimeUnit.MILLISECONDS;
3335
import static java.util.concurrent.TimeUnit.MINUTES;
@@ -54,6 +56,7 @@ public class KerberosSubjectProvider implements SubjectProvider {
5456
private static final Logger LOGGER = Loggers.getLogger("authenticator");
5557
private static final String TGT_PREFIX = "krbtgt/";
5658

59+
private final ReentrantLock lock = new ReentrantLock();
5760
private String loginContextName;
5861
private String fallbackLoginContextName;
5962
private Subject subject;
@@ -87,11 +90,13 @@ private KerberosSubjectProvider(final String loginContextName, @Nullable final S
8790
* @throws LoginException any exception resulting from a call to {@link LoginContext#login()}
8891
*/
8992
@NonNull
90-
public synchronized Subject getSubject() throws LoginException {
91-
if (subject == null || needNewSubject(subject)) {
92-
subject = createNewSubject();
93-
}
94-
return subject;
93+
public Subject getSubject() throws LoginException {
94+
return checkedWithLock(lock, () -> {
95+
if (subject == null || needNewSubject(subject)) {
96+
subject = createNewSubject();
97+
}
98+
return subject;
99+
});
95100
}
96101

97102
private Subject createNewSubject() throws LoginException {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.internal;
18+
19+
/**
20+
* This class is not part of the public API and may be removed or changed at any time.
21+
*/
22+
@FunctionalInterface
23+
public interface CheckedSupplier<T, E extends Exception> {
24+
25+
/**
26+
* Gets a result.
27+
*
28+
* @return a result
29+
* @throws E the checked exception to throw
30+
*/
31+
T get() throws E;
32+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.internal;
18+
19+
import com.mongodb.MongoInterruptedException;
20+
21+
import java.util.concurrent.locks.Lock;
22+
import java.util.function.Supplier;
23+
24+
/**
25+
* This class is not part of the public API and may be removed or changed at any time.
26+
*/
27+
public final class Locks {
28+
public static void withLock(final Lock lock, final Runnable action) {
29+
withLock(lock, () -> {
30+
action.run();
31+
return null;
32+
});
33+
}
34+
35+
public static <V> V withLock(final Lock lock, final Supplier<V> supplier) {
36+
return checkedWithLock(lock, supplier::get);
37+
}
38+
39+
public static <V, E extends Exception> V checkedWithLock(final Lock lock, final CheckedSupplier<V, E> supplier) throws E {
40+
try {
41+
lock.lockInterruptibly();
42+
try {
43+
return supplier.get();
44+
} finally {
45+
lock.unlock();
46+
}
47+
} catch (InterruptedException e) {
48+
Thread.currentThread().interrupt();
49+
throw new MongoInterruptedException("Interrupted waiting for lock", e);
50+
}
51+
}
52+
53+
private Locks() {
54+
}
55+
}

driver-core/src/main/com/mongodb/internal/connection/BaseCluster.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import com.mongodb.event.ClusterDescriptionChangedEvent;
3333
import com.mongodb.event.ClusterListener;
3434
import com.mongodb.event.ClusterOpeningEvent;
35+
import com.mongodb.internal.Locks;
3536
import com.mongodb.internal.VisibleForTesting;
3637
import com.mongodb.internal.async.SingleResultCallback;
3738
import com.mongodb.internal.selector.LatencyMinimizingServerSelector;
@@ -48,6 +49,7 @@
4849
import java.util.concurrent.CountDownLatch;
4950
import java.util.concurrent.ThreadLocalRandom;
5051
import java.util.concurrent.atomic.AtomicReference;
52+
import java.util.concurrent.locks.ReentrantLock;
5153
import java.util.function.Function;
5254

5355
import static com.mongodb.assertions.Assertions.isTrue;
@@ -68,6 +70,7 @@ abstract class BaseCluster implements Cluster {
6870

6971
private static final Logger LOGGER = Loggers.getLogger("cluster");
7072

73+
private final ReentrantLock lock = new ReentrantLock();
7174
private final AtomicReference<CountDownLatch> phase = new AtomicReference<CountDownLatch>(new CountDownLatch(1));
7275
private final ClusterableServerFactory serverFactory;
7376
private final ClusterId clusterId;
@@ -268,8 +271,8 @@ public ClusterDescription getCurrentDescription() {
268271
}
269272

270273
@Override
271-
public synchronized void withLock(final Runnable action) {
272-
action.run();
274+
public void withLock(final Runnable action) {
275+
Locks.withLock(lock, action);
273276
}
274277

275278
private void updatePhase() {

driver-core/src/main/com/mongodb/internal/connection/ClusterClock.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,36 @@
1919
import org.bson.BsonDocument;
2020
import org.bson.BsonTimestamp;
2121

22+
import java.util.concurrent.locks.ReentrantLock;
23+
24+
import static com.mongodb.internal.Locks.withLock;
25+
2226
public class ClusterClock {
2327
private static final String CLUSTER_TIME_KEY = "clusterTime";
28+
private final ReentrantLock lock = new ReentrantLock();
2429
private BsonDocument clusterTime;
2530

26-
public synchronized BsonDocument getCurrent() {
27-
return clusterTime;
31+
public BsonDocument getCurrent() {
32+
return withLock(lock, () -> clusterTime);
2833
}
2934

30-
public synchronized BsonTimestamp getClusterTime() {
31-
return clusterTime != null ? clusterTime.getTimestamp(CLUSTER_TIME_KEY) : null;
35+
public BsonTimestamp getClusterTime() {
36+
return withLock(lock, () -> clusterTime != null ? clusterTime.getTimestamp(CLUSTER_TIME_KEY) : null);
3237
}
3338

34-
public synchronized void advance(final BsonDocument other) {
35-
this.clusterTime = greaterOf(other);
39+
public void advance(final BsonDocument other) {
40+
withLock(lock, () -> this.clusterTime = greaterOf(other));
3641
}
3742

38-
public synchronized BsonDocument greaterOf(final BsonDocument other) {
39-
if (other == null) {
40-
return clusterTime;
41-
} else if (clusterTime == null) {
42-
return other;
43-
} else {
44-
return other.getTimestamp(CLUSTER_TIME_KEY).compareTo(clusterTime.getTimestamp(CLUSTER_TIME_KEY)) > 0 ? other : clusterTime;
45-
}
43+
public BsonDocument greaterOf(final BsonDocument other) {
44+
return withLock(lock, () -> {
45+
if (other == null) {
46+
return clusterTime;
47+
} else if (clusterTime == null) {
48+
return other;
49+
} else {
50+
return other.getTimestamp(CLUSTER_TIME_KEY).compareTo(clusterTime.getTimestamp(CLUSTER_TIME_KEY)) > 0 ? other : clusterTime;
51+
}
52+
});
4653
}
4754
}

driver-core/src/main/com/mongodb/internal/connection/MongoCredentialWithCache.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
import com.mongodb.AuthenticationMechanism;
2020
import com.mongodb.MongoCredential;
2121

22+
import java.util.concurrent.locks.Lock;
23+
import java.util.concurrent.locks.ReentrantLock;
24+
25+
import static com.mongodb.internal.Locks.withLock;
26+
2227
public class MongoCredentialWithCache {
2328
private final MongoCredential credential;
2429
private final Cache cache;
@@ -53,21 +58,29 @@ public void putInCache(final Object key, final Object value) {
5358
cache.set(key, value);
5459
}
5560

61+
public Lock getLock() {
62+
return cache.lock;
63+
}
5664

5765
static class Cache {
66+
private final ReentrantLock lock = new ReentrantLock();
5867
private Object cacheKey;
5968
private Object cacheValue;
6069

61-
synchronized Object get(final Object key) {
62-
if (cacheKey != null && cacheKey.equals(key)) {
63-
return cacheValue;
64-
}
65-
return null;
70+
Object get(final Object key) {
71+
return withLock(lock, () -> {
72+
if (cacheKey != null && cacheKey.equals(key)) {
73+
return cacheValue;
74+
}
75+
return null;
76+
});
6677
}
6778

68-
synchronized void set(final Object key, final Object value) {
69-
cacheKey = key;
70-
cacheValue = value;
79+
void set(final Object key, final Object value) {
80+
withLock(lock, () -> {
81+
cacheKey = key;
82+
cacheValue = value;
83+
});
7184
}
7285
}
7386
}

driver-core/src/main/com/mongodb/internal/connection/SaslAuthenticator.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@
4242

4343
import static com.mongodb.MongoCredential.JAVA_SUBJECT_KEY;
4444
import static com.mongodb.MongoCredential.JAVA_SUBJECT_PROVIDER_KEY;
45+
import static com.mongodb.internal.Locks.withLock;
4546
import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback;
4647
import static com.mongodb.internal.connection.CommandHelper.executeCommand;
4748
import static com.mongodb.internal.connection.CommandHelper.executeCommandAsync;
4849

4950
abstract class SaslAuthenticator extends Authenticator implements SpeculativeAuthenticator {
5051
public static final Logger LOGGER = Loggers.getLogger("authenticator");
5152
private static final String SUBJECT_PROVIDER_CACHE_KEY = "SUBJECT_PROVIDER";
52-
5353
SaslAuthenticator(final MongoCredentialWithCache credential, final ClusterConnectionMode clusterConnectionMode,
5454
final @Nullable ServerApi serverApi) {
5555
super(credential, clusterConnectionMode, serverApi);
@@ -205,7 +205,7 @@ protected Subject getSubject() {
205205

206206
@NonNull
207207
private SubjectProvider getSubjectProvider() {
208-
synchronized (getMongoCredentialWithCache()) {
208+
return withLock(getMongoCredentialWithCache().getLock(), () -> {
209209
SubjectProvider subjectProvider =
210210
getMongoCredentialWithCache().getFromCache(SUBJECT_PROVIDER_CACHE_KEY, SubjectProvider.class);
211211
if (subjectProvider == null) {
@@ -216,7 +216,7 @@ private SubjectProvider getSubjectProvider() {
216216
getMongoCredentialWithCache().putInCache(SUBJECT_PROVIDER_CACHE_KEY, subjectProvider);
217217
}
218218
return subjectProvider;
219-
}
219+
});
220220
}
221221

222222
@NonNull

driver-sync/src/main/com/mongodb/client/gridfs/GridFSDownloadStreamImpl.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,21 @@
1717
package com.mongodb.client.gridfs;
1818

1919
import com.mongodb.MongoGridFSException;
20+
import com.mongodb.client.ClientSession;
2021
import com.mongodb.client.FindIterable;
2122
import com.mongodb.client.MongoCollection;
2223
import com.mongodb.client.MongoCursor;
2324
import com.mongodb.client.gridfs.model.GridFSFile;
2425
import com.mongodb.lang.Nullable;
25-
import com.mongodb.client.ClientSession;
2626
import org.bson.BsonValue;
2727
import org.bson.Document;
2828
import org.bson.types.Binary;
2929

30+
import java.util.concurrent.locks.ReentrantLock;
31+
3032
import static com.mongodb.assertions.Assertions.isTrueArgument;
3133
import static com.mongodb.assertions.Assertions.notNull;
34+
import static com.mongodb.internal.Locks.withLock;
3235
import static java.lang.String.format;
3336

3437
class GridFSDownloadStreamImpl extends GridFSDownloadStream {
@@ -47,8 +50,8 @@ class GridFSDownloadStreamImpl extends GridFSDownloadStream {
4750
private byte[] buffer = null;
4851
private long markPosition;
4952

50-
private final Object closeLock = new Object();
51-
private final Object cursorLock = new Object();
53+
private final ReentrantLock closeLock = new ReentrantLock();
54+
private final ReentrantLock cursorLock = new ReentrantLock();
5255
private boolean closed = false;
5356

5457
GridFSDownloadStreamImpl(@Nullable final ClientSession clientSession, final GridFSFile fileInfo,
@@ -156,12 +159,12 @@ public void mark() {
156159
}
157160

158161
@Override
159-
public synchronized void mark(final int readlimit) {
162+
public void mark(final int readlimit) {
160163
markPosition = currentPosition;
161164
}
162165

163166
@Override
164-
public synchronized void reset() {
167+
public void reset() {
165168
checkClosed();
166169
if (currentPosition == markPosition) {
167170
return;
@@ -184,29 +187,29 @@ public boolean markSupported() {
184187

185188
@Override
186189
public void close() {
187-
synchronized (closeLock) {
190+
withLock(closeLock, () -> {
188191
if (!closed) {
189192
closed = true;
190193
}
191194
discardCursor();
192-
}
195+
});
193196
}
194197

195198
private void checkClosed() {
196-
synchronized (closeLock) {
199+
withLock(closeLock, () -> {
197200
if (closed) {
198201
throw new MongoGridFSException("The InputStream has been closed");
199202
}
200-
}
203+
});
201204
}
202205

203206
private void discardCursor() {
204-
synchronized (cursorLock) {
207+
withLock(cursorLock, () -> {
205208
if (cursor != null) {
206209
cursor.close();
207210
cursor = null;
208211
}
209-
}
212+
});
210213
}
211214

212215
@Nullable

0 commit comments

Comments
 (0)