effective_replication_map, abstract_replication_strategy: get_ranges: call on_internal_error in empty sorted_tokens case

Accessing tm.sorted_tokens().back() causes undefined behavior
if tm.sorted_tokens is empty.

Check that first and throw/abort using on_internal_error
in this case.

This will prevent the segfault but it doesn't fix the root cause
which is getting here with empty token_metadata.  That will be fixed
by the following patch.

Refs #9494

Signed-off-by: Benny Halevy <bhalevy@scylladb.com>
Message-Id: <20211019075710.1626808-1-bhalevy@scylladb.com>
This commit is contained in:
Benny Halevy
2021-10-19 10:57:09 +03:00
committed by Avi Kivity
parent 7c35d47690
commit dc091fc952
2 changed files with 19 additions and 4 deletions

View File

@@ -156,8 +156,12 @@ dht::token_range_vector
effective_replication_map::do_get_ranges(noncopyable_function<bool(inet_address_vector_replica_set)> should_add_range) const {
dht::token_range_vector ret;
const auto& tm = *_tmptr;
auto prev_tok = tm.sorted_tokens().back();
for (const auto& tok : tm.sorted_tokens()) {
const auto& sorted_tokens = tm.sorted_tokens();
if (sorted_tokens.empty()) {
on_internal_error(rslogger, "Token metadata is empty");
}
auto prev_tok = sorted_tokens.back();
for (const auto& tok : sorted_tokens) {
if (should_add_range(get_natural_endpoints(tok))) {
insert_token_range_to_sorted_container_while_unwrapping(prev_tok, tok, ret);
}
@@ -183,8 +187,12 @@ future<dht::token_range_vector>
abstract_replication_strategy::get_ranges(inet_address ep, token_metadata_ptr tmptr) const {
dht::token_range_vector ret;
const auto& tm = *tmptr;
auto prev_tok = tm.sorted_tokens().back();
for (auto tok : tm.sorted_tokens()) {
const auto& sorted_tokens = tm.sorted_tokens();
if (sorted_tokens.empty()) {
on_internal_error(rslogger, "Token metadata is empty");
}
auto prev_tok = sorted_tokens.back();
for (auto tok : sorted_tokens) {
for (inet_address a : co_await calculate_natural_endpoints(tok, tm)) {
if (a == ep) {
insert_token_range_to_sorted_container_while_unwrapping(prev_tok, tok, ret);

View File

@@ -117,6 +117,7 @@ public:
replication_strategy_type get_type() const { return _my_type; }
// Use the token_metadata provided by the caller instead of _token_metadata
// Note: must be called with initialized, non-empty token_metadata.
future<dht::token_range_vector> get_ranges(inet_address ep, token_metadata_ptr tmptr) const;
public:
@@ -175,6 +176,8 @@ public:
// The list is sorted, and its elements are non overlapping and non wrap-around.
// It the analogue of Origin's getAddressRanges().get(endpoint).
// This function is not efficient, and not meant for the fast path.
//
// Note: must be called after token_metadata has been initialized.
dht::token_range_vector get_ranges(inet_address ep) const;
// get_primary_ranges() returns the list of "primary ranges" for the given
@@ -183,11 +186,15 @@ public:
// returned calculate_natural_endpoints().
// This function is the analogue of Origin's
// StorageService.getPrimaryRangesForEndpoint().
//
// Note: must be called after token_metadata has been initialized.
dht::token_range_vector get_primary_ranges(inet_address ep) const;
// get_primary_ranges_within_dc() is similar to get_primary_ranges()
// except it assigns a primary node for each range within each dc,
// instead of one node globally.
//
// Note: must be called after token_metadata has been initialized.
dht::token_range_vector get_primary_ranges_within_dc(inet_address ep) const;
std::unordered_map<dht::token_range, inet_address_vector_replica_set>