neo4j-driver-core
Version:
Internals of neo4j-driver
673 lines (672 loc) • 35.5 kB
JavaScript
"use strict";
/**
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [https://neo4j.com]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var pool_config_1 = __importDefault(require("./pool-config"));
var error_1 = require("../../error");
var logger_1 = require("../logger");
var Pool = /** @class */ (function () {
/**
* @param {function(acquisitionContext: object, address: ServerAddress, function(address: ServerAddress, resource: object): Promise<object>): Promise<object>} create
* an allocation function that creates a promise with a new resource. It's given an address for which to
* allocate the connection and a function that will return the resource to the pool if invoked, which is
* meant to be called on .dispose or .close or whatever mechanism the resource uses to finalize.
* @param {function(acquisitionContext: object, resource: object): boolean} validateOnAcquire
* called at various times when an instance is acquired
* If this returns false, the resource will be evicted
* @param {function(resource: object): boolean} validateOnRelease
* called at various times when an instance is released
* If this returns false, the resource will be evicted
* @param {function(resource: object): Promise<void>} destroy
* called with the resource when it is evicted from this pool
* @param {function(resource: object, observer: { onError }): void} installIdleObserver
* called when the resource is released back to pool
* @param {function(resource: object): void} removeIdleObserver
* called when the resource is acquired from the pool
* @param {PoolConfig} config configuration for the new driver.
* @param {Logger} log the driver logger.
*/
function Pool(_a) {
var _b = _a.create, create = _b === void 0 ? function (acquisitionContext, address, release) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.reject(new Error('Not implemented'))];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); } : _b, _c = _a.destroy, destroy = _c === void 0 ? function (conn) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, Promise.resolve()];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); } : _c, _d = _a.validateOnAcquire, validateOnAcquire = _d === void 0 ? function (acquisitionContext, conn) { return true; } : _d, _e = _a.validateOnRelease, validateOnRelease = _e === void 0 ? function (conn) { return true; } : _e, _f = _a.installIdleObserver, installIdleObserver = _f === void 0 ? function (conn, observer) { } : _f, _g = _a.removeIdleObserver, removeIdleObserver = _g === void 0 ? function (conn) { } : _g, _h = _a.config, config = _h === void 0 ? pool_config_1.default.defaultConfig() : _h, _j = _a.log, log = _j === void 0 ? logger_1.Logger.noOp() : _j;
var _this = this;
this._create = create;
this._destroy = destroy;
this._validateOnAcquire = validateOnAcquire;
this._validateOnRelease = validateOnRelease;
this._installIdleObserver = installIdleObserver;
this._removeIdleObserver = removeIdleObserver;
this._maxSize = config.maxSize;
this._acquisitionTimeout = config.acquisitionTimeout;
this._pools = {};
this._pendingCreates = {};
this._acquireRequests = {};
this._activeResourceCounts = {};
this._release = this._release.bind(this);
this._log = log;
this._closed = false;
}
/**
* Acquire and idle resource fom the pool or create a new one.
* @param {object} acquisitionContext the acquisition context used for create and validateOnAcquire connection
* @param {ServerAddress} address the address for which we're acquiring.
* @param {object} config the config
* @param {boolean} config.requireNew Indicate it requires a new resource
* @return {Promise<Object>} resource that is ready to use.
*/
Pool.prototype.acquire = function (acquisitionContext, address, config) {
return __awaiter(this, void 0, void 0, function () {
var key, allRequests, requests, elapsedTime;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
key = address.asKey();
allRequests = this._acquireRequests;
requests = allRequests[key];
elapsedTime = (acquisitionContext.startTime != null && acquisitionContext.startTime !== 0) ? new Date().getTime() - acquisitionContext.startTime : 0;
if (elapsedTime >= this._acquisitionTimeout) {
throw this.getAcquisitionTimeoutError(address);
}
if (requests == null) {
allRequests[key] = [];
}
return [4 /*yield*/, new Promise(function (resolve, reject) {
var timeoutId = setTimeout(function () {
// acquisition timeout fired
// remove request from the queue of pending requests, if it's still there
// request might've been taken out by the release operation
var pendingRequests = allRequests[key];
if (pendingRequests != null) {
allRequests[key] = pendingRequests.filter(function (item) { return item !== request; });
}
if (request.isCompleted()) {
// request already resolved/rejected by the release operation; nothing to do
}
else {
// request is still pending and needs to be failed
request.reject(_this.getAcquisitionTimeoutError(address));
}
}, _this._acquisitionTimeout - elapsedTime);
if (typeof timeoutId === 'object') {
// eslint-disable-next-line
// @ts-ignore
timeoutId.unref();
}
var request = new PendingRequest(key, acquisitionContext, config, resolve, reject, timeoutId, _this._log);
allRequests[key].push(request);
_this._processPendingAcquireRequests(address);
})];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
Pool.prototype.getAcquisitionTimeoutError = function (address) {
var key = address.asKey();
var activeCount = this.activeResourceCount(address);
var idleCount = this.has(address) ? this._pools[key].length : 0;
return (0, error_1.newError)("Connection acquisition timed out in ".concat(this._acquisitionTimeout, " ms. Pool status: Active conn count = ").concat(activeCount, ", Idle conn count = ").concat(idleCount, "."));
};
/**
* Destroy all idle resources for the given address.
* @param {ServerAddress} address the address of the server to purge its pool.
* @returns {Promise<void>} A promise that is resolved when the resources are purged
*/
Pool.prototype.purge = function (address) {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._purgeKey(address.asKey())];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
Pool.prototype.apply = function (address, resourceConsumer) {
var key = address.asKey();
if (key in this._pools) {
this._pools[key].apply(resourceConsumer);
}
};
/**
* Destroy all idle resources in this pool.
* @returns {Promise<void>} A promise that is resolved when the resources are purged
*/
Pool.prototype.close = function () {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
this._closed = true;
return [4 /*yield*/, Promise.all(Object.keys(this._pools).map(function (key) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._purgeKey(key)];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); })).then()];
case 1:
/**
* The lack of Promise consuming was making the driver do not close properly in the scenario
* captured at result.test.js:it('should handle missing onCompleted'). The test was timing out
* because while waiting for the driver close.
*
* Consuming the Promise.all or by calling then or by awaiting in the result inside this method solved
* the issue somehow.
*
* PS: the return of this method was already awaited at PooledConnectionProvider.close, but the await bellow
* seems to be need also.
*/
return [2 /*return*/, _a.sent()];
}
});
});
};
/**
* Keep the idle resources for the provided addresses and purge the rest.
* @returns {Promise<void>} A promise that is resolved when the other resources are purged
*/
Pool.prototype.keepAll = function (addresses) {
return __awaiter(this, void 0, void 0, function () {
var keysToKeep, keysPresent, keysToPurge;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
keysToKeep = addresses.map(function (a) { return a.asKey(); });
keysPresent = Object.keys(this._pools);
keysToPurge = keysPresent.filter(function (k) { return !keysToKeep.includes(k); });
return [4 /*yield*/, Promise.all(keysToPurge.map(function (key) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._purgeKey(key)];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); })).then()];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
/**
* Check if this pool contains resources for the given address.
* @param {ServerAddress} address the address of the server to check.
* @return {boolean} `true` when pool contains entries for the given key, <code>false</code> otherwise.
*/
Pool.prototype.has = function (address) {
return address.asKey() in this._pools;
};
/**
* Get count of active (checked out of the pool) resources for the given key.
* @param {ServerAddress} address the address of the server to check.
* @return {number} count of resources acquired by clients.
*/
Pool.prototype.activeResourceCount = function (address) {
var _a;
return (_a = this._activeResourceCounts[address.asKey()]) !== null && _a !== void 0 ? _a : 0;
};
Pool.prototype._getOrInitializePoolFor = function (key) {
var pool = this._pools[key];
if (pool == null) {
pool = new SingleAddressPool();
this._pools[key] = pool;
this._pendingCreates[key] = 0;
}
return pool;
};
Pool.prototype._acquire = function (acquisitionContext, address, requireNew) {
return __awaiter(this, void 0, void 0, function () {
var key, pool, resource_1, valid, e_1, numConnections, resource, numConnections, resource_2;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (this._closed) {
throw (0, error_1.newError)('Pool is closed, it is no more able to serve requests.');
}
key = address.asKey();
pool = this._getOrInitializePoolFor(key);
if (!!requireNew) return [3 /*break*/, 10];
_a.label = 1;
case 1:
if (!(pool.length > 0)) return [3 /*break*/, 10];
resource_1 = pool.pop();
if (resource_1 == null) {
return [3 /*break*/, 1];
}
resourceAcquired(key, this._activeResourceCounts);
if (this._removeIdleObserver != null) {
this._removeIdleObserver(resource_1);
}
valid = false;
_a.label = 2;
case 2:
_a.trys.push([2, 4, , 6]);
return [4 /*yield*/, this._validateOnAcquire(acquisitionContext, resource_1)];
case 3:
valid = _a.sent();
return [3 /*break*/, 6];
case 4:
e_1 = _a.sent();
resourceReleased(key, this._activeResourceCounts);
pool.removeInUse(resource_1);
return [4 /*yield*/, this._destroy(resource_1)];
case 5:
_a.sent();
throw e_1;
case 6:
if (!valid) return [3 /*break*/, 7];
// idle resource is valid and can be acquired
if (this._log.isDebugEnabled()) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this._log.debug("".concat(resource_1, " acquired from the pool ").concat(key));
}
return [2 /*return*/, { resource: resource_1, pool: pool }];
case 7:
resourceReleased(key, this._activeResourceCounts);
pool.removeInUse(resource_1);
return [4 /*yield*/, this._destroy(resource_1)];
case 8:
_a.sent();
_a.label = 9;
case 9: return [3 /*break*/, 1];
case 10:
// Ensure requested max pool size
if (this._maxSize > 0) {
numConnections = this.activeResourceCount(address) + this._pendingCreates[key];
if (numConnections >= this._maxSize) {
// Will put this request in queue instead since the pool is full
return [2 /*return*/, { resource: null, pool: pool }];
}
}
// there exist no idle valid resources, create a new one for acquisition
// Keep track of how many pending creates there are to avoid making too many connections.
this._pendingCreates[key] = this._pendingCreates[key] + 1;
_a.label = 11;
case 11:
_a.trys.push([11, , 15, 16]);
numConnections = this.activeResourceCount(address) + pool.length;
if (!(numConnections >= this._maxSize && requireNew)) return [3 /*break*/, 13];
resource_2 = pool.pop();
if (!(resource_2 != null)) return [3 /*break*/, 13];
if (this._removeIdleObserver != null) {
this._removeIdleObserver(resource_2);
}
pool.removeInUse(resource_2);
return [4 /*yield*/, this._destroy(resource_2)];
case 12:
_a.sent();
_a.label = 13;
case 13: return [4 /*yield*/, this._create(acquisitionContext, address, function (address, resource) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this._release(address, resource, pool)];
case 1: return [2 /*return*/, _a.sent()];
}
}); }); })];
case 14:
// Invoke callback that creates actual connection
resource = _a.sent();
pool.pushInUse(resource);
resourceAcquired(key, this._activeResourceCounts);
if (this._log.isDebugEnabled()) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this._log.debug("".concat(resource, " created for the pool ").concat(key));
}
return [3 /*break*/, 16];
case 15:
this._pendingCreates[key] = this._pendingCreates[key] - 1;
return [7 /*endfinally*/];
case 16: return [2 /*return*/, { resource: resource, pool: pool }];
}
});
});
};
Pool.prototype._release = function (address, resource, pool) {
return __awaiter(this, void 0, void 0, function () {
var key;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
key = address.asKey();
_a.label = 1;
case 1:
_a.trys.push([1, , 9, 10]);
if (!pool.isActive()) return [3 /*break*/, 6];
return [4 /*yield*/, this._validateOnRelease(resource)];
case 2:
if (!!(_a.sent())) return [3 /*break*/, 4];
if (this._log.isDebugEnabled()) {
this._log.debug(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
"".concat(resource, " destroyed and can't be released to the pool ").concat(key, " because it is not functional"));
}
pool.removeInUse(resource);
return [4 /*yield*/, this._destroy(resource)];
case 3:
_a.sent();
return [3 /*break*/, 5];
case 4:
if (this._installIdleObserver != null) {
this._installIdleObserver(resource, {
onError: function (error) {
_this._log.debug(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
"Idle connection ".concat(resource, " destroyed because of error: ").concat(error));
var pool = _this._pools[key];
if (pool != null) {
_this._pools[key] = pool.filter(function (r) { return r !== resource; });
pool.removeInUse(resource);
}
// let's not care about background clean-ups due to errors but just trigger the destroy
// process for the resource, we especially catch any errors and ignore them to avoid
// unhandled promise rejection warnings
_this._destroy(resource).catch(function () { });
}
});
}
pool.push(resource);
if (this._log.isDebugEnabled()) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this._log.debug("".concat(resource, " released to the pool ").concat(key));
}
_a.label = 5;
case 5: return [3 /*break*/, 8];
case 6:
// key has been purged, don't put it back, just destroy the resource
if (this._log.isDebugEnabled()) {
this._log.debug(
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
"".concat(resource, " destroyed and can't be released to the pool ").concat(key, " because pool has been purged"));
}
pool.removeInUse(resource);
return [4 /*yield*/, this._destroy(resource)];
case 7:
_a.sent();
_a.label = 8;
case 8: return [3 /*break*/, 10];
case 9:
resourceReleased(key, this._activeResourceCounts);
this._processPendingAcquireRequests(address);
return [7 /*endfinally*/];
case 10: return [2 /*return*/];
}
});
});
};
Pool.prototype._purgeKey = function (key) {
return __awaiter(this, void 0, void 0, function () {
var pool, destructionList, resource;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
pool = this._pools[key];
destructionList = [];
if (!(pool != null)) return [3 /*break*/, 2];
while (pool.length > 0) {
resource = pool.pop();
if (resource == null) {
continue;
}
if (this._removeIdleObserver != null) {
this._removeIdleObserver(resource);
}
destructionList.push(this._destroy(resource));
}
pool.close();
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this._pools[key];
return [4 /*yield*/, Promise.all(destructionList)];
case 1:
_a.sent();
_a.label = 2;
case 2: return [2 /*return*/];
}
});
});
};
Pool.prototype._processPendingAcquireRequests = function (address) {
var _this = this;
var key = address.asKey();
var requests = this._acquireRequests[key];
if (requests != null) {
var pendingRequest_1 = requests.shift(); // pop a pending acquire request
if (pendingRequest_1 != null) {
this._acquire(pendingRequest_1.context, address, pendingRequest_1.requireNew)
.catch(function (error) {
// failed to acquire/create a new connection to resolve the pending acquire request
// propagate the error by failing the pending request
pendingRequest_1.reject(error);
return { resource: null, pool: null };
})
.then(function (_a) {
var resource = _a.resource, pool = _a.pool;
// there is not situation where the pool resource is not null and the
// pool is null.
if (resource != null && pool != null) {
// managed to acquire a valid resource from the pool
if (pendingRequest_1.isCompleted()) {
// request has been completed, most likely failed by a timeout
// return the acquired resource back to the pool
_this._release(address, resource, pool)
.catch(function (error) {
if (_this._log.isDebugEnabled()) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
_this._log.debug("".concat(resource, " could not be release back to the pool. Cause: ").concat(error));
}
});
}
else {
// request is still pending and can be resolved with the newly acquired resource
pendingRequest_1.resolve(resource); // resolve the pending request with the acquired resource
}
}
else {
// failed to acquire a valid resource from the pool
// return the pending request back to the pool
if (!pendingRequest_1.isCompleted()) {
if (_this._acquireRequests[key] == null) {
_this._acquireRequests[key] = [];
}
_this._acquireRequests[key].unshift(pendingRequest_1);
}
}
}).catch(function (error) { return pendingRequest_1.reject(error); });
}
else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this._acquireRequests[key];
}
}
};
return Pool;
}());
/**
* Increment active (checked out of the pool) resource counter.
* @param {string} key the resource group identifier (server address for connections).
* @param {Object.<string, number>} activeResourceCounts the object holding active counts per key.
*/
function resourceAcquired(key, activeResourceCounts) {
var _a;
var currentCount = (_a = activeResourceCounts[key]) !== null && _a !== void 0 ? _a : 0;
activeResourceCounts[key] = currentCount + 1;
}
/**
* Decrement active (checked out of the pool) resource counter.
* @param {string} key the resource group identifier (server address for connections).
* @param {Object.<string, number>} activeResourceCounts the object holding active counts per key.
*/
function resourceReleased(key, activeResourceCounts) {
var _a;
var currentCount = (_a = activeResourceCounts[key]) !== null && _a !== void 0 ? _a : 0;
var nextCount = currentCount - 1;
if (nextCount > 0) {
activeResourceCounts[key] = nextCount;
}
else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete activeResourceCounts[key];
}
}
var PendingRequest = /** @class */ (function () {
function PendingRequest(key, context, config, resolve, reject, timeoutId, log) {
this._key = key;
this._context = context;
this._resolve = resolve;
this._reject = reject;
this._timeoutId = timeoutId;
this._log = log;
this._completed = false;
this._config = config !== null && config !== void 0 ? config : {};
}
Object.defineProperty(PendingRequest.prototype, "context", {
get: function () {
return this._context;
},
enumerable: false,
configurable: true
});
Object.defineProperty(PendingRequest.prototype, "requireNew", {
get: function () {
var _a;
return (_a = this._config.requireNew) !== null && _a !== void 0 ? _a : false;
},
enumerable: false,
configurable: true
});
PendingRequest.prototype.isCompleted = function () {
return this._completed;
};
PendingRequest.prototype.resolve = function (resource) {
if (this._completed) {
return;
}
this._completed = true;
clearTimeout(this._timeoutId);
if (this._log.isDebugEnabled()) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
this._log.debug("".concat(resource, " acquired from the pool ").concat(this._key));
}
this._resolve(resource);
};
PendingRequest.prototype.reject = function (error) {
if (this._completed) {
return;
}
this._completed = true;
clearTimeout(this._timeoutId);
this._reject(error);
};
return PendingRequest;
}());
var SingleAddressPool = /** @class */ (function () {
function SingleAddressPool() {
this._active = true;
this._elements = [];
this._elementsInUse = new Set();
}
SingleAddressPool.prototype.isActive = function () {
return this._active;
};
SingleAddressPool.prototype.close = function () {
this._active = false;
this._elements = [];
this._elementsInUse = new Set();
};
SingleAddressPool.prototype.filter = function (predicate) {
this._elements = this._elements.filter(predicate);
return this;
};
SingleAddressPool.prototype.apply = function (resourceConsumer) {
this._elements.forEach(resourceConsumer);
this._elementsInUse.forEach(resourceConsumer);
};
Object.defineProperty(SingleAddressPool.prototype, "length", {
get: function () {
return this._elements.length;
},
enumerable: false,
configurable: true
});
SingleAddressPool.prototype.pop = function () {
var element = this._elements.pop();
if (element != null) {
this._elementsInUse.add(element);
}
return element;
};
SingleAddressPool.prototype.push = function (element) {
this._elementsInUse.delete(element);
return this._elements.push(element);
};
SingleAddressPool.prototype.pushInUse = function (element) {
this._elementsInUse.add(element);
};
SingleAddressPool.prototype.removeInUse = function (element) {
this._elementsInUse.delete(element);
};
return SingleAddressPool;
}());
exports.default = Pool;