@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,631 @@
|
|
|
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 types from "./types/index.js"
|
|
19
|
+
import token from "./token.js"
|
|
20
|
+
import utils from "./utils.js"
|
|
21
|
+
import MutableLong from "./types/mutable-long.js"
|
|
22
|
+
import crypto from "crypto"
|
|
23
|
+
const { Integer } = types
|
|
24
|
+
|
|
25
|
+
// Murmur3 constants
|
|
26
|
+
//-0x783C846EEEBDAC2B
|
|
27
|
+
const mconst1 = new MutableLong(0x53d5, 0x1142, 0x7b91, 0x87c3)
|
|
28
|
+
//0x4cf5ad432745937f
|
|
29
|
+
const mconst2 = new MutableLong(0x937f, 0x2745, 0xad43, 0x4cf5)
|
|
30
|
+
const mlongFive = MutableLong.fromNumber(5)
|
|
31
|
+
//0xff51afd7ed558ccd
|
|
32
|
+
const mconst3 = new MutableLong(0x8ccd, 0xed55, 0xafd7, 0xff51)
|
|
33
|
+
//0xc4ceb9fe1a85ec53
|
|
34
|
+
const mconst4 = new MutableLong(0xec53, 0x1a85, 0xb9fe, 0xc4ce)
|
|
35
|
+
const mconst5 = MutableLong.fromNumber(0x52dce729)
|
|
36
|
+
const mconst6 = MutableLong.fromNumber(0x38495ab5)
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Represents a set of methods that are able to generate and parse tokens for the C* partitioner.
|
|
40
|
+
* @abstract
|
|
41
|
+
*/
|
|
42
|
+
class Tokenizer {
|
|
43
|
+
constructor() {}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a token based on the Buffer value provided
|
|
47
|
+
* @abstract
|
|
48
|
+
* @param {Buffer|Array} value
|
|
49
|
+
* @returns {Token} Computed token
|
|
50
|
+
*/
|
|
51
|
+
hash(value) {
|
|
52
|
+
throw new Error("You must implement a hash function for the tokenizer")
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Parses a token string and returns a representation of the token
|
|
57
|
+
* @abstract
|
|
58
|
+
* @param {String} value
|
|
59
|
+
*/
|
|
60
|
+
parse(value) {
|
|
61
|
+
throw new Error("You must implement a parse function for the tokenizer")
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
minToken() {
|
|
65
|
+
throw new Error(
|
|
66
|
+
"You must implement a minToken function for the tokenizer",
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Splits the range specified by start and end into numberOfSplits equal parts.
|
|
72
|
+
* @param {Token} start Starting token
|
|
73
|
+
* @param {Token} end End token
|
|
74
|
+
* @param {Number} numberOfSplits Number of splits to make.
|
|
75
|
+
*/
|
|
76
|
+
split(start, end, numberOfSplits) {
|
|
77
|
+
throw new Error("You must implement a split function for the tokenizer")
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Common implementation for splitting token ranges when start is in
|
|
82
|
+
* a shared Integer format.
|
|
83
|
+
*
|
|
84
|
+
* @param {Integer} start Starting token
|
|
85
|
+
* @param {Integer} range How large the range of the split is
|
|
86
|
+
* @param {Integer} ringEnd The end point of the ring so we know where to wrap
|
|
87
|
+
* @param {Integer} ringLength The total size of the ring
|
|
88
|
+
* @param {Number} numberOfSplits The number of splits to make
|
|
89
|
+
* @returns {Array<Integer>} The evenly-split points on the range
|
|
90
|
+
*/
|
|
91
|
+
splitBase(start, range, ringEnd, ringLength, numberOfSplits) {
|
|
92
|
+
const numberOfSplitsInt = Integer.fromInt(numberOfSplits)
|
|
93
|
+
const divider = range.divide(numberOfSplitsInt)
|
|
94
|
+
let remainder = range.modulo(numberOfSplitsInt)
|
|
95
|
+
|
|
96
|
+
const results = []
|
|
97
|
+
let current = start
|
|
98
|
+
const dividerPlusOne = divider.add(Integer.ONE)
|
|
99
|
+
|
|
100
|
+
for (let i = 1; i < numberOfSplits; i++) {
|
|
101
|
+
if (remainder.greaterThan(Integer.ZERO)) {
|
|
102
|
+
current = current.add(dividerPlusOne)
|
|
103
|
+
} else {
|
|
104
|
+
current = current.add(divider)
|
|
105
|
+
}
|
|
106
|
+
if (ringLength && current.greaterThan(ringEnd)) {
|
|
107
|
+
current = current.subtract(ringLength)
|
|
108
|
+
}
|
|
109
|
+
results.push(current)
|
|
110
|
+
remainder = remainder.subtract(Integer.ONE)
|
|
111
|
+
}
|
|
112
|
+
return results
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Return internal string based representation of a Token.
|
|
117
|
+
* @param {Token} token
|
|
118
|
+
*/
|
|
119
|
+
stringify(token) {
|
|
120
|
+
return token.getValue().toString()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Uniformly distributes data across the cluster based on Cassandra flavored Murmur3 hashed values.
|
|
126
|
+
*/
|
|
127
|
+
class Murmur3Tokenizer extends Tokenizer {
|
|
128
|
+
constructor() {
|
|
129
|
+
super()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {Buffer} value
|
|
134
|
+
* @return {Murmur3Token}
|
|
135
|
+
*/
|
|
136
|
+
hash(value) {
|
|
137
|
+
// This is an adapted version of the MurmurHash.hash3_x64_128 from Cassandra used
|
|
138
|
+
// for M3P. Compared to that methods, there's a few inlining of arguments and we
|
|
139
|
+
// only return the first 64-bits of the result since that's all M3 partitioner uses.
|
|
140
|
+
|
|
141
|
+
const data = value
|
|
142
|
+
let offset = 0
|
|
143
|
+
const length = data.length
|
|
144
|
+
|
|
145
|
+
const nblocks = length >> 4 // Process as 128-bit blocks.
|
|
146
|
+
|
|
147
|
+
const h1 = new MutableLong()
|
|
148
|
+
const h2 = new MutableLong()
|
|
149
|
+
let k1 = new MutableLong()
|
|
150
|
+
let k2 = new MutableLong()
|
|
151
|
+
|
|
152
|
+
for (let i = 0; i < nblocks; i++) {
|
|
153
|
+
k1 = this.getBlock(data, offset, i * 2)
|
|
154
|
+
k2 = this.getBlock(data, offset, i * 2 + 1)
|
|
155
|
+
|
|
156
|
+
k1.multiply(mconst1)
|
|
157
|
+
this.rotl64(k1, 31)
|
|
158
|
+
k1.multiply(mconst2)
|
|
159
|
+
|
|
160
|
+
h1.xor(k1)
|
|
161
|
+
this.rotl64(h1, 27)
|
|
162
|
+
h1.add(h2)
|
|
163
|
+
h1.multiply(mlongFive).add(mconst5)
|
|
164
|
+
|
|
165
|
+
k2.multiply(mconst2)
|
|
166
|
+
this.rotl64(k2, 33)
|
|
167
|
+
k2.multiply(mconst1)
|
|
168
|
+
h2.xor(k2)
|
|
169
|
+
this.rotl64(h2, 31)
|
|
170
|
+
h2.add(h1)
|
|
171
|
+
h2.multiply(mlongFive).add(mconst6)
|
|
172
|
+
}
|
|
173
|
+
//----------
|
|
174
|
+
// tail
|
|
175
|
+
|
|
176
|
+
// Advance offset to the unprocessed tail of the data.
|
|
177
|
+
offset += nblocks * 16
|
|
178
|
+
|
|
179
|
+
k1 = new MutableLong()
|
|
180
|
+
k2 = new MutableLong()
|
|
181
|
+
|
|
182
|
+
/* eslint-disable no-fallthrough */
|
|
183
|
+
switch (length & 15) {
|
|
184
|
+
case 15:
|
|
185
|
+
k2.xor(fromSignedByte(data[offset + 14]).shiftLeft(48))
|
|
186
|
+
case 14:
|
|
187
|
+
k2.xor(fromSignedByte(data[offset + 13]).shiftLeft(40))
|
|
188
|
+
case 13:
|
|
189
|
+
k2.xor(fromSignedByte(data[offset + 12]).shiftLeft(32))
|
|
190
|
+
case 12:
|
|
191
|
+
k2.xor(fromSignedByte(data[offset + 11]).shiftLeft(24))
|
|
192
|
+
case 11:
|
|
193
|
+
k2.xor(fromSignedByte(data[offset + 10]).shiftLeft(16))
|
|
194
|
+
case 10:
|
|
195
|
+
k2.xor(fromSignedByte(data[offset + 9]).shiftLeft(8))
|
|
196
|
+
case 9:
|
|
197
|
+
k2.xor(fromSignedByte(data[offset + 8]))
|
|
198
|
+
k2.multiply(mconst2)
|
|
199
|
+
this.rotl64(k2, 33)
|
|
200
|
+
k2.multiply(mconst1)
|
|
201
|
+
h2.xor(k2)
|
|
202
|
+
case 8:
|
|
203
|
+
k1.xor(fromSignedByte(data[offset + 7]).shiftLeft(56))
|
|
204
|
+
case 7:
|
|
205
|
+
k1.xor(fromSignedByte(data[offset + 6]).shiftLeft(48))
|
|
206
|
+
case 6:
|
|
207
|
+
k1.xor(fromSignedByte(data[offset + 5]).shiftLeft(40))
|
|
208
|
+
case 5:
|
|
209
|
+
k1.xor(fromSignedByte(data[offset + 4]).shiftLeft(32))
|
|
210
|
+
case 4:
|
|
211
|
+
k1.xor(fromSignedByte(data[offset + 3]).shiftLeft(24))
|
|
212
|
+
case 3:
|
|
213
|
+
k1.xor(fromSignedByte(data[offset + 2]).shiftLeft(16))
|
|
214
|
+
case 2:
|
|
215
|
+
k1.xor(fromSignedByte(data[offset + 1]).shiftLeft(8))
|
|
216
|
+
case 1:
|
|
217
|
+
k1.xor(fromSignedByte(data[offset]))
|
|
218
|
+
k1.multiply(mconst1)
|
|
219
|
+
this.rotl64(k1, 31)
|
|
220
|
+
k1.multiply(mconst2)
|
|
221
|
+
h1.xor(k1)
|
|
222
|
+
}
|
|
223
|
+
/* eslint-enable no-fallthrough */
|
|
224
|
+
|
|
225
|
+
h1.xor(MutableLong.fromNumber(length))
|
|
226
|
+
h2.xor(MutableLong.fromNumber(length))
|
|
227
|
+
|
|
228
|
+
h1.add(h2)
|
|
229
|
+
h2.add(h1)
|
|
230
|
+
|
|
231
|
+
this.fmix(h1)
|
|
232
|
+
this.fmix(h2)
|
|
233
|
+
|
|
234
|
+
h1.add(h2)
|
|
235
|
+
|
|
236
|
+
return new token.Murmur3Token(h1)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
*
|
|
241
|
+
* @param {Array<Number>} key
|
|
242
|
+
* @param {Number} offset
|
|
243
|
+
* @param {Number} index
|
|
244
|
+
* @return {MutableLong}
|
|
245
|
+
*/
|
|
246
|
+
getBlock(key, offset, index) {
|
|
247
|
+
const i8 = index << 3
|
|
248
|
+
const blockOffset = offset + i8
|
|
249
|
+
return new MutableLong(
|
|
250
|
+
key[blockOffset] | (key[blockOffset + 1] << 8),
|
|
251
|
+
key[blockOffset + 2] | (key[blockOffset + 3] << 8),
|
|
252
|
+
key[blockOffset + 4] | (key[blockOffset + 5] << 8),
|
|
253
|
+
key[blockOffset + 6] | (key[blockOffset + 7] << 8),
|
|
254
|
+
)
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* @param {MutableLong} v
|
|
259
|
+
* @param {Number} n
|
|
260
|
+
*/
|
|
261
|
+
rotl64(v, n) {
|
|
262
|
+
const left = v.clone().shiftLeft(n)
|
|
263
|
+
v.shiftRightUnsigned(64 - n).or(left)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** @param {MutableLong} k */
|
|
267
|
+
fmix(k) {
|
|
268
|
+
k.xor(
|
|
269
|
+
new MutableLong(
|
|
270
|
+
(k.getUint16(2) >>> 1) | ((k.getUint16(3) << 15) & 0xffff),
|
|
271
|
+
k.getUint16(3) >>> 1,
|
|
272
|
+
0,
|
|
273
|
+
0,
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
k.multiply(mconst3)
|
|
277
|
+
const other = new MutableLong(
|
|
278
|
+
(k.getUint16(2) >>> 1) | ((k.getUint16(3) << 15) & 0xffff),
|
|
279
|
+
k.getUint16(3) >>> 1,
|
|
280
|
+
0,
|
|
281
|
+
0,
|
|
282
|
+
)
|
|
283
|
+
k.xor(other)
|
|
284
|
+
k.multiply(mconst4)
|
|
285
|
+
k.xor(
|
|
286
|
+
new MutableLong(
|
|
287
|
+
(k.getUint16(2) >>> 1) | ((k.getUint16(3) << 15) & 0xffff),
|
|
288
|
+
k.getUint16(3) >>> 1,
|
|
289
|
+
0,
|
|
290
|
+
0,
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Parses a int64 decimal string representation into a MutableLong.
|
|
297
|
+
* @param {String} value
|
|
298
|
+
* @returns {Murmur3Token}
|
|
299
|
+
*/
|
|
300
|
+
parse(value) {
|
|
301
|
+
return new token.Murmur3Token(MutableLong.fromString(value))
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
minToken() {
|
|
305
|
+
if (!this._minToken) {
|
|
306
|
+
// minimum long value.
|
|
307
|
+
this._minToken = this.parse("-9223372036854775808")
|
|
308
|
+
}
|
|
309
|
+
return this._minToken
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
maxToken() {
|
|
313
|
+
if (!this._maxToken) {
|
|
314
|
+
this._maxToken = this.parse("9223372036854775807")
|
|
315
|
+
}
|
|
316
|
+
return this._maxToken
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
maxValue() {
|
|
320
|
+
if (!this._maxValue) {
|
|
321
|
+
this._maxValue = Integer.fromString("9223372036854775807")
|
|
322
|
+
}
|
|
323
|
+
return this._maxValue
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
minValue() {
|
|
327
|
+
if (!this._minValue) {
|
|
328
|
+
this._minValue = Integer.fromString("-9223372036854775808")
|
|
329
|
+
}
|
|
330
|
+
return this._minValue
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
ringLength() {
|
|
334
|
+
if (!this._ringLength) {
|
|
335
|
+
this._ringLength = this.maxValue().subtract(this.minValue())
|
|
336
|
+
}
|
|
337
|
+
return this._ringLength
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
split(start, end, numberOfSplits) {
|
|
341
|
+
// ]min, min] means the whole ring.
|
|
342
|
+
if (start.equals(end) && start.equals(this.minToken())) {
|
|
343
|
+
end = this.maxToken()
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
const startVal = Integer.fromString(start.getValue().toString())
|
|
347
|
+
const endVal = Integer.fromString(end.getValue().toString())
|
|
348
|
+
|
|
349
|
+
let range = endVal.subtract(startVal)
|
|
350
|
+
if (range.isNegative()) {
|
|
351
|
+
range = range.add(this.ringLength())
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const values = this.splitBase(
|
|
355
|
+
startVal,
|
|
356
|
+
range,
|
|
357
|
+
this.maxValue(),
|
|
358
|
+
this.ringLength(),
|
|
359
|
+
numberOfSplits,
|
|
360
|
+
)
|
|
361
|
+
return values.map((v) => this.parse(v.toString()))
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
stringify(token) {
|
|
365
|
+
// Get the underlying MutableLong
|
|
366
|
+
const value = token.getValue()
|
|
367
|
+
// We need a way to uniquely represent a token, it doesn't have to be the decimal string representation
|
|
368
|
+
// Using the uint16 avoids divisions and other expensive operations on the longs
|
|
369
|
+
return (
|
|
370
|
+
value.getUint16(0) +
|
|
371
|
+
"," +
|
|
372
|
+
value.getUint16(1) +
|
|
373
|
+
"," +
|
|
374
|
+
value.getUint16(2) +
|
|
375
|
+
"," +
|
|
376
|
+
value.getUint16(3)
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Uniformly distributes data across the cluster based on MD5 hash values.
|
|
383
|
+
*/
|
|
384
|
+
class RandomTokenizer extends Tokenizer {
|
|
385
|
+
constructor() {
|
|
386
|
+
super()
|
|
387
|
+
this._crypto = crypto
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* @param {Buffer|Array} value
|
|
392
|
+
* @returns {RandomToken}
|
|
393
|
+
*/
|
|
394
|
+
hash(value) {
|
|
395
|
+
if (Array.isArray(value)) {
|
|
396
|
+
value = utils.allocBufferFromArray(value)
|
|
397
|
+
}
|
|
398
|
+
const hashedValue = this._crypto
|
|
399
|
+
.createHash("md5")
|
|
400
|
+
.update(value)
|
|
401
|
+
.digest()
|
|
402
|
+
return new token.RandomToken(Integer.fromBuffer(hashedValue).abs())
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* @returns {Token}
|
|
407
|
+
*/
|
|
408
|
+
parse(value) {
|
|
409
|
+
return new token.RandomToken(Integer.fromString(value))
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
minToken() {
|
|
413
|
+
if (!this._minToken) {
|
|
414
|
+
this._minToken = this.parse("-1")
|
|
415
|
+
}
|
|
416
|
+
return this._minToken
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
maxValue() {
|
|
420
|
+
if (!this._maxValue) {
|
|
421
|
+
this._maxValue = Integer.fromNumber(Math.pow(2, 127))
|
|
422
|
+
}
|
|
423
|
+
return this._maxValue
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
maxToken() {
|
|
427
|
+
if (!this._maxToken) {
|
|
428
|
+
this._maxToken = new token.RandomToken(this.maxValue())
|
|
429
|
+
}
|
|
430
|
+
return this._maxToken
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
ringLength() {
|
|
434
|
+
if (!this._ringLength) {
|
|
435
|
+
this._ringLength = this.maxValue().add(Integer.ONE)
|
|
436
|
+
}
|
|
437
|
+
return this._ringLength
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
split(start, end, numberOfSplits) {
|
|
441
|
+
// ]min, min] means the whole ring.
|
|
442
|
+
if (start.equals(end) && start.equals(this.minToken())) {
|
|
443
|
+
end = this.maxToken()
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
const startVal = start.getValue()
|
|
447
|
+
const endVal = end.getValue()
|
|
448
|
+
|
|
449
|
+
let range = endVal.subtract(startVal)
|
|
450
|
+
if (range.lessThan(Integer.ZERO)) {
|
|
451
|
+
range = range.add(this.ringLength())
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const values = this.splitBase(
|
|
455
|
+
startVal,
|
|
456
|
+
range,
|
|
457
|
+
this.maxValue(),
|
|
458
|
+
this.ringLength(),
|
|
459
|
+
numberOfSplits,
|
|
460
|
+
)
|
|
461
|
+
return values.map((v) => new token.RandomToken(v))
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
class ByteOrderedTokenizer extends Tokenizer {
|
|
466
|
+
constructor() {
|
|
467
|
+
super()
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* @param {Buffer} value
|
|
472
|
+
* @returns {ByteOrderedToken}
|
|
473
|
+
*/
|
|
474
|
+
hash(value) {
|
|
475
|
+
// strip any trailing zeros as tokens with trailing zeros are equivalent
|
|
476
|
+
// to those who don't have them.
|
|
477
|
+
if (Array.isArray(value)) {
|
|
478
|
+
value = utils.allocBufferFromArray(value)
|
|
479
|
+
}
|
|
480
|
+
let zeroIndex = value.length
|
|
481
|
+
for (let i = value.length - 1; i > 0; i--) {
|
|
482
|
+
if (value[i] === 0) {
|
|
483
|
+
zeroIndex = i
|
|
484
|
+
} else {
|
|
485
|
+
break
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return new token.ByteOrderedToken(value.slice(0, zeroIndex))
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
stringify(token) {
|
|
492
|
+
return token.getValue().toString("hex")
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
parse(value) {
|
|
496
|
+
return this.hash(utils.allocBufferFromString(value, "hex"))
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
minToken() {
|
|
500
|
+
if (!this._minToken) {
|
|
501
|
+
this._minToken = this.hash([])
|
|
502
|
+
}
|
|
503
|
+
return this._minToken
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
_toNumber(buffer, significantBytes) {
|
|
507
|
+
// Convert a token's byte array to a number in order to perform computations.
|
|
508
|
+
// This depends on the number of significant bytes that is used to normalize all tokens
|
|
509
|
+
// to the same size. For example if the token is 0x01 but significant bytes is 2, the
|
|
510
|
+
// result is 0x0100.
|
|
511
|
+
let target = buffer
|
|
512
|
+
if (buffer.length !== significantBytes) {
|
|
513
|
+
target = Buffer.alloc(significantBytes)
|
|
514
|
+
buffer.copy(target)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// similar to Integer.fromBuffer except we force the sign to 0.
|
|
518
|
+
const bits = new Array(Math.ceil(target.length / 4))
|
|
519
|
+
for (let i = 0; i < bits.length; i++) {
|
|
520
|
+
let offset = target.length - (i + 1) * 4
|
|
521
|
+
let value
|
|
522
|
+
if (offset < 0) {
|
|
523
|
+
//The buffer length is not multiple of 4
|
|
524
|
+
offset = offset + 4
|
|
525
|
+
value = 0
|
|
526
|
+
for (let j = 0; j < offset; j++) {
|
|
527
|
+
const byte = target[j]
|
|
528
|
+
value = value | (byte << ((offset - j - 1) * 8))
|
|
529
|
+
}
|
|
530
|
+
} else {
|
|
531
|
+
value = target.readInt32BE(offset)
|
|
532
|
+
}
|
|
533
|
+
bits[i] = value
|
|
534
|
+
}
|
|
535
|
+
return new Integer(bits, 0)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
_toBuffer(number, significantBytes) {
|
|
539
|
+
// Convert numeric representation back to a buffer.
|
|
540
|
+
const buffer = Integer.toBuffer(number)
|
|
541
|
+
if (buffer.length === significantBytes) {
|
|
542
|
+
return buffer
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// if first byte is a sign byte, skip it.
|
|
546
|
+
let start, length
|
|
547
|
+
if (buffer[0] === 0) {
|
|
548
|
+
start = 1
|
|
549
|
+
length = buffer.length - 1
|
|
550
|
+
} else {
|
|
551
|
+
start = 0
|
|
552
|
+
length = buffer.length
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const target = Buffer.alloc(significantBytes)
|
|
556
|
+
buffer.copy(target, significantBytes - length, start, length + start)
|
|
557
|
+
return target
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
split(start, end, numberOfSplits) {
|
|
561
|
+
const tokenOrder = start.compare(end)
|
|
562
|
+
|
|
563
|
+
if (tokenOrder === 0 && start.equals(this.minToken())) {
|
|
564
|
+
throw new Error("Cannot split whole ring with ordered partitioner")
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
let startVal, endVal, range, ringLength, ringEnd
|
|
568
|
+
const intNumberOfSplits = Integer.fromNumber(numberOfSplits)
|
|
569
|
+
// Since tokens are compared lexicographically, convert to numbers using the
|
|
570
|
+
// largest length (i.e. given 0x0A and 0x0BCD, switch to 0x0A00 and 0x0BCD)
|
|
571
|
+
let significantBytes = Math.max(
|
|
572
|
+
start.getValue().length,
|
|
573
|
+
end.getValue().length,
|
|
574
|
+
)
|
|
575
|
+
if (tokenOrder < 0) {
|
|
576
|
+
let addedBytes = 0
|
|
577
|
+
while (true) {
|
|
578
|
+
startVal = this._toNumber(start.getValue(), significantBytes)
|
|
579
|
+
endVal = this._toNumber(end.getValue(), significantBytes)
|
|
580
|
+
range = endVal.subtract(startVal)
|
|
581
|
+
if (addedBytes === 4 || range.compare(intNumberOfSplits) >= 0) {
|
|
582
|
+
break
|
|
583
|
+
}
|
|
584
|
+
significantBytes += 1
|
|
585
|
+
addedBytes += 1
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
let addedBytes = 0
|
|
589
|
+
while (true) {
|
|
590
|
+
startVal = this._toNumber(start.getValue(), significantBytes)
|
|
591
|
+
endVal = this._toNumber(end.getValue(), significantBytes)
|
|
592
|
+
ringLength = Integer.fromNumber(
|
|
593
|
+
Math.pow(2, significantBytes * 8),
|
|
594
|
+
)
|
|
595
|
+
ringEnd = ringLength.subtract(Integer.ONE)
|
|
596
|
+
range = endVal.subtract(startVal).add(ringLength)
|
|
597
|
+
if (addedBytes === 4 || range.compare(intNumberOfSplits) >= 0) {
|
|
598
|
+
break
|
|
599
|
+
}
|
|
600
|
+
significantBytes += 1
|
|
601
|
+
addedBytes += 1
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const values = this.splitBase(
|
|
606
|
+
startVal,
|
|
607
|
+
range,
|
|
608
|
+
ringEnd,
|
|
609
|
+
ringLength,
|
|
610
|
+
numberOfSplits,
|
|
611
|
+
)
|
|
612
|
+
return values.map(
|
|
613
|
+
(v) =>
|
|
614
|
+
new token.ByteOrderedToken(this._toBuffer(v, significantBytes)),
|
|
615
|
+
)
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @param {Number} value
|
|
621
|
+
* @return {MutableLong}
|
|
622
|
+
*/
|
|
623
|
+
function fromSignedByte(value) {
|
|
624
|
+
if (value < 128) {
|
|
625
|
+
return new MutableLong(value, 0, 0, 0)
|
|
626
|
+
}
|
|
627
|
+
return new MutableLong((value - 256) & 0xffff, 0xffff, 0xffff, 0xffff)
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
export { Murmur3Tokenizer, RandomTokenizer, ByteOrderedTokenizer }
|
|
631
|
+
export default { Murmur3Tokenizer, RandomTokenizer, ByteOrderedTokenizer }
|