Merge connection pool cache feature

This commit is contained in:
Christopher Jones 2016-08-19 13:22:18 +10:00
parent db9ef8b5b0
commit 515f718f04
11 changed files with 464 additions and 93 deletions

View File

@ -53,6 +53,7 @@ limitations under the License.
- 3.3 [Oracledb Methods](#oracledbmethods)
- 3.3.1 [`createPool()`](#createpool)
- 3.3.2 [`getConnection()`](#getconnectiondb)
- 3.3.3 [`getPool()`](#getpool)
4. [Connection Class](#connectionclass)
- 4.1 [Connection Properties](#connectionproperties)
- 4.1.1 [`action`](#propconnaction)
@ -122,8 +123,9 @@ limitations under the License.
- 8.1.3 [JDBC and Node-oracledb Connection Strings Compared](#notjdbc)
- 8.2 [Connections and Number of Threads](#numberofthreads)
- 8.3 [Connection Pooling](#connpooling)
- 8.3.1 [Connection Pool Queue](#connpoolqueue)
- 8.3.2 [Connection Pool Monitoring and Throughput](#connpoolmonitor)
- 8.3.1 [Connection Pool Cache](#connpoolcache)
- 8.3.2 [Connection Pool Queue](#connpoolqueue)
- 8.3.3 [Connection Pool Monitoring and Throughput](#connpoolmonitor)
- 8.4 [Database Resident Connection Pooling (DRCP)](#drcp)
- 8.5 [External Authentication](#extauth)
9. [SQL Execution](#sqlexecution)
@ -885,7 +887,7 @@ console.log("Driver version number is " + oracledb.version);
##### Prototype
Callback (Asynchronous):
Callback:
```
createPool(Object poolAttrs, function(Error error, Pool pool){});
```
@ -906,11 +908,14 @@ for each Pool object.
The default properties may be overridden by specifying new properties
in the `poolAttrs` parameter.
A pool should be terminated with the [`Pool.close()`](#poolclose)
It is possible to add pools to the pool cache when calling `createPool()`.
See [Connection Pool Cache](#connpoolcache) for more details.
A pool should be terminated with the [`pool.close()`](#poolclose)
call, but only after all connections have been released.
##### Parameters
<a name="createpoolpoolattrs"></a>
```
Object poolAttrs
```
@ -977,6 +982,18 @@ The number of statements to be cached in the
This optional property overrides the *Oracledb*
[`stmtCacheSize`](#propdbstmtcachesize) property.
<a name="createpoolpoolattrspoolalias"></a>
```
String poolAlias
```
The `poolAlias` is an optional property that is used to explicitly add pools to the
connection pool cache. If a pool alias is provided, then the new pool will be added
to the connection pool cache and the `poolAlias` value can then be used with methods
that utilize the connection pool cache, such as [oracledb.getPool()](#getpool) and
[oracledb.getConnection()](#getconnectiondb).
See [Connection Pool Cache](#connpoolcache) for details and examples.
```
Number poolMax
@ -1055,30 +1072,48 @@ Callback function parameter | Description
##### Prototype
Callback (Asynchronous):
Callback:
```
getConnection(Object connAttrs, function(Error error, Connection conn){});
getConnection([String poolAlias | Object connAttrs], function(Error error, Connection conn){});
```
Promise:
```
promise = getConnection(Object connAttrs);
promise = getConnection([String poolAlias | Object connAttrs]);
```
##### Description
Obtains a connection directly from an *Oracledb* object.
Obtains a connection from a pool in the [connection pool cache](#connpoolcache) or creates a new,
non-pooled connection.
These connections are not pooled. For situations where connections
are used infrequently, this call may be more efficient than creating
and managing a connection pool. However, in most cases, Oracle
recommends getting new connections from a
[connection pool](#createpool).
For situations where connections are used infrequently, creating a new connection
may be more efficient than creating and managing a connection pool. However, in
most cases, Oracle recommends getting connections from a [connection pool](#createpool).
The following table shows the various signatures that can be used when invoking
`getConnection` and describes how the function will behave as a result.
Signature | Description
--------- | -----------
oracledb.getConnection() | Gets a connection from the default pool, returns a promise.
oracledb.getConnection(callback) | Gets a connection from the default pool, invokes the callback.
oracledb.getConnection(poolAlias) | Gets a connection from the pool with the specified `poolAlias`, returns a promise.
oracledb.getConnection(poolAlias, callback) | Gets a connection from the pool with the specified `poolAlias`, invokes the callback.
oracledb.getConnection(connAttrs) | Creates a standalone connection, returns a promise.
oracledb.getConnection(connAttrs, callback) | Creates a standalone connection, invokes the callback.
See [Connection Handling](#connectionhandling) for more information on
connections.
##### Parameters
```
String poolAlias
```
The `poolAlias` parameter is used to specify which pool in the connection pool
cache to use to obtain the connection.
```
Object connAttrs
```
@ -1154,6 +1189,28 @@ Callback function parameter | Description
*Error error* | If `getConnection()` succeeds, `error` is NULL. If an error occurs, then `error` contains the [error message](#errorobj).
*Connection connection* | The newly created connection. If `getConnection()` fails, `connection` will be NULL. See [Connection class](#connectionclass) for more details.
#### <a name="getpool"></a> 3.3.3 getPool()
##### Prototype
```
getPool([String poolAlias]);
```
##### Description
Retrieves a pool from the [connection pool cache](#connpoolcache). Note that this is a synchronous
method.
##### Parameters
```
String poolAlias
```
The pool alias of the pool to retrieve from the connection pool cache. The default
value is 'default' which will retrieve the default pool.
## <a name="connectionclass"></a> 4. Connection Class
A *Connection* object is obtained by a *Pool* class
@ -1234,7 +1291,7 @@ connection is created in the pool.
##### Prototype
Callback (Asynchronous):
Callback:
```
break(function(Error error){});
```
@ -1269,7 +1326,7 @@ Callback function parameter | Description
##### Prototype
Callback (Asynchronous):
Callback:
```
close(function(Error error){});
```
@ -1311,7 +1368,7 @@ Callback function parameter | Description
##### Prototype
Callback (Asynchronous):
Callback:
```
commit(function(Error error){});
```
@ -1340,7 +1397,7 @@ Callback function parameter | Description
##### Prototype
Callback (Asynchronous):
Callback:
```
execute(String sql, [Object bindParams, [Object options,]] function(Error error, [Object result]){});
```
@ -1676,13 +1733,13 @@ See [execute()](#execute).
#### <a name="release"></a> 4.2.6 release()
An alias for [Connection.close()](#connectionclose).
An alias for [connection.close()](#connectionclose).
#### <a name="rollback"></a> 4.2.7 rollback()
##### Prototype
Callback (Asynchronous):
Callback:
```
rollback(function(Error error){});
```
@ -1878,7 +1935,7 @@ The number of statements to be cached in the
##### Prototype
Callback (Asynchronous):
Callback:
```
close(function(Error error){});
```
@ -1891,8 +1948,10 @@ promise = close();
This call terminates the connection pool.
Any open connections should be released with [`Connection.close()`](#connectionclose)
before `Pool.close()` is called.
Any open connections should be released with [`connection.close()`](#connectionclose)
before `pool.close()` is called.
If the pool was cached in the [connection pool cache](#connpoolcache) it will be removed automatically.
##### Parameters
@ -1911,7 +1970,7 @@ Callback function parameter | Description
##### Prototype
Callback (Asynchronous):
Callback:
```
getConnection(function(Error error, Connection conn){});
```
@ -1949,7 +2008,7 @@ Callback function parameter | Description
#### <a name="terminate"></a> 6.2.3 terminate()
An alias for [Pool.close()](#poolclose).
An alias for [pool.close()](#poolclose).
## <a name="resultsetclass"></a> 7. ResultSet Class
@ -1999,7 +2058,7 @@ See [`result.metaData`](#execmetadata) for the available attributes.
##### Prototype
Callback (Asynchronous):
Callback:
```
close(function(Error error){});
```
@ -2017,7 +2076,7 @@ of fetch or when no more rows are needed.
##### Prototype
Callback (Asynchronous):
Callback:
```
getRow(function(Error error, Object row){});
```
@ -2036,7 +2095,7 @@ At the end of fetching, the `ResultSet` should be freed by calling [`close()`](#
##### Prototype
Callback (Asynchronous):
Callback:
```
getRows(Number numRows, function(Error error, Array rows){});
```
@ -2098,7 +2157,7 @@ oracledb.getConnection(
});
```
Connections should be released with [`Connection.close()`](#connectionclose) when no
Connections should be released with [`connection.close()`](#connectionclose) when no
longer needed:
```javascript
@ -2327,7 +2386,7 @@ oracledb.createPool (
});
```
Connections should be released with [`Connection.close()`](#connectionclose) when no
Connections should be released with [`connection.close()`](#connectionclose) when no
longer needed:
```javascript
@ -2340,7 +2399,7 @@ longer needed:
After an application finishes using a connection pool, it should
release all connections and terminate the connection pool by calling
the [`Pool.close()`](#poolclose) method.
the [`pool.close()`](#poolclose) method.
The growth characteristics of a connection pool are determined by the
Pool attributes [`poolIncrement`](#proppoolpoolincrement),
@ -2353,7 +2412,125 @@ The Pool attribute [`stmtCacheSize`](#propconnstmtcachesize) can be
used to set the statement cache size used by connections in the pool,
see [Statement Caching](#stmtcache).
#### <a name="connpoolqueue"></a> 8.3.1 Connection Pool Queue
#### <a name="connpoolcache"></a> 8.3.1 Connection Pool Cache
Node-oracledb has an internal connection pool cache which can be used to
facilitate sharing pools across modules and simplify getting connections from
pools in the cache.
Methods that can affect or use the connection pool cache include:
- [oracledb.createPool()](#createpool) - can add a pool to the cache
- [oracledb.getPool()](#getpool) - retrieves a pool from the cache (synchronous)
- [oracledb.getConnection()](#getconnectiondb) - can use a pool in the cache to retrieve connections
- [pool.close()](#closepool) - automatically removes the pool from the cache if needed
Pools are added to the cache if a [`poolAlias`](#createpoolpoolattrspoolalias)
property is provided in the [`poolAttrs`](#createpoolpoolattrs) object when
invoking `oracledb.createPool()`. If a pool with the alias 'default' is not in the
cache and a pool is created without providing a pool alias, that pool will be cached
using the pool alias 'default'. The pool with this pool alias is used by default in
methods that utilize the connection pool cache.
There can be multiple pools in the cache provided each pool is created with
a unique pool alias.
##### Examples using the default pool
Assuming the connection pool cache is empty, the following will create a new pool
and cache it using the pool alias 'default':
```javascript
var oracledb = require('oracledb');
oracledb.createPool (
{
user: 'hr',
password: 'welcome',
connectString: 'localhost/XE'
},
function(err, pool) {
console.log(pool.poolAlias); // default
}
);
```
Once cached, the default pool can be retrieved using `oracledb.getPool()` without
passing the `poolAlias` parameter:
```javascript
var oracledb = require('oracledb');
var pool = oracledb.getPool();
pool.getConnection(function(err, conn) {
// Use connection
});
```
If the pool is being retrieved only to call `pool.getConnection`, then the shortcut
`oracledb.getConnection` may be used instead:
```javascript
var oracledb = require('oracledb');
oracledb.getConnection(function(err, conn) {
// Use connection
});
```
##### Examples using multiple pools
If the application needs to use more than one pool at a time, unique pool aliases
can be used when creating the pools:
```javascript
var oracledb = require('oracledb');
var hrPoolPromise = oracledb.createPool({
poolAlias: 'pool1',
users: 'hr',
password: 'welcome',
connectString: 'localhost/XE'
});
var shPoolPromise = oracledb.createPool({
poolAlias: 'pool2',
user: 'sh',
password: 'welcome',
connectString: 'localhost/XE'
});
Promise.all([hrPoolPromise, shPoolPromise])
.then(function(pools) {
console.log(pools[0].poolAlias); // pool1
console.log(pools[1].poolAlias); // pool2
})
.catch(function(err) {
// handle error
})
```
To use the methods or attributes of a pool in the cache, a pool can be retrieved
from the cache by passing its pool alias to `oracledb.getPool()`:
```javascript
var oracledb = require('oracledb');
var pool = oracledb.getPool('pool1'); // or 'pool2'
pool.getConnection(function(err, conn) {
// Use connection
});
```
The `oracledb.getConnection` shortcut can also be used with a pool alias:
```javascript
var oracledb = require('oracledb');
oracledb.getConnection('pool1', function(err, conn) { // or 'pool2'
// Use connection
});
```
#### <a name="connpoolqueue"></a> 8.3.2 Connection Pool Queue
By default when `poolMax` has been reached (meaning all connections in
a pool are in use), and more
@ -2380,7 +2557,7 @@ connection is [released](#connectionclose), and the number of
connections in use drops below the value of
[`poolMax`](#proppoolpoolmax).
#### <a name="connpoolmonitor"></a> 8.3.2 Connection Pool Monitoring and Throughput
#### <a name="connpoolmonitor"></a> 8.3.3 Connection Pool Monitoring and Throughput
Connection pool usage should be monitored to choose the appropriate
connection pool settings for your workload.
@ -2430,17 +2607,17 @@ The statistics displayed by `_logStats()` in this release are:
Statistic | Description
--------------------------|-------------
total up time | The number of milliseconds this pool has been running.
total connection requests | Number of `Pool.getConnection()` requests made by the application to this pool.
total requests enqueued | Number of `Pool.getConnection()` requests that could not be immediately satisfied because every connection in this pool was already being used, and so they had to be queued waiting for the application to return an in-use connection to the pool.
total requests dequeued | Number of `Pool.getConnection()` requests that were dequeued when a connection in this pool became available for use.
total requests failed | Number of `Pool.getConnection()` requests that invoked the underlying C++ `Pool.getConnection()` callback with an error state. Does not include queue request timeout errors.
total request timeouts | Number of queued `Pool.getConnection()` requests that were timed out after they had spent [queueTimeout](#propdbqueuetimeout) or longer in this pool's queue.
max queue length | Maximum number of `Pool.getConnection()` requests that were ever waiting at one time.
total connection requests | Number of `pool.getConnection()` requests made by the application to this pool.
total requests enqueued | Number of `pool.getConnection()` requests that could not be immediately satisfied because every connection in this pool was already being used, and so they had to be queued waiting for the application to return an in-use connection to the pool.
total requests dequeued | Number of `pool.getConnection()` requests that were dequeued when a connection in this pool became available for use.
total requests failed | Number of `pool.getConnection()` requests that invoked the underlying C++ `pool.getConnection()` callback with an error state. Does not include queue request timeout errors.
total request timeouts | Number of queued `pool.getConnection()` requests that were timed out after they had spent [queueTimeout](#propdbqueuetimeout) or longer in this pool's queue.
max queue length | Maximum number of `pool.getConnection()` requests that were ever waiting at one time.
sum of time in queue | The sum of the time (milliseconds) that dequeued requests spent in the queue.
min time in queue | The minimum time (milliseconds) that any dequeued request spent in the queue.
max time in queue | The maximum time (milliseconds) that any dequeued request spent in the queue.
avg time in queue | The average time (milliseconds) that dequeued requests spent in the queue.
pool connections in use | The number of connections from this pool that `Pool.getConnection()` returned successfully to the application and have not yet been released back to the pool.
pool connections in use | The number of connections from this pool that `pool.getConnection()` returned successfully to the application and have not yet been released back to the pool.
pool connections open | The number of connections in this pool that have been established to the database.
Note that for efficiency, the minimum, maximum, average, and sum of
@ -2452,15 +2629,16 @@ still waiting in the queue.
The `_logStats()` method also shows attribute values in effect for the pool:
Attribute |
----------------------------------------|
[`queueRequests`](#propdbqueuerequests) |
[`queueTimeout`](#propdbqueuetimeout) |
[`poolMin`](#propdbpoolmin) |
[`poolMax`](#propdbpoolmax) |
[`poolIncrement`](#propdbpoolincrement) |
[`poolTimeout`](#propdbpooltimeout) |
[`stmtCacheSize`](#propdbstmtcachesize) |
Attribute |
--------------------------------------------|
[`poolAlias`](#createpoolpoolattrspoolalias)|
[`queueRequests`](#propdbqueuerequests) |
[`queueTimeout`](#propdbqueuetimeout) |
[`poolMin`](#propdbpoolmin) |
[`poolMax`](#propdbpoolmax) |
[`poolIncrement`](#propdbpoolincrement) |
[`poolTimeout`](#propdbpooltimeout) |
[`stmtCacheSize`](#propdbstmtcachesize) |
##### Related Environment Variables
@ -2568,7 +2746,7 @@ A SQL or PL/SQL statement may be executed using the *Connection*
below, or [promises](#promiseoverview) may be used.
After all database calls on the connection complete, the application
should use the [`Connection.close()`](#connectionclose) call to
should use the [`connection.close()`](#connectionclose) call to
release the connection.
Queries may optionally be streamed using the *Connection*

View File

@ -159,9 +159,7 @@ function rollback(rollbackCb) {
rollbackPromisified = nodbUtil.promisify(rollback);
// This release function is used to override the release method of the Connection
// class, which is defined in the C layer. Currently the main difference is that
// connections obtained from a pool need to invoke the pool's _onConnectionRelease
// method so the pool can dequeue the next connection request.
// class, which is defined in the C layer.
function release(releaseCb) {
var self = this;
@ -169,13 +167,11 @@ function release(releaseCb) {
nodbUtil.assert(typeof releaseCb === 'function', 'NJS-006', 1);
self._release(function(err) {
releaseCb(err);
// pool will only exist for connections obtained from a pool.
if (self._pool && self._pool.queueRequests !== false) {
self._pool._onConnectionRelease();
if (!err) {
self.emit('_after_close');
}
releaseCb(err);
});
}
@ -198,6 +194,8 @@ breakPromisified = nodbUtil.promisify(module.break);
// custom properties and method overrides. References to the original methods are
// maintained so they can be invoked by the overriding method at the right time.
function extend(conn, oracledb, pool) {
nodbUtil.makeEventEmitter(conn);
// Using Object.defineProperties to add properties to the Connection instance with
// special properties, such as enumerable but not writable.
Object.defineProperties(
@ -206,7 +204,7 @@ function extend(conn, oracledb, pool) {
_oracledb: { // storing a reference to the base instance to avoid circular references with require
value: oracledb
},
_pool: {
_pool: { // storing a reference to the pool, if any, from which the connection was obtained
value: pool
},
_execute: {

View File

@ -27,6 +27,9 @@ var connection = require('./connection.js');
var nodbUtil = require('./util.js');
var createPoolPromisified;
var getConnectionPromisified;
var poolCache = {};
var tempUsedPoolAliases = {};
var defaultPoolAlias = 'default';
try {
oracledbCLib = require('../build/Release/oracledb');
@ -55,18 +58,70 @@ oracledbCLib.Oracledb.prototype.newLob = function(iLob) {
// things like extend out the pool instance prior to passing it to the caller.
function createPool(poolAttrs, createPoolCb) {
var self = this;
var poolAlias;
// Initial argument count and type checks are done first and throw in the same
// call stack.
nodbUtil.assert(arguments.length === 2, 'NJS-009');
nodbUtil.assert(nodbUtil.isObject(poolAttrs), 'NJS-006', 1);
nodbUtil.assert(typeof createPoolCb === 'function', 'NJS-006', 2);
self._createPool(poolAttrs, function(err, poolInst) {
if (err) {
createPoolCb(err);
// Additional validations should pass errors via the callback. Need to ensure
// that errors are raised prior to actually creating the pool via _createPool.
if (poolAttrs.poolAlias !== undefined) {
if (typeof poolAttrs.poolAlias !== 'string' || poolAttrs.poolAlias.length === 0) {
createPoolCb(new Error(nodbUtil.getErrorMessage('NJS-004', 'poolAttrs.poolAlias')));
return;
}
pool.extend(poolInst, poolAttrs, self);
poolAlias = poolAttrs.poolAlias;
} else if (poolAttrs.poolAlias === undefined
&& !poolCache[defaultPoolAlias]
&& !tempUsedPoolAliases[defaultPoolAlias]
) {
poolAlias = defaultPoolAlias;
}
if (poolCache[poolAlias] || tempUsedPoolAliases[poolAlias]) {
createPoolCb(new Error(nodbUtil.getErrorMessage('NJS-046', poolAlias)));
return;
}
// Need to prevent another call in the same stack from succeeding, otherwise
// two pools could be created with the same poolAlias and the second one that
// comes back would overwrite the first in the cache.
if (poolAlias) {
tempUsedPoolAliases[poolAlias] = true;
}
self._createPool(poolAttrs, function(err, poolInst) {
if (err) {
// We need to free this up since the creation of the pool failed.
if (poolAlias) {
delete tempUsedPoolAliases[poolAlias];
}
createPoolCb(err);
return;
}
if (poolAlias) {
poolCache[poolAlias] = poolInst;
// It's now safe to remove this alias from the tempUsedPoolAliases.
delete tempUsedPoolAliases[poolAlias];
}
pool.extend(poolInst, poolAttrs, poolAlias, self);
poolInst.on('_after_close', function() {
var pool = this;
if (pool.poolAlias) {
delete poolCache[pool.poolAlias];
}
});
createPoolCb(null, poolInst);
});
@ -74,26 +129,92 @@ function createPool(poolAttrs, createPoolCb) {
createPoolPromisified = nodbUtil.promisify(createPool);
// The getPool function is a synchronous method used to retrieve pools from the
// pool cache.
function getPool(poolAlias) {
var pool;
nodbUtil.assert(arguments.length < 2, 'NJS-009');
if (poolAlias) {
nodbUtil.assert(typeof poolAlias === 'string' || typeof poolAlias === 'number', 'NJS-006', 1);
}
poolAlias = poolAlias || defaultPoolAlias;
pool = poolCache[poolAlias];
if (!pool) {
throw new Error(nodbUtil.getErrorMessage('NJS-047', poolAlias));
}
return pool;
}
// This getConnection function is used the override the getConnection method of the
// Oracledb class, which is defined in the C layer. The override allows us to do
// things like extend out the connection instance prior to passing it to the caller.
function getConnection(connAttrs, createConnectionCb) {
function getConnection(a1, a2) {
var self = this;
var pool;
var poolAlias;
var connAttrs;
var getConnectionCb;
nodbUtil.assert(arguments.length === 2, 'NJS-009');
nodbUtil.assert(nodbUtil.isObject(connAttrs), 'NJS-006', 1);
nodbUtil.assert(typeof createConnectionCb === 'function', 'NJS-006', 2);
nodbUtil.assert(arguments.length < 3, 'NJS-009');
self._getConnection(connAttrs, function(err, connInst) {
if (err) {
createConnectionCb(err);
// Verify the number and types of arguments, then initialize the local poolAlias,
// connAttrs, and getConnectionCb variables based on the arguments.
switch (arguments.length) {
case 1:
nodbUtil.assert(typeof a1 === 'function', 'NJS-006', 1);
poolAlias = defaultPoolAlias;
getConnectionCb = a1;
break;
case 2:
nodbUtil.assert(typeof a1 === 'string' || nodbUtil.isObject(a1), 'NJS-006', 1);
nodbUtil.assert(typeof a2 === 'function', 'NJS-006', 2);
if (typeof a1 === 'string') {
poolAlias = a1;
} else if (nodbUtil.isObject(a1)) {
connAttrs = a1;
if (connAttrs.poolAlias) {
poolAlias = connAttrs.poolAlias;
}
}
getConnectionCb = a2;
break;
}
// Proceed to execution based on values in local variables. Look for the poolAlias
// first and only attempt to use connAttrs if the poolAlias isn't set.
if (poolAlias) {
pool = poolCache[poolAlias];
if (!pool) {
getConnectionCb(new Error(nodbUtil.getErrorMessage('NJS-047', poolAlias)));
return;
}
connection.extend(connInst, self);
pool.getConnection(getConnectionCb);
} else {
self._getConnection(connAttrs, function(err, connInst) {
if (err) {
getConnectionCb(err);
return;
}
createConnectionCb(null, connInst);
});
connection.extend(connInst, self);
getConnectionCb(null, connInst);
});
}
}
getConnectionPromisified = nodbUtil.promisify(getConnection);
@ -258,6 +379,11 @@ function extend(oracledb) {
enumerable: true,
writable: true
},
getPool: {
value: getPool,
enumerable: true,
writable: true
},
_getConnection: {
value: oracledb.getConnection
},

View File

@ -55,6 +55,12 @@ function completeConnectionRequest(getConnectionCb) {
connection.extend(connInst, self._oracledb, self);
connInst.on('_after_close', function() {
self._connectionsOut -= 1;
checkRequestQueue.call(self);
});
getConnectionCb(null, connInst);
});
}
@ -95,16 +101,6 @@ function checkRequestQueue() {
completeConnectionRequest.call(self, payload.getConnectionCb);
}
// onConnectionRelease contains the logic that should be executed when a connection
// that was obtained from a pool is released back to the pool.
function onConnectionRelease() {
var self = this;
self._connectionsOut -= 1;
checkRequestQueue.call(self);
}
// onRequestTimeout is used to prevent requests for connections from sitting in the
// queue for too long. The number of milliseconds can be set via queueTimeout
// property of the poolAttrs used when creating a pool.
@ -219,6 +215,8 @@ function terminate(terminateCb) {
self._terminate(function(err) {
if (!err) {
self._isValid = false;
self.emit('_after_close', self);
}
terminateCb(err);
@ -265,6 +263,7 @@ function logStats() {
console.log('...pool connections in use:', self.connectionsInUse);
console.log('...pool connections open:', self.connectionsOpen);
console.log('Related pool attributes:');
console.log('...poolAlias:', self.poolAlias);
console.log('...queueRequests:', self.queueRequests);
console.log('...queueTimeout (milliseconds):', self.queueTimeout);
console.log('...poolMin:', self.poolMin);
@ -279,7 +278,7 @@ function logStats() {
// The extend method is used to extend Pool instances from the C layer with custom
// properties, methods, and method overrides. References to the original methods are
// maintained so they can be invoked by the overriding method at the right time.
function extend(pool, poolAttrs, oracledb) {
function extend(pool, poolAttrs, poolAlias, oracledb) {
var queueRequests;
var queueTimeout;
@ -295,6 +294,8 @@ function extend(pool, poolAttrs, oracledb) {
queueTimeout = oracledb.queueTimeout;
}
nodbUtil.makeEventEmitter(pool);
// Using Object.defineProperties to add properties to the Pool instance with special
// properties, such as enumerable but not writable.
Object.defineProperties(
@ -389,12 +390,18 @@ function extend(pool, poolAttrs, oracledb) {
value: {},
writable: true
},
_onConnectionRelease: {
value: onConnectionRelease
},
_getConnection: {
value: pool.getConnection
},
poolAlias: {
enumerable: true,
get: function() {
return poolAlias;
},
set: function() {
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'poolAlias'));
}
},
getConnection: {
value: getConnectionPromisified,
enumerable: true,

View File

@ -19,10 +19,17 @@
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var eventEmitterKeys = Object.keys(EventEmitter.prototype);
var eventEmitterFuncKeys = eventEmitterKeys.filter(function(key) {
return typeof EventEmitter.prototype[key] === 'function';
});
// errorMessages is a temporary duplication of error messages defined in the C
// layer that will be removed once a function to fetch from the C layer is added.
var errorMessages = {
'NJS-002': 'NJS-002: invalid pool',
'NJS-004': 'NJS-004: invalid value for property %s',
'NJS-005': 'NJS-005: invalid value for parameter %d',
'NJS-006': 'NJS-006: invalid type for parameter %d',
'NJS-009': 'NJS-009: invalid number of parameters',
@ -31,10 +38,26 @@ var errorMessages = {
'NJS-040': 'NJS-040: connection request timeout',
'NJS-041': 'NJS-041: cannot convert ResultSet to QueryStream after invoking methods',
'NJS-042': 'NJS-042: cannot invoke ResultSet methods after converting to QueryStream',
'NJS-043': "NJS-043: ResultSet already converted to QueryStream",
'NJS-045': "NJS-045: cannot load the oracledb add-on binary"
'NJS-043': 'NJS-043: ResultSet already converted to QueryStream',
'NJS-045': 'NJS-045: cannot load the oracledb add-on binary',
'NJS-046': 'NJS-046: poolAlias "%s" already exists in the connection pool cache',
'NJS-047': 'NJS-047: poolAlias "%s" not found in the connection pool cache'
};
// makeEventEmitter is used to make class instances inherit from the EventEmitter
// class. This is needed because we extend instances from the C layer and thus
// don't have JavaScript constructor functions we can use for more traditional
// inheritance.
function makeEventEmitter(instance){
eventEmitterFuncKeys.forEach(function(key) {
instance[key] = EventEmitter.prototype[key];
});
EventEmitter.call(instance);
}
module.exports.makeEventEmitter = makeEventEmitter;
// getErrorMessage is used to get and format error messages to make throwing errors
// a little more convenient.
function getErrorMessage(errorCode, messageArg1) {

View File

@ -82,6 +82,8 @@ static const char *errMsg[] =
"NJS-043: ResultSet already converted to QueryStream", // errResultSetAlreadyConverted
"NJS-044: named JSON object is not expected in this context", // errNamedJSON
"NJS-045: cannot load the oracledb add-on binary", // errCannotLoadBinary
"NJS-046: pool alias \"%s\" already exists in the connection pool cache", // errPoolWithAliasAlreadyExists
"NJS-047: pool alias \"%s\" not found in connection pool cache", // errPoolWithAliasNotFound
};
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )

View File

@ -81,6 +81,8 @@ typedef enum
errResultSetAlreadyConverted,
errNamedJSON,
errCannotLoadBinary,
errPoolWithAliasAlreadyExists,
errPoolWithAliasNotFound,
// New ones should be added here

View File

@ -797,7 +797,29 @@ Overview of node-oracledb functional tests
66.3 allows overwriting of public methods on resultset instances
66.4 allows overwriting of public methods on lob instances
67. poolCache.js
67.1 basic functional tests
67.1.1 caches pool as default if pool is created when cache is empty
67.1.2 removes the pool from the cache on terminate
67.1.3 can cache and retrieve an aliased pool
67.1.4 throws an error if the poolAlias already exists in the cache
67.1.5 does not throw an error if multiple pools are created without an alias
67.1.6 throws an error if poolAttrs.poolAlias is not a string or number
67.1.7 makes poolAttrs.poolAlias a read-only attribute on the pool named alias
67.1.8 retrieves the default pool, even after an aliased pool is created
67.1.9 retrieves the right pool, even after multiple pools are created
67.1.10 throws an error if the pool specified in getPool doesn't exist
67.1.11 does not throw an error if multiple pools are created without a poolAlias in the same call stack
67.2 oracledb.getConnection functional tests
67.2.1 gets a connection from the default pool, returns a promise
67.2.2 gets a connection from the default pool, invokes the callback
67.2.3 gets a connection from the pool with the specified alias, returns a promise
67.2.4 gets a connection from the pool with the specified alias, invokes the callback
67.2.5 throws an error if an attempt is made to use the default pool when it does not exist
67.2.6 throws an error if an attempt is made to use a poolAlias for a pool that is not in the cache
67.2.7 gets a connection from the default pool, even after an aliased pool is created
67.2.8 uses the right pool, even after multiple pools are created
68. multipleLobInsertion.js
68.1 inserts multiple BLOBs
68.2 inserts multiple CLOBs
68.2 inserts multiple CLOBs

View File

@ -68,4 +68,5 @@ test/autoCommit4nestedExecutes.js
test/sqlWithWarnings.js
test/uninitializedLob.js
test/writableProperties.js
test/multipleLobInsertion.js
test/poolCache.js
test/multipleLobInsertion.js

View File

@ -60,7 +60,13 @@ describe('53. poolValidityAfterFailingTernimate.js', function() {
should.not.exist(err);
// console.log("Open connections: " + pool.connectionsOpen);
done();
// Still need to clean up the pool from this test.
pool.terminate(function(err) {
should.not.exist(err);
done();
});
});
}
);

View File

@ -56,7 +56,13 @@ describe('54. releaseAfterFailingTerminate.js', function() {
connection.release( function(err){
should.not.exist(err);
done();
// Still need to clean up the pool from this test.
pool.terminate(function(err) {
should.not.exist(err);
done();
});
});
}
);