-
Notifications
You must be signed in to change notification settings - Fork 872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(AclFamily): add acl commands #1844
Conversation
47a0884
to
bb220fa
Compare
regression tests run https://github.com/dragonflydb/dragonfly/actions/runs/6159488030 |
@dranikpg Do not hate me, this is the only large PR that was left. It's mostly boilerplate, so you don't have to worry 😛 Maybe I could have move the utility functions in AclFamily.cc in another PR but it was such a pain to have them in the same file so I moved them here |
src/server/bitops_family.cc
Outdated
@@ -850,6 +850,8 @@ void BitOpsFamily::Register(CommandRegistry* registry) { | |||
<< CI{"BITOP", CO::WRITE | CO::NO_AUTOJOURNAL, -4, 2, -1, 1, acl::kBitOp}.SetHandler(&BitOp) | |||
<< CI{"GETBIT", CO::READONLY | CO::FAST, 3, 1, 1, 1, acl::kGetBit}.SetHandler(&GetBit) | |||
<< CI{"SETBIT", CO::WRITE | CO::DENYOOM, 4, 1, 1, 1, acl::kSetBit}.SetHandler(&SetBit); | |||
|
|||
builder | "BITPOS" | "BITCOUNT" | "BITFIELD" | "BITFIELD_RO" | "BITOP" | "GETBIT" | "SETBIT"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dranikpg I Know what your thoughts are here. Probably you would comment that why don't you move this to the Command constructor such that we get the strings naturally. The reason is:
- It requires passing the builder to the construction of the CI objects. That means that we make the same amount of line changes
- I think it's better this way because it decouples it. If we push everything in the constructor of the CI it will be painfully to work with all these parameters
- The only downside is that I might misspelled a command name. I trust my copy pasting ninja skills so I would say that this won't happen. If it happens we will get a bug report and fix this quickly. Either way not a big deal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You guessed correctly. Duplicating all command names yet a third time is hilarious
I'd argue there is a muuuch better approach. The CommandRegistry is not a relict of the past - change it as you like. Lets add the notion of families there. Lets change it to a CommandRegistryBuilder if it becomes too much.
In short, I'd like to keep existing code as simple as possible. It is possible, without changing all the familes and passing the acl stuff around to keep track of families.
Let then your builder access that information from the command registry. Also if you have it already prepared, you don't need a full blown builder for it
src/server/acl/acl_commands_def.h
Outdated
using RevCommandField = std::vector<std::string>; | ||
using RevCommandsIndexStore = std::vector<RevCommandField>; | ||
|
||
class CommandTableBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bread and butter of this PR. This allows us to build adhoc the index table for commands, since it's so large and I didn't even bother hardcoding the index structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot the letter i in Pair
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah you have a typedef one line above, matched the wrong line
I am also planning some small refactoring of the common logic found in helpers.hpp/cpp but that will be done in a separate PR. This is too large, I don't want to make it even harder for reviewing |
src/server/acl/acl_commands_def.h
Outdated
using RevCommandField = std::vector<std::string>; | ||
using RevCommandsIndexStore = std::vector<RevCommandField>; | ||
|
||
class CommandTableBuilder { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot the letter i in Pair
src/server/acl/user.cc
Outdated
void User::SetAclCommands(size_t index, uint64_t bit_index, bool all) { | ||
if (all) { | ||
for (auto& family : commands_) { | ||
family = ALL_COMMANDS; | ||
} | ||
return; | ||
} | ||
commands_[index] |= bit_index; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its kinda confusing that with the all argument your index & bit_index have no meaning
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree on this, let me see what I can do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up using the index, if it's numeric_limits::max() then it denotes an all
. I also added a comment
src/server/bitops_family.cc
Outdated
@@ -850,6 +850,8 @@ void BitOpsFamily::Register(CommandRegistry* registry) { | |||
<< CI{"BITOP", CO::WRITE | CO::NO_AUTOJOURNAL, -4, 2, -1, 1, acl::kBitOp}.SetHandler(&BitOp) | |||
<< CI{"GETBIT", CO::READONLY | CO::FAST, 3, 1, 1, 1, acl::kGetBit}.SetHandler(&GetBit) | |||
<< CI{"SETBIT", CO::WRITE | CO::DENYOOM, 4, 1, 1, 1, acl::kSetBit}.SetHandler(&SetBit); | |||
|
|||
builder | "BITPOS" | "BITCOUNT" | "BITFIELD" | "BITFIELD_RO" | "BITOP" | "GETBIT" | "SETBIT"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You guessed correctly. Duplicating all command names yet a third time is hilarious
I'd argue there is a muuuch better approach. The CommandRegistry is not a relict of the past - change it as you like. Lets add the notion of families there. Lets change it to a CommandRegistryBuilder if it becomes too much.
In short, I'd like to keep existing code as simple as possible. It is possible, without changing all the familes and passing the acl stuff around to keep track of families.
Let then your builder access that information from the command registry. Also if you have it already prepared, you don't need a full blown builder for it
src/server/acl/acl_commands_def.h
Outdated
friend CommandTableBuilder& operator|(CommandTableBuilder& builder, std::string name) { | ||
(*builder.index_)[name] = {builder.pos_, 1ULL << (builder.bit_number_++)}; | ||
(*builder.rindex_)[builder.pos_].push_back(std::move(name)); | ||
// We should crash if somehow we end up feeding more than the bitfield size | ||
// This won't happen in production, since our tests will fail and we will never | ||
// merge something that violates this | ||
CHECK_LT(++builder.bits_limit, size_t(64)); | ||
return builder; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whats the difference between the builder and a single function that accepts an absl::Span<string_view> 😆
But as I suggested above, lets not duplicate everything a third time. Lets finally make the command registry itself usable and then you don't need 800 lines of changes to do this all
Does redis actually do the same with bitfields? What if I persist search settings and now a new command is added in-between? All the bit indices become displaced and the settings are wrong noq |
Persistence does not write the index structure on the file but rather the full command that was used to create the user. Therefore, we won't ever have to deal with such problem |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll approve to not delay this PR any longer, but please see my comments. Briefly, I suggest fully removing the CommandsIndexer and store family id / command it in the commands itself. I don't see any downsides and it makes it much simpler
src/server/acl/validator.cc
Outdated
const auto& commands = acl::CommandsIndexer(); | ||
DCHECK(commands.contains(id.name())); | ||
auto [index, command_mask] = commands.find(id.name())->second; | ||
DCHECK_LT(index, cntx.acl_commands.size()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, on a second thought 😅 we don't need any of the global stores if we store the family index & command index in the CommandId itself and as a bonus we save a hashmap lookup... I don't see any downsides in storing this info there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a good idea, I will get back on this. I won't merge this PR. Let's make it as good as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Smallest nit
|
||
family_of_commands_.back().push_back(std::string(k)); | ||
cmd.SetFamily(family_of_commands_.size() - 1); | ||
cmd.SetBitIndex(1ULL << bit_index_++); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then its a bit mask 🙂 actually you can store only the index and return 1<<i in get bit mask
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it's a bit mask! Don't hate me, too lazy to make this change and I don't want to do a shift every time I access it :P (not that it matters though)
resolves #1809