| /* |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you 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. |
| */ |
| |
| #include "token_map_impl.hpp" |
| |
| #include "md5.hpp" |
| #include "murmur3.hpp" |
| |
| using namespace datastax; |
| using namespace datastax::internal::core; |
| |
| static int64_t parse_int64(const char* p, size_t n) { |
| int c; |
| const char* s = p; |
| for (; n != 0 && isspace(c = *s); ++s, --n) { |
| } |
| |
| if (n == 0) { |
| return 0; |
| } |
| |
| int64_t sign = 1; |
| if (c == '-') { |
| sign = -1; |
| ++s; |
| --n; |
| } |
| |
| int64_t value = 0; |
| for (; n != 0 && isdigit(c = *s); ++s, --n) { |
| value *= 10; |
| value += c - '0'; |
| } |
| |
| return sign * value; |
| } |
| |
| static void parse_int128(const char* p, size_t n, uint64_t* h, uint64_t* l) { |
| // no sign handling because C* uses [0, 2^127] |
| int c; |
| const char* s = p; |
| |
| for (; n != 0 && isspace(c = *s); ++s, --n) { |
| } |
| |
| if (n == 0) { |
| *h = *l = 0; |
| return; |
| } |
| |
| uint64_t hi = 0; |
| uint64_t lo = 0; |
| uint64_t hi_tmp; |
| uint64_t lo_tmp; |
| uint64_t lo_tmp2; |
| for (; n != 0 && isdigit(c = *s); ++s, --n) { |
| hi_tmp = hi; |
| lo_tmp = lo; |
| |
| // value *= 10; |
| lo = lo_tmp << 1; |
| hi = (lo_tmp >> 63) + (hi_tmp << 1); |
| lo_tmp2 = lo; |
| lo += lo_tmp << 3; |
| hi += (lo_tmp >> 61) + (hi_tmp << 3) + (lo < lo_tmp2 ? 1 : 0); |
| |
| // value += c - '0'; |
| lo_tmp = lo; |
| lo += c - '0'; |
| hi += (lo < lo_tmp) ? 1 : 0; |
| } |
| |
| *h = hi; |
| *l = lo; |
| } |
| |
| const uint32_t IdGenerator::EMPTY_KEY(0); |
| const uint32_t IdGenerator::DELETED_KEY(CASS_UINT32_MAX); |
| |
| Murmur3Partitioner::Token Murmur3Partitioner::from_string(const StringRef& str) { |
| return parse_int64(str.data(), str.size()); |
| } |
| |
| Murmur3Partitioner::Token Murmur3Partitioner::hash(const StringRef& str) { |
| return MurmurHash3_x64_128(str.data(), str.size(), 0); |
| } |
| |
| RandomPartitioner::Token RandomPartitioner::from_string(const StringRef& str) { |
| Token token; |
| parse_int128(str.data(), str.size(), &token.hi, &token.lo); |
| return token; |
| } |
| |
| uint64_t RandomPartitioner::encode(uint8_t* bytes) { |
| uint64_t result = 0; |
| const size_t num_bytes = sizeof(uint64_t); |
| for (size_t i = 0; i < num_bytes; ++i) { |
| result |= (static_cast<uint64_t>(bytes[i]) << (8 * (num_bytes - i - 1))); |
| } |
| return result; |
| } |
| |
| RandomPartitioner::Token RandomPartitioner::abs(RandomPartitioner::Token token) { |
| if (token.hi & 0x8000000000000000ULL) { |
| token.hi = ~token.hi; |
| token.lo = ~token.lo; |
| |
| uint64_t old_lo = token.lo; |
| ++token.lo; |
| // Carry to "hi" if our "lo" value wrapped |
| if (token.lo < old_lo) { |
| ++token.hi; |
| } |
| } |
| return token; |
| } |
| |
| RandomPartitioner::Token RandomPartitioner::hash(const StringRef& str) { |
| Md5 hash; |
| hash.update(reinterpret_cast<const uint8_t*>(str.data()), str.size()); |
| uint8_t digest[16]; |
| hash.final(digest); |
| Token token; |
| |
| // For compatability with Cassandra we interpret the MD5 as a big-endian value: |
| // Reference: |
| // https://docs.oracle.com/javase/7/docs/api/java/math/BigInteger.html#BigInteger(byte[]) |
| token.hi = encode(digest); |
| token.lo = encode(digest + 8); |
| |
| // Then we find the absolute value of the two's complement representation. |
| token = abs(token); |
| |
| return token; |
| } |
| |
| ByteOrderedPartitioner::Token ByteOrderedPartitioner::from_string(const StringRef& str) { |
| const uint8_t* data = reinterpret_cast<const uint8_t*>(str.data()); |
| return Token(data, data + str.size()); |
| } |
| |
| ByteOrderedPartitioner::Token ByteOrderedPartitioner::hash(const StringRef& str) { |
| const uint8_t* data = reinterpret_cast<const uint8_t*>(str.data()); |
| return Token(data, data + str.size()); |
| } |