Skip to content

Conversation

kostasrim
Copy link
Contributor

  1. Add acl categories to each command
  2. Extend facade::CommandId to include acl category
  3. Add dragonfly extensions to acl categories for modules like search, json etc (since modules in redis do not have acl categories by default but in dragonfly these are not implemented as modules)

@royjacobson
Copy link
Contributor

Ok, this is a LOT to review :)

Quick comment before I review the permissions for the actual commands - there are some 'old style' attributes like CO::WRITE that are redundant now, no? Do you plan to get rid of them in the future?

#include "absl/container/flat_hash_map.h"

namespace dfly {
namespace AclCategory {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a big fan of introducing lots of namespaces because it eats up horizontal space and hurts eyes.

  1. if you want to add a namespace, then it's better to make it short and consistent with the folder name (i.e. acl).
  2. everything in the folder should be under the same namespace.
  3. classes inside the namespace should not have Acl prefix - i.e. either with namespace and without Acl or without the namespace with prefix.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 . note that I introduced the acl namespace here just so the enum constants in enum AclCat don't leak (since it's an unscoped enum). A class enum would not do either, because each time you assign one of its constants to a variable you need to static_cast. The last one was constexpr variables (which was originally what I did) but later Vlad pointed out that grouping with the enum is nice and I ended up opting for namespace + enum.

I will put everything in acl subfolder under the same namespace acl.

Just to clarify, the acl should be a top level namespace, that is ::acl::some_def and not dfly::acl::some_def is that correct?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everything is dfly under src/server, therefore I think it makes sense to introduce dfly::acl.
facade is the only other top-level namespace we introduced in dragonfly repo, imho.

};

// Special flag/mask for all
inline constexpr uint32_t NONE = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what inline gives us in this context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing, muscle memory because I like to be explicit, constexpr variables are implicitly inline. I will remove this :)

Copy link
Contributor Author

@kostasrim kostasrim Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and they are not implicitly inline! http://eel.is/c++draft/dcl.constexpr#1.sentence-3 . But constexpr implies const which enforces internal linkage (implies static unless declared as extern). However, I like inline because the compiler folds it, meaning that if-ever we take its address, all the TU will see the same address instead of a copy. Simply put, it's redundant to have multiple copies of the same constant (ok this will elided anyway since we don't use its address but I am being pedantic here)

@@ -598,12 +599,24 @@ inline CommandId::Handler HandlerFunc(ClusterFamily* se, EngineFunc f) {

#define HFUNC(x) SetHandler(HandlerFunc(this, &ClusterFamily::x))

namespace {
namespace Acl {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namespaces should be all lowercase, and for consistency, I suggest using acl everywhere.
and you probably won't need namespace Cat = AclCategory; then.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, I really like the change, it's so much simpler now without the nested namespaces. Moreover, I removed the unnamed namespaces since constexpr implies const which implies static which has internal linkage

namespace {
namespace Acl {
namespace Cat = AclCategory;
constexpr uint32_t kPFAdd = Cat::WRITE | Cat::HYPERLOGLOG | Cat::FAST;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe introduce a macro to reduce the boilerplate? i.e. ACL_CATEGORY(WRITE, FAST, HYPERLOGLOG)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

though it does not look like it will reduce much

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will change the syntax but not really reduce the boilerplate. I really don't like macros (unless there is a very good reason to use them) and since this won't add much here I rather not do it atm.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! most comments I had - are purely subjective. Regarding macros - surprisingly I actually find them very useful for the production-grade code (i.e debug checks etc). (this case is irrelevant of course). Macros are one of the bigger reasons why I do not enjoy coding in golang or Java. Though I must say, the Rust "macro" language is 10 times better than C/C++.

Copy link
Contributor Author

@kostasrim kostasrim Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding macros - surprisingly I actually find them very useful for the production-grade code (i.e debug checks etc)

100% macros have good use cases and that's why are a necessary evil :D IMO, I have seen a lot of macro wonkery over the years (in places where templates would have been a better option) and my despise towards them comes from that.

p.s. one of the cases that macros are infamous but very very useful, is when you want to implement reflection in C++ with templates -- that is a library feature not a language feature. You need macros for that + SFINAE (since we don't have reflection implemented as a language feature -- soon though hopefully in 26 or 29)

for java and golang

Not a big fun of GC based languages especially when you want raw control. If you want to fine tune something that relies on GC you pretty much screwed -- meaning that you end up fighting the GC instead of solving the actual issue

Though I must say, the Rust "macro" language is 10 times better

I never tried Rust macros. I played with rust a little bit but IMO I don't buy its safety guarantees mostly because:

  1. One way or another you will write rust that interferes with C/C++ code. You need unsafe for that so it kinda beats the purpose of the language
  2. Compile times are SLOW AF. I have seen small codebases requiring hours to compile. People who complain about TMP and SFINAE compilation times would panic (pan intended here 🤣 ) when they see the compile times of Rust in big codebases.
  3. You want to leverage RUST without a performance hit? You still need to write unsafe code :/
  4. There are some TMP tricks that you just can't do with rust no matter how you try
  5. The quality of the libraries found in rust are subpar compared to C++. One example is p2300 aka senders and receivers. It's a very complicated async model but it has 0 overhead compared to other async abstractions like futures and promises. The former does not require dynamic memory allocation for the shared state neither syncronization primitives for attaching continuations while the later does. You won't find high calibre libraries like that in Rust... Yes there is a learning curve here which is expensive but very rightfully so for certain cases and problems.

Plz don't get me wrong, my mental model is that every language and feature is tool -- I would program in any of them if it solves my problem elegantly. In my view, it's always a matter of asking the correct questions when you are implementing something (a good example here is your decision with boost fibers and helio -- can they be optimized further ? YES! Is it worth it ? NO! Why? Because there are other parts that bring more value!)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw I am not ranting here, I just love to think out loud and discuss these kind of things. I can do that for hours. Save it for when I am in Israel. I WOULD LOOOOOVE to discuss this!

Copy link
Contributor Author

@kostasrim kostasrim Aug 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaaaaalso one more thing. The goto async abstraction for Rust is https://tokio.rs/ which is AWESOME to play with and implement/try out new things. It just works!

However, I could write a lib that outperforms tokio (both in terms of performance and memory) any day -- it would be just like running to a park -- cardio 😄

<< CI{"HSETNX", CO::WRITE | CO::DENYOOM | CO::FAST, 4, 1, 1, 1}.HFUNC(HSetNx)
<< CI{"HSTRLEN", CO::READONLY | CO::FAST, 3, 1, 1, 1}.HFUNC(HStrLen)
<< CI{"HVALS", CO::READONLY, 2, 1, 1, 1}.HFUNC(HVals);
*registry
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another idea - to introduce manipulators:

 *registry << EnableCat(HASH) << ....
<< DisableCat(HASH)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a nice one and I was thinking of it for acl commands/subcommands but for this case it will add a lot of verbosity. At least with the constexpr variables we have everything in one place and we just pass a small (meaning in letters small) argument to the constructor.

@kostasrim
Copy link
Contributor Author

kostasrim commented Aug 18, 2023

@royjacobson

Ok, this is a LOT to review :)

Sorry, this one could not be made smaller :(

Quick comment before I review the permissions for the actual commands - there are some 'old style' attributes like CO::WRITE that are redundant now, no? Do you plan to get rid of them in the future?

Good question, I was thinking of removing them as well. However, there are also some CO:: variants that do not map 1-1 with the new Categories introduced (and from the redis command json files do not include anything regarding the ACL) and I will need to check this. Since this PR is already large, I would rather leave it as is for now and check back in the future.

@kostasrim kostasrim self-assigned this Aug 18, 2023
@kostasrim kostasrim requested review from romange and dranikpg August 18, 2023 16:29
Copy link
Contributor

@dranikpg dranikpg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna approve here but I really hope those giant blocks will diminish sometime in the future 😀

@kostasrim
Copy link
Contributor Author

I'm gonna approve here but I really hope those giant blocks will diminish sometime in the future 😀

I am not a huge fan of this either, once we get a prototype working I will see how we can clean up(I don't like tech debt neither do I like long blocks of literals). The constexpr transformations you mentioned are really nice -- but as I said I want to keep things decoupled for now to avoid any large change because of something that we missed. It's better to have something that you can reduce and simplify than the opposite way around (this is just my opinion -- take it with a grain of salt)

@kostasrim kostasrim merged commit cfc04cf into main Aug 20, 2023
@kostasrim kostasrim deleted the acl_part_2_add_acl_commands branch August 20, 2023 10:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants