Fixed FPE in yandexConsistentHash

This commit is contained in:
Alexey Milovidov 2019-08-03 01:40:28 +03:00
parent f149e3b436
commit 62053314bb
2 changed files with 15 additions and 13 deletions

View File

@ -29,11 +29,12 @@ struct YandexConsistentHashImpl
static constexpr auto name = "yandexConsistentHash"; static constexpr auto name = "yandexConsistentHash";
using HashType = UInt64; using HashType = UInt64;
/// Actually it supports UInt64, but it is effective only if n < 65536 /// Actually it supports UInt64, but it is efficient only if n <= 32768
using ResultType = UInt32; using ResultType = UInt16;
using BucketsCountType = ResultType; using BucketsType = ResultType;
static constexpr auto max_buckets = 32768;
static inline ResultType apply(UInt64 hash, BucketsCountType n) static inline ResultType apply(UInt64 hash, BucketsType n)
{ {
return ConsistentHashing(hash, n); return ConsistentHashing(hash, n);
} }
@ -59,9 +60,10 @@ struct JumpConsistentHashImpl
using HashType = UInt64; using HashType = UInt64;
using ResultType = Int32; using ResultType = Int32;
using BucketsCountType = ResultType; using BucketsType = ResultType;
static constexpr auto max_buckets = static_cast<UInt64>(std::numeric_limits<BucketsType>::max());
static inline ResultType apply(UInt64 hash, BucketsCountType n) static inline ResultType apply(UInt64 hash, BucketsType n)
{ {
return JumpConsistentHash(hash, n); return JumpConsistentHash(hash, n);
} }
@ -74,9 +76,10 @@ struct SumburConsistentHashImpl
using HashType = UInt32; using HashType = UInt32;
using ResultType = UInt16; using ResultType = UInt16;
using BucketsCountType = ResultType; using BucketsType = ResultType;
static constexpr auto max_buckets = static_cast<UInt64>(std::numeric_limits<BucketsType>::max());
static inline ResultType apply(HashType hash, BucketsCountType n) static inline ResultType apply(HashType hash, BucketsType n)
{ {
return static_cast<ResultType>(sumburConsistentHash(hash, n)); return static_cast<ResultType>(sumburConsistentHash(hash, n));
} }
@ -143,8 +146,7 @@ public:
private: private:
using HashType = typename Impl::HashType; using HashType = typename Impl::HashType;
using ResultType = typename Impl::ResultType; using ResultType = typename Impl::ResultType;
using BucketsType = typename Impl::BucketsCountType; using BucketsType = typename Impl::BucketsType;
static constexpr auto max_buckets = static_cast<UInt64>(std::numeric_limits<BucketsType>::max());
template <typename T> template <typename T>
inline BucketsType checkBucketsRange(T buckets) inline BucketsType checkBucketsRange(T buckets)
@ -153,7 +155,7 @@ private:
throw Exception( throw Exception(
"The second argument of function " + getName() + " (number of buckets) must be positive number", ErrorCodes::BAD_ARGUMENTS); "The second argument of function " + getName() + " (number of buckets) must be positive number", ErrorCodes::BAD_ARGUMENTS);
if (unlikely(static_cast<UInt64>(buckets) > max_buckets)) if (unlikely(static_cast<UInt64>(buckets) > Impl::max_buckets))
throw Exception("The value of the second argument of function " + getName() + " (number of buckets) is not fit to " throw Exception("The value of the second argument of function " + getName() + " (number of buckets) is not fit to "
+ DataTypeNumber<BucketsType>().getName(), + DataTypeNumber<BucketsType>().getName(),
ErrorCodes::BAD_ARGUMENTS); ErrorCodes::BAD_ARGUMENTS);

View File

@ -15,5 +15,5 @@
* It requires O(1) memory and cpu to calculate. So, it is faster than classic * It requires O(1) memory and cpu to calculate. So, it is faster than classic
* consistent hashing algos with points on circle. * consistent hashing algos with points on circle.
*/ */
std::size_t ConsistentHashing(std::uint64_t x, std::size_t n); // Works good for n < 65536 std::size_t ConsistentHashing(std::uint64_t x, std::size_t n); // Works for n <= 32768
std::size_t ConsistentHashing(std::uint64_t lo, std::uint64_t hi, std::size_t n); // Works good for n < 4294967296 std::size_t ConsistentHashing(std::uint64_t lo, std::uint64_t hi, std::size_t n); // Works for n <= 2^31