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

Adds new pop-push commands (LMOVE, BLMOVE) #6929

Merged
merged 19 commits into from Oct 8, 2020

Conversation

felipou
Copy link
Contributor

@felipou felipou commented Feb 24, 2020

Adds lpoprpush, rpoprpush and lpoplpush, and the equivalent blocking commands: blpoprpush, brpoprpush and blpoplpush.

@felipou
Copy link
Contributor Author

felipou commented Feb 24, 2020

I started implementing this almost 5 years ago, so I decided to create a new PR. The old one is here: #2664

@felipou
Copy link
Contributor Author

felipou commented Feb 24, 2020

I was in doubt about mainly 3 things:

  • Tests: I just replicated all the RPOPLPUSH and BRPOPLPUSH tests. They add quite some testing time (only the blocking ones), but I think they add very little value, since the code is practically the same. But anyway, I felt that I should replicate then all, it's easier to just erase some now if that's the case.
  • Comments: I didn't add any new comments, just modified the existing ones. Didn't really feel the need to, since the lists code is quite clean and easy to understand, and my changes don't make it more complicated.
  • Coding style: I did my best to comply to overall coding style, although I haven't seen any guideline, just tried to look at the surrounding code to grasp it. But I'm a strong advocate of strict and consistent coding style, so I was confused because there are some bits of code that don't seem to comply with the overall style, like for example max line length. I tried to keep my code under 80 characters, but there were some long lines already, so when I modified these I just kept it as one-line. If anyone wants to point something that is not conformant with the project coding style, I'd be very grateful and eager to fix it.

@itamarhaber
Copy link
Member

I started implementing this almost 5 years ago

+1 for being persistent :)

These new commands are symmetrical to the rpoplpush command, and
they've been implemented using a generic method (poppushGenericCommand)
with the existing pattern of a flag begin LIST_HEAD or LIST_TAIL to
indicate the start or end of a list. The blocking equivalents will come
in the following commit.
These new commands are symmetrical to the brpoplpush command, and
they've been implemented using a generic method (blockingPopPushGenericCommand)
with the existing pattern of a flag begin LIST_HEAD or LIST_TAIL to
indicate the start or end of a list. The non-blocking alternatives
were implemented in the previous commit.
@felipou
Copy link
Contributor Author

felipou commented Jun 23, 2020

Did a rebase with unstable solving a minor conflict (wasn't an actual conflict, just a change very close to my changes flagged as a possible conflict). As a plus it solved the CI checks that were failing before (and wasn't my fault as expected).

@antirez
Copy link
Contributor

antirez commented Jun 24, 2020

Looks like a good coincise implementation @felipou, thanks. And since this is a plain extension of the original implementation, I guess the replication part should work as expected (didn't check the details). So indeed it is worth a careful review and a potential merge.

@felipou
Copy link
Contributor Author

felipou commented Jun 25, 2020

Great, let me know if there is anything else I can do to help or improve the code!

@itamarhaber
Copy link
Member

@yossigo @oranagra @madolson @soloestoy please review and consider for 6.0.6

@felipou would it be too much to ask you to help with the respective docs once approved? ;)

Copy link
Member

@oranagra oranagra left a comment

Choose a reason for hiding this comment

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

@felipou thank you for this PR.
i've added a few minor comments about the code.
some suggestions about improving some tests, and trimming others.

src/help.h Outdated Show resolved Hide resolved
redis.conf Outdated Show resolved Hide resolved
src/t_list.c Outdated Show resolved Hide resolved
src/t_list.c Outdated Show resolved Hide resolved
src/t_list.c Show resolved Hide resolved
tests/unit/type/list.tcl Outdated Show resolved Hide resolved
tests/unit/type/list.tcl Outdated Show resolved Hide resolved
tests/unit/type/list.tcl Outdated Show resolved Hide resolved
tests/unit/type/list.tcl Outdated Show resolved Hide resolved
tests/unit/type/list.tcl Outdated Show resolved Hide resolved
@felipou
Copy link
Contributor Author

felipou commented Jul 12, 2020

@felipou would it be too much to ask you to help with the respective docs once approved? ;)

Not at all, please count me in for anything you need, it's a pleasure contributing to Redis!

@felipou
Copy link
Contributor Author

felipou commented Jul 12, 2020

@oranagra Thanks for your review, I'll go over everything right now. I may struggle a bit with the tests, since I've never worked with tcl, I just copied the existing tests for RPOPLPUSH, but I think I'll manage.

Just a quick question: what is the usual process here, do I overwrite my branch (push --force), or should I push multiple commits and afterwards we squash them (or maybe don't even squash, just merge as it is)? For now I'll just push new commits, but I'm asking because I like to keep my git history very clean, so I usually do a lot of overwrites on feature branches to keep them as tidy as possible before merging.

@oranagra
Copy link
Member

@felipou i like my git history clean too, we'll either squash it at the end, or if for some reason we want to keep some changes in separate commit, we'll do some cleanup.
for now you can either add more commits, or amend and push-f.

if you need help with the tests let me know, i think you'll just be able to use your clipboard and common sense..

- Replace "after 1000" with "wait_for_condition" when wait for
clients to block/unblock.
- Add a pre-existing element to target list on basic tests so
that we can check if the new element was added to the correct
side of the list.
- Changed second call on linked poppush call test (instead of
two brpoplpush, we do first a brpoplpush and then blpoprpush).

Changes suggested by @oranagra during PR review.
Rename two functions, remove some empty lines and add some
comments.
@felipou
Copy link
Contributor Author

felipou commented Jul 12, 2020

@oranagra I just pushed some new commits addressing everything you commented. I just replied every thread instead of resolving the conversations, if you want I can resolve all the trivial ones (removing duplicate tests for example).

@oranagra
Copy link
Member

@felipou thanks you. everything looks great.
hope to merge it soon (although not sure it can go into 6.0).

p.s. out of curiosity i run the list test.
original version took me 11 seconds
the one before my review comments took 26 seconds
and the last revision took just 7 seconds.
so adding tests and still runs faster.

oranagra
oranagra previously approved these changes Jul 13, 2020
@felipou
Copy link
Contributor Author

felipou commented Jul 13, 2020

@oranagra Great, thanks!

Makes total sense that it runs faster too, the idea you gave of replacing the after calls with wait_for_condition is a very good optimization, no sense in waiting a full 1s for something that usually happens a lot faster.

@oranagra
Copy link
Member

@redis/core-team since this PR adds commands (which we can't later remove or rename), it requires more than lazy consensus.
There's no need to review the code again, but please approve the addition of these 6 new commands.

itamarhaber
itamarhaber previously approved these changes Jul 15, 2020
@oranagra oranagra self-assigned this Jul 19, 2020
@madolson
Copy link
Contributor

I think the new commands are sensible.

I want to bring up a separate point that I think we should rewrite the blocking command infrastructure. Today it works by marking the client as blocked on a key with a bunch of special variables, when that key is written to we used those stored special variables to complete the request. This has several issues:

  1. We maintain a lot of duplicate code to process the requests.
  2. The code as written is sort of spaghetti code.
  3. We may still have to re-block after the command is executed, which requires special handling in that case which is unnecessary.
  4. Explicit rewriting for replication.

Instead, I think we should merge the blocking framework with the mechanism that was outlined for the background threads. If a client is block from a non-existent key, it should just remove itself from the event handler and register that it is blocked on a key. When that key is touched, the blocked client will be unblocked and will attempt to re-execute the command that blocked it in the first place. This shouldn't introduce any major compatibility issues and should throw the same exceptions we do today. It can then inline the command it has within the replication system. It should hopefully remove a lot of the weird checks that we have to do that are included in the CR.

I think this refactor is worth it either for this change or so that it is easier to make these sort of changes in the future. (If we agree it's worth it for this change, I'm okay with this specific PR getting merged and a separate one for the refactor)

Instead of using rewriteClientCommandVector to transform
rpoplpush/brpoplpush commands into lmove/blmove commands, we
created generic functions that both commands use.

At the same time, we have changed the rewrites and propagations
to maintain compatibility for the rpoplpush/brpoplpush commands.
@felipou
Copy link
Contributor Author

felipou commented Oct 6, 2020

Just pushed 3 commits with:

  • The joined tests (I changed them a bit from the commit I had sent before, just to make it a little simpler by avoiding nested ifs)
  • The left and right shared strings
  • Replacement of rewriteClientCommandVector with more generic function that both commands can use
  • Compatibility for rpoplpush/brpoplpush when propagating or rewriting

I'll now experiment with the wherefrom/whereto parameters of the blockForKeys function, and update the redis-doc PR.

@felipou
Copy link
Contributor Author

felipou commented Oct 6, 2020

Option 1 - using LIST_NONE: felipou@073bb77
Option 2 - using a struct: felipou@0cd3feb

Not sure if it was just me choosing terrible names, but option 2 doesn't look very good.

Copy link
Member

@oranagra oranagra left a comment

Choose a reason for hiding this comment

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

all looks good. the only thing that may be missing is maybe add a test to cover the propagation of BRPOPLPUSH and BLMOVE to AOF or Replicas.
i see replication.tcl has these two tests:

        test {BRPOPLPUSH replication, when blocking against empty list} {
        test {BRPOPLPUSH replication, list exists} {

i guess these can be improved to look at the command stats to check which command was executed on the replica.
and add similar tests for BLMOVE.

maybe move proc cmdstat from integration/introspection-2.tcl to support/util.tcl and use it in replication.tcl

@felipou
Copy link
Contributor Author

felipou commented Oct 6, 2020

Just pushed the commit to create the internal listPos struct as you suggested @oranagra, looks much better now, thanks!

@felipou
Copy link
Contributor Author

felipou commented Oct 6, 2020

I'll take a look at the tests you mentioned.

@felipou
Copy link
Contributor Author

felipou commented Oct 6, 2020

Ok, I think I managed. TCL is really new to me, so I didn't know much about what was possible. I created a new proc to avoid changing the file tests/unit/introspection-2.tcl too much.

Copy link
Member

@oranagra oranagra left a comment

Choose a reason for hiding this comment

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

hope my changes actually work (not a TCL expert either)

tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
tests/integration/replication.tcl Outdated Show resolved Hide resolved
Change the redis client used to check for the cmd stats in the
replica client. Also change the name of the commands searched for
in the stats to be the non-blocking version.
@felipou
Copy link
Contributor Author

felipou commented Oct 7, 2020

Ok, great, thanks for the orientation! This actually helped me understand something I had suspected but wasn't really sure: the propagated command is actually the non-blocking version (I had to fix that for the tests to pass).

That's how it worked in the rpoplpush command before my changes, so I just replicated the same idea (BLMOVE propagates LMOVE). Should we change that?

@oranagra
Copy link
Member

oranagra commented Oct 7, 2020

@felipou change what?
you're right, the propagated command is the non-blocking one.
and with the changes we did, when the original command was [B]RPOPLPUSH we propagate an RPOPLPUSH, and when it's [B]LMOVE we propagate an LMOVE.
is that not what we did? i think the tests prove it.
so what did you suggest to change?

@felipou
Copy link
Contributor Author

felipou commented Oct 7, 2020

I thought maybe this wasn't the intended behaviour, and that perhaps we should propagate the same command (the blocking one) instead.

@oranagra
Copy link
Member

oranagra commented Oct 7, 2020

@redis/core-team please approve the addition of new LMOVE and BLMOVE commands (deprecating [B]RPOPLPUSH).

Note that when receiving a BRPOPLPUSH we'll still propagate an RPOPLPUSH (but on BLMOVE RIGHT LEFT we'll propagate an LMOVE)

@oranagra oranagra changed the title Adds new pop-push commands Adds new pop-push commands (LMOVE, BLMOVE) Oct 8, 2020
@oranagra oranagra merged commit c3f9e01 into redis:unstable Oct 8, 2020
@oranagra
Copy link
Member

oranagra commented Oct 8, 2020

merged.. @felipou thanks a lot for sticking that long and implementing all the feedback.

@oranagra oranagra added the release-notes indication that this issue needs to be mentioned in the release notes label Oct 8, 2020
@felipou
Copy link
Contributor Author

felipou commented Oct 8, 2020

Hey, thank you all very much for all the feedback and for taking this in, especially you @oranagra! It was my first significant contribution to an important open-source project, and I have to say, the experience was great. Looking forward to contribute more!

@oranagra oranagra moved this from In progress to Done in 6.2 Oct 19, 2020
@oranagra oranagra removed this from the Next minor backlog milestone Oct 19, 2020
JackieXie168 pushed a commit to JackieXie168/redis that referenced this pull request Nov 4, 2020
Adding [B]LMOVE <src> <dst> RIGHT|LEFT RIGHT|LEFT. deprecating [B]RPOPLPUSH.

Note that when receiving a BRPOPLPUSH we'll still propagate an RPOPLPUSH,
but on BLMOVE RIGHT LEFT we'll propagate an LMOVE

improvement to existing tests
- Replace "after 1000" with "wait_for_condition" when wait for
  clients to block/unblock.
- Add a pre-existing element to target list on basic tests so
  that we can check if the new element was added to the correct
  side of the list.
- check command stats on the replica to make sure the right
  command was replicated

Co-authored-by: Oran Agra <oran@redislabs.com>
@oranagra oranagra mentioned this pull request Jan 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-notes indication that this issue needs to be mentioned in the release notes state:major-decision Requires core team consensus state:to-be-merged The PR should be merged soon, even if not yet ready, this is used so that it won't be forgotten
Projects
No open projects
6.2
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

8 participants