Skip to content

Commit 5bcaea0

Browse files
authored
Merge pull request #1638 from marklogic/feature/configurator-fix
Fixing bug with multiple threads using configurators
2 parents f94eb07 + a85db53 commit 5bcaea0

File tree

2 files changed

+55
-8
lines changed

2 files changed

+55
-8
lines changed

marklogic-client-api/src/main/java/com/marklogic/client/DatabaseClientFactory.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@
2828
import java.security.cert.CertificateParsingException;
2929
import java.security.cert.X509Certificate;
3030
import java.time.Instant;
31-
import java.util.ArrayList;
32-
import java.util.Collection;
33-
import java.util.Collections;
34-
import java.util.HashMap;
35-
import java.util.List;
36-
import java.util.Map;
37-
import java.util.Set;
31+
import java.util.*;
3832
import java.util.function.Function;
3933

4034
import javax.naming.InvalidNameException;
@@ -63,7 +57,8 @@
6357
*/
6458
public class DatabaseClientFactory {
6559

66-
static private List<ClientConfigurator<?>> clientConfigurators = new ArrayList<>();
60+
static private List<ClientConfigurator<?>> clientConfigurators = Collections.synchronizedList(new ArrayList<>());
61+
6762
static private HandleFactoryRegistry handleRegistry =
6863
HandleFactoryRegistryImpl.newDefault();
6964

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.marklogic.client.extra.okhttpclient;
2+
3+
import com.marklogic.client.DatabaseClientFactory;
4+
import com.marklogic.client.test.Common;
5+
import org.junit.jupiter.api.Test;
6+
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import java.util.concurrent.ExecutorService;
10+
import java.util.concurrent.Executors;
11+
import java.util.concurrent.Future;
12+
import java.util.concurrent.TimeUnit;
13+
14+
import static org.junit.jupiter.api.Assertions.assertEquals;
15+
16+
public class OkHttpClientConfiguratorTest {
17+
18+
/**
19+
* Not a test exactly of OkHttp, but rather that multiple threads can add configurators and create clients without
20+
* encountering a ConcurrentModificationException, which used to occur due to the list of configurators in
21+
* DatabaseClientFactory not being synchronized.
22+
*
23+
* @throws Exception
24+
*/
25+
@Test
26+
void multipleThreads() throws Exception {
27+
final int clientsToCreate = 100;
28+
29+
ExecutorService service = Executors.newFixedThreadPool(16);
30+
List<Future> futures = new ArrayList<>();
31+
for (int i = 0; i < clientsToCreate; i++) {
32+
futures.add(service.submit(() -> {
33+
DatabaseClientFactory.addConfigurator((OkHttpClientConfigurator) client -> {
34+
client.callTimeout(10, TimeUnit.SECONDS);
35+
});
36+
Common.newClient().release();
37+
}));
38+
}
39+
40+
int clientsCreated = 0;
41+
for (Future f : futures) {
42+
f.get();
43+
clientsCreated++;
44+
}
45+
service.shutdown();
46+
47+
assertEquals(clientsToCreate, clientsCreated, "The expectation is that many threads can " +
48+
"add a configurator and create a client at the same time because DatabaseClientFactory " +
49+
"uses a synchronized list for the configurators. So all of the expected clients should be " +
50+
"created successfully with no concurrent modification errors occurring.");
51+
}
52+
}

0 commit comments

Comments
 (0)