tchannel 3.6.14 → 3.6.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/as/http.js +2 -2
- package/benchmarks/Makefile +5 -1
- package/benchmarks/index.js +1 -0
- package/benchmarks/multi_bench.js +15 -1
- package/channel.js +18 -5
- package/hyperbahn-client.js +3 -1
- package/lazy_relay.js +167 -24
- package/lib/object_pool.js +209 -0
- package/package.json +4 -4
- package/peer.js +143 -6
- package/peer_heap.js +52 -36
- package/relay_handler.js +4 -1
- package/service-name-handler.js +4 -1
- package/stat-tags.js +24 -1
- package/sub_peers.js +79 -9
- package/test/index.js +2 -0
- package/test/lazy_conn_handler.js +6 -2
- package/test/lazy_handler.js +6 -2
- package/test/lib/alloc-cluster.js +27 -1
- package/test/lib/batch-client.js +17 -2
- package/test/object_pool.js +119 -0
- package/test/peer-to-peer-load-balance.js +459 -0
- package/test/relay_lazy.js +2 -1
- package/test/v2/call.js +1 -0
- package/test/v2/lazy_frame.js +17 -12
- package/v2/args.js +28 -29
- package/v2/call.js +108 -68
- package/v2/checksum.js +2 -2
- package/v2/cont.js +19 -18
- package/v2/error_response.js +6 -8
- package/v2/frame.js +16 -14
- package/v2/handler.js +4 -1
- package/v2/header.js +30 -29
- package/v2/init.js +10 -12
- package/v2/tracing.js +21 -20
package/stat-tags.js
CHANGED
|
@@ -58,7 +58,8 @@ module.exports = {
|
|
|
58
58
|
ConnectionsErrorsTags: ConnectionsErrorsTags,
|
|
59
59
|
ConnectionsClosedTags: ConnectionsClosedTags,
|
|
60
60
|
RelayLatencyTags: RelayLatencyTags,
|
|
61
|
-
HTTPHanlderBuildLatencyTags: HTTPHanlderBuildLatencyTags
|
|
61
|
+
HTTPHanlderBuildLatencyTags: HTTPHanlderBuildLatencyTags,
|
|
62
|
+
ObjectPoolTags: ObjectPoolTags
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
function InboundCallsRecvdTags(cn, serviceName, endpoint) {
|
|
@@ -663,3 +664,25 @@ HTTPHanlderBuildLatencyTags.prototype.toStatKey = function toStatKey(prefix) {
|
|
|
663
664
|
clean(this.targetService, 'no-target-service') + '.' +
|
|
664
665
|
(this.streamed ? 'streamed' : 'unstreamed');
|
|
665
666
|
};
|
|
667
|
+
|
|
668
|
+
function ObjectPoolTags(poolName, statType) {
|
|
669
|
+
this.app = '';
|
|
670
|
+
this.host = '';
|
|
671
|
+
this.cluster = '';
|
|
672
|
+
this.version = '';
|
|
673
|
+
|
|
674
|
+
this.poolName = poolName;
|
|
675
|
+
this.statType = statType;
|
|
676
|
+
|
|
677
|
+
this._cachedPrefix = '';
|
|
678
|
+
this._key = '';
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
ObjectPoolTags.prototype.toStatKey = function toStatKey(prefix) {
|
|
682
|
+
// prefix should never change but we store it in _cachedPrefix just in case
|
|
683
|
+
if (!this._key || prefix !== this._cachedPrefix) {
|
|
684
|
+
this._key = prefix + '.' + this.poolName + '.' + this.statType;
|
|
685
|
+
this._cachedPrefix = prefix;
|
|
686
|
+
}
|
|
687
|
+
return this._key;
|
|
688
|
+
};
|
package/sub_peers.js
CHANGED
|
@@ -27,13 +27,37 @@ var PeerHeap = require('./peer_heap.js');
|
|
|
27
27
|
|
|
28
28
|
function TChannelSubPeers(channel, options) {
|
|
29
29
|
TChannelPeersBase.call(this, channel, options);
|
|
30
|
+
|
|
31
|
+
var self = this;
|
|
30
32
|
this.peerScoreThreshold = this.options.peerScoreThreshold || 0;
|
|
31
|
-
this._heap = new PeerHeap(channel.random);
|
|
32
33
|
this.choosePeerWithHeap = channel.choosePeerWithHeap;
|
|
34
|
+
|
|
35
|
+
this.hasMinConnections = typeof options.minConnections === 'number';
|
|
36
|
+
this.minConnections = options.minConnections;
|
|
37
|
+
|
|
38
|
+
this.currentConnectedPeers = 0;
|
|
39
|
+
this._heap = new PeerHeap(this, channel.random);
|
|
40
|
+
|
|
41
|
+
this.boundOnOutConnectionDelta = boundOnOutConnectionDelta;
|
|
42
|
+
|
|
43
|
+
function boundOnOutConnectionDelta(delta, peer) {
|
|
44
|
+
self.onOutConnectionDelta(peer, delta);
|
|
45
|
+
}
|
|
33
46
|
}
|
|
34
47
|
|
|
35
48
|
inherits(TChannelSubPeers, TChannelPeersBase);
|
|
36
49
|
|
|
50
|
+
TChannelSubPeers.prototype.onOutConnectionDelta =
|
|
51
|
+
function onOutConnectionDelta(peer, delta) {
|
|
52
|
+
var connCount = peer.countConnections('out');
|
|
53
|
+
|
|
54
|
+
if (delta === 1 && connCount === 1) {
|
|
55
|
+
this.currentConnectedPeers++;
|
|
56
|
+
} else if (delta === -1 && connCount === 0) {
|
|
57
|
+
this.currentConnectedPeers--;
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
37
61
|
TChannelSubPeers.prototype.close = function close(callback) {
|
|
38
62
|
var self = this;
|
|
39
63
|
|
|
@@ -55,6 +79,12 @@ TChannelSubPeers.prototype.add = function add(hostPort, options) {
|
|
|
55
79
|
peer = topChannel.peers.add(hostPort, options);
|
|
56
80
|
peer.setPreferConnectionDirection(self.preferConnectionDirection);
|
|
57
81
|
|
|
82
|
+
if (peer.countConnections('out') > 0) {
|
|
83
|
+
this.currentConnectedPeers++;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
peer.deltaOutConnectionEvent.on(self.boundOnOutConnectionDelta);
|
|
87
|
+
|
|
58
88
|
self._map[hostPort] = peer;
|
|
59
89
|
self._keys.push(hostPort);
|
|
60
90
|
|
|
@@ -80,6 +110,13 @@ TChannelSubPeers.prototype._delete = function _del(peer) {
|
|
|
80
110
|
return;
|
|
81
111
|
}
|
|
82
112
|
|
|
113
|
+
if (peer.countConnections('out') > 0) {
|
|
114
|
+
this.currentConnectedPeers--;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
peer.deltaOutConnectionEvent
|
|
118
|
+
.removeListener(self.boundOnOutConnectionDelta);
|
|
119
|
+
|
|
83
120
|
delete self._map[peer.hostPort];
|
|
84
121
|
popout(self._keys, index);
|
|
85
122
|
|
|
@@ -109,6 +146,7 @@ TChannelSubPeers.prototype.choosePeer = function choosePeer(req) {
|
|
|
109
146
|
return self.chooseLinearPeer(req);
|
|
110
147
|
};
|
|
111
148
|
|
|
149
|
+
/*eslint max-statements: [2, 40]*/
|
|
112
150
|
TChannelSubPeers.prototype.chooseLinearPeer = function chooseLinearPeer(req) {
|
|
113
151
|
/* eslint complexity: [2, 15]*/
|
|
114
152
|
var self = this;
|
|
@@ -121,11 +159,22 @@ TChannelSubPeers.prototype.chooseLinearPeer = function chooseLinearPeer(req) {
|
|
|
121
159
|
var threshold = self.peerScoreThreshold;
|
|
122
160
|
|
|
123
161
|
var selectedPeer = null;
|
|
162
|
+
var secondaryPeer = null;
|
|
124
163
|
var selectedScore = 0;
|
|
164
|
+
var secondaryScore = 0;
|
|
165
|
+
|
|
166
|
+
var notEnoughPeers = false;
|
|
167
|
+
if (this.hasMinConnections) {
|
|
168
|
+
notEnoughPeers = this.currentConnectedPeers < this.minConnections;
|
|
169
|
+
}
|
|
170
|
+
|
|
125
171
|
for (var i = 0; i < hosts.length; i++) {
|
|
126
172
|
var hostPort = hosts[i];
|
|
127
173
|
var peer = self._map[hostPort];
|
|
128
|
-
|
|
174
|
+
|
|
175
|
+
var shouldSkip = req && req.triedRemoteAddrs && req.triedRemoteAddrs[hostPort];
|
|
176
|
+
if (!shouldSkip) {
|
|
177
|
+
var isSecondary = notEnoughPeers && peer.isConnected('out');
|
|
129
178
|
var score = peer.getScore(req);
|
|
130
179
|
|
|
131
180
|
if (self.channel.topChannel.peerScoredEvent) {
|
|
@@ -136,11 +185,24 @@ TChannelSubPeers.prototype.chooseLinearPeer = function chooseLinearPeer(req) {
|
|
|
136
185
|
});
|
|
137
186
|
}
|
|
138
187
|
|
|
139
|
-
var want
|
|
140
|
-
|
|
188
|
+
var want;
|
|
189
|
+
if (isSecondary) {
|
|
190
|
+
want = score > threshold && (
|
|
191
|
+
secondaryPeer === null || score > secondaryScore
|
|
192
|
+
);
|
|
193
|
+
} else {
|
|
194
|
+
want = score > threshold &&
|
|
195
|
+
(selectedPeer === null || score > selectedScore);
|
|
196
|
+
}
|
|
197
|
+
|
|
141
198
|
if (want) {
|
|
142
|
-
|
|
143
|
-
|
|
199
|
+
if (isSecondary) {
|
|
200
|
+
secondaryPeer = peer;
|
|
201
|
+
secondaryScore = score;
|
|
202
|
+
} else {
|
|
203
|
+
selectedPeer = peer;
|
|
204
|
+
selectedScore = score;
|
|
205
|
+
}
|
|
144
206
|
}
|
|
145
207
|
}
|
|
146
208
|
}
|
|
@@ -152,14 +214,21 @@ TChannelSubPeers.prototype.chooseLinearPeer = function chooseLinearPeer(req) {
|
|
|
152
214
|
});
|
|
153
215
|
}
|
|
154
216
|
|
|
155
|
-
|
|
217
|
+
if (secondaryScore > selectedScore && selectedPeer) {
|
|
218
|
+
selectedPeer.tryConnect(noop);
|
|
219
|
+
return secondaryPeer;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return selectedPeer || secondaryPeer;
|
|
156
223
|
};
|
|
157
224
|
|
|
225
|
+
function noop() {}
|
|
226
|
+
|
|
158
227
|
TChannelSubPeers.prototype.chooseHeapPeer = function chooseHeapPeer(req) {
|
|
159
228
|
var self = this;
|
|
160
229
|
|
|
161
230
|
var peer;
|
|
162
|
-
if (req && req.triedRemoteAddrs) {
|
|
231
|
+
if ((req && req.triedRemoteAddrs)) {
|
|
163
232
|
peer = self._choosePeerSkipTried(req);
|
|
164
233
|
} else {
|
|
165
234
|
peer = self._heap.choose(self.peerScoreThreshold);
|
|
@@ -182,7 +251,8 @@ function _choosePeerSkipTried(req) {
|
|
|
182
251
|
return self._heap.choose(self.peerScoreThreshold, filterTriedPeers);
|
|
183
252
|
|
|
184
253
|
function filterTriedPeers(peer) {
|
|
185
|
-
|
|
254
|
+
var shouldSkip = req.triedRemoteAddrs[peer.hostPort];
|
|
255
|
+
return !shouldSkip;
|
|
186
256
|
}
|
|
187
257
|
};
|
|
188
258
|
|
package/test/index.js
CHANGED
|
@@ -76,6 +76,8 @@ require('./peer_drain.js');
|
|
|
76
76
|
require('./relay-clamps-the-ttl.js');
|
|
77
77
|
require('./relay-under-timeouts.js');
|
|
78
78
|
require('./relay-kills-socket-after-timeouts.js');
|
|
79
|
+
require('./object_pool.js');
|
|
80
|
+
require('./peer-to-peer-load-balance.js');
|
|
79
81
|
|
|
80
82
|
require('./trace/basic_server.js');
|
|
81
83
|
require('./trace/server_2_requests.js');
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
|
|
21
21
|
'use strict';
|
|
22
22
|
|
|
23
|
+
var ReadResult = require('bufrw').ReadResult;
|
|
24
|
+
|
|
23
25
|
var v2 = require('../v2/index.js');
|
|
24
26
|
var allocCluster = require('./lib/alloc-cluster.js');
|
|
25
27
|
|
|
@@ -45,16 +47,18 @@ allocCluster.test('connection.handler: lazy call handling', 2, function t(cluste
|
|
|
45
47
|
conn.handler.handleCallLazily = handleCallLazily;
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
var readRes = new ReadResult();
|
|
51
|
+
|
|
48
52
|
function handleCallLazily(frame) {
|
|
49
53
|
// this is conn.handler
|
|
50
54
|
|
|
51
|
-
var res = frame.bodyRW.lazy.
|
|
55
|
+
var res = frame.bodyRW.lazy.poolReadService(readRes, frame);
|
|
52
56
|
if (res.err) {
|
|
53
57
|
throw res.err;
|
|
54
58
|
}
|
|
55
59
|
assert.equal(res.value, 'bob', 'expected called service name');
|
|
56
60
|
|
|
57
|
-
res = frame.bodyRW.lazy.
|
|
61
|
+
res = frame.bodyRW.lazy.poolReadArg1(readRes, frame);
|
|
58
62
|
if (res.err) {
|
|
59
63
|
throw res.err;
|
|
60
64
|
}
|
package/test/lazy_handler.js
CHANGED
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
var v2 = require('../v2/index.js');
|
|
24
24
|
var allocCluster = require('./lib/alloc-cluster.js');
|
|
25
25
|
|
|
26
|
+
var ReadResult = require('bufrw').ReadResult;
|
|
27
|
+
|
|
28
|
+
var readRes = new ReadResult();
|
|
29
|
+
|
|
26
30
|
allocCluster.test('channel.handler: lazy call handling', 2, function t(cluster, assert) {
|
|
27
31
|
var one = cluster.channels[0];
|
|
28
32
|
var two = cluster.channels[1];
|
|
@@ -42,13 +46,13 @@ allocCluster.test('channel.handler: lazy call handling', 2, function t(cluster,
|
|
|
42
46
|
server.handler.handleLazily = handleCallLazily;
|
|
43
47
|
|
|
44
48
|
function handleCallLazily(conn, frame) {
|
|
45
|
-
var res = frame.bodyRW.lazy.
|
|
49
|
+
var res = frame.bodyRW.lazy.poolReadService(readRes, frame);
|
|
46
50
|
if (res.err) {
|
|
47
51
|
throw res.err;
|
|
48
52
|
}
|
|
49
53
|
assert.equal(res.value, 'bob', 'expected called service name');
|
|
50
54
|
|
|
51
|
-
res = frame.bodyRW.lazy.
|
|
55
|
+
res = frame.bodyRW.lazy.poolReadArg1(readRes, frame);
|
|
52
56
|
if (res.err) {
|
|
53
57
|
throw res.err;
|
|
54
58
|
}
|
|
@@ -29,6 +29,7 @@ var debugLogtron = require('debug-logtron');
|
|
|
29
29
|
|
|
30
30
|
var TChannel = require('../../channel.js');
|
|
31
31
|
var CollapsedAssert = require('./collapsed-assert.js');
|
|
32
|
+
var ObjectPool = require('../../lib/object_pool');
|
|
32
33
|
|
|
33
34
|
var loadConfig = require('./load_config.js');
|
|
34
35
|
|
|
@@ -77,7 +78,8 @@ function allocCluster(opts) {
|
|
|
77
78
|
var channelOptions = extend({
|
|
78
79
|
logger: logger,
|
|
79
80
|
timeoutFuzz: 0,
|
|
80
|
-
traceSample: 1
|
|
81
|
+
traceSample: 1,
|
|
82
|
+
objectPoolDebug: true
|
|
81
83
|
}, defaultChannelOptions, opts.channelOptions || opts);
|
|
82
84
|
|
|
83
85
|
for (var i = 0; i < opts.numPeers; i++) {
|
|
@@ -217,6 +219,8 @@ function clusterTester(opts, t) {
|
|
|
217
219
|
|
|
218
220
|
cluster.assertEmptyState(collapsedAssert);
|
|
219
221
|
collapsedAssert.report(assert, 'cluster has an empty state');
|
|
222
|
+
|
|
223
|
+
checkObjectPools(assert);
|
|
220
224
|
}
|
|
221
225
|
cluster.destroy();
|
|
222
226
|
});
|
|
@@ -225,6 +229,24 @@ function clusterTester(opts, t) {
|
|
|
225
229
|
}
|
|
226
230
|
}
|
|
227
231
|
|
|
232
|
+
function checkObjectPools(assert) {
|
|
233
|
+
var i;
|
|
234
|
+
var pool;
|
|
235
|
+
var length;
|
|
236
|
+
for (i = 0; i < ObjectPool.pools.length; i++) {
|
|
237
|
+
pool = ObjectPool.pools[i];
|
|
238
|
+
length = pool.outstandingList.length;
|
|
239
|
+
assert.ok(
|
|
240
|
+
length === 0,
|
|
241
|
+
'expected object pool ' + pool.name + ' to have no outstanding ' +
|
|
242
|
+
'instances, found ' + length + ' instances'
|
|
243
|
+
);
|
|
244
|
+
if (length) {
|
|
245
|
+
assert.comment(util.inspect(pool.outstandingList));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
228
250
|
allocCluster.test = function testCluster(desc, opts, t) {
|
|
229
251
|
if (opts === undefined) {
|
|
230
252
|
return test(desc);
|
|
@@ -237,6 +259,10 @@ allocCluster.test.only = function testClusterOnly(desc, opts, t) {
|
|
|
237
259
|
test.only(desc, clusterTester(opts, t));
|
|
238
260
|
};
|
|
239
261
|
|
|
262
|
+
allocCluster.test.skip = function testClusterSkip(desc, opts, t) {
|
|
263
|
+
test.skip(desc, clusterTester(opts, t));
|
|
264
|
+
};
|
|
265
|
+
|
|
240
266
|
function connectChannels(channels, callback) {
|
|
241
267
|
return parallel(channels.map(function (channel) {
|
|
242
268
|
return function connectChannelToHosts(callback) {
|
package/test/lib/batch-client.js
CHANGED
|
@@ -24,6 +24,19 @@ var parallel = require('run-parallel');
|
|
|
24
24
|
var collectParallel = require('collect-parallel/array');
|
|
25
25
|
var setTimeout = require('timers').setTimeout;
|
|
26
26
|
|
|
27
|
+
/*
|
|
28
|
+
BatchClient takes a channel and a set of peers to talk
|
|
29
|
+
to.
|
|
30
|
+
|
|
31
|
+
It has a set of options including:
|
|
32
|
+
- totalRequests
|
|
33
|
+
- delay
|
|
34
|
+
- batchSize
|
|
35
|
+
|
|
36
|
+
If you want to do 100QPS you can set batchSize=1 and delay=10
|
|
37
|
+
If you want to do 1000QPS you can set batchSize=50 and delay=50
|
|
38
|
+
|
|
39
|
+
*/
|
|
27
40
|
module.exports = BatchClient;
|
|
28
41
|
|
|
29
42
|
function BatchClient(channel, hosts, options) {
|
|
@@ -42,11 +55,12 @@ function BatchClient(channel, hosts, options) {
|
|
|
42
55
|
self.serviceName = 'server';
|
|
43
56
|
self.endpoint = options.endpoint || 'echo';
|
|
44
57
|
self.body = 'foobar';
|
|
45
|
-
self.timeout = 500;
|
|
58
|
+
self.timeout = options.timeout || 500;
|
|
46
59
|
|
|
47
60
|
self.subChannel = self.channel.makeSubChannel({
|
|
48
61
|
serviceName: self.serviceName,
|
|
49
|
-
peers: self.hosts
|
|
62
|
+
peers: self.hosts,
|
|
63
|
+
minConnections: options.minConnections || null
|
|
50
64
|
});
|
|
51
65
|
|
|
52
66
|
self.requestOptions = {
|
|
@@ -54,6 +68,7 @@ function BatchClient(channel, hosts, options) {
|
|
|
54
68
|
hasNoParent: true,
|
|
55
69
|
timeout: self.timeout,
|
|
56
70
|
retryFlags: options && options.retryFlags,
|
|
71
|
+
retryLimit: options && options.retryLimit ? options.retryLimit : 5,
|
|
57
72
|
headers: {
|
|
58
73
|
cn: 'client',
|
|
59
74
|
as: 'raw'
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Copyright (c) 2015 Uber Technologies, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
// in the Software without restriction, including without limitation the rights
|
|
6
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
// furnished to do so, subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in
|
|
11
|
+
// all copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
// THE SOFTWARE.
|
|
20
|
+
|
|
21
|
+
'use strict';
|
|
22
|
+
|
|
23
|
+
var test = require('tape');
|
|
24
|
+
var ObjectPool = require('../lib/object_pool');
|
|
25
|
+
var Timer = require('time-mock');
|
|
26
|
+
|
|
27
|
+
function Widget() {
|
|
28
|
+
this.type = null;
|
|
29
|
+
this.count = null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Widget.prototype.reset = function reset(options) {
|
|
33
|
+
this.type = options.type;
|
|
34
|
+
this.count = options.count;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
Widget.prototype.clear = function clear() {
|
|
38
|
+
this.type = null;
|
|
39
|
+
this.count = null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
ObjectPool.setup({
|
|
43
|
+
Type: Widget,
|
|
44
|
+
maxSize: 2
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('object pool happy', function t1(assert) {
|
|
48
|
+
var timers = Timer(0);
|
|
49
|
+
var stats = {};
|
|
50
|
+
var channel = {emitFastStat: fakeEmitFastStat};
|
|
51
|
+
|
|
52
|
+
function fakeEmitFastStat(name, type, val, tags) {
|
|
53
|
+
stats[name + tags.toStatKey('')] = val;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
ObjectPool.bootstrap({
|
|
57
|
+
channel: channel,
|
|
58
|
+
timers: timers,
|
|
59
|
+
reportInterval: 500
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
var pool = ObjectPool.pools.filter(function (p) {
|
|
63
|
+
return p.name === 'Widget';
|
|
64
|
+
})[0];
|
|
65
|
+
|
|
66
|
+
var w = Widget.alloc();
|
|
67
|
+
w.reset({type: 'foo', count: 10});
|
|
68
|
+
|
|
69
|
+
assert.equal(pool.freeList.length, 0, 'no free instances yet');
|
|
70
|
+
assert.equal(pool.outstanding, 1, '1 outstanding instace');
|
|
71
|
+
|
|
72
|
+
var w2 = Widget.alloc();
|
|
73
|
+
w2.reset({type: 'foo', count: 10});
|
|
74
|
+
|
|
75
|
+
assert.equal(pool.freeList.length, 0, 'no free instances yet');
|
|
76
|
+
assert.equal(pool.outstanding, 2, '2 outstanding instace');
|
|
77
|
+
|
|
78
|
+
var w3 = Widget.alloc();
|
|
79
|
+
w3.reset({type: 'foo', count: 10});
|
|
80
|
+
|
|
81
|
+
assert.equal(pool.freeList.length, 0, 'no free instances yet');
|
|
82
|
+
assert.equal(pool.outstanding, 3, '3 outstanding instace');
|
|
83
|
+
|
|
84
|
+
w.free();
|
|
85
|
+
// after w.free() the free list is still 0 because maxSize of the pool is 2
|
|
86
|
+
|
|
87
|
+
assert.equal(pool.freeList.length, 0, 'no free instances');
|
|
88
|
+
assert.equal(pool.outstanding, 2, '2 outstanding instace');
|
|
89
|
+
|
|
90
|
+
w2.free();
|
|
91
|
+
|
|
92
|
+
assert.equal(pool.freeList.length, 1, '1 free instance');
|
|
93
|
+
assert.equal(pool.outstanding, 1, '1 outstanding instace');
|
|
94
|
+
|
|
95
|
+
timers.advance(500);
|
|
96
|
+
assert.equal(stats['tchannel.object-pool.Widget.free'], 1);
|
|
97
|
+
assert.equal(stats['tchannel.object-pool.Widget.outstanding'], 1);
|
|
98
|
+
|
|
99
|
+
w = Widget.alloc();
|
|
100
|
+
|
|
101
|
+
assert.ok(w2 === w, 'object was allocated from free list');
|
|
102
|
+
assert.equal(w2.type, null, 'object type field was cleared');
|
|
103
|
+
assert.equal(w2.count, null, 'object count field was cleared');
|
|
104
|
+
|
|
105
|
+
assert.equal(pool.freeList.length, 0, '0 free instances');
|
|
106
|
+
assert.equal(pool.outstanding, 2, '2 outstanding instace');
|
|
107
|
+
|
|
108
|
+
w.free();
|
|
109
|
+
w3.free();
|
|
110
|
+
|
|
111
|
+
assert.equal(pool.freeList.length, 2, '2 free instances');
|
|
112
|
+
assert.equal(pool.outstanding, 0, '0 outstanding instace');
|
|
113
|
+
|
|
114
|
+
timers.advance(500);
|
|
115
|
+
assert.equal(stats['tchannel.object-pool.Widget.free'], 2);
|
|
116
|
+
assert.equal(stats['tchannel.object-pool.Widget.outstanding'], 0);
|
|
117
|
+
|
|
118
|
+
assert.end();
|
|
119
|
+
});
|