add comparison and hash operators for dht::token
Inspired in Gleb's previous patch, this patch adds a hash and comparison operator for dht::token. The previous patch, however, had a number of problems. Comparisons were failing in tokens that were verified (by me) to be equal to the ones Origin was generating. The main reasons for that, was that the byte-comparison loop must be unsigned, not signed. With the above change, the comparison function would always succeed *except* when the integer version of _data was that of a signed one. Looking at Origin, one verifies that the Murmur3Partitioner class overrides the comparison functions, and just does a Long comparison with the token. This patch implements a similar mechanism. With that, a list of tokens generated by origin in ascending order is verified by us to also be in ascending order. Signed-off-by: Glauber Costa <glommer@cloudius-systems.com>
This commit is contained in:
committed by
Tomasz Grabiec
parent
66924090c6
commit
eee72251d0
@@ -70,6 +70,80 @@ midpoint(const token& t1, const token& t2) {
|
||||
return token{token::kind::key, std::move(avg)};
|
||||
}
|
||||
|
||||
static inline unsigned char get_byte(const bytes& b, size_t off) {
|
||||
if (off < b.size()) {
|
||||
return b[off];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool i_partitioner::is_equal(const token& t1, const token& t2) {
|
||||
|
||||
size_t sz = std::max(t1._data.size(), t2._data.size());
|
||||
|
||||
for (size_t i = 0; i < sz; i++) {
|
||||
auto b1 = get_byte(t1._data, i);
|
||||
auto b2 = get_byte(t2._data, i);
|
||||
if (b1 != b2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool i_partitioner::is_less(const token& t1, const token& t2) {
|
||||
|
||||
size_t sz = std::max(t1._data.size(), t2._data.size());
|
||||
|
||||
for (size_t i = 0; i < sz; i++) {
|
||||
auto b1 = get_byte(t1._data, i);
|
||||
auto b2 = get_byte(t2._data, i);
|
||||
if (b1 < b2) {
|
||||
return true;
|
||||
} else if (b1 > b2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator==(const token& t1, const token& t2)
|
||||
{
|
||||
if (t1._kind != t2._kind) {
|
||||
return false;
|
||||
} else if (t1._kind == token::kind::key) {
|
||||
return global_partitioner().is_equal(t1, t2);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator<(const token& t1, const token& t2)
|
||||
{
|
||||
if (t1._kind < t2._kind) {
|
||||
return true;
|
||||
} else if (t1._kind == token::kind::key && t2._kind == token::kind::key) {
|
||||
return global_partitioner().is_less(t1, t2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator<(const decorated_key& lht, const decorated_key& rht) {
|
||||
if (lht._token == rht._token) {
|
||||
return static_cast<bytes_view>(lht._key) < rht._key;
|
||||
} else {
|
||||
return lht._token < rht._token;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const decorated_key& lht, const decorated_key& rht) {
|
||||
if (lht._token == rht._token) {
|
||||
return static_cast<bytes_view>(lht._key) == rht._key;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// FIXME: get from global config
|
||||
// FIXME: make it per-keyspace
|
||||
murmur3_partitioner default_partitioner;
|
||||
|
||||
@@ -63,6 +63,9 @@ public:
|
||||
|
||||
token midpoint(const token& t1, const token& t2);
|
||||
token minimum_token();
|
||||
bool operator==(const token& t1, const token& t2);
|
||||
bool operator<(const token& t1, const token& t2);
|
||||
|
||||
|
||||
class decorated_key {
|
||||
public:
|
||||
@@ -143,8 +146,30 @@ public:
|
||||
virtual std::map<token, float> describe_ownership(const std::vector<token>& sorted_tokens) = 0;
|
||||
|
||||
virtual data_type get_token_validator() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @return true if t1's _data array is equal t2's. _kind comparison should be done separately.
|
||||
*/
|
||||
virtual bool is_equal(const token& t1, const token& t2);
|
||||
/**
|
||||
* @return true if t1's _data array is less then t2's. _kind comparison should be done separately.
|
||||
*/
|
||||
virtual bool is_less(const token& t1, const token& t2);
|
||||
|
||||
friend bool operator==(const token& t1, const token& t2);
|
||||
friend bool operator<(const token& t1, const token& t2);
|
||||
};
|
||||
|
||||
i_partitioner& global_partitioner();
|
||||
|
||||
} // dht
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<dht::token> {
|
||||
size_t operator()(const dht::token& t) const {
|
||||
return (t._kind == dht::token::kind::key) ? std::hash<bytes>()(t._data) : 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,6 +32,33 @@ murmur3_partitioner::get_token(const partition_key& key_) {
|
||||
return token{token::kind::key, std::move(b)};
|
||||
}
|
||||
|
||||
inline long long_token(const token& t) {
|
||||
|
||||
if (t._data.size() != sizeof(long)) {
|
||||
throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(long), t._data.size()));
|
||||
}
|
||||
|
||||
auto ptr = const_cast<char *>(t._data.c_str());
|
||||
auto lp = reinterpret_cast<long *>(ptr);
|
||||
return net::ntoh(*lp);
|
||||
}
|
||||
|
||||
bool murmur3_partitioner::is_equal(const token& t1, const token& t2) {
|
||||
|
||||
auto l1 = long_token(t1);
|
||||
auto l2 = long_token(t2);
|
||||
|
||||
return l1 == l2;
|
||||
}
|
||||
|
||||
bool murmur3_partitioner::is_less(const token& t1, const token& t2) {
|
||||
|
||||
auto l1 = long_token(t1);
|
||||
auto l2 = long_token(t2);
|
||||
|
||||
return l1 < l2;
|
||||
}
|
||||
|
||||
std::map<token, float>
|
||||
murmur3_partitioner::describe_ownership(const std::vector<token>& sorted_tokens) {
|
||||
abort();
|
||||
|
||||
@@ -14,6 +14,8 @@ public:
|
||||
virtual bool preserves_order() override { return false; }
|
||||
virtual std::map<token, float> describe_ownership(const std::vector<token>& sorted_tokens);
|
||||
virtual data_type get_token_validator();
|
||||
virtual bool is_equal(const token& t1, const token& t2);
|
||||
virtual bool is_less(const token& t1, const token& t2);
|
||||
private:
|
||||
static int64_t normalize(int64_t in);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user