Skip to content

Commit 77937ce

Browse files
committed
Add basic session pooling
1 parent bf82d0a commit 77937ce

File tree

5 files changed

+170
-5
lines changed

5 files changed

+170
-5
lines changed

src/v1/internal/pool.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright (c) 2002-2016 "Neo Technology,"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
class Pool {
21+
/**
22+
* @param create an allocation function that creates a new resource. It's given
23+
* a single argument, a function that will return the resource to
24+
* the pool if invoked, which is meant to be called on .dispose
25+
* or .close or whatever mechanism the resource uses to finalize.
26+
* @param destroy called with the resource when it is evicted from this pool
27+
* @param validate called at various times (like when an instance is acquired and
28+
* when it is returned). If this returns false, the resource will
29+
* be evicted
30+
* @param maxIdle the max number of resources that are allowed idle in the pool at
31+
* any time. If this threshold is exceeded, resources will be evicted.
32+
*/
33+
constructor(create, destroy=(()=>true), validate=(()=>true), maxIdle=50) {
34+
this._create = create;
35+
this._destroy = destroy;
36+
this._validate = validate;
37+
this._maxIdle = maxIdle;
38+
this._pool = [];
39+
this._release = this._release.bind(this);
40+
}
41+
42+
acquire() {
43+
if( this._pool.length > 0 ) {
44+
return this._pool.pop();
45+
} else {
46+
return this._create( this._release );
47+
}
48+
}
49+
50+
_release(resource) {
51+
if( this._pool.length >= this._maxIdle || !this._validate(resource) ) {
52+
this._destroy(resource);
53+
} else {
54+
this._pool.push(resource);
55+
}
56+
}
57+
}
58+
59+
export default {
60+
Pool
61+
}

src/v1/session.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class Session {
6868
* Begin a new transaction in this session. A session can have at most one transaction running at a time, if you
6969
* want to run multiple concurrent transactions, you should use multiple concurrent sessions.
7070
*
71-
* While a transaction is open the session cannot be used to run statements.
71+
* While a transaction is open the session cannot be used to run statements outside the transaction.
7272
*
7373
* @returns {Transaction} - New Transaction
7474
*/
@@ -82,8 +82,8 @@ class Session {
8282
}
8383

8484
/**
85-
* Close connection
86-
* @param {function()} cb - Function to be called on connection close
85+
* Close this session
86+
* @param {function()} cb - Function to be called after the session has been closed
8787
* @return
8888
*/
8989
close(cb) {

test/internal/connector.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ var connect = require("../../lib/v1/internal/connector.js").connect;
2121

2222
describe('connector', function() {
2323

24-
fit('should read/write basic messages', function(done) {
24+
it('should read/write basic messages', function(done) {
2525
// Given
2626
var conn = connect("bolt://localhost")
2727

test/internal/pool.test.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright (c) 2002-2016 "Neo Technology,"
3+
* Network Engine for Objects in Lund AB [http://neotechnology.com]
4+
*
5+
* This file is part of Neo4j.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
var Pool = require('../../lib/v1/internal/pool').Pool;
21+
22+
fdescribe('Pool', function() {
23+
it('allocates if pool is empty', function() {
24+
// Given
25+
var counter = 0;
26+
var pool = new Pool( function (release) { return new Resource(counter++, release) } );
27+
28+
// When
29+
var r0 = pool.acquire();
30+
var r1 = pool.acquire();
31+
32+
// Then
33+
expect( r0.id ).toBe( 0 );
34+
expect( r1.id ).toBe( 1 );
35+
});
36+
37+
it('pools if resources are returned', function() {
38+
// Given a pool that allocates
39+
var counter = 0;
40+
var pool = new Pool( function (release) { return new Resource(counter++, release) } );
41+
42+
// When
43+
var r0 = pool.acquire();
44+
r0.close();
45+
var r1 = pool.acquire();
46+
47+
// Then
48+
expect( r0.id ).toBe( 0 );
49+
expect( r1.id ).toBe( 0 );
50+
});
51+
52+
it('frees if pool reaches max size', function() {
53+
// Given a pool that tracks destroyed resources
54+
var counter = 0,
55+
destroyed = [];
56+
var pool = new Pool(
57+
function (release) { return new Resource(counter++, release) },
58+
function (resource) { destroyed.push(resource); },
59+
function (resource) { return true; },
60+
2 // maxIdle
61+
);
62+
63+
// When
64+
var r0 = pool.acquire();
65+
var r1 = pool.acquire();
66+
var r2 = pool.acquire();
67+
r0.close();
68+
r1.close();
69+
r2.close();
70+
71+
// Then
72+
expect( destroyed.length ).toBe( 1 );
73+
expect( destroyed[0].id ).toBe( r2.id );
74+
});
75+
76+
it('frees if validate returns false', function() {
77+
// Given a pool that allocates
78+
var counter = 0,
79+
destroyed = [];
80+
var pool = new Pool(
81+
function (release) { return new Resource(counter++, release) },
82+
function (resource) { destroyed.push(resource); },
83+
function (resource) { return false; },
84+
1000 // maxIdle
85+
);
86+
87+
// When
88+
var r0 = pool.acquire();
89+
var r1 = pool.acquire();
90+
r0.close();
91+
r1.close();
92+
93+
// Then
94+
expect( destroyed.length ).toBe( 2 );
95+
expect( destroyed[0].id ).toBe( r0.id );
96+
expect( destroyed[1].id ).toBe( r1.id );
97+
});
98+
});
99+
100+
function Resource( id, release ) {
101+
var self = this;
102+
this.id = id;
103+
this.close = function() { release(self); };
104+
}

test/v1/session.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ describe('session', function() {
194194
.then(function(result) {
195195
var sum = result.summary;
196196
expect(sum.notifications.length).toBeGreaterThan(0);
197-
expect(sum.notifications[0].code).toBe("Neo.ClientNotification.Statement.CartesianProduct");
197+
expect(sum.notifications[0].code).toBe("Neo.ClientNotification.Statement.CartesianProductWarning");
198198
expect(sum.notifications[0].title).toBe("This query builds a cartesian product between disconnected patterns.");
199199
expect(sum.notifications[0].position.column).toBeGreaterThan(0);
200200
done();

0 commit comments

Comments
 (0)