db/hints: introduce host_filter

Adds a db::hints::host_filter structure, which determines if generating
hints towards a given target is currently allowed. It supports
serialization and deserialization between the hinted_handoff_enabled
configuration/cli option.

This patch only introduces this structure, but does not make other code
use it. It will be plugged into the configuration architecture in the
following commits.
This commit is contained in:
Piotr Dulikowski
2020-07-24 12:46:15 +02:00
parent a4f03d72b3
commit 5c3c7c946b
3 changed files with 229 additions and 0 deletions

View File

@@ -718,6 +718,7 @@ scylla_core = (['database.cc',
'db/data_listeners.cc',
'db/hints/manager.cc',
'db/hints/resource_manager.cc',
'db/hints/host_filter.cc',
'db/config.cc',
'db/extensions.cc',
'db/heat_load_balance.cc',

125
db/hints/host_filter.cc Normal file
View File

@@ -0,0 +1,125 @@
/*
* Copyright (C) 2020 ScyllaDB
*/
/*
* This file is part of Scylla.
*
* Scylla is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Scylla is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string_view>
#include <boost/algorithm/string.hpp>
#include "to_string.hh"
#include "host_filter.hh"
namespace db {
namespace hints {
host_filter::host_filter(host_filter::enabled_for_all_tag)
: _enabled_kind(host_filter::enabled_kind::enabled_for_all) {
}
host_filter::host_filter(host_filter::disabled_for_all_tag)
: _enabled_kind(host_filter::enabled_kind::disabled_for_all) {
}
host_filter::host_filter(std::unordered_set<sstring> allowed_dcs)
: _enabled_kind(allowed_dcs.empty() ? enabled_kind::disabled_for_all : enabled_kind::enabled_selectively)
, _dcs(std::move(allowed_dcs)) {
}
bool host_filter::can_hint_for(locator::snitch_ptr& snitch, gms::inet_address ep) const {
switch (_enabled_kind) {
case enabled_kind::enabled_for_all:
return true;
case enabled_kind::enabled_selectively:
return _dcs.count(snitch->get_datacenter(ep));
case enabled_kind::disabled_for_all:
return false;
}
throw std::logic_error("Uncovered variant of enabled_kind");
}
host_filter host_filter::parse_from_config_string(sstring opt) {
if (boost::iequals(opt, "false") || opt == "0") {
return host_filter(disabled_for_all_tag());
} else if (boost::iequals(opt, "true") || opt == "1") {
return host_filter(enabled_for_all_tag());
}
return parse_from_dc_list(std::move(opt));
}
host_filter host_filter::parse_from_dc_list(sstring opt) {
using namespace boost::algorithm;
std::vector<sstring> dcs;
split(dcs, opt, is_any_of(","));
std::for_each(dcs.begin(), dcs.end(), [] (sstring& dc) {
trim(dc);
if (dc.empty()) {
throw hints_configuration_parse_error("hinted_handoff_enabled: DC name may not be an empty string");
}
});
return host_filter(std::unordered_set<sstring>(dcs.begin(), dcs.end()));
}
std::istream& operator>>(std::istream& is, host_filter& f) {
sstring tmp;
is >> tmp;
f = host_filter::parse_from_config_string(std::move(tmp));
return is;
}
sstring host_filter::to_configuration_string() const {
switch (_enabled_kind) {
case enabled_kind::enabled_for_all:
return "true";
case enabled_kind::enabled_selectively:
return ::join(",", _dcs);
case enabled_kind::disabled_for_all:
return "false";
}
throw std::logic_error("Uncovered variant of enabled_kind");
}
std::string_view host_filter::enabled_kind_to_string(host_filter::enabled_kind ek) {
switch (ek) {
case host_filter::enabled_kind::enabled_for_all:
return "enabled_for_all";
case host_filter::enabled_kind::enabled_selectively:
return "enabled_selectively";
case host_filter::enabled_kind::disabled_for_all:
return "disabled_for_all";
}
throw std::logic_error("Uncovered variant of enabled_kind");
}
std::ostream& operator<<(std::ostream& os, const host_filter& f) {
os << "host_filter{enabled_kind="
<< host_filter::enabled_kind_to_string(f._enabled_kind);
if (f._enabled_kind == host_filter::enabled_kind::enabled_selectively) {
os << ", dcs={" << ::join(",", f._dcs);
}
os << "}";
return os;
}
}
}

103
db/hints/host_filter.hh Normal file
View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2020 ScyllaDB
*/
/*
* This file is part of Scylla.
*
* Scylla is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Scylla is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Scylla. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <functional>
#include <unordered_set>
#include <exception>
#include <iostream>
#include <string_view>
#include <seastar/core/sstring.hh>
#include "gms/inet_address.hh"
#include "locator/snitch_base.hh"
#include "seastarx.hh"
namespace db {
namespace hints {
// host_filter tells hints_manager towards which endpoints it is allowed to generate hints.
class host_filter final {
private:
enum class enabled_kind {
enabled_for_all,
enabled_selectively,
disabled_for_all,
};
enabled_kind _enabled_kind;
std::unordered_set<sstring> _dcs;
static std::string_view enabled_kind_to_string(host_filter::enabled_kind ek);
public:
struct enabled_for_all_tag {};
struct disabled_for_all_tag {};
// Creates a filter that allows hints to all endpoints (default)
host_filter(enabled_for_all_tag tag = {});
// Creates a filter that does not allow any hints.
host_filter(disabled_for_all_tag);
// Creates a filter that allows sending hints to specified DCs.
explicit host_filter(std::unordered_set<sstring> allowed_dcs);
// Parses hint filtering configuration from the hinted_handoff_enabled option.
static host_filter parse_from_config_string(sstring opt);
// Parses hint filtering configuration from a list of DCs.
static host_filter parse_from_dc_list(sstring opt);
bool can_hint_for(locator::snitch_ptr& snitch, gms::inet_address ep) const;
inline const std::unordered_set<sstring>& get_dcs() const {
return _dcs;
}
bool operator==(const host_filter& other) const noexcept {
return _enabled_kind == other._enabled_kind
&& _dcs == other._dcs;
}
inline bool is_enabled_for_all() const noexcept {
return _enabled_kind == enabled_kind::enabled_for_all;
}
inline bool is_disabled_for_all() const noexcept {
return _enabled_kind == enabled_kind::disabled_for_all;
}
sstring to_configuration_string() const;
friend std::ostream& operator<<(std::ostream& os, const host_filter& f);
};
std::istream& operator>>(std::istream& is, host_filter& f);
class hints_configuration_parse_error : public std::runtime_error {
public:
using std::runtime_error::runtime_error;
};
}
}