Skip to content

Commit bef1710

Browse files
committed
JAVA-2564: Prune server sessions on release
1 parent 6e510b3 commit bef1710

File tree

3 files changed

+75
-13
lines changed

3 files changed

+75
-13
lines changed

driver/src/main/com/mongodb/ServerSession.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,11 @@ public interface ServerSession {
3838
* @return the next transaction number
3939
*/
4040
long advanceTransactionNumber();
41+
42+
/**
43+
* Whether the server session is closed.
44+
*
45+
* @return true if the session has been closed
46+
*/
47+
boolean isClosed();
4148
}

driver/src/main/com/mongodb/ServerSessionPool.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ ServerSession get() {
8181

8282
void release(final ServerSession serverSession) {
8383
serverSessionPool.release((ServerSessionImpl) serverSession);
84+
serverSessionPool.prune();
8485
}
8586

8687
void close() {
@@ -94,6 +95,7 @@ void close() {
9495
}
9596

9697
private void closeSession(final ServerSessionImpl serverSession) {
98+
serverSession.close();
9799
// only track closed sessions when pool is in the process of closing
98100
if (!closing) {
99101
return;
@@ -139,11 +141,16 @@ final class ServerSessionImpl implements ServerSession {
139141
private final BsonDocument identifier;
140142
private int transactionNumber;
141143
private volatile long lastUsedAtMillis = clock.millis();
144+
private volatile boolean closed;
142145

143146
ServerSessionImpl(final BsonBinary identifier) {
144147
this.identifier = new BsonDocument("id", identifier);
145148
}
146149

150+
void close() {
151+
closed = true;
152+
}
153+
147154
long getLastUsedAtMillis() {
148155
return lastUsedAtMillis;
149156
}
@@ -162,6 +169,11 @@ public BsonDocument getIdentifier() {
162169
public long advanceTransactionNumber() {
163170
return transactionNumber++;
164171
}
172+
173+
@Override
174+
public boolean isClosed() {
175+
return closed;
176+
}
165177
}
166178

167179
private final class ServerSessionItemFactory implements ConcurrentPool.ItemFactory<ServerSessionImpl> {
@@ -177,7 +189,7 @@ public void close(final ServerSessionImpl serverSession) {
177189

178190
@Override
179191
public Prune shouldPrune(final ServerSessionImpl serverSession) {
180-
return Prune.STOP;
192+
return ServerSessionPool.this.shouldPrune(serverSession) ? Prune.YES : Prune.STOP;
181193
}
182194

183195
private BsonBinary createNewServerSessionIdentifier() {

driver/src/test/unit/com/mongodb/ServerSessionPoolSpecification.groovy

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,33 +108,76 @@ class ServerSessionPoolSpecification extends Specification {
108108
session == pooledSession
109109
}
110110

111-
def 'should prune session'() {
111+
def 'should prune sessions on release'() {
112112
given:
113113
def cluster = Mock(Cluster) {
114114
getDescription() >> connectedDescription
115115
}
116116
def clock = Stub(ServerSessionPool.Clock) {
117-
millis() >>> [0,
118-
1,
119-
MINUTES.toMillis(29),
120-
MINUTES.toMillis(29) + 1]
117+
millis() >>> [0, 0, // first get
118+
1, 1, // second get
119+
2, 2, // third get
120+
3, // first release
121+
MINUTES.toMillis(29), // second release
122+
MINUTES.toMillis(29) + 2, // third release
123+
MINUTES.toMillis(29) + 2,
124+
MINUTES.toMillis(29) + 2
125+
]
121126
}
122127
def pool = new ServerSessionPool(cluster, clock)
123-
def session = pool.get()
128+
def sessionOne = pool.get()
129+
def sessionTwo = pool.get()
130+
def sessionThree = pool.get()
124131

125132
when:
126-
pool.release(session)
127-
def newSession = pool.get()
133+
pool.release(sessionOne)
128134

129135
then:
130-
session == newSession
136+
!sessionOne.closed
137+
138+
when:
139+
pool.release(sessionTwo)
140+
141+
then:
142+
!sessionOne.closed
143+
!sessionTwo.closed
144+
145+
when:
146+
pool.release(sessionThree)
147+
148+
then:
149+
sessionOne.closed
150+
sessionTwo.closed
151+
!sessionThree.closed
152+
0 * cluster.selectServer(_)
153+
}
154+
155+
def 'should prune sessions on get'() {
156+
given:
157+
def cluster = Mock(Cluster) {
158+
getDescription() >> connectedDescription
159+
}
160+
def clock = Stub(ServerSessionPool.Clock) {
161+
millis() >>> [0, 0, // first get
162+
0, // first release
163+
MINUTES.toMillis(29) + 1, // second get
164+
]
165+
}
166+
def pool = new ServerSessionPool(cluster, clock)
167+
def sessionOne = pool.get()
168+
169+
when:
170+
pool.release(sessionOne)
171+
172+
then:
173+
!sessionOne.closed
131174

132175
when:
133-
pool.release(newSession)
134-
newSession = pool.get()
176+
def sessionTwo = pool.get()
135177

136178
then:
137-
session != newSession
179+
sessionTwo != sessionOne
180+
sessionOne.closed
138181
0 * cluster.selectServer(_)
139182
}
140183

0 commit comments

Comments
 (0)