Support Redis inline commands#7687
Conversation
Motivation: The RESP protocol implementation lacked inline command support. Modifications: Added logic to decode and encode inline commands. Result: Inline commands are supported. Fixes #7686.
Motivation: There is some cleanup that can be done. Modifications: - Remove unused code - Move common code to base class Result: Cleaner code.
|
@ddossot PTAL |
ddossot
left a comment
There was a problem hiding this comment.
One nit, one question, otherwise LGTM 👍
| * Returns length of this type. | ||
| */ | ||
| public int length() { | ||
| return (value != null) ? RedisConstants.TYPE_LENGTH : 0; |
There was a problem hiding this comment.
nit: remove parenthesis around condition for consistency with other ternaries, for ex. in RedisDecoder
| return ARRAY_HEADER; | ||
| default: | ||
| throw new RedisCodecException("Unknown RedisMessageType: " + value); | ||
| return INLINE_COMMAND; |
There was a problem hiding this comment.
We're changing a catch-all exception to an accept-all use case. I'm wondering if there's something more accurate we could do, for ex. only recognize a-zA-Z as the marker of an inline command and restore the RedisCodecException for all other cases?
There was a problem hiding this comment.
Redis commands can be renamed for security reasons. Substitute commands are not limited to a-zA-Z though:
redis.conf
rename-command PING もしもし # hello in Japanese
Invoke renamed command (works in redis-cli, too)
$ echo もしもし | nc localhost 6379
+PONG
I don't see any good reason to be more restrictive than Redis itself is.
There was a problem hiding this comment.
The intent was not to be more restrictive than Redis is. Since rename-command allows using any character in commands, there's unfortunately not much check we can do.
|
I wondering if we even need to support these inline-commands. It seems like an alternative variant on the original protocol for text-based clients which may require additional work to represent the original protocol [1]. It also introduces additional complexity for encoding/decoding (as indicated above in #7687 (comment)) and may allow for malformed input to be parsed. [1] https://redis.io/topics/protocol#inline-commands
|
|
@Scottmitch The inline protocol being human centric, I reckon the main use case would be people building new cli tools for Redis, which is a narrow use case. @mseitner Did you have other use cases in mind? |
|
I'm working on a Redis proxy, so I have to be transparent towards the client. I got everything up and running, but of all things it was However, my concrete use case should have nothing to do with the level of protocol support. Do we agree that inline commands are part of the RESP protocol? If so, they should be supported. Regarding backward compatibility/consistency I suggest to make inline command support configurable via constructor argument, with the default being |
|
@ddossot @Scottmitch How should I continue? |
|
@mseitner I would say as long as it is "optional" and the old behaviour is the default it should be "ok" |
|
@mseitner +1 for optional support for inline-cmd, off by default. This would address my main concern, which I detailed above about becoming too lax by default. |
|
Done. |
There was a problem hiding this comment.
the length() method isn't really used in a generic fashion here and is a bit misleading. For example we always read 1 byte above without considering length(). Can we instead handle this INLINE_COMMAND logic as a continuation of the special case above?
There was a problem hiding this comment.
I'll move the entire type detection to RedisMessageType. This will also improve functional consistency with the suggested serialization change below.
There was a problem hiding this comment.
instead of length here, we could just let RedisMessageType write itself to the buf:
enum RedisMessageType {
public void serialize(ByteBuf but) {
if (value != null) { buf.writeByte(value); }
}
}There was a problem hiding this comment.
if we introduce the serialize method above, perhaps we don't have to change to Byte. We could use \0 or some "token" to represent null.
There was a problem hiding this comment.
I don't see the benefits of a magic number to represent the absence(!) of a Redis type indicator.
|
Changed as promised, the entire type detection is now implemented in |
|
|
||
| @Override | ||
| public String toString() { | ||
| return new StringBuilder(StringUtil.simpleClassName(this)) |
There was a problem hiding this comment.
Just use normal string concats or at least size the StringBuilder correctly ?
There was a problem hiding this comment.
As you can see I just pulled up the toString() method from existing sub-classes. The implementation is similar to that of other (core) classes. Is a more complex implementation that calculates the needed size really worth it? I suggest to never call the toString() method in a productive environment anyway.
There was a problem hiding this comment.
I think it worth it... that said I think we can improve it in another PR.
There was a problem hiding this comment.
Great! I'd be happy to help with that :-) Anything else that should be done?
| public static RedisMessageType valueOf(byte value) { | ||
| public static RedisMessageType readFrom(ByteBuf in, boolean decodeInlineCommands) { | ||
| final int initialIndex = in.readerIndex(); | ||
| final RedisMessageType type = valueOf(in.readByte()); |
There was a problem hiding this comment.
just use in.getByte(in.readerIndex()) this way you will not need to reset the index
There was a problem hiding this comment.
How does that help? If I use the suggested method I instead have to manually advance the reader index in all other cases to "consume" the type indicator.
|
Squashed and cherry-picked into 4.1 (c75bc1f). Sorry for the slow turn-around |
Motivation:
The RESP protocol implementation lacked inline command
support.
Modifications:
Added logic to decode and encode inline commands.
Result:
Inline commands are supported. Fixes #7686.