mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2024-12-14 11:58:02 +00:00
chore(acl): Implicit categories (#3411)
Most of our CO:: categories became meaningless with the introduction of acl. For example, CO::FAST literally doesn't mean anything, it's never read or used. * add implicit categories --------- Signed-off-by: Vladislav Oleshko <vlad@dragonflydb.io>
This commit is contained in:
parent
c9537bb52e
commit
b860b712c0
4 changed files with 95 additions and 68 deletions
|
@ -37,11 +37,48 @@ using absl::StrAppend;
|
||||||
using absl::StrCat;
|
using absl::StrCat;
|
||||||
using absl::StrSplit;
|
using absl::StrSplit;
|
||||||
|
|
||||||
CommandId::CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key,
|
namespace {
|
||||||
int8_t last_key, uint32_t acl_categories)
|
|
||||||
: facade::CommandId(name, mask, arity, first_key, last_key, acl_categories) {
|
uint32_t ImplicitCategories(uint32_t mask) {
|
||||||
if (mask & CO::ADMIN)
|
if (mask & CO::ADMIN)
|
||||||
opt_mask_ |= CO::NOSCRIPT;
|
mask |= CO::NOSCRIPT;
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t ImplicitAclCategories(uint32_t mask) {
|
||||||
|
mask = ImplicitCategories(mask);
|
||||||
|
uint32_t out = 0;
|
||||||
|
|
||||||
|
if (mask & CO::WRITE)
|
||||||
|
out |= acl::WRITE;
|
||||||
|
|
||||||
|
if ((mask & CO::READONLY) && ((mask & CO::NOSCRIPT) == 0))
|
||||||
|
out |= acl::READ;
|
||||||
|
|
||||||
|
if (mask & CO::ADMIN)
|
||||||
|
out |= acl::ADMIN | acl::DANGEROUS;
|
||||||
|
|
||||||
|
// todo pubsub
|
||||||
|
|
||||||
|
if (mask & CO::FAST)
|
||||||
|
out |= acl::FAST;
|
||||||
|
|
||||||
|
if (mask & CO::BLOCKING)
|
||||||
|
out |= acl::BLOCKING;
|
||||||
|
|
||||||
|
if ((out & acl::FAST) == 0)
|
||||||
|
out |= acl::SLOW;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
CommandId::CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key,
|
||||||
|
int8_t last_key, std::optional<uint32_t> acl_categories)
|
||||||
|
: facade::CommandId(name, ImplicitCategories(mask), arity, first_key, last_key,
|
||||||
|
acl_categories.value_or(ImplicitAclCategories(mask))) {
|
||||||
|
implicit_acl_ = !acl_categories.has_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CommandId::IsTransactional() const {
|
bool CommandId::IsTransactional() const {
|
||||||
|
@ -152,6 +189,9 @@ CommandRegistry& CommandRegistry::operator<<(CommandId cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.SetFamily(family_of_commands_.size() - 1);
|
cmd.SetFamily(family_of_commands_.size() - 1);
|
||||||
|
if (acl_category_)
|
||||||
|
cmd.SetAclCategory(*acl_category_);
|
||||||
|
|
||||||
if (!is_sub_command || absl::StartsWith(cmd.name(), "ACL")) {
|
if (!is_sub_command || absl::StartsWith(cmd.name(), "ACL")) {
|
||||||
cmd.SetBitIndex(1ULL << bit_index_);
|
cmd.SetBitIndex(1ULL << bit_index_);
|
||||||
family_of_commands_.back().push_back(std::string(k));
|
family_of_commands_.back().push_back(std::string(k));
|
||||||
|
@ -165,9 +205,10 @@ CommandRegistry& CommandRegistry::operator<<(CommandId cmd) {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandRegistry::StartFamily() {
|
void CommandRegistry::StartFamily(std::optional<uint32_t> acl_category) {
|
||||||
family_of_commands_.push_back({});
|
family_of_commands_.emplace_back();
|
||||||
bit_index_ = 0;
|
bit_index_ = 0;
|
||||||
|
acl_category_ = acl_category;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view CommandRegistry::RenamedOrOriginal(std::string_view orig) const {
|
std::string_view CommandRegistry::RenamedOrOriginal(std::string_view orig) const {
|
||||||
|
|
|
@ -77,7 +77,7 @@ class CommandId : public facade::CommandId {
|
||||||
// NOTICE: name must be a literal string, otherwise metrics break! (see cmd_stats_map in
|
// NOTICE: name must be a literal string, otherwise metrics break! (see cmd_stats_map in
|
||||||
// server_state.h)
|
// server_state.h)
|
||||||
CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key, int8_t last_key,
|
CommandId(const char* name, uint32_t mask, int8_t arity, int8_t first_key, int8_t last_key,
|
||||||
uint32_t acl_categories);
|
std::optional<uint32_t> acl_categories = std::nullopt);
|
||||||
|
|
||||||
CommandId(CommandId&&) = default;
|
CommandId(CommandId&&) = default;
|
||||||
|
|
||||||
|
@ -146,7 +146,13 @@ class CommandId : public facade::CommandId {
|
||||||
return command_stats_[thread_index];
|
return command_stats_[thread_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetAclCategory(uint32_t mask) {
|
||||||
|
if (implicit_acl_)
|
||||||
|
acl_categories_ |= mask;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool implicit_acl_;
|
||||||
std::unique_ptr<CmdCallStats[]> command_stats_;
|
std::unique_ptr<CmdCallStats[]> command_stats_;
|
||||||
Handler handler_;
|
Handler handler_;
|
||||||
ArgValidator validator_;
|
ArgValidator validator_;
|
||||||
|
@ -194,7 +200,7 @@ class CommandRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartFamily();
|
void StartFamily(std::optional<uint32_t> acl_category = std::nullopt);
|
||||||
|
|
||||||
std::string_view RenamedOrOriginal(std::string_view orig) const;
|
std::string_view RenamedOrOriginal(std::string_view orig) const;
|
||||||
|
|
||||||
|
@ -212,6 +218,7 @@ class CommandRegistry {
|
||||||
|
|
||||||
FamiliesVec family_of_commands_;
|
FamiliesVec family_of_commands_;
|
||||||
size_t bit_index_;
|
size_t bit_index_;
|
||||||
|
std::optional<uint32_t> acl_category_; // category of family currently being built
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
|
@ -2487,8 +2487,8 @@ void Service::Command(CmdArgList args, Transaction* tx, SinkReplyBuilder* builde
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* rb = static_cast<RedisReplyBuilder*>(builder);
|
auto* rb = static_cast<RedisReplyBuilder*>(builder);
|
||||||
auto serialize_command = [&rb](string_view name, const CommandId& cid) {
|
auto serialize_command = [&rb, this](string_view name, const CommandId& cid) {
|
||||||
rb->StartArray(6);
|
rb->StartArray(7);
|
||||||
rb->SendSimpleString(cid.name());
|
rb->SendSimpleString(cid.name());
|
||||||
rb->SendLong(cid.arity());
|
rb->SendLong(cid.arity());
|
||||||
rb->StartArray(CommandId::OptCount(cid.opt_mask()));
|
rb->StartArray(CommandId::OptCount(cid.opt_mask()));
|
||||||
|
@ -2504,6 +2504,17 @@ void Service::Command(CmdArgList args, Transaction* tx, SinkReplyBuilder* builde
|
||||||
rb->SendLong(cid.first_key_pos());
|
rb->SendLong(cid.first_key_pos());
|
||||||
rb->SendLong(cid.last_key_pos());
|
rb->SendLong(cid.last_key_pos());
|
||||||
rb->SendLong(cid.opt_mask() & CO::INTERLEAVED_KEYS ? 2 : 1);
|
rb->SendLong(cid.opt_mask() & CO::INTERLEAVED_KEYS ? 2 : 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto& table = acl_family_.GetRevTable();
|
||||||
|
vector<string> cats;
|
||||||
|
for (uint32_t i = 0; i < 32; i++) {
|
||||||
|
if (cid.acl_categories() & (1 << i)) {
|
||||||
|
cats.emplace_back("@" + table[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rb->SendSimpleStrArr(cats);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If no arguments are specified, reply with all commands
|
// If no arguments are specified, reply with all commands
|
||||||
|
|
|
@ -1530,68 +1530,36 @@ void StringFamily::ClThrottle(CmdArgList args, Transaction* tx, SinkReplyBuilder
|
||||||
|
|
||||||
#define HFUNC(x) SetHandler(&StringFamily::x)
|
#define HFUNC(x) SetHandler(&StringFamily::x)
|
||||||
|
|
||||||
namespace acl {
|
|
||||||
constexpr uint32_t kSet = WRITE | STRING | SLOW;
|
|
||||||
constexpr uint32_t kSetEx = WRITE | STRING | SLOW;
|
|
||||||
constexpr uint32_t kPSetEx = WRITE | STRING | SLOW;
|
|
||||||
constexpr uint32_t kSetNx = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kAppend = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kPrepend = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kIncr = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kDecr = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kIncrBy = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kIncrByFloat = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kDecrBy = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kGet = READ | STRING | FAST;
|
|
||||||
constexpr uint32_t kGetDel = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kGetEx = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kGetSet = WRITE | STRING | FAST;
|
|
||||||
constexpr uint32_t kMGet = READ | STRING | FAST;
|
|
||||||
constexpr uint32_t kMSet = WRITE | STRING | SLOW;
|
|
||||||
constexpr uint32_t kMSetNx = WRITE | STRING | SLOW;
|
|
||||||
constexpr uint32_t kStrLen = READ | STRING | FAST;
|
|
||||||
constexpr uint32_t kGetRange = READ | STRING | SLOW;
|
|
||||||
constexpr uint32_t kSubStr = READ | STRING | SLOW;
|
|
||||||
constexpr uint32_t kSetRange = WRITE | STRING | SLOW;
|
|
||||||
// ClThrottle is a module in redis. Therefore we introduce a new extension
|
|
||||||
// to the category. We should consider other defaults as well
|
|
||||||
constexpr uint32_t kClThrottle = THROTTLE;
|
|
||||||
} // namespace acl
|
|
||||||
|
|
||||||
void StringFamily::Register(CommandRegistry* registry) {
|
void StringFamily::Register(CommandRegistry* registry) {
|
||||||
constexpr uint32_t kMSetMask =
|
constexpr uint32_t kMSetMask =
|
||||||
CO::WRITE | CO::DENYOOM | CO::INTERLEAVED_KEYS | CO::NO_AUTOJOURNAL;
|
CO::WRITE | CO::DENYOOM | CO::INTERLEAVED_KEYS | CO::NO_AUTOJOURNAL;
|
||||||
|
|
||||||
registry->StartFamily();
|
registry->StartFamily(acl::STRING);
|
||||||
*registry
|
*registry << CI{"SET", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, -3, 1, 1}.HFUNC(Set)
|
||||||
<< CI{"SET", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, -3, 1, 1, acl::kSet}.HFUNC(Set)
|
<< CI{"SETEX", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, 4, 1, 1}.HFUNC(SetEx)
|
||||||
<< CI{"SETEX", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, 4, 1, 1, acl::kSetEx}.HFUNC(
|
<< CI{"PSETEX", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, 4, 1, 1}.HFUNC(PSetEx)
|
||||||
SetEx)
|
<< CI{"SETNX", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1}.HFUNC(SetNx)
|
||||||
<< CI{"PSETEX", CO::WRITE | CO::DENYOOM | CO::NO_AUTOJOURNAL, 4, 1, 1, acl::kPSetEx}.HFUNC(
|
<< CI{"APPEND", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1}.HFUNC(Append)
|
||||||
PSetEx)
|
<< CI{"PREPEND", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1}.HFUNC(Prepend)
|
||||||
<< CI{"SETNX", CO::WRITE | CO::DENYOOM, 3, 1, 1, acl::kSetNx}.HFUNC(SetNx)
|
<< CI{"INCR", CO::WRITE | CO::FAST, 2, 1, 1}.HFUNC(Incr)
|
||||||
<< CI{"APPEND", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1, acl::kAppend}.HFUNC(Append)
|
<< CI{"DECR", CO::WRITE | CO::FAST, 2, 1, 1}.HFUNC(Decr)
|
||||||
<< CI{"PREPEND", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1, acl::kPrepend}.HFUNC(Prepend)
|
<< CI{"INCRBY", CO::WRITE | CO::FAST, 3, 1, 1}.HFUNC(IncrBy)
|
||||||
<< CI{"INCR", CO::WRITE | CO::FAST, 2, 1, 1, acl::kIncr}.HFUNC(Incr)
|
<< CI{"INCRBYFLOAT", CO::WRITE | CO::FAST, 3, 1, 1}.HFUNC(IncrByFloat)
|
||||||
<< CI{"DECR", CO::WRITE | CO::FAST, 2, 1, 1, acl::kDecr}.HFUNC(Decr)
|
<< CI{"DECRBY", CO::WRITE | CO::FAST, 3, 1, 1}.HFUNC(DecrBy)
|
||||||
<< CI{"INCRBY", CO::WRITE | CO::FAST, 3, 1, 1, acl::kIncrBy}.HFUNC(IncrBy)
|
<< CI{"GET", CO::READONLY | CO::FAST, 2, 1, 1}.HFUNC(Get)
|
||||||
<< CI{"INCRBYFLOAT", CO::WRITE | CO::FAST, 3, 1, 1, acl::kIncrByFloat}.HFUNC(IncrByFloat)
|
<< CI{"GETDEL", CO::WRITE | CO::FAST, 2, 1, 1}.HFUNC(GetDel)
|
||||||
<< CI{"DECRBY", CO::WRITE | CO::FAST, 3, 1, 1, acl::kDecrBy}.HFUNC(DecrBy)
|
<< CI{"GETEX", CO::WRITE | CO::DENYOOM | CO::FAST | CO::NO_AUTOJOURNAL, -2, 1, 1}.HFUNC(
|
||||||
<< CI{"GET", CO::READONLY | CO::FAST, 2, 1, 1, acl::kGet}.HFUNC(Get)
|
GetEx)
|
||||||
<< CI{"GETDEL", CO::WRITE | CO::FAST, 2, 1, 1, acl::kGetDel}.HFUNC(GetDel)
|
<< CI{"GETSET", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1}.HFUNC(GetSet)
|
||||||
<< CI{"GETEX", CO::WRITE | CO::DENYOOM | CO::FAST | CO::NO_AUTOJOURNAL, -2, 1, 1, acl::kGetEx}
|
<< CI{"MGET", CO::READONLY | CO::FAST | CO::IDEMPOTENT, -2, 1, -1}.HFUNC(MGet)
|
||||||
.HFUNC(GetEx)
|
<< CI{"MSET", kMSetMask, -3, 1, -1}.HFUNC(MSet)
|
||||||
<< CI{"GETSET", CO::WRITE | CO::DENYOOM | CO::FAST, 3, 1, 1, acl::kGetSet}.HFUNC(GetSet)
|
<< CI{"MSETNX", kMSetMask, -3, 1, -1}.HFUNC(MSetNx)
|
||||||
<< CI{"MGET", CO::READONLY | CO::FAST | CO::IDEMPOTENT, -2, 1, -1, acl::kMGet}.HFUNC(MGet)
|
<< CI{"STRLEN", CO::READONLY | CO::FAST, 2, 1, 1}.HFUNC(StrLen)
|
||||||
<< CI{"MSET", kMSetMask, -3, 1, -1, acl::kMSet}.HFUNC(MSet)
|
<< CI{"GETRANGE", CO::READONLY, 4, 1, 1}.HFUNC(GetRange)
|
||||||
<< CI{"MSETNX", kMSetMask, -3, 1, -1, acl::kMSetNx}.HFUNC(MSetNx)
|
<< CI{"SUBSTR", CO::READONLY, 4, 1, 1}.HFUNC(GetRange) // Alias for GetRange
|
||||||
<< CI{"STRLEN", CO::READONLY | CO::FAST, 2, 1, 1, acl::kStrLen}.HFUNC(StrLen)
|
<< CI{"SETRANGE", CO::WRITE | CO::DENYOOM, 4, 1, 1}.HFUNC(SetRange)
|
||||||
<< CI{"GETRANGE", CO::READONLY | CO::FAST, 4, 1, 1, acl::kGetRange}.HFUNC(GetRange)
|
<< CI{"CL.THROTTLE", CO::WRITE | CO::DENYOOM | CO::FAST, -5, 1, 1, acl::THROTTLE}.HFUNC(
|
||||||
<< CI{"SUBSTR", CO::READONLY | CO::FAST, 4, 1, 1, acl::kSubStr}.HFUNC(
|
ClThrottle);
|
||||||
GetRange) // Alias for GetRange
|
|
||||||
<< CI{"SETRANGE", CO::WRITE | CO::FAST | CO::DENYOOM, 4, 1, 1, acl::kSetRange}.HFUNC(SetRange)
|
|
||||||
<< CI{"CL.THROTTLE", CO::WRITE | CO::DENYOOM | CO::FAST, -5, 1, 1, acl::kClThrottle}.HFUNC(
|
|
||||||
ClThrottle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
Loading…
Reference in a new issue