Skip to content

Commit 9df320a

Browse files
author
mpv1989
committed
added connection pooling (issue #103)
1 parent 07f1371 commit 9df320a

File tree

9 files changed

+138
-21
lines changed

9 files changed

+138
-21
lines changed

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ v4.1.11 (2017-03-xx)
33
* added convenience methods (ArangoDatabase.arango(), ArangoCollection.db(), ArangoGraph.db())
44
* added convenience methods (ArangoCollection.getIndex(String), .deleteIndex(key))
55
* fixed exception handling in Connection (issue #110)
6+
* added connection pooling (issue #103)
67

78
v4.1.10 (2017-02-22)
89
---------------------------

docs/setup.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ The driver is configured with some default values:
1818
<tr><td>arangodb.user</td><td>Basic Authentication User</td><td></td></tr>
1919
<tr><td>arangodb.password</td><td>Basic Authentication Password</td><td></td></tr>
2020
<tr><td>arangodb.useSsl</td><td>use SSL connection</td><td>false</td></tr>
21-
<tr><td>harangodb.chunksize</td><td>VelocyStream Chunk content-size(bytes)</td><td>30000</td></tr>
21+
<tr><td>arangodb.chunksize</td><td>VelocyStream Chunk content-size(bytes)</td><td>30000</td></tr>
22+
<tr><td>arangodb.connections.max</td><td>max number of connections</td><td>1</td></tr>
2223
</table>
2324

2425
To customize the configuration the parameters can be changed in the code...
@@ -51,4 +52,14 @@ To use SSL, you have to set the configuration `useSsl` to `true` and set a `SSLC
5152

5253
ArangoDB arangoDB = new ArangoDB.Builder().useSsl(true).sslContext(sc).build();
5354

55+
```
56+
57+
## Connection Pooling
58+
59+
The driver supports connection pooling with a default of 1 maximum connections. To change this value use the method `maxConnections(Integer)` in `ArangoDB.Builder`.
60+
61+
``` Java
62+
63+
ArangoDB arangoDB = new ArangoDB.Builder().maxConnections(8).build();
64+
5465
```

src/main/java/com/arangodb/ArangoDB.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ public static class Builder {
8080
private Boolean useSsl;
8181
private SSLContext sslContext;
8282
private Integer chunksize;
83+
private Integer maxConnections;
8384
private final VPack.Builder vpackBuilder;
8485
private final CollectionCache collectionCache;
8586
private final VPackParser vpackParser;
@@ -109,6 +110,7 @@ public Builder loadProperties(final InputStream in) throws ArangoDBException {
109110
password = loadPassword(properties, password);
110111
useSsl = loadUseSsl(properties, useSsl);
111112
chunksize = loadChunkSize(properties, chunksize);
113+
maxConnections = loadMaxConnections(properties, maxConnections);
112114
} catch (final IOException e) {
113115
throw new ArangoDBException(e);
114116
}
@@ -184,6 +186,11 @@ public Builder chunksize(final Integer chunksize) {
184186
return this;
185187
}
186188

189+
public Builder maxConnections(final Integer maxConnections) {
190+
this.maxConnections = maxConnections;
191+
return this;
192+
}
193+
187194
public <T> Builder registerSerializer(final Class<T> clazz, final VPackSerializer<T> serializer) {
188195
vpackBuilder.registerSerializer(clazz, serializer);
189196
return this;
@@ -259,7 +266,8 @@ public ArangoDB build() {
259266
}
260267
return new ArangoDB(
261268
new CommunicationSync.Builder(new DefaultHostHandler(hosts)).timeout(timeout).user(user)
262-
.password(password).useSsl(useSsl).sslContext(sslContext).chunksize(chunksize),
269+
.password(password).useSsl(useSsl).sslContext(sslContext).chunksize(chunksize)
270+
.maxConnections(maxConnections),
263271
vpackBuilder.build(), vpackBuilder.serializeNullValues(true).build(), vpackParser, collectionCache);
264272
}
265273

@@ -279,6 +287,7 @@ public ArangoDatabase db(final String name) {
279287
});
280288
}
281289

290+
@Override
282291
protected ArangoExecutorSync executor() {
283292
return executor;
284293
}

src/main/java/com/arangodb/internal/ArangoDBConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class ArangoDBConstants {
3737
public static final int CHUNK_MIN_HEADER_SIZE = INTEGER_BYTES + INTEGER_BYTES + LONG_BYTES;
3838
public static final int CHUNK_MAX_HEADER_SIZE = CHUNK_MIN_HEADER_SIZE + LONG_BYTES;
3939
public static final int CHUNK_DEFAULT_CONTENT_SIZE = 30000;
40+
public static final int MAX_CONNECTIONS_DEFAULT = 1;
4041

4142
public static final String PATH_API_DOCUMENT = "/_api/document";
4243
public static final String PATH_API_COLLECTION = "/_api/collection";

src/main/java/com/arangodb/internal/InternalArangoDB.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public class InternalArangoDB<E extends ArangoExecutor<R, C>, R, C extends Conne
6161
private static final String PROPERTY_KEY_PASSWORD = "arangodb.password";
6262
private static final String PROPERTY_KEY_USE_SSL = "arangodb.usessl";
6363
private static final String PROPERTY_KEY_V_STREAM_CHUNK_CONTENT_SIZE = "arangodb.chunksize";
64+
private static final String PROPERTY_KEY_MAX_CONNECTIONS = "arangodb.connections.max";
6465
protected static final String DEFAULT_PROPERTY_FILE = "/arangodb.properties";
6566

6667
public InternalArangoDB(final E executor) {
@@ -116,6 +117,11 @@ protected static Integer loadChunkSize(final Properties properties, final Intege
116117
ArangoDBConstants.CHUNK_DEFAULT_CONTENT_SIZE));
117118
}
118119

120+
protected static Integer loadMaxConnections(final Properties properties, final Integer currentValue) {
121+
return Integer.parseInt(getProperty(properties, PROPERTY_KEY_MAX_CONNECTIONS, currentValue,
122+
ArangoDBConstants.MAX_CONNECTIONS_DEFAULT));
123+
}
124+
119125
private static <T> String getProperty(
120126
final Properties properties,
121127
final String key,

src/main/java/com/arangodb/internal/velocystream/Communication.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public abstract class Communication<R, C extends Connection> {
5252

5353
protected static final AtomicLong mId = new AtomicLong(0L);
5454
protected final VPack vpack;
55-
protected final C connection;
55+
protected final ConnectionPool<C> connectionPool;
5656
protected final CollectionCache collectionCache;
5757

5858
protected final String user;
@@ -62,21 +62,21 @@ public abstract class Communication<R, C extends Connection> {
6262

6363
protected Communication(final Integer timeout, final String user, final String password, final Boolean useSsl,
6464
final SSLContext sslContext, final VPack vpack, final CollectionCache collectionCache, final Integer chunksize,
65-
final C connection) {
65+
final ConnectionPool<C> connectionPool) {
6666
this.user = user;
6767
this.password = password;
6868
this.vpack = vpack;
6969
this.collectionCache = collectionCache;
70-
this.connection = connection;
70+
this.connectionPool = connectionPool;
7171
this.chunksize = chunksize != null ? chunksize : ArangoDBConstants.CHUNK_DEFAULT_CONTENT_SIZE;
7272
}
7373

74-
protected void connect(final Connection connection) {
74+
protected void connect(final C connection) {
7575
if (!connection.isOpen()) {
7676
try {
7777
connection.open();
7878
if (user != null) {
79-
authenticate();
79+
authenticate(connection);
8080
}
8181
} catch (final IOException e) {
8282
LOGGER.error(e.getMessage(), e);
@@ -85,17 +85,17 @@ protected void connect(final Connection connection) {
8585
}
8686
}
8787

88-
protected abstract void authenticate();
88+
protected abstract void authenticate(final C connection);
8989

9090
public void disconnect() {
91-
disconnect(connection);
91+
connectionPool.disconnect();
9292
}
9393

94-
public void disconnect(final Connection connection) {
95-
connection.close();
94+
public R execute(final Request request) throws ArangoDBException {
95+
return execute(request, connectionPool.connection());
9696
}
9797

98-
public abstract R execute(final Request request) throws ArangoDBException;
98+
public abstract R execute(final Request request, C connection) throws ArangoDBException;
9999

100100
protected void checkError(final Response response) throws ArangoDBException {
101101
try {

src/main/java/com/arangodb/internal/velocystream/CommunicationSync.java

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public static class Builder {
5050
private Boolean useSsl;
5151
private SSLContext sslContext;
5252
private Integer chunksize;
53+
private Integer maxConnections;
5354

5455
public Builder(final HostHandler hostHandler) {
5556
super();
@@ -86,26 +87,38 @@ public Builder chunksize(final Integer chunksize) {
8687
return this;
8788
}
8889

90+
public Builder maxConnections(final Integer maxConnections) {
91+
this.maxConnections = maxConnections;
92+
return this;
93+
}
94+
8995
public Communication<Response, ConnectionSync> build(final VPack vpack, final CollectionCache collectionCache) {
9096
return new CommunicationSync(hostHandler, timeout, user, password, useSsl, sslContext, vpack,
91-
collectionCache, chunksize);
97+
collectionCache, chunksize, maxConnections);
9298
}
9399
}
94100

95101
protected CommunicationSync(final HostHandler hostHandler, final Integer timeout, final String user,
96102
final String password, final Boolean useSsl, final SSLContext sslContext, final VPack vpack,
97-
final CollectionCache collectionCache, final Integer chunksize) {
103+
final CollectionCache collectionCache, final Integer chunksize, final Integer maxConnections) {
98104
super(timeout, user, password, useSsl, sslContext, vpack, collectionCache, chunksize,
99-
new ConnectionSync.Builder(hostHandler, new MessageStore()).timeout(timeout).useSsl(useSsl)
100-
.sslContext(sslContext).build());
105+
new ConnectionPool<ConnectionSync>(maxConnections) {
106+
private final ConnectionSync.Builder builder = new ConnectionSync.Builder(hostHandler,
107+
new MessageStore()).timeout(timeout).useSsl(useSsl).sslContext(sslContext);
108+
109+
@Override
110+
public ConnectionSync createConnection() {
111+
return builder.build();
112+
}
113+
});
101114
}
102115

103116
@Override
104-
public Response execute(final Request request) throws ArangoDBException {
117+
public Response execute(final Request request, final ConnectionSync connection) throws ArangoDBException {
105118
connect(connection);
106119
try {
107120
final Message requestMessage = createMessage(request);
108-
final Message responseMessage = send(requestMessage);
121+
final Message responseMessage = send(requestMessage, connection);
109122
collectionCache.setDb(request.getDatabase());
110123
final Response response = createResponse(responseMessage);
111124
checkError(response);
@@ -116,7 +129,7 @@ public Response execute(final Request request) throws ArangoDBException {
116129

117130
}
118131

119-
private Message send(final Message message) throws ArangoDBException {
132+
private Message send(final Message message, final ConnectionSync connection) throws ArangoDBException {
120133
if (LOGGER.isDebugEnabled()) {
121134
LOGGER.debug(String.format("Send Message (id=%s, head=%s, body=%s)", message.getId(), message.getHead(),
122135
message.getBody() != null ? message.getBody() : "{}"));
@@ -125,9 +138,10 @@ private Message send(final Message message) throws ArangoDBException {
125138
}
126139

127140
@Override
128-
protected void authenticate() {
141+
protected void authenticate(final ConnectionSync connection) {
129142
final Response response = execute(
130-
new AuthenticationRequest(user, password != null ? password : "", ArangoDBConstants.ENCRYPTION_PLAIN));
143+
new AuthenticationRequest(user, password != null ? password : "", ArangoDBConstants.ENCRYPTION_PLAIN),
144+
connection);
131145
checkError(response);
132146
}
133147

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* DISCLAIMER
3+
*
4+
* Copyright 2016 ArangoDB GmbH, Cologne, Germany
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*
18+
* Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
*/
20+
21+
package com.arangodb.internal.velocystream;
22+
23+
import java.util.LinkedList;
24+
25+
import com.arangodb.internal.ArangoDBConstants;
26+
27+
/**
28+
* @author Mark - mark at arangodb.com
29+
*
30+
*/
31+
public abstract class ConnectionPool<C extends Connection> {
32+
33+
private final LinkedList<C> connections;
34+
private final int maxConnections;
35+
36+
public ConnectionPool(final Integer maxConnections) {
37+
super();
38+
this.maxConnections = maxConnections != null ? Math.max(1, maxConnections)
39+
: ArangoDBConstants.MAX_CONNECTIONS_DEFAULT;
40+
connections = new LinkedList<C>();
41+
}
42+
43+
public abstract C createConnection();
44+
45+
public synchronized C connection() {
46+
final C c;
47+
if (connections.size() < maxConnections) {
48+
c = createConnection();
49+
} else {
50+
c = connections.removeFirst();
51+
}
52+
connections.add(c);
53+
return c;
54+
}
55+
56+
public void disconnect() {
57+
while (!connections.isEmpty()) {
58+
connections.removeLast().close();
59+
}
60+
}
61+
62+
}

src/test/java/com/arangodb/internal/velocystream/CommunicationTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,17 @@ public void run() {
9191
assertThat(iterator.next(), is(SLOW));
9292
}
9393

94+
@Test
95+
public void minOneConnection() {
96+
final ArangoDB arangoDB = new ArangoDB.Builder().maxConnections(0).build();
97+
final ArangoDBVersion version = arangoDB.getVersion();
98+
assertThat(version, is(notNullValue()));
99+
}
100+
101+
@Test
102+
public void defaultMaxConnection() {
103+
final ArangoDB arangoDB = new ArangoDB.Builder().maxConnections(null).build();
104+
final ArangoDBVersion version = arangoDB.getVersion();
105+
assertThat(version, is(notNullValue()));
106+
}
94107
}

0 commit comments

Comments
 (0)