Node JS version
This commit is contained in:
286
node_modules/cassandra-driver/lib/token.js
generated
vendored
Normal file
286
node_modules/cassandra-driver/lib/token.js
generated
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright DataStax, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const types = require('./types');
|
||||
const util = require('util');
|
||||
|
||||
const _Murmur3TokenType = types.dataTypes.getByName('bigint');
|
||||
const _RandomTokenType = types.dataTypes.getByName('varint');
|
||||
const _OrderedTokenType = types.dataTypes.getByName('blob');
|
||||
|
||||
/**
|
||||
* Represents a token on the Cassandra ring.
|
||||
*/
|
||||
class Token {
|
||||
constructor(value) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {{code: number, info: *|Object}} The type info for the
|
||||
* type of the value of the token.
|
||||
*/
|
||||
getType() {
|
||||
throw new Error('You must implement a getType function for this Token instance');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {*} The raw value of the token.
|
||||
*/
|
||||
getValue() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this._value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 if the values are equal, 1 if greater than other, -1
|
||||
* otherwise.
|
||||
*
|
||||
* @param {Token} other
|
||||
* @returns {Number}
|
||||
*/
|
||||
compare(other) {
|
||||
return this._value.compare(other._value);
|
||||
}
|
||||
|
||||
equals(other) {
|
||||
return this.compare(other) === 0;
|
||||
}
|
||||
|
||||
inspect() {
|
||||
return this.constructor.name + ' { ' + this.toString() + ' }';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a token from a Cassandra ring where the partitioner
|
||||
* is Murmur3Partitioner.
|
||||
*
|
||||
* The raw token type is a varint (represented by MutableLong).
|
||||
*/
|
||||
class Murmur3Token extends Token {
|
||||
constructor(value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
getType() {
|
||||
return _Murmur3TokenType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a token from a Cassandra ring where the partitioner
|
||||
* is RandomPartitioner.
|
||||
*
|
||||
* The raw token type is a bigint (represented by Number).
|
||||
*/
|
||||
class RandomToken extends Token {
|
||||
constructor(value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
getType() {
|
||||
return _RandomTokenType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a token from a Cassandra ring where the partitioner
|
||||
* is ByteOrderedPartitioner.
|
||||
*
|
||||
* The raw token type is a blob (represented by Buffer or Array).
|
||||
*/
|
||||
class ByteOrderedToken extends Token {
|
||||
constructor(value) {
|
||||
super(value);
|
||||
}
|
||||
|
||||
getType() {
|
||||
return _OrderedTokenType;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this._value.toString('hex').toUpperCase();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a range of tokens on a Cassandra ring.
|
||||
*
|
||||
* A range is start-exclusive and end-inclusive. It is empty when
|
||||
* start and end are the same token, except if that is the minimum
|
||||
* token, in which case the range covers the whole ring (this is
|
||||
* consistent with the behavior of CQL range queries).
|
||||
*
|
||||
* Note that CQL does not handle wrapping. To query all partitions
|
||||
* in a range, see {@link unwrap}.
|
||||
*/
|
||||
class TokenRange {
|
||||
constructor(start, end, tokenizer) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
Object.defineProperty(this, '_tokenizer', { value: tokenizer, enumerable: false});
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this range into a number of smaller ranges of equal "size"
|
||||
* (referring to the number of tokens, not the actual amount of data).
|
||||
*
|
||||
* Splitting an empty range is not permitted. But not that, in edge
|
||||
* cases, splitting a range might produce one or more empty ranges.
|
||||
*
|
||||
* @param {Number} numberOfSplits Number of splits to make.
|
||||
* @returns {TokenRange[]} Split ranges.
|
||||
* @throws {Error} If splitting an empty range.
|
||||
*/
|
||||
splitEvenly(numberOfSplits) {
|
||||
if (numberOfSplits < 1) {
|
||||
throw new Error(util.format("numberOfSplits (%d) must be greater than 0.", numberOfSplits));
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
throw new Error("Can't split empty range " + this.toString());
|
||||
}
|
||||
|
||||
const tokenRanges = [];
|
||||
const splitPoints = this._tokenizer.split(this.start, this.end, numberOfSplits);
|
||||
let splitStart = this.start;
|
||||
let splitEnd;
|
||||
for (let splitIndex = 0; splitIndex < splitPoints.length; splitIndex++) {
|
||||
splitEnd = splitPoints[splitIndex];
|
||||
tokenRanges.push(new TokenRange(splitStart, splitEnd, this._tokenizer));
|
||||
splitStart = splitEnd;
|
||||
}
|
||||
tokenRanges.push(new TokenRange(splitStart, this.end, this._tokenizer));
|
||||
return tokenRanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* A range is empty when start and end are the same token, except if
|
||||
* that is the minimum token, in which case the range covers the
|
||||
* whole ring. This is consistent with the behavior of CQL range
|
||||
* queries.
|
||||
*
|
||||
* @returns {boolean} Whether this range is empty.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.start.equals(this.end) && !this.start.equals(this._tokenizer.minToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* A range wraps around the end of the ring when the start token
|
||||
* is greater than the end token and the end token is not the
|
||||
* minimum token.
|
||||
*
|
||||
* @returns {boolean} Whether this range wraps around.
|
||||
*/
|
||||
isWrappedAround() {
|
||||
return this.start.compare(this.end) > 0 && !this.end.equals(this._tokenizer.minToken());
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits this range into a list of two non-wrapping ranges.
|
||||
*
|
||||
* This will return the range itself if it is non-wrapped, or two
|
||||
* ranges otherwise.
|
||||
*
|
||||
* This is useful for CQL range queries, which do not handle
|
||||
* wrapping.
|
||||
*
|
||||
* @returns {TokenRange[]} The list of non-wrapping ranges.
|
||||
*/
|
||||
unwrap() {
|
||||
if (this.isWrappedAround()) {
|
||||
return [
|
||||
new TokenRange(this.start, this._tokenizer.minToken(), this._tokenizer),
|
||||
new TokenRange(this._tokenizer.minToken(), this.end, this._tokenizer)
|
||||
];
|
||||
}
|
||||
return [this];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this range contains a given Token.
|
||||
*
|
||||
* @param {*} token Token to check for.
|
||||
* @returns {boolean} Whether or not the Token is in this range.
|
||||
*/
|
||||
contains(token) {
|
||||
if (this.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const minToken = this._tokenizer.minToken();
|
||||
if (this.end.equals(minToken)) {
|
||||
if (this.start.equals(minToken)) {
|
||||
return true; // ]minToken, minToken] === full ring
|
||||
} else if (token.equals(minToken)) {
|
||||
return true;
|
||||
}
|
||||
return token.compare(this.start) > 0;
|
||||
}
|
||||
|
||||
const isAfterStart = token.compare(this.start) > 0;
|
||||
const isBeforeEnd = token.compare(this.end) <= 0;
|
||||
// if wrapped around ring, token is in ring if its after start or before end.
|
||||
// otherwise, token is in ring if its after start and before end.
|
||||
return this.isWrappedAround()
|
||||
? isAfterStart || isBeforeEnd
|
||||
: isAfterStart && isBeforeEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the input range is equivalent to this one.
|
||||
*
|
||||
* @param {TokenRange} other Range to compare with.
|
||||
* @returns {boolean} Whether or not the ranges are equal.
|
||||
*/
|
||||
equals(other) {
|
||||
if (other === this) {
|
||||
return true;
|
||||
} else if (other instanceof TokenRange) {
|
||||
return this.compare(other) === 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 0 if the values are equal, otherwise compares against
|
||||
* start, if start is equal, compares against end.
|
||||
*
|
||||
* @param {TokenRange} other Range to compare with.
|
||||
* @returns {Number}
|
||||
*/
|
||||
compare(other) {
|
||||
const compareStart = this.start.compare(other.start);
|
||||
return compareStart !== 0 ? compareStart : this.end.compare(other.end);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return util.format(']%s, %s]',
|
||||
this.start.toString(),
|
||||
this.end.toString()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.Token = Token;
|
||||
exports.TokenRange = TokenRange;
|
||||
exports.ByteOrderedToken = ByteOrderedToken;
|
||||
exports.Murmur3Token = Murmur3Token;
|
||||
exports.RandomToken = RandomToken;
|
Reference in New Issue
Block a user