Skip to content
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(server): support config set for some flags #1624

Merged
merged 11 commits into from
Aug 9, 2023
Merged

Conversation

adiholden
Copy link
Collaborator

@adiholden adiholden commented Aug 2, 2023

  1. support config set for the following flags: rename_command,dir,requirepass,masterauth
  2. add tcp_keepalive flag and add supprot with config set
  3. more print details when failing on dbfilename flag validation

@adiholden adiholden requested a review from chakaz August 2, 2023 12:10
@@ -617,6 +617,10 @@ void Service::Init(util::AcceptServer* acceptor, std::vector<facade::Listener*>
return true;
});

config_registry.Register("dir", [](const absl::CommandLineFlag& flag) { return true; });
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps we could add some default function that does nothing, or an overload that does so?


if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
LOG(WARNING) << "Could not set reuse addr on socket " << SafeErrorMessage(errno);
}
bool success = ConfigureKeepAlive(fd, kInterval);
uint32_t interval = absl::GetFlag(FLAGS_tcp_keepalive);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I'd remove the var interval and call GetFlag() inline of ConfigureKeepAlive(), your call

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually I need to do validation on this flag value, so register call back is needed.pushing now my changes

Comment on lines 90 to 91
string_view origin_name = AsciiStrToUpper(kv.first);
string_view new_name = AsciiStrToUpper(kv.second);
Copy link
Collaborator

Choose a reason for hiding this comment

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

These are actually undefined behavior and could crash
AsciiStrToUpper()'s return type is string, and assigning such temporaries into a string_view is bad.
I wish we had something to catch such cases :(
Anyway, origin_name and new_name should be of type string

auto apply_cb_on_all_commands = [](const std::vector<std::string>& commands,
std::function<bool(string_view, string_view)> cb) {
for (string command_data : commands) {
pair<string_view, string_view> kv = StrSplit(command_data, '=');
Copy link
Collaborator

Choose a reason for hiding this comment

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

Here and above, this will be unexpected behavior if the new value is expected to have = inside the name.
Maybe use absl::MaxSplits('=', 1) instead of just '='?

src/server/command_registry.cc Outdated Show resolved Hide resolved
@romange
Copy link
Collaborator

romange commented Aug 3, 2023

please note that cmd_stats_map relies on cid->name() be const char. Please double check if it still holds.

@chakaz
Copy link
Collaborator

chakaz commented Aug 3, 2023

please note that cmd_stats_map relies on cid->name() be const char. Please double check if it still holds.

@adiholden correct me if I'm wrong, but I think that specifically this string never changes. It's just how we get to the CommandId that's different.
A side effect of this would be that, even if we rename some command (like FLUSHDB -> NOOOOOOO), the stats will still be gathered around FLUSHDB.
(right?)

1. support config set for the following flags: rename_command,dir,requirepass,masterauth
2. more print details when failing on dbfilename flag validation

Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
@@ -139,6 +142,18 @@ Listener::Listener(Protocol protocol, ServiceInterface* si) : service_(si), prot
http_base_.reset(new HttpListener<>);
http_base_->set_resource_prefix("http://static.dragonflydb.io/data-plane");
si->ConfigureHttpHandlers(http_base_.get());

tcp_keepalive = absl::GetFlag(FLAGS_tcp_keepalive);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This cache is not thread safe, in that an access to tcp_keepalive can occur in parallel to setting it.
However, are you sure it's something we need to cache? We read it upon receiving a new connection, it's definitely something that can be slowed down. I'd vote to reduce complexity and not cache.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I concur. connection creation is not on a hotpath.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So the reason here to use static variable is not to cache the flag but to enable the validation of the flag value i.e that it is bigger than 3. As when we call config set command we first set the flag value and then call the registered callback so I did the validation in the callback and if the validation passed I set the tcp_keepalive var. I spoke with @chakaz and he suggested to do this validation with using the absl custom flags inside the AbslParseFlag. I can do this but then the question raised do we really need this validation @romange ? I believe we have this validation today because we devide tcp_keepalive value by 3 when setting the interval between subsequent keep-alive probes. But I could just make it min value 1. Does this makes sense?

src/server/command_registry.cc Outdated Show resolved Hide resolved
@adiholden
Copy link
Collaborator Author

please note that cmd_stats_map relies on cid->name() be const char. Please double check if it still holds.

Indead there is a problem here and also not only here but when we run find command we return a pointer to the map, so I can not change the command map .I will need to think on another solutions

@adiholden
Copy link
Collaborator Author

please note that cmd_stats_map relies on cid->name() be const char. Please double check if it still holds.

@adiholden correct me if I'm wrong, but I think that specifically this string never changes. It's just how we get to the CommandId that's different. A side effect of this would be that, even if we rename some command (like FLUSHDB -> NOOOOOOO), the stats will still be gathered around FLUSHDB. (right?)

The string in CommadId class does not change but we have another problem here. It is that we return a pointer to the map item CommandId when we execute a command and in the current implementation I move the object, so when executing a command the pointer maybe invalid after rename

@romange
Copy link
Collaborator

romange commented Aug 7, 2023

I did not understand the problematic scenario. Where exactly we keep the stale pointer?

@chakaz
Copy link
Collaborator

chakaz commented Aug 7, 2023

Adi and I just discussed this.
The issue is that CommandId* is returned from the registry, which is held directly in a flat_hash_map (i.e. no pointer stability).
It's easy to support command renaming via flat_hash_map<..., unique_ptr<CommandId>>. Supporting erasing of commands is a bit hacky if we want to support the case of erasing a command while it is invoked - we can just push the unique_ptr<CommandId> into some vector of zombie commands.
The real issue is that this registry is used across threads, but it is not protected by any means. I imagine we'll either duplicate it across all threads (like we do for the cluster config), or use some locking/atomics mechanism (but probably not because it's used in all hot paths essentially)

@adiholden
Copy link
Collaborator Author

Adi and I just discussed this. The issue is that CommandId* is returned from the registry, which is held directly in a flat_hash_map (i.e. no pointer stability). It's easy to support command renaming via flat_hash_map<..., unique_ptr<CommandId>>. Supporting erasing of commands is a bit hacky if we want to support the case of erasing a command while it is invoked - we can just push the unique_ptr<CommandId> into some vector of zombie commands. The real issue is that this registry is used across threads, but it is not protected by any means. I imagine we'll either duplicate it across all threads (like we do for the cluster config), or use some locking/atomics mechanism (but probably not because it's used in all hot paths essentially)

I am going to remove the support for config set rename_command in this PR as it looks to be a bigger change than what I thought and I will do it in a different PR

Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
Signed-off-by: adi_holden <adi@dragonflydb.io>
@romange
Copy link
Collaborator

romange commented Aug 9, 2023

@adiholden let's not support rename via config. I do not see why we must do it dynamically, the intent is to have "hidden" commands that can be accessed internally. The whole concept of rename is weird (hacky) and should be handled by ACLs, imho.
So supporting ti via flags is more than enough.

romange
romange previously approved these changes Aug 9, 2023
@romange
Copy link
Collaborator

romange commented Aug 9, 2023

another thing: the renamee feature can be redesigned differently if we take into account the admin port.

@@ -27,6 +26,7 @@ ABSL_FLAG(string, tls_cert_file, "", "cert file for tls connections");
ABSL_FLAG(string, tls_key_file, "", "key file for tls connections");
ABSL_FLAG(string, tls_ca_cert_file, "", "ca signed certificate to validate tls connections");
ABSL_FLAG(string, tls_ca_cert_dir, "", "ca signed certificates directory");
ABSL_FLAG(uint32_t, tcp_keepalive, 300, "the period in seconds used to send ACKs to client");
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the description of this flag is not accurate.

  1. We start sending acks after the idle time that is bound to the value of this flag.,
  2. We give up on the connection if we have not got any ack response during the additional period that equals to the same value.

So it's worth to mention that it's a period of inactivity after which keep-alives are triggerred and the total time until the dead connection is closed is twice the specified value.

image

Signed-off-by: adi_holden <adi@dragonflydb.io>
@adiholden adiholden requested a review from romange August 9, 2023 10:23
@adiholden adiholden merged commit 6d84515 into main Aug 9, 2023
10 checks passed
@adiholden adiholden deleted the config_set_some_flags branch August 9, 2023 11:16
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.

None yet

3 participants