@ragestudio/scylla-odm 0.22.2 → 0.22.4
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/batch/index.d.ts +3 -3
- package/batch/index.d.ts.map +1 -1
- package/client.d.ts +6 -5
- package/client.d.ts.map +1 -1
- package/client.js +11 -12
- package/client.js.map +1 -1
- package/cql_gen/create_table.d.ts +1 -1
- package/cql_gen/create_table.d.ts.map +1 -1
- package/document/index.d.ts +3 -3
- package/document/index.d.ts.map +1 -1
- package/driver/LICENSE.txt +177 -0
- package/driver/NOTICE.txt +67 -0
- package/driver/auth/index.d.ts +37 -0
- package/driver/auth/index.js +37 -0
- package/driver/auth/no-auth-provider.js +73 -0
- package/driver/auth/plain-text-auth-provider.js +81 -0
- package/driver/auth/provider.js +77 -0
- package/driver/client-options.js +442 -0
- package/driver/client.js +1267 -0
- package/driver/concurrent/index.d.ts +49 -0
- package/driver/concurrent/index.js +366 -0
- package/driver/connection.js +1034 -0
- package/driver/control-connection.js +1282 -0
- package/driver/encoder.js +2316 -0
- package/driver/errors.js +223 -0
- package/driver/execution-options.js +612 -0
- package/driver/execution-profile.js +274 -0
- package/driver/host-connection-pool.js +587 -0
- package/driver/host.js +699 -0
- package/driver/index.d.ts +387 -0
- package/driver/index.js +81 -0
- package/driver/mapping/cache.js +214 -0
- package/driver/mapping/doc-info-adapter.js +171 -0
- package/driver/mapping/index.d.ts +219 -0
- package/driver/mapping/index.js +57 -0
- package/driver/mapping/mapper.js +225 -0
- package/driver/mapping/mapping-handler.js +641 -0
- package/driver/mapping/model-batch-item.js +215 -0
- package/driver/mapping/model-batch-mapper.js +141 -0
- package/driver/mapping/model-mapper.js +315 -0
- package/driver/mapping/model-mapping-info.js +225 -0
- package/driver/mapping/object-selector.js +417 -0
- package/driver/mapping/q.js +156 -0
- package/driver/mapping/query-generator.js +556 -0
- package/driver/mapping/result-mapper.js +123 -0
- package/driver/mapping/result.js +139 -0
- package/driver/mapping/table-mappings.js +133 -0
- package/driver/mapping/tree.js +160 -0
- package/driver/metadata/aggregate.js +79 -0
- package/driver/metadata/client-state.js +119 -0
- package/driver/metadata/data-collection.js +182 -0
- package/driver/metadata/event-debouncer.js +174 -0
- package/driver/metadata/index.d.ts +276 -0
- package/driver/metadata/index.js +1156 -0
- package/driver/metadata/materialized-view.js +49 -0
- package/driver/metadata/schema-function.js +98 -0
- package/driver/metadata/schema-index.js +166 -0
- package/driver/metadata/schema-parser.js +1399 -0
- package/driver/metadata/table-metadata.js +77 -0
- package/driver/operation-state.js +206 -0
- package/driver/policies/address-resolution.js +145 -0
- package/driver/policies/index.d.ts +241 -0
- package/driver/policies/index.js +110 -0
- package/driver/policies/load-balancing.js +970 -0
- package/driver/policies/reconnection.js +166 -0
- package/driver/policies/retry.js +326 -0
- package/driver/policies/speculative-execution.js +150 -0
- package/driver/policies/timestamp-generation.js +176 -0
- package/driver/prepare-handler.js +347 -0
- package/driver/promise-utils.js +191 -0
- package/driver/readers.js +624 -0
- package/driver/request-execution.js +644 -0
- package/driver/request-handler.js +332 -0
- package/driver/requests.js +618 -0
- package/driver/stream-id-stack.js +209 -0
- package/driver/streams.js +745 -0
- package/driver/token.js +325 -0
- package/driver/tokenizer.js +631 -0
- package/driver/types/big-decimal.js +282 -0
- package/driver/types/duration.js +576 -0
- package/driver/types/index.d.ts +486 -0
- package/driver/types/index.js +733 -0
- package/driver/types/inet-address.js +262 -0
- package/driver/types/integer.js +818 -0
- package/driver/types/local-date.js +280 -0
- package/driver/types/local-time.js +299 -0
- package/driver/types/mutable-long.js +385 -0
- package/driver/types/protocol-version.js +391 -0
- package/driver/types/result-set.js +287 -0
- package/driver/types/result-stream.js +164 -0
- package/driver/types/row.js +85 -0
- package/driver/types/time-uuid.js +414 -0
- package/driver/types/tuple.js +103 -0
- package/driver/types/uuid.js +160 -0
- package/driver/types/vector.js +130 -0
- package/driver/types/version-number.js +153 -0
- package/driver/utils.js +1485 -0
- package/driver/writers.js +350 -0
- package/global.d.ts +1 -1
- package/global.d.ts.map +1 -1
- package/index.d.ts +6 -6
- package/index.d.ts.map +1 -1
- package/index.js +6 -6
- package/index.js.map +1 -1
- package/migrate/index.d.ts +1 -1
- package/migrate/index.d.ts.map +1 -1
- package/migrate/index.js +1 -1
- package/migrate/index.js.map +1 -1
- package/model/index.d.ts +6 -6
- package/model/index.d.ts.map +1 -1
- package/model/index.js +10 -10
- package/model/index.js.map +1 -1
- package/operations/countAll.d.ts +1 -1
- package/operations/countAll.d.ts.map +1 -1
- package/operations/delete.d.ts +3 -4
- package/operations/delete.d.ts.map +1 -1
- package/operations/delete.js +1 -1
- package/operations/delete.js.map +1 -1
- package/operations/find.d.ts +2 -2
- package/operations/find.d.ts.map +1 -1
- package/operations/find.js +1 -1
- package/operations/find.js.map +1 -1
- package/operations/findOne.d.ts +2 -2
- package/operations/findOne.d.ts.map +1 -1
- package/operations/findOne.js +1 -1
- package/operations/findOne.js.map +1 -1
- package/operations/insert.d.ts +3 -3
- package/operations/insert.d.ts.map +1 -1
- package/operations/insert.js +2 -2
- package/operations/insert.js.map +1 -1
- package/operations/sync.d.ts +1 -1
- package/operations/sync.d.ts.map +1 -1
- package/operations/sync.js +1 -1
- package/operations/sync.js.map +1 -1
- package/operations/tableExists.d.ts +1 -1
- package/operations/tableExists.d.ts.map +1 -1
- package/operations/update.d.ts +3 -3
- package/operations/update.d.ts.map +1 -1
- package/operations/update.js +2 -2
- package/operations/update.js.map +1 -1
- package/package.json +4 -12
- package/schema/index.d.ts +1 -1
- package/schema/index.d.ts.map +1 -1
- package/types.d.ts +4 -4
- package/types.d.ts.map +1 -1
- package/utils/queryParser.d.ts +1 -1
- package/utils/queryParser.d.ts.map +1 -1
- package/utils/queryParser.js +1 -1
- package/utils/queryParser.js.map +1 -1
- package/utils/typeChecker.d.ts +1 -1
- package/utils/typeChecker.d.ts.map +1 -1
- package/utils/typeChecker.js +1 -1
- package/utils/typeChecker.js.map +1 -1
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Licensed to the Apache Software Foundation (ASF) under one
|
|
3
|
+
* or more contributor license agreements. See the NOTICE file
|
|
4
|
+
* distributed with this work for additional information
|
|
5
|
+
* regarding copyright ownership. The ASF licenses this file
|
|
6
|
+
* to you under the Apache License, Version 2.0 (the
|
|
7
|
+
* "License"); you may not use this file except in compliance
|
|
8
|
+
* with the License. You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
import util from "util"
|
|
19
|
+
import types from "../types/index.js"
|
|
20
|
+
import utils from "../utils.js"
|
|
21
|
+
import errors from "../errors.js"
|
|
22
|
+
|
|
23
|
+
const doneIteratorObject = Object.freeze({ done: true })
|
|
24
|
+
const newlyUpInterval = 60000
|
|
25
|
+
|
|
26
|
+
/** @module policies/loadBalancing */
|
|
27
|
+
/**
|
|
28
|
+
* Base class for Load Balancing Policies
|
|
29
|
+
* @constructor
|
|
30
|
+
*/
|
|
31
|
+
function LoadBalancingPolicy() {}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Initializes the load balancing policy, called after the driver obtained the information of the cluster.
|
|
35
|
+
* @param {Client} client
|
|
36
|
+
* @param {HostMap} hosts
|
|
37
|
+
* @param {Function} callback
|
|
38
|
+
*/
|
|
39
|
+
LoadBalancingPolicy.prototype.init = function (client, hosts, callback) {
|
|
40
|
+
this.client = client
|
|
41
|
+
this.hosts = hosts
|
|
42
|
+
callback()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Returns the distance assigned by this policy to the provided host.
|
|
47
|
+
* @param {Host} host
|
|
48
|
+
*/
|
|
49
|
+
LoadBalancingPolicy.prototype.getDistance = function (host) {
|
|
50
|
+
return types.distance.local
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Returns an iterator with the hosts for a new query.
|
|
55
|
+
* Each new query will call this method. The first host in the result will
|
|
56
|
+
* then be used to perform the query.
|
|
57
|
+
* @param {String} keyspace Name of currently logged keyspace at <code>Client</code> level.
|
|
58
|
+
* @param {ExecutionOptions|null} executionOptions The information related to the execution of the request.
|
|
59
|
+
* @param {Function} callback The function to be invoked with the error as first parameter and the host iterator as
|
|
60
|
+
* second parameter.
|
|
61
|
+
*/
|
|
62
|
+
LoadBalancingPolicy.prototype.newQueryPlan = function (
|
|
63
|
+
keyspace,
|
|
64
|
+
executionOptions,
|
|
65
|
+
callback,
|
|
66
|
+
) {
|
|
67
|
+
callback(
|
|
68
|
+
new Error(
|
|
69
|
+
"You must implement a query plan for the LoadBalancingPolicy class",
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Gets an associative array containing the policy options.
|
|
76
|
+
*/
|
|
77
|
+
LoadBalancingPolicy.prototype.getOptions = function () {
|
|
78
|
+
return new Map()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* This policy yield nodes in a round-robin fashion.
|
|
83
|
+
* @extends LoadBalancingPolicy
|
|
84
|
+
* @constructor
|
|
85
|
+
*/
|
|
86
|
+
function RoundRobinPolicy() {
|
|
87
|
+
this.index = 0
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
util.inherits(RoundRobinPolicy, LoadBalancingPolicy)
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Returns an iterator with the hosts to be used as coordinator for a query.
|
|
94
|
+
* @param {String} keyspace Name of currently logged keyspace at <code>Client</code> level.
|
|
95
|
+
* @param {ExecutionOptions|null} executionOptions The information related to the execution of the request.
|
|
96
|
+
* @param {Function} callback The function to be invoked with the error as first parameter and the host iterator as
|
|
97
|
+
* second parameter.
|
|
98
|
+
*/
|
|
99
|
+
RoundRobinPolicy.prototype.newQueryPlan = function (
|
|
100
|
+
keyspace,
|
|
101
|
+
executionOptions,
|
|
102
|
+
callback,
|
|
103
|
+
) {
|
|
104
|
+
if (!this.hosts) {
|
|
105
|
+
return callback(new Error("Load balancing policy not initialized"))
|
|
106
|
+
}
|
|
107
|
+
const hosts = this.hosts.values()
|
|
108
|
+
const self = this
|
|
109
|
+
let counter = 0
|
|
110
|
+
|
|
111
|
+
let planIndex = self.index % hosts.length
|
|
112
|
+
self.index += 1
|
|
113
|
+
if (self.index >= utils.maxInt) {
|
|
114
|
+
self.index = 0
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
callback(null, {
|
|
118
|
+
next: function () {
|
|
119
|
+
if (++counter > hosts.length) {
|
|
120
|
+
return doneIteratorObject
|
|
121
|
+
}
|
|
122
|
+
return { value: hosts[planIndex++ % hosts.length], done: false }
|
|
123
|
+
},
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* A data-center aware Round-robin load balancing policy.
|
|
129
|
+
* This policy provides round-robin queries over the nodes of the local
|
|
130
|
+
* data center.
|
|
131
|
+
* @param {?String} [localDc] local datacenter name. This value overrides the 'localDataCenter' Client option \
|
|
132
|
+
* and is useful for cases where you have multiple execution profiles that you intend on using for routing
|
|
133
|
+
* requests to different data centers.
|
|
134
|
+
* @extends {LoadBalancingPolicy}
|
|
135
|
+
* @constructor
|
|
136
|
+
*/
|
|
137
|
+
function DCAwareRoundRobinPolicy(localDc) {
|
|
138
|
+
this.localDc = localDc
|
|
139
|
+
this.index = 0
|
|
140
|
+
/** @type {Array} */
|
|
141
|
+
this.localHostsArray = null
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
util.inherits(DCAwareRoundRobinPolicy, LoadBalancingPolicy)
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Initializes the load balancing policy.
|
|
148
|
+
* @param {Client} client
|
|
149
|
+
* @param {HostMap} hosts
|
|
150
|
+
* @param {Function} callback
|
|
151
|
+
*/
|
|
152
|
+
DCAwareRoundRobinPolicy.prototype.init = function (client, hosts, callback) {
|
|
153
|
+
this.client = client
|
|
154
|
+
this.hosts = hosts
|
|
155
|
+
hosts.on("add", this._cleanHostCache.bind(this))
|
|
156
|
+
hosts.on("remove", this._cleanHostCache.bind(this))
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
setLocalDc(this, client, this.hosts)
|
|
160
|
+
} catch (err) {
|
|
161
|
+
return callback(err)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
callback()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Returns the distance depending on the datacenter.
|
|
169
|
+
* @param {Host} host
|
|
170
|
+
*/
|
|
171
|
+
DCAwareRoundRobinPolicy.prototype.getDistance = function (host) {
|
|
172
|
+
if (host.datacenter === this.localDc) {
|
|
173
|
+
return types.distance.local
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return types.distance.ignored
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
DCAwareRoundRobinPolicy.prototype._cleanHostCache = function () {
|
|
180
|
+
this.localHostsArray = null
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
DCAwareRoundRobinPolicy.prototype._resolveLocalHosts = function () {
|
|
184
|
+
const hosts = this.hosts.values()
|
|
185
|
+
if (this.localHostsArray) {
|
|
186
|
+
//there were already calculated
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
this.localHostsArray = []
|
|
190
|
+
hosts.forEach(function (h) {
|
|
191
|
+
if (!h.datacenter) {
|
|
192
|
+
//not a remote dc node
|
|
193
|
+
return
|
|
194
|
+
}
|
|
195
|
+
if (h.datacenter === this.localDc) {
|
|
196
|
+
this.localHostsArray.push(h)
|
|
197
|
+
}
|
|
198
|
+
}, this)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* It returns an iterator that yields local nodes.
|
|
203
|
+
* @param {String} keyspace Name of currently logged keyspace at <code>Client</code> level.
|
|
204
|
+
* @param {ExecutionOptions|null} executionOptions The information related to the execution of the request.
|
|
205
|
+
* @param {Function} callback The function to be invoked with the error as first parameter and the host iterator as
|
|
206
|
+
* second parameter.
|
|
207
|
+
*/
|
|
208
|
+
DCAwareRoundRobinPolicy.prototype.newQueryPlan = function (
|
|
209
|
+
keyspace,
|
|
210
|
+
executionOptions,
|
|
211
|
+
callback,
|
|
212
|
+
) {
|
|
213
|
+
if (!this.hosts) {
|
|
214
|
+
return callback(new Error("Load balancing policy not initialized"))
|
|
215
|
+
}
|
|
216
|
+
this.index += 1
|
|
217
|
+
if (this.index >= utils.maxInt) {
|
|
218
|
+
this.index = 0
|
|
219
|
+
}
|
|
220
|
+
this._resolveLocalHosts()
|
|
221
|
+
// Use a local reference of hosts
|
|
222
|
+
const localHostsArray = this.localHostsArray
|
|
223
|
+
let planLocalIndex = this.index
|
|
224
|
+
let counter = 0
|
|
225
|
+
callback(null, {
|
|
226
|
+
next: function () {
|
|
227
|
+
let host
|
|
228
|
+
if (counter++ < localHostsArray.length) {
|
|
229
|
+
host =
|
|
230
|
+
localHostsArray[planLocalIndex++ % localHostsArray.length]
|
|
231
|
+
return { value: host, done: false }
|
|
232
|
+
}
|
|
233
|
+
return doneIteratorObject
|
|
234
|
+
},
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Gets an associative array containing the policy options.
|
|
240
|
+
*/
|
|
241
|
+
DCAwareRoundRobinPolicy.prototype.getOptions = function () {
|
|
242
|
+
return new Map([["localDataCenter", this.localDc]])
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* A wrapper load balancing policy that add token awareness to a child policy.
|
|
247
|
+
* @param {LoadBalancingPolicy} childPolicy
|
|
248
|
+
* @extends LoadBalancingPolicy
|
|
249
|
+
* @constructor
|
|
250
|
+
*/
|
|
251
|
+
function TokenAwarePolicy(childPolicy) {
|
|
252
|
+
if (!childPolicy) {
|
|
253
|
+
throw new Error("You must specify a child load balancing policy")
|
|
254
|
+
}
|
|
255
|
+
this.childPolicy = childPolicy
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
util.inherits(TokenAwarePolicy, LoadBalancingPolicy)
|
|
259
|
+
|
|
260
|
+
TokenAwarePolicy.prototype.init = function (client, hosts, callback) {
|
|
261
|
+
this.client = client
|
|
262
|
+
this.hosts = hosts
|
|
263
|
+
this.childPolicy.init(client, hosts, callback)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
TokenAwarePolicy.prototype.getDistance = function (host) {
|
|
267
|
+
return this.childPolicy.getDistance(host)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Returns the hosts to use for a new query.
|
|
272
|
+
* The returned plan will return local replicas first, if replicas can be determined, followed by the plan of the
|
|
273
|
+
* child policy.
|
|
274
|
+
* @param {String} keyspace Name of currently logged keyspace at <code>Client</code> level.
|
|
275
|
+
* @param {ExecutionOptions|null} executionOptions The information related to the execution of the request.
|
|
276
|
+
* @param {Function} callback The function to be invoked with the error as first parameter and the host iterator as
|
|
277
|
+
* second parameter.
|
|
278
|
+
*/
|
|
279
|
+
TokenAwarePolicy.prototype.newQueryPlan = function (
|
|
280
|
+
keyspace,
|
|
281
|
+
executionOptions,
|
|
282
|
+
callback,
|
|
283
|
+
) {
|
|
284
|
+
let routingKey
|
|
285
|
+
if (executionOptions) {
|
|
286
|
+
routingKey = executionOptions.getRoutingKey()
|
|
287
|
+
if (executionOptions.getKeyspace()) {
|
|
288
|
+
keyspace = executionOptions.getKeyspace()
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
let replicas
|
|
292
|
+
if (routingKey) {
|
|
293
|
+
replicas = this.client.getReplicas(keyspace, routingKey)
|
|
294
|
+
}
|
|
295
|
+
if (!routingKey || !replicas) {
|
|
296
|
+
return this.childPolicy.newQueryPlan(
|
|
297
|
+
keyspace,
|
|
298
|
+
executionOptions,
|
|
299
|
+
callback,
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
const iterator = new TokenAwareIterator(
|
|
303
|
+
keyspace,
|
|
304
|
+
executionOptions,
|
|
305
|
+
replicas,
|
|
306
|
+
this.childPolicy,
|
|
307
|
+
)
|
|
308
|
+
iterator.iterate(callback)
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* An iterator that holds the context for the subsequent next() calls
|
|
313
|
+
* @param {String} keyspace
|
|
314
|
+
* @param {ExecutionOptions} execOptions
|
|
315
|
+
* @param {Array} replicas
|
|
316
|
+
* @param childPolicy
|
|
317
|
+
* @constructor
|
|
318
|
+
* @ignore
|
|
319
|
+
*/
|
|
320
|
+
function TokenAwareIterator(keyspace, execOptions, replicas, childPolicy) {
|
|
321
|
+
this.keyspace = keyspace
|
|
322
|
+
this.childPolicy = childPolicy
|
|
323
|
+
this.options = execOptions
|
|
324
|
+
this.localReplicas = []
|
|
325
|
+
this.replicaIndex = 0
|
|
326
|
+
this.replicaMap = {}
|
|
327
|
+
this.childIterator = null
|
|
328
|
+
// Memoize the local replicas
|
|
329
|
+
// The amount of local replicas should be defined before start iterating, in order to select an
|
|
330
|
+
// appropriate (pseudo random) startIndex
|
|
331
|
+
for (let i = 0; i < replicas.length; i++) {
|
|
332
|
+
const host = replicas[i]
|
|
333
|
+
if (this.childPolicy.getDistance(host) !== types.distance.local) {
|
|
334
|
+
continue
|
|
335
|
+
}
|
|
336
|
+
this.replicaMap[host.address] = true
|
|
337
|
+
this.localReplicas.push(host)
|
|
338
|
+
}
|
|
339
|
+
// We use a PRNG to set the replica index
|
|
340
|
+
// We only care about proportional fair scheduling between replicas of a given token
|
|
341
|
+
// Math.random() has an extremely short permutation cycle length but we don't care about collisions
|
|
342
|
+
this.startIndex = Math.floor(Math.random() * this.localReplicas.length)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
TokenAwareIterator.prototype.iterate = function (callback) {
|
|
346
|
+
//Load the child policy hosts
|
|
347
|
+
const self = this
|
|
348
|
+
this.childPolicy.newQueryPlan(
|
|
349
|
+
this.keyspace,
|
|
350
|
+
this.options,
|
|
351
|
+
function (err, iterator) {
|
|
352
|
+
if (err) {
|
|
353
|
+
return callback(err)
|
|
354
|
+
}
|
|
355
|
+
//get the iterator of the child policy in case is needed
|
|
356
|
+
self.childIterator = iterator
|
|
357
|
+
callback(null, {
|
|
358
|
+
next: function () {
|
|
359
|
+
return self.computeNext()
|
|
360
|
+
},
|
|
361
|
+
})
|
|
362
|
+
},
|
|
363
|
+
)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
TokenAwareIterator.prototype.computeNext = function () {
|
|
367
|
+
let host
|
|
368
|
+
if (this.replicaIndex < this.localReplicas.length) {
|
|
369
|
+
host =
|
|
370
|
+
this.localReplicas[
|
|
371
|
+
(this.startIndex + this.replicaIndex++) %
|
|
372
|
+
this.localReplicas.length
|
|
373
|
+
]
|
|
374
|
+
return { value: host, done: false }
|
|
375
|
+
}
|
|
376
|
+
// Return hosts from child policy
|
|
377
|
+
let item
|
|
378
|
+
while ((item = this.childIterator.next()) && !item.done) {
|
|
379
|
+
if (this.replicaMap[item.value.address]) {
|
|
380
|
+
// Avoid yielding local replicas from the child load balancing policy query plan
|
|
381
|
+
continue
|
|
382
|
+
}
|
|
383
|
+
return item
|
|
384
|
+
}
|
|
385
|
+
return doneIteratorObject
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Gets an associative array containing the policy options.
|
|
390
|
+
*/
|
|
391
|
+
TokenAwarePolicy.prototype.getOptions = function () {
|
|
392
|
+
const map = new Map([
|
|
393
|
+
[
|
|
394
|
+
"childPolicy",
|
|
395
|
+
this.childPolicy.constructor !== undefined
|
|
396
|
+
? this.childPolicy.constructor.name
|
|
397
|
+
: null,
|
|
398
|
+
],
|
|
399
|
+
])
|
|
400
|
+
|
|
401
|
+
if (this.childPolicy instanceof DCAwareRoundRobinPolicy) {
|
|
402
|
+
map.set("localDataCenter", this.childPolicy.localDc)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return map
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Create a new policy that wraps the provided child policy but only "allow" hosts
|
|
410
|
+
* from the provided list.
|
|
411
|
+
* @class
|
|
412
|
+
* @classdesc
|
|
413
|
+
* A load balancing policy wrapper that ensure that only hosts from a provided
|
|
414
|
+
* allow list will ever be returned.
|
|
415
|
+
* <p>
|
|
416
|
+
* This policy wraps another load balancing policy and will delegate the choice
|
|
417
|
+
* of hosts to the wrapped policy with the exception that only hosts contained
|
|
418
|
+
* in the allow list provided when constructing this policy will ever be
|
|
419
|
+
* returned. Any host not in the while list will be considered ignored
|
|
420
|
+
* and thus will not be connected to.
|
|
421
|
+
* <p>
|
|
422
|
+
* This policy can be useful to ensure that the driver only connects to a
|
|
423
|
+
* predefined set of hosts. Keep in mind however that this policy defeats
|
|
424
|
+
* somewhat the host auto-detection of the driver. As such, this policy is only
|
|
425
|
+
* useful in a few special cases or for testing, but is not optimal in general.
|
|
426
|
+
* If all you want to do is limiting connections to hosts of the local
|
|
427
|
+
* data-center then you should use DCAwareRoundRobinPolicy and *not* this policy
|
|
428
|
+
* in particular.
|
|
429
|
+
* @param {LoadBalancingPolicy} childPolicy the wrapped policy.
|
|
430
|
+
* @param {Array.<string>} allowList The hosts address in the format ipAddress:port.
|
|
431
|
+
* Only hosts from this list may get connected
|
|
432
|
+
* to (whether they will get connected to or not depends on the child policy).
|
|
433
|
+
* @extends LoadBalancingPolicy
|
|
434
|
+
* @constructor
|
|
435
|
+
*/
|
|
436
|
+
function AllowListPolicy(childPolicy, allowList) {
|
|
437
|
+
if (!childPolicy) {
|
|
438
|
+
throw new Error("You must specify a child load balancing policy")
|
|
439
|
+
}
|
|
440
|
+
if (!Array.isArray(allowList)) {
|
|
441
|
+
throw new Error("You must provide the list of allowed host addresses")
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
this.childPolicy = childPolicy
|
|
445
|
+
this.allowList = new Map(allowList.map((address) => [address, true]))
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
util.inherits(AllowListPolicy, LoadBalancingPolicy)
|
|
449
|
+
|
|
450
|
+
AllowListPolicy.prototype.init = function (client, hosts, callback) {
|
|
451
|
+
this.childPolicy.init(client, hosts, callback)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Uses the child policy to return the distance to the host if included in the allow list.
|
|
456
|
+
* Any host not in the while list will be considered ignored.
|
|
457
|
+
* @param host
|
|
458
|
+
*/
|
|
459
|
+
AllowListPolicy.prototype.getDistance = function (host) {
|
|
460
|
+
if (!this._contains(host)) {
|
|
461
|
+
return types.distance.ignored
|
|
462
|
+
}
|
|
463
|
+
return this.childPolicy.getDistance(host)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* @param {Host} host
|
|
468
|
+
* @returns {boolean}
|
|
469
|
+
* @private
|
|
470
|
+
*/
|
|
471
|
+
AllowListPolicy.prototype._contains = function (host) {
|
|
472
|
+
return !!this.allowList.get(host.address)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Returns the hosts to use for a new query filtered by the allow list.
|
|
477
|
+
*/
|
|
478
|
+
AllowListPolicy.prototype.newQueryPlan = function (keyspace, info, callback) {
|
|
479
|
+
const self = this
|
|
480
|
+
this.childPolicy.newQueryPlan(keyspace, info, function (err, iterator) {
|
|
481
|
+
if (err) {
|
|
482
|
+
return callback(err)
|
|
483
|
+
}
|
|
484
|
+
callback(null, self._filter(iterator))
|
|
485
|
+
})
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
AllowListPolicy.prototype._filter = function (childIterator) {
|
|
489
|
+
const self = this
|
|
490
|
+
return {
|
|
491
|
+
next: function () {
|
|
492
|
+
const item = childIterator.next()
|
|
493
|
+
if (!item.done && !self._contains(item.value)) {
|
|
494
|
+
return this.next()
|
|
495
|
+
}
|
|
496
|
+
return item
|
|
497
|
+
},
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* Gets an associative array containing the policy options.
|
|
503
|
+
*/
|
|
504
|
+
AllowListPolicy.prototype.getOptions = function () {
|
|
505
|
+
return new Map([
|
|
506
|
+
[
|
|
507
|
+
"childPolicy",
|
|
508
|
+
this.childPolicy.constructor !== undefined
|
|
509
|
+
? this.childPolicy.constructor.name
|
|
510
|
+
: null,
|
|
511
|
+
],
|
|
512
|
+
["allowList", Array.from(this.allowList.keys())],
|
|
513
|
+
])
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Creates a new instance of the policy.
|
|
518
|
+
* @classdesc
|
|
519
|
+
* Exposed for backward-compatibility only, it's recommended that you use {@link AllowListPolicy} instead.
|
|
520
|
+
* @param {LoadBalancingPolicy} childPolicy the wrapped policy.
|
|
521
|
+
* @param {Array.<string>} allowList The hosts address in the format ipAddress:port.
|
|
522
|
+
* Only hosts from this list may get connected to (whether they will get connected to or not depends on the child
|
|
523
|
+
* policy).
|
|
524
|
+
* @extends AllowListPolicy
|
|
525
|
+
* @deprecated Use allow-list instead. It will be removed in future major versions.
|
|
526
|
+
* @constructor
|
|
527
|
+
*/
|
|
528
|
+
function WhiteListPolicy(childPolicy, allowList) {
|
|
529
|
+
AllowListPolicy.call(this, childPolicy, allowList)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
util.inherits(WhiteListPolicy, AllowListPolicy)
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* A load-balancing policy implementation that attempts to fairly distribute the load based on the amount of in-flight
|
|
536
|
+
* request per hosts. The local replicas are initially shuffled and
|
|
537
|
+
* <a href="https://www.eecs.harvard.edu/~michaelm/postscripts/mythesis.pdf">between the first two nodes in the
|
|
538
|
+
* shuffled list, the one with fewer in-flight requests is selected as coordinator</a>.
|
|
539
|
+
*
|
|
540
|
+
* <p>
|
|
541
|
+
* Additionally, it detects unresponsive replicas and reorders them at the back of the query plan.
|
|
542
|
+
* </p>
|
|
543
|
+
*
|
|
544
|
+
* <p>
|
|
545
|
+
* For graph analytics queries, it uses the preferred analytics graph server previously obtained by driver as first
|
|
546
|
+
* host in the query plan.
|
|
547
|
+
* </p>
|
|
548
|
+
*/
|
|
549
|
+
class DefaultLoadBalancingPolicy extends LoadBalancingPolicy {
|
|
550
|
+
/**
|
|
551
|
+
* Creates a new instance of <code>DefaultLoadBalancingPolicy</code>.
|
|
552
|
+
* @param {String|Object} [options] The local data center name or the optional policy options object.
|
|
553
|
+
* <p>
|
|
554
|
+
* Note that when providing the local data center name, it overrides <code>localDataCenter</code> option at
|
|
555
|
+
* <code>Client</code> level.
|
|
556
|
+
* </p>
|
|
557
|
+
* @param {String} [options.localDc] local data center name. This value overrides the 'localDataCenter' Client option
|
|
558
|
+
* and is useful for cases where you have multiple execution profiles that you intend on using for routing
|
|
559
|
+
* requests to different data centers.
|
|
560
|
+
* @param {Function} [options.filter] A function to apply to determine if hosts are included in the query plan.
|
|
561
|
+
* The function takes a Host parameter and returns a Boolean.
|
|
562
|
+
*/
|
|
563
|
+
constructor(options) {
|
|
564
|
+
super()
|
|
565
|
+
|
|
566
|
+
if (typeof options === "string") {
|
|
567
|
+
options = { localDc: options }
|
|
568
|
+
} else if (!options) {
|
|
569
|
+
options = utils.emptyObject
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
this._client = null
|
|
573
|
+
this._hosts = null
|
|
574
|
+
this._filteredHosts = null
|
|
575
|
+
this._preferredHost = null
|
|
576
|
+
this._index = 0
|
|
577
|
+
this.localDc = options.localDc
|
|
578
|
+
this._filter = options.filter || this._defaultFilter
|
|
579
|
+
|
|
580
|
+
// Allow some checks to be injected
|
|
581
|
+
if (options.isHostNewlyUp) {
|
|
582
|
+
this._isHostNewlyUp = options.isHostNewlyUp
|
|
583
|
+
}
|
|
584
|
+
if (options.healthCheck) {
|
|
585
|
+
this._healthCheck = options.healthCheck
|
|
586
|
+
}
|
|
587
|
+
if (options.compare) {
|
|
588
|
+
this._compare = options.compare
|
|
589
|
+
}
|
|
590
|
+
if (options.getReplicas) {
|
|
591
|
+
this._getReplicas = options.getReplicas
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Initializes the load balancing policy, called after the driver obtained the information of the cluster.
|
|
597
|
+
* @param {Client} client
|
|
598
|
+
* @param {HostMap} hosts
|
|
599
|
+
* @param {Function} callback
|
|
600
|
+
*/
|
|
601
|
+
init(client, hosts, callback) {
|
|
602
|
+
this._client = client
|
|
603
|
+
this._hosts = hosts
|
|
604
|
+
|
|
605
|
+
// Clean local host cache
|
|
606
|
+
this._hosts.on("add", () => (this._filteredHosts = null))
|
|
607
|
+
this._hosts.on("remove", () => (this._filteredHosts = null))
|
|
608
|
+
|
|
609
|
+
try {
|
|
610
|
+
setLocalDc(this, client, this._hosts)
|
|
611
|
+
} catch (err) {
|
|
612
|
+
return callback(err)
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
callback()
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Returns the distance assigned by this policy to the provided host, relatively to the client instance.
|
|
620
|
+
* @param {Host} host
|
|
621
|
+
*/
|
|
622
|
+
getDistance(host) {
|
|
623
|
+
if (this._preferredHost !== null && host === this._preferredHost) {
|
|
624
|
+
// Set the last preferred host as local.
|
|
625
|
+
// It ensures that the pool for the graph analytics host has the appropriate size
|
|
626
|
+
return types.distance.local
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
if (!this._filter(host)) {
|
|
630
|
+
return types.distance.ignored
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
return host.datacenter === this.localDc
|
|
634
|
+
? types.distance.local
|
|
635
|
+
: types.distance.ignored
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Returns a host iterator to be used for a query execution.
|
|
640
|
+
* @override
|
|
641
|
+
* @param {String} keyspace
|
|
642
|
+
* @param {ExecutionOptions} executionOptions
|
|
643
|
+
* @param {Function} callback
|
|
644
|
+
*/
|
|
645
|
+
newQueryPlan(keyspace, executionOptions, callback) {
|
|
646
|
+
let routingKey
|
|
647
|
+
let preferredHost
|
|
648
|
+
|
|
649
|
+
if (executionOptions) {
|
|
650
|
+
routingKey = executionOptions.getRoutingKey()
|
|
651
|
+
|
|
652
|
+
if (executionOptions.getKeyspace()) {
|
|
653
|
+
keyspace = executionOptions.getKeyspace()
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
preferredHost = executionOptions.getPreferredHost()
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
let iterable
|
|
660
|
+
|
|
661
|
+
if (!keyspace || !routingKey) {
|
|
662
|
+
iterable = this._getLocalHosts()
|
|
663
|
+
} else {
|
|
664
|
+
iterable = this._getReplicasAndLocalHosts(keyspace, routingKey)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
if (preferredHost) {
|
|
668
|
+
// Set it on an instance level field to set the distance
|
|
669
|
+
this._preferredHost = preferredHost
|
|
670
|
+
iterable = DefaultLoadBalancingPolicy._getPreferredHostFirst(
|
|
671
|
+
preferredHost,
|
|
672
|
+
iterable,
|
|
673
|
+
)
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
return callback(null, iterable)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Yields the preferred host first, followed by the host in the provided iterable
|
|
681
|
+
* @param preferredHost
|
|
682
|
+
* @param iterable
|
|
683
|
+
* @private
|
|
684
|
+
*/
|
|
685
|
+
static *_getPreferredHostFirst(preferredHost, iterable) {
|
|
686
|
+
yield preferredHost
|
|
687
|
+
|
|
688
|
+
for (const host of iterable) {
|
|
689
|
+
if (host !== preferredHost) {
|
|
690
|
+
yield host
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Yields the local hosts without the replicas already yielded
|
|
697
|
+
* @param {Array<Host>} [localReplicas] The local replicas that we should avoid to include again
|
|
698
|
+
* @private
|
|
699
|
+
*/
|
|
700
|
+
*_getLocalHosts(localReplicas) {
|
|
701
|
+
// Use a local reference
|
|
702
|
+
const hosts = this._getFilteredLocalHosts()
|
|
703
|
+
const initialIndex = this._getIndex()
|
|
704
|
+
|
|
705
|
+
// indexOf() over an Array is a O(n) operation but given that there should be 3 to 7 replicas,
|
|
706
|
+
// it shouldn't be an expensive call. Additionally, this will only be executed when the local replicas
|
|
707
|
+
// have been exhausted in a lazy manner.
|
|
708
|
+
const canBeYield = localReplicas
|
|
709
|
+
? (h) => localReplicas.indexOf(h) === -1
|
|
710
|
+
: (h) => true
|
|
711
|
+
|
|
712
|
+
for (let i = 0; i < hosts.length; i++) {
|
|
713
|
+
const h = hosts[(i + initialIndex) % hosts.length]
|
|
714
|
+
if (canBeYield(h) && h.isUp()) {
|
|
715
|
+
yield h
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
_getReplicasAndLocalHosts(keyspace, routingKey) {
|
|
721
|
+
let replicas = this._getReplicas(keyspace, routingKey)
|
|
722
|
+
if (replicas === null) {
|
|
723
|
+
return this._getLocalHosts()
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const filteredReplicas = []
|
|
727
|
+
let newlyUpReplica = null
|
|
728
|
+
let newlyUpReplicaTimestamp = Number.MIN_SAFE_INTEGER
|
|
729
|
+
let unhealthyReplicas = 0
|
|
730
|
+
|
|
731
|
+
// Filter by DC, predicate and UP replicas
|
|
732
|
+
// Use the same iteration to perform other checks: whether if its newly UP or unhealthy
|
|
733
|
+
// As this is part of the hot path, we use a simple loop and avoid using Array.prototype.filter() + closure
|
|
734
|
+
for (let i = 0; i < replicas.length; i++) {
|
|
735
|
+
const h = replicas[i]
|
|
736
|
+
if (
|
|
737
|
+
!this._filter(h) ||
|
|
738
|
+
h.datacenter !== this.localDc ||
|
|
739
|
+
!h.isUp()
|
|
740
|
+
) {
|
|
741
|
+
continue
|
|
742
|
+
}
|
|
743
|
+
const isUpSince = this._isHostNewlyUp(h)
|
|
744
|
+
if (isUpSince !== null && isUpSince > newlyUpReplicaTimestamp) {
|
|
745
|
+
newlyUpReplica = h
|
|
746
|
+
newlyUpReplicaTimestamp = isUpSince
|
|
747
|
+
}
|
|
748
|
+
if (newlyUpReplica === null && !this._healthCheck(h)) {
|
|
749
|
+
unhealthyReplicas++
|
|
750
|
+
}
|
|
751
|
+
filteredReplicas.push(h)
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
replicas = filteredReplicas
|
|
755
|
+
|
|
756
|
+
// Shuffle remaining local replicas
|
|
757
|
+
utils.shuffleArray(replicas)
|
|
758
|
+
|
|
759
|
+
if (replicas.length < 3) {
|
|
760
|
+
// Avoid reordering replicas of a set of 2 as we could be doing more harm than good
|
|
761
|
+
return this.yieldReplicasFirst(replicas)
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
let temp
|
|
765
|
+
|
|
766
|
+
if (newlyUpReplica === null) {
|
|
767
|
+
if (
|
|
768
|
+
unhealthyReplicas > 0 &&
|
|
769
|
+
unhealthyReplicas < Math.floor(replicas.length / 2 + 1)
|
|
770
|
+
) {
|
|
771
|
+
// There is one or more unhealthy replicas and there is a majority of healthy replicas
|
|
772
|
+
this._sendUnhealthyToTheBack(replicas, unhealthyReplicas)
|
|
773
|
+
}
|
|
774
|
+
} else if (
|
|
775
|
+
(newlyUpReplica === replicas[0] ||
|
|
776
|
+
newlyUpReplica === replicas[1]) &&
|
|
777
|
+
Math.random() * 4 >= 1
|
|
778
|
+
) {
|
|
779
|
+
// There is a newly UP replica and the replica in first or second position is the most recent replica
|
|
780
|
+
// marked as UP and dice roll 1d4!=1 -> Send it to the back of the Array
|
|
781
|
+
const index = newlyUpReplica === replicas[0] ? 0 : 1
|
|
782
|
+
temp = replicas[replicas.length - 1]
|
|
783
|
+
replicas[replicas.length - 1] = replicas[index]
|
|
784
|
+
replicas[index] = temp
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
if (this._compare(replicas[1], replicas[0]) > 0) {
|
|
788
|
+
// Power of two random choices
|
|
789
|
+
temp = replicas[0]
|
|
790
|
+
replicas[0] = replicas[1]
|
|
791
|
+
replicas[1] = temp
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
return this.yieldReplicasFirst(replicas)
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Yields the local replicas followed by the rest of local nodes.
|
|
799
|
+
* @param {Array<Host>} replicas The local replicas
|
|
800
|
+
*/
|
|
801
|
+
*yieldReplicasFirst(replicas) {
|
|
802
|
+
for (let i = 0; i < replicas.length; i++) {
|
|
803
|
+
yield replicas[i]
|
|
804
|
+
}
|
|
805
|
+
yield* this._getLocalHosts(replicas)
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
_isHostNewlyUp(h) {
|
|
809
|
+
return h.isUpSince !== null &&
|
|
810
|
+
Date.now() - h.isUpSince < newlyUpInterval
|
|
811
|
+
? h.isUpSince
|
|
812
|
+
: null
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Returns a boolean determining whether the host health is ok or not.
|
|
817
|
+
* A Host is considered unhealthy when there are enough items in the queue (10 items in-flight) but the
|
|
818
|
+
* Host is not responding to those requests.
|
|
819
|
+
* @param {Host} h
|
|
820
|
+
* @return {boolean}
|
|
821
|
+
* @private
|
|
822
|
+
*/
|
|
823
|
+
_healthCheck(h) {
|
|
824
|
+
return !(h.getInFlight() >= 10 && h.getResponseCount() <= 1)
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
/**
|
|
828
|
+
* Compares to host and returns 1 if it needs to favor the first host otherwise, -1.
|
|
829
|
+
* @return {number}
|
|
830
|
+
* @private
|
|
831
|
+
*/
|
|
832
|
+
_compare(h1, h2) {
|
|
833
|
+
return h1.getInFlight() < h2.getInFlight() ? 1 : -1
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
_getReplicas(keyspace, routingKey) {
|
|
837
|
+
return this._client.getReplicas(keyspace, routingKey)
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Returns an Array of hosts filtered by DC and predicate.
|
|
842
|
+
* @returns {Array<Host>}
|
|
843
|
+
* @private
|
|
844
|
+
*/
|
|
845
|
+
_getFilteredLocalHosts() {
|
|
846
|
+
if (this._filteredHosts === null) {
|
|
847
|
+
this._filteredHosts = this._hosts
|
|
848
|
+
.values()
|
|
849
|
+
.filter((h) => this._filter(h) && h.datacenter === this.localDc)
|
|
850
|
+
}
|
|
851
|
+
return this._filteredHosts
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
_getIndex() {
|
|
855
|
+
const result = this._index++
|
|
856
|
+
// Overflow protection
|
|
857
|
+
if (this._index === 0x7fffffff) {
|
|
858
|
+
this._index = 0
|
|
859
|
+
}
|
|
860
|
+
return result
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
_sendUnhealthyToTheBack(replicas, unhealthyReplicas) {
|
|
864
|
+
let counter = 0
|
|
865
|
+
|
|
866
|
+
// Start from the back, move backwards and stop once all unhealthy replicas are at the back
|
|
867
|
+
for (
|
|
868
|
+
let i = replicas.length - 1;
|
|
869
|
+
i >= 0 && counter < unhealthyReplicas;
|
|
870
|
+
i--
|
|
871
|
+
) {
|
|
872
|
+
const host = replicas[i]
|
|
873
|
+
if (this._healthCheck(host)) {
|
|
874
|
+
continue
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const targetIndex = replicas.length - 1 - counter
|
|
878
|
+
if (targetIndex !== i) {
|
|
879
|
+
const temp = replicas[targetIndex]
|
|
880
|
+
replicas[targetIndex] = host
|
|
881
|
+
replicas[i] = temp
|
|
882
|
+
}
|
|
883
|
+
counter++
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
_defaultFilter() {
|
|
888
|
+
return true
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Gets an associative array containing the policy options.
|
|
893
|
+
*/
|
|
894
|
+
getOptions() {
|
|
895
|
+
return new Map([
|
|
896
|
+
["localDataCenter", this.localDc],
|
|
897
|
+
["filterFunction", this._filter !== this._defaultFilter],
|
|
898
|
+
])
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Validates and sets the local data center to be used.
|
|
904
|
+
* @param {LoadBalancingPolicy} lbp
|
|
905
|
+
* @param {Client} client
|
|
906
|
+
* @param {HostMap} hosts
|
|
907
|
+
* @private
|
|
908
|
+
*/
|
|
909
|
+
function setLocalDc(lbp, client, hosts) {
|
|
910
|
+
if (!(lbp instanceof LoadBalancingPolicy)) {
|
|
911
|
+
throw new errors.DriverInternalError(
|
|
912
|
+
"LoadBalancingPolicy instance was not provided",
|
|
913
|
+
)
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (client && client.options) {
|
|
917
|
+
if (lbp.localDc && !client.options.localDataCenter) {
|
|
918
|
+
client.log(
|
|
919
|
+
"info",
|
|
920
|
+
`Local data center '${lbp.localDc}' was provided as an argument to the load-balancing` +
|
|
921
|
+
` policy. It is preferable to specify the local data center using 'localDataCenter' in Client` +
|
|
922
|
+
` options instead when your application is targeting a single data center.`,
|
|
923
|
+
)
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
// If localDc is unset, use value set in client options.
|
|
927
|
+
lbp.localDc = lbp.localDc || client.options.localDataCenter
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
const dcs = getDataCenters(hosts)
|
|
931
|
+
|
|
932
|
+
if (!lbp.localDc) {
|
|
933
|
+
throw new errors.ArgumentError(
|
|
934
|
+
`'localDataCenter' is not defined in Client options and also was not specified in constructor.` +
|
|
935
|
+
` At least one is required. Available DCs are: [${Array.from(dcs)}]`,
|
|
936
|
+
)
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
if (!dcs.has(lbp.localDc)) {
|
|
940
|
+
throw new errors.ArgumentError(
|
|
941
|
+
`Datacenter ${lbp.localDc} was not found. Available DCs are: [${Array.from(dcs)}]`,
|
|
942
|
+
)
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function getDataCenters(hosts) {
|
|
947
|
+
return new Set(hosts.values().map((h) => h.datacenter))
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
export {
|
|
951
|
+
AllowListPolicy,
|
|
952
|
+
DCAwareRoundRobinPolicy,
|
|
953
|
+
DefaultLoadBalancingPolicy,
|
|
954
|
+
LoadBalancingPolicy,
|
|
955
|
+
RoundRobinPolicy,
|
|
956
|
+
TokenAwarePolicy,
|
|
957
|
+
// Deprecated: for backward compatibility only.
|
|
958
|
+
WhiteListPolicy,
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
export default {
|
|
962
|
+
AllowListPolicy,
|
|
963
|
+
DCAwareRoundRobinPolicy,
|
|
964
|
+
DefaultLoadBalancingPolicy,
|
|
965
|
+
LoadBalancingPolicy,
|
|
966
|
+
RoundRobinPolicy,
|
|
967
|
+
TokenAwarePolicy,
|
|
968
|
+
// Deprecated: for backward compatibility only.
|
|
969
|
+
WhiteListPolicy,
|
|
970
|
+
}
|