Getex extra options to avoid duplicate options#10419
Conversation
| !(*flags & OBJ_EX) && !(*flags & OBJ_EXAT) && | ||
| !(*flags & OBJ_PX) && !(*flags & OBJ_PXAT) && | ||
| !(*flags & OBJ_KEEPTTL)) | ||
| !(*flags & OBJ_KEEPTTL) && !(*flags & OBJ_PERSIST)) |
There was a problem hiding this comment.
how about this (extra line without touching the line), but its not critical
| !(*flags & OBJ_KEEPTTL) && !(*flags & OBJ_PERSIST)) | |
| !(*flags & OBJ_PERSIST) && | |
| !(*flags & OBJ_KEEPTTL)) |
zuiderkwast
left a comment
There was a problem hiding this comment.
Good and simple solution.
| !(*flags & OBJ_KEEPTTL) && !(*flags & OBJ_PERSIST) && | ||
| !(*flags & OBJ_EXAT) && !(*flags & OBJ_PX) && | ||
| !(*flags & OBJ_PXAT) && next) | ||
| !(*flags & OBJ_PXAT) && next && !(*flags & OBJ_EX)) |
There was a problem hiding this comment.
(Minor unimportant suggestion) Since all these options are mutually exclusive, they can be listed in the same order in every else-if branch. next is different so I think it can be on a separate line. The flags could be checked all at once if you want:
} else if ((opt[0] == 'e' || opt[0] == 'E') &&
(opt[1] == 'x' || opt[1] == 'X') && opt[2] == '\0' &&
!(*flags & (OBJ_KEEPTTL | OBJ_PERSIST | OBJ_EX | OBJ_PX | OBJ_EXAT | OBJ_PXAT)) &&
next)There was a problem hiding this comment.
Hello, thanks for the idea. I like this change as it will simplify the if statements. I have updated the code.
Thanks
|
don't we have that problem in many many commands? |
|
@oranagra I tend to agree with you. This is not necessarily a bug and if we're able to define how this uncommon case is expected to behave across all commands, that may be a better option vs. changing behavior. |
|
FWIW, I think it should be considered a bug and fixed. The documented syntax only allows one option. Nobody wants hidden bugs in their application. Btw, the PR seems to affect all SET and GET related commands with expire options. It needs to be reflected in the title and top comment. |
|
The problem is even deeper than just these two commands, if we wanna considering fixing it, we need to first compose a full list of the affected commands. Note that even fixing it can possibly lead to bugs in some apps, the ones who log the error and keep running. with the above example, in the past these some set and expiration succeed, and now it would be empty. |
|
If we don't fix it, then I think we should document the behaviour (the last occurrence of the duplicated option wins) so that we can avoid future PRs fixing this again and again. (I think I have seen some similar fix before, with a similar discussion.) |
|
In either case new tests would be a good idea. The same tests for both cases, just different expected results. |
|
@oranagra "we need to first compose a full list of the affected commands" There are exactly 2 affected commands: GETEX and SET. Those are the only commands that call the code with the bug ... oops, I mean the undocumented feature :) |
|
@daniel-house these are the two commands that call the code modified here. but there are a ton of other commands that probably do the same practice. |
|
@oranagra I'm not sure what you mean by "the same practice". I looked at the code for RESTORE and I might make a guess that you mean "any command that takes options". Could you please elaborate on your criteria for a command being affected? |
|
yes, any command that takes argument, for instance |
|
My vote would be to go through all of the commands that have the issue and fix it for Redis 7. I think some specific use cases aren't a big deal, since adding the flag multiple times is idempotent (ZADD with XX for example), but the other cases where providing the same argument multiple times can cause different behavior can be a source of bugs. |
I could help community summarize the command list, and find a proper way to solve this issue. |
|
@madolson The specific use case that I am thinking of is Note, my testing shows that |
|
@daniel-house Yes, my brain was not working. The getex case is an example where it does matter. I was thinking about cases like ZADD with XX (Which my brain somehow made the jump too) |
|
I agree that in some cases like ZADD with XX adding the same flag more than once does not change the behavior. However, if I do something like that it will be a mistake on my part. I find it difficult to imagine a use case where anyone would want to do that. My personal preference when I write queries is to get strict feedback about mistakes as early as possible, and for me a mistake like this could be a symptom of bigger problems. |
|
we discussed this in a core-team meeting, and came to two important realizations:
so if we wanna fix it safely, we may need to reject commands with repeated arguments, only when they didn't originate from the master or AOF client. |
|
i went over other breaking changes we recently made, to check which of them could have caused issues of rejecting (or resulting with a different outcome) when executed on an upgraded replica, vs it's master. a few examples that are not a problem:
the only one i could find that can cause such issues are:
This realization means that not only that we must always respect commands propagated from masters / AOF, we might also have to be aware which version of redis was the source of that command. @redis/core-team FYI. |
|
2 more interesting cases:
|
This PR fixes the bug in redis related to getex.

Currently there is no check if duplicate options are added. For example
getex key ex 100 ex 400 will set the expiry to 400 and ignore ex 100
getex key ex x ex 400 will set the expiry to 400 and ignore the wrong argument x for ex

After the change we get the following result which is the default error being used in redis
