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

Hash field is not a key #3124

Closed
Xxdnx opened this issue Jan 13, 2025 · 5 comments
Closed

Hash field is not a key #3124

Xxdnx opened this issue Jan 13, 2025 · 5 comments

Comments

@Xxdnx
Copy link

Xxdnx commented Jan 13, 2025

Bug Report

Current Behavior

There is a business scenario where a fixed prefix needs to be added to Redis keys for specific requests. In the current implementation, when using Java Agent to rewrite the io.lettuce.core.protocol.CommandArgs#addKey(K key) method for adding a fixed prefix to Redis keys, there is an issue with Hash commands, as they wrongly consider the field as a key.

Input Code

image

Expected behavior/code

The encoding method logic of io.lettuce.core.protocol.CommandArgs$KeyArgument and io.lettuce.core.protocol.CommandArgs$ValueArgument is consistent. Therefore, it is expected to use addValue to add the Field.

Environment

  • Lettuce version(s): [6.2.3.RELEASE]
  • Redis version: [6.2.4]

Possible Solution

Perhaps we can directly use io.lettuce.core.protocol.CommandArgs#addValue to add the field.

Questions

  • Why is the field of a Hash regarded as a key? Is there any special consideration?
@tishun
Copy link
Collaborator

tishun commented Jan 14, 2025

Greetings @Xxdnx ,

What is your logic of treating the field name as a value?

Why is the field of a Hash regarded as a key? Is there any special consideration?

In my perspective a key is used to identify data. Since there are two types of coding/decoding (one for key and one for value) the field argument would more semantically belong to the keys then to the values, as it is (similarly to keys) responsible for identifying data (in this case sub-data)

@tishun tishun added the status: waiting-for-feedback We need additional information before we can continue label Jan 14, 2025
@Xxdnx
Copy link
Author

Xxdnx commented Jan 16, 2025

@tishun Thank you very much for your reply. As you mentioned above, the "Field" in Hash is the key of the sub-data, and I agree with this statement. However, I still think it is more appropriate to use the field of the hash as the value.
The reasons are as follows:

  1. I think the key in the io.lettuce.core.protocol.CommandArgs#addKey(K key) method refers to the key of the Redis command, rather than the key in a broader sense.
  2. The role of io.lettuce.core.protocol.CommandArg is consistent with that of redis.clients.jedis.CommandArguments in Jedis (version 4.x and above). However, it regards the Field as the value, and I think this is more reasonable.

The following is the code for the hset method of redis.clients.jedis.CommandObjects in Jedis using redis.clients.jedis.CommandArguments:
Image

@tishun
Copy link
Collaborator

tishun commented Jan 17, 2025

Hey again,

I think the key in the io.lettuce.core.protocol.CommandArgs#addKey(K key) method refers to the key of the Redis command, rather than the key in a broader sense.

Strictly speaking - yes. As I mentioned the model of Codec <Key, Value> is not perfect, because it does not define if fields are to be encoded as key or value and it is a matter of interpretation. As I mentioned - currently - the assumption is that the field is more likely to be a key than a value (in terms of encoding). In a perfect world we would have codecs define <K,F,V> but this is a huge and breaking change.

The role of io.lettuce.core.protocol.CommandArg is consistent with that of redis.clients.jedis.CommandArguments in Jedis (version 4.x and above). However, it regards the Field as the value, and I think this is more reasonable.

It is quite unfortunate that there are differences between Jedis and Lettuce. However both drivers have a complex history and were maintained by different people, so there are inconsistencies between them.

The bigger issue here is that of compatibility and consistency. They make any change very unlikely.

Consistency

Currently all hash field commands consider the field as data that needs to be encoded as a key, not only the HSET. So changing it in one place would require changing it everywhere.

Compatibility

Additionally any change right now would break existing users (as they already rely on the existing model). So any change would be a breaking change and as such I cannot accommodate it unless the community overwhelmingly agrees it needs to be done.

Suggested solution

I think that your use case is more of an edge case. As such it would be prudent to just override the way the command is built and build it yourself. You could wrap the class you are using, e.g. RedisReactiveCommandsImpl and override the hset(K key, K field, V value) to build up the command in a way that you prefer, e.g.

    @Override
    public Mono<Boolean> hset(K key, K field, V value) {
        return createMono(() -> 
           notNullKey(key);
           LettuceAssert.notNull(field, "Field " + MUST_NOT_BE_NULL);

           CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).addValue(field).addValue(value);
           return createCommand(HSET, new BooleanOutput<>(codec), args);
         );
    }

Thus overriding the default way the driver works for all HSET calls. Does that work for you?

@Xxdnx
Copy link
Author

Xxdnx commented Jan 24, 2025

Overriding the default way the driver works for all HSET calls is feasible. However, for our business scenarios, making the modifications and rolling them out would take too much time. I'll think about other solutions. Thank you for your reply.

@tishun tishun removed the status: waiting-for-feedback We need additional information before we can continue label Jan 24, 2025
@tishun tishun closed this as completed Jan 24, 2025
@tishun
Copy link
Collaborator

tishun commented Jan 24, 2025

If you need more help or have some comments please do not hesitate to reopen.
Closing for now as there is nothing actionable on our side.

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

No branches or pull requests

2 participants