Skip to content

Commit eb6a742

Browse files
committed
JAVA-1005, JAVA-1003, JAVA-1007, JAVA-1009: Ported PooledConnectionProvider from 3.0.x, and refactored DBPort to work with it by extracting a Connection interface that it implements. This new connection pool is non-blocking, and supports enforcement of max idle time, max life time, and minimum size. It also abstracts the JMX monitoring into an implementation of the ConnectionPoolListener interface, which the connection pool fires events to.
Conflicts: src/main/com/mongodb/BaseCluster.java src/main/com/mongodb/Clusters.java src/main/com/mongodb/DBTCPConnector.java src/main/com/mongodb/DefaultServer.java src/main/com/mongodb/Server.java src/main/com/mongodb/ServerStateNotifier.java
1 parent 2a86ada commit eb6a742

40 files changed

Lines changed: 2752 additions & 507 deletions

src/main/com/mongodb/BaseCluster.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,15 @@ public WrappedServer(final ClusterableServer server) {
220220
public ServerDescription getDescription() {
221221
return wrapped.getDescription();
222222
}
223+
224+
@Override
225+
public Connection getConnection() {
226+
return wrapped.getConnection();
227+
}
228+
229+
@Override
230+
public void invalidate() {
231+
wrapped.invalidate();
232+
}
223233
}
224234
}

src/main/com/mongodb/Clusters.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public static Cluster create(final ClusterSettings settings, final ServerSetting
3535
final Mongo mongo) {
3636
String clusterId = Integer.toString(NEXT_CLUSTER_ID.getAndIncrement());
3737

38-
ClusterableServerFactory serverFactory = new DefaultClusterableServerFactory(serverSettings, scheduledExecutorService, mongo);
38+
ClusterableServerFactory serverFactory = new DefaultClusterableServerFactory(clusterId, serverSettings, scheduledExecutorService,
39+
mongo);
3940

4041
if (settings.getMode() == ClusterConnectionMode.Single) {
4142
return new SingleServerCluster(clusterId, settings, serverFactory,
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc., Inc. <http://mongodb.com>
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;
18+
19+
import java.util.Iterator;
20+
import java.util.Queue;
21+
import java.util.concurrent.ConcurrentLinkedQueue;
22+
import java.util.concurrent.Semaphore;
23+
import java.util.concurrent.TimeUnit;
24+
25+
class ConcurrentPool<T> {
26+
27+
private final int maxSize;
28+
private final ItemFactory<T> itemFactory;
29+
30+
private final Queue<T> available = new ConcurrentLinkedQueue<T>();
31+
private final Semaphore permits;
32+
private volatile boolean closed;
33+
34+
/**
35+
* Factory for creating and closing pooled items.
36+
*
37+
* @param <T>
38+
*/
39+
interface ItemFactory<T> {
40+
T create();
41+
42+
void close(T t);
43+
44+
boolean shouldPrune(T t);
45+
}
46+
47+
/**
48+
* Initializes a new pool of objects.
49+
*
50+
* @param maxSize max to hold to at any given time. if < 0 then no limit
51+
* @param itemFactory factory used to create and close items in the pool
52+
*/
53+
public ConcurrentPool(final int maxSize, final ItemFactory<T> itemFactory) {
54+
this.maxSize = maxSize;
55+
this.itemFactory = itemFactory;
56+
permits = new Semaphore(maxSize, true);
57+
}
58+
59+
/**
60+
* Return an instance of T to the pool. This method simply calls {@code release(t, false)}
61+
*
62+
* @param t item to return to the pool
63+
*/
64+
public void release(final T t) {
65+
release(t, false);
66+
}
67+
68+
/**
69+
* call done when you are done with an object from the pool if there is room and the object is ok will get added
70+
*
71+
* @param t item to return to the pool
72+
* @param prune true if the item should be closed, false if it should be put back in the pool
73+
*/
74+
public void release(final T t, final boolean prune) {
75+
if (t == null) {
76+
throw new IllegalArgumentException("Can not return a null item to the pool");
77+
}
78+
if (closed) {
79+
close(t);
80+
return;
81+
}
82+
83+
if (prune) {
84+
close(t);
85+
} else {
86+
available.add(t);
87+
}
88+
89+
releasePermit();
90+
}
91+
92+
/**
93+
* Gets an object from the pool. This method will block until a permit is available.
94+
*
95+
* @return An object from the pool.
96+
*/
97+
public T get() {
98+
return get(-1, TimeUnit.MILLISECONDS);
99+
}
100+
101+
/**
102+
* Gets an object from the pool - will block if none are available
103+
*
104+
* @param timeout negative - forever 0 - return immediately no matter what positive ms to wait
105+
* @param timeUnit the time unit of the timeout
106+
* @return An object from the pool, or null if can't get one in the given waitTime
107+
* @throws MongoTimeoutException if the timeout has been exceeded
108+
*/
109+
public T get(final long timeout, final TimeUnit timeUnit) {
110+
if (closed) {
111+
throw new IllegalStateException("The pool is closed");
112+
}
113+
114+
if (!acquirePermit(timeout, timeUnit)) {
115+
throw new MongoTimeoutException(String.format("Timeout waiting for a pooled item after %d %s", timeout, timeUnit));
116+
}
117+
118+
T t = available.poll();
119+
if (t == null) {
120+
t = createNewAndReleasePermitIfFailure();
121+
}
122+
123+
return t;
124+
}
125+
126+
public void prune() {
127+
int currentAvailableCount = getAvailableCount();
128+
for (int numAttempts = 0; numAttempts < currentAvailableCount; numAttempts++) {
129+
if (!acquirePermit(10, TimeUnit.MILLISECONDS)) {
130+
break;
131+
}
132+
T cur = available.poll();
133+
if (cur == null) {
134+
releasePermit();
135+
break;
136+
}
137+
release(cur, itemFactory.shouldPrune(cur));
138+
}
139+
}
140+
141+
public void ensureMinSize(final int minSize) {
142+
while (getCount() < minSize) {
143+
if (!acquirePermit(10, TimeUnit.MILLISECONDS)) {
144+
break;
145+
}
146+
release(createNewAndReleasePermitIfFailure());
147+
}
148+
}
149+
150+
private T createNewAndReleasePermitIfFailure() {
151+
try {
152+
T newMember = itemFactory.create();
153+
if (newMember == null) {
154+
throw new MongoInternalException("The factory for the pool created a null item");
155+
}
156+
return newMember;
157+
} catch (RuntimeException e) {
158+
permits.release();
159+
throw e;
160+
}
161+
}
162+
163+
protected boolean acquirePermit(final long timeout, final TimeUnit timeUnit) {
164+
try {
165+
if (closed) {
166+
return false;
167+
} else if (timeout >= 0) {
168+
return permits.tryAcquire(timeout, timeUnit);
169+
} else {
170+
permits.acquire();
171+
return true;
172+
}
173+
} catch (InterruptedException e) {
174+
throw new MongoInterruptedException("Interrupted acquiring a permit to retrieve an item from the pool ", e);
175+
}
176+
}
177+
178+
protected void releasePermit() {
179+
permits.release();
180+
}
181+
182+
/**
183+
* Clears the pool of all objects.
184+
*/
185+
public void close() {
186+
closed = true;
187+
Iterator<T> iter = available.iterator();
188+
while (iter.hasNext()) {
189+
T t = iter.next();
190+
close(t);
191+
iter.remove();
192+
}
193+
}
194+
195+
public int getMaxSize() {
196+
return maxSize;
197+
}
198+
199+
public int getInUseCount() {
200+
return maxSize - permits.availablePermits();
201+
}
202+
203+
public int getAvailableCount() {
204+
return available.size();
205+
}
206+
207+
public int getCount() {
208+
return getInUseCount() + getAvailableCount();
209+
}
210+
211+
public String toString() {
212+
StringBuilder buf = new StringBuilder();
213+
buf.append("pool: ")
214+
.append(" maxSize: ").append(maxSize)
215+
.append(" availableCount ").append(getAvailableCount())
216+
.append(" inUseCount ").append(getInUseCount());
217+
return buf.toString();
218+
}
219+
220+
// swallow exceptions from ItemFactory.close()
221+
private void close(final T t) {
222+
try {
223+
itemFactory.close(t);
224+
} catch (RuntimeException e) {
225+
// ItemFactory.close() really should not throw
226+
}
227+
}
228+
}
Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/**
2-
* Copyright (c) 2008 - 2012 10gen, Inc. <http://10gen.com>
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc., Inc. <http://mongodb.com>
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -12,17 +12,18 @@
1212
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
15-
*
1615
*/
1716

1817
package com.mongodb;
1918

20-
/**
21-
* This class exists only so that, on Java 6 and above, the driver can create instances of an MXBean.
22-
*/
23-
class MongoConnectionPool extends DBPortPool implements MongoConnectionPoolMXBean {
19+
interface Connection {
20+
int getGeneration();
21+
22+
long getOpenedAt();
23+
24+
long getLastUsedAt();
25+
26+
boolean isClosed();
2427

25-
MongoConnectionPool(ServerAddress addr, MongoOptions options) {
26-
super(addr, options);
27-
}
28+
void close();
2829
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc., Inc. <http://mongodb.com>
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;
18+
19+
/**
20+
* A connection-related event.
21+
*/
22+
class ConnectionEvent extends ClusterEvent {
23+
private final ServerAddress serverAddress;
24+
25+
/**
26+
* Constructs a new instance of the event.
27+
*
28+
* @param clusterId the cluster id
29+
* @param serverAddress the server address
30+
*/
31+
public ConnectionEvent(final String clusterId, final ServerAddress serverAddress) {
32+
super(clusterId);
33+
this.serverAddress = serverAddress;
34+
}
35+
36+
/**
37+
* Gets the server address associated with this connection.
38+
*
39+
* @return the server address
40+
*/
41+
public ServerAddress getServerAddress() {
42+
return serverAddress;
43+
}
44+
45+
@Override
46+
public boolean equals(final Object o) {
47+
if (this == o) {
48+
return true;
49+
}
50+
if (o == null || getClass() != o.getClass()) {
51+
return false;
52+
}
53+
if (!super.equals(o)) {
54+
return false;
55+
}
56+
57+
ConnectionEvent that = (ConnectionEvent) o;
58+
59+
if (!getClusterId().equals(that.getClusterId())) {
60+
return false;
61+
}
62+
if (!getServerAddress().equals(that.getServerAddress())) {
63+
return false;
64+
}
65+
if (!serverAddress.equals(that.serverAddress)) {
66+
return false;
67+
}
68+
69+
return true;
70+
}
71+
72+
@Override
73+
public int hashCode() {
74+
int result = super.hashCode();
75+
result = 31 * result + serverAddress.hashCode();
76+
return result;
77+
}
78+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2008 - 2013 MongoDB Inc., Inc. <http://mongodb.com>
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;
18+
19+
interface ConnectionFactory {
20+
Connection create(ServerAddress serverAddress, PooledConnectionProvider provider, int generation);
21+
}

0 commit comments

Comments
 (0)