-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Feat: Added BZMPOP Command #5436
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
base: main
Are you sure you want to change the base?
Conversation
src/server/zset_family.cc
Outdated
@@ -1819,12 +1819,23 @@ std::optional<std::string_view> GetFirstNonEmptyKeyFound(EngineShard* shard, Tra | |||
return std::nullopt; | |||
} | |||
|
|||
// Validates the ZMPop command arguments and extracts the values to the output params. | |||
// Validates the ZMPop and BZMPop command arguments and extracts the values to the output params. | |||
// If the arguments are invalid sends the appropiate error to builder and returns false. | |||
bool ValidateZMPopCommand(CmdArgList args, uint32* num_keys, bool* is_max, int* pop_count, |
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.
Ok this function has not a very nice interface. Please introduce ValidateZMPopResult
consisting of num_keys, is_max, pop_count and timeout.
The interface should be something like this: bool (CmdArgList args, bool is_blocking, SinkReplyBuilder* builder, ValidateZMPopResult* result)
src/server/zset_family.cc
Outdated
auto* ns = &trans->GetNamespace(); | ||
|
||
// Concluding transaction if it's multi mode as blocking is not allowed in it. | ||
if (trans->IsMulti()) { |
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 would unify this and the block at line 2509 before you handle the blocking case:
if (!key_to_pop && (!is_blocking || trans->IsMulti())) {
....
src/server/zset_family.cc
Outdated
@@ -2783,6 +2850,9 @@ void ZSetFamily::Register(CommandRegistry* registry) { | |||
ZInterCard) | |||
<< CI{"ZLEXCOUNT", CO::READONLY, 4, 1, 1, acl::kZLexCount}.HFUNC(ZLexCount) | |||
<< CI{"ZMPOP", CO::SLOW | CO::WRITE | CO::VARIADIC_KEYS, -4, 2, 2, acl::kZMPop}.HFUNC(ZMPop) | |||
<< CI{"BZMPOP", CO::SLOW | CO::WRITE | CO::VARIADIC_KEYS | CO::BLOCKING, -5, 3, 3, |
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 also need CO::NO_AUTOJOURNAL
to replicate this correctly. this also requires a emitting a custom journal command. Look at the other NO_AUTOJOURNAL commands.
src/server/zset_family.cc
Outdated
// if command conatins no_autojournal and it's BZMPOP then we will write to journal manually. | ||
if ((result == OpStatus::OK) && (cid->opt_mask() & CO::NO_AUTOJOURNAL) && | ||
(cid->name() == "BZMPOP")) { | ||
OpArgs op_args = t->GetOpArgs(shard); |
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 just checked and actually we have the same bug in ZMPOP. Even with ZMPOP, there is no need to pass all the keys because the outcome is already known: we need to fetch from key
.
Therefore, I suggest to move RecordJournal
into OpPopCount and rewrite both commands as ZPOPMIN
or ZPOPMAX
accordingly. Also please do not forget to mark ZMPOP
as NO_AUTOJOURNAL.
Look at how it's done in OpBZPop
. Thanks!
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.
Yup I also thought that but then I thought to make it consistent as ZMPOP so I added it like ZMPOP journal. Cool I will move journaling to OpPopCount and add custom journal to ZMPOP as well that will be much better.
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.
Almost there. I appreciate your effort!
src/server/zset_family.cc
Outdated
bool ValidateZMPopCommand(CmdArgList args, uint32* num_keys, bool* is_max, int* pop_count, | ||
SinkReplyBuilder* builder) { | ||
bool ValidateZMPopCommand(CmdArgList args, ZSetFamily::ValidateZMPopResult* result, | ||
SinkReplyBuilder* builder, bool is_blocking) { |
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.
nit: we put output arguments at the end, so is_blocking
should be second here
src/server/zset_family.h
Outdated
@@ -66,6 +67,13 @@ class ZSetFamily { | |||
bool override = false; | |||
}; | |||
|
|||
struct ValidateZMPopResult { |
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 do not need this struct to be defined in the header file. please move it to the cc file.
src/server/zset_family.h
Outdated
@@ -66,6 +67,13 @@ class ZSetFamily { | |||
bool override = false; | |||
}; | |||
|
|||
struct ValidateZMPopResult { | |||
uint32* num_keys; |
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.
no need to pass pointers. you can just define:
struct ValidateZMPopResult {
uint32_t num_keys;
bool is_max;
int pop_count;
float timeout;
};
and everything will be much simpler in the code.
src/server/zset_family.h
Outdated
@@ -7,6 +7,7 @@ | |||
#include <string_view> | |||
#include <variant> | |||
|
|||
#include "base/integral_types.h" |
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.
not needed
tests/dragonfly/replication_test.py
Outdated
# check BZMPOP turns into ZMPOP command | ||
await c_master.zadd("key", {"a": 1, "b": 2, "c": 3}) | ||
await skip_cmd() | ||
await check("BZMPOP 0 3 key3 key2 key MAX COUNT 3", r"ZMPOP 1 key MAX COUNT 3") |
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.
very nice, thank you! but it should turn as ZPOPMAX/ZPOPMIN :)
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.
Sure I will change it
src/server/zset_family.cc
Outdated
if (!ValidateZMPopCommand(args, &num_keys, &is_max, &pop_count, cmd_cntx.rb)) { | ||
// Generic function for ZMPop and BZMPop commands | ||
void ZMPopGeneric(CmdArgList args, const CommandContext& cmd_cntx, bool is_blocking) { | ||
ValidateZMPopResult zmpopArgs; |
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.
naming: zmpop_args
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.
minor comments
src/server/zset_family.cc
Outdated
// Check if we have additional COUNT argument. | ||
if (parser.HasNext()) { | ||
if (!parser.Check("COUNT", pop_count)) { | ||
if (!parser.Check("COUNT", &(result->pop_count))) { |
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.
if (!parser.Check("COUNT", &(result->pop_count))) { | |
if (!parser.Check("COUNT", &result->pop_count)) { |
src/server/zset_family.cc
Outdated
CmdArgParser parser{args}; | ||
|
||
if (!SimpleAtoi(parser.Next(), num_keys)) { | ||
if (is_blocking) { | ||
if (!absl::SimpleAtof(parser.Next(), &(result->timeout))) { |
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.
if (!absl::SimpleAtof(parser.Next(), &(result->timeout))) { | |
if (!absl::SimpleAtof(parser.Next(), &result->timeout)) { |
Also added test for BZMPOP custom journal by checking replication.
- Added Custom journaling for BZMPOP command. - Created ValidateZMPopResults Interface.
Added manual journaling for ZMPOP and BZMPOP which turns them into ZPOPMAX/ZPOPMIN. Also refactored the code a bit.
Fixes #3877