-
Notifications
You must be signed in to change notification settings - Fork 955
Adds HGETDEL Support to Valkey #2851
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
Changes from all commits
fddacdb
07e548f
714da0f
658054d
73cd821
809de8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| { | ||
| "HGETDEL": { | ||
| "summary": "Returns the values of one or more fields and deletes them from a hash.", | ||
| "complexity": "O(N) where N is the number of fields to be retrieved and deleted.", | ||
| "group": "hash", | ||
| "since": "9.1.0", | ||
| "arity": -5, | ||
| "function": "hgetdelCommand", | ||
| "command_flags": [ | ||
| "WRITE", | ||
| "FAST" | ||
| ], | ||
| "acl_categories": [ | ||
| "HASH" | ||
| ], | ||
| "key_specs": [ | ||
| { | ||
| "flags": [ | ||
| "RW", | ||
| "ACCESS", | ||
| "DELETE" | ||
| ], | ||
| "begin_search": { | ||
| "index": { | ||
| "pos": 1 | ||
| } | ||
| }, | ||
| "find_keys": { | ||
| "range": { | ||
| "lastkey": 0, | ||
| "step": 1, | ||
| "limit": 0 | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "reply_schema": { | ||
| "description": "List of values associated with the given fields, in the same order as they are requested. Returns nil for fields that do not exist.", | ||
| "type": "array", | ||
| "minItems": 1, | ||
| "items": { | ||
| "oneOf": [ | ||
| { | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "type": "null" | ||
| } | ||
| ] | ||
| } | ||
| }, | ||
| "arguments": [ | ||
| { | ||
| "name": "key", | ||
| "type": "key", | ||
| "key_spec_index": 0 | ||
| }, | ||
| { | ||
| "name": "fields", | ||
| "token": "FIELDS", | ||
| "type": "block", | ||
| "arguments": [ | ||
| { | ||
| "name": "numfields", | ||
| "type": "integer", | ||
| "key_spec_index": 0, | ||
| "multiple": false, | ||
| "minimum": 1 | ||
| }, | ||
| { | ||
| "name": "field", | ||
| "type": "string", | ||
| "multiple": true | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1053,6 +1053,57 @@ void hdelCommand(client *c) { | |
| addReplyLongLong(c, deleted); | ||
| } | ||
|
|
||
| void hgetdelCommand(client *c) { | ||
| /* argv: [0]=HGETDEL, [1]=key, [2]=FIELDS, [3]=numfields, [4...]=fields */ | ||
| int fields_index = 4; | ||
ranshid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| int i, deleted = 0; | ||
| long long num_fields = 0; | ||
| bool keyremoved = false; | ||
|
|
||
| if (getLongLongFromObjectOrReply(c, c->argv[fields_index - 1], &num_fields, NULL) != C_OK) return; | ||
|
|
||
| /* Check that the parsed fields number matches the real provided number of fields */ | ||
| if (!num_fields || num_fields != (c->argc - fields_index)) { | ||
| addReplyError(c, "numfields should be greater than 0 and match the provided number of fields"); | ||
| return; | ||
| } | ||
|
|
||
| /* Don't abort when the key cannot be found. Non-existing keys are empty | ||
| * hashes, where HGETDEL should respond with a series of null bulks. */ | ||
| robj *o = lookupKeyWrite(c->db, c->argv[1]); | ||
| if (checkType(c, o, OBJ_HASH)) return; | ||
|
|
||
| bool hash_volatile_items = hashTypeHasVolatileFields(o); | ||
|
|
||
| /* Reply with array of values and delete at the same time */ | ||
| addReplyArrayLen(c, num_fields); | ||
| for (i = fields_index; i < c->argc; i++) { | ||
| addHashFieldToReply(c, o, c->argv[i]->ptr); | ||
|
|
||
| /* If hash doesn't exist, continue as already replied with NULL */ | ||
| if (o == NULL) continue; | ||
| if (hashTypeDelete(o, c->argv[i]->ptr)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NOTE: I know that I drove you to implement it this way, but now I thought of a reason why the old way might have been "useful". What should we do in case the same fields is provided multiple times? in your previous implementation is would be: which is slightly less efficient, but might fits better with common sense. BTW - Redis does as as the CURRENT implementation does (which means they return IMO we are doing the right thing just need to make sure we document it correctly
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just place a test for it, so that we know we do not break this in the future?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @valkey-io/core-team I think we are taking the right decision (although maybe common sense would say otherwise), just raising this as an FYI |
||
| deleted++; | ||
| if (hashTypeLength(o) == 0) { | ||
| if (hash_volatile_items) dbUntrackKeyWithVolatileItems(c->db, o); | ||
| dbDelete(c->db, c->argv[1]); | ||
| keyremoved = true; | ||
| o = NULL; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (deleted) { | ||
| if (!keyremoved && hash_volatile_items != hashTypeHasVolatileFields(o)) { | ||
| dbUpdateObjectWithVolatileItemsTracking(c->db, o); | ||
| } | ||
| signalModifiedKey(c, c->db, c->argv[1]); | ||
| notifyKeyspaceEvent(NOTIFY_HASH, "hdel", c->argv[1], c->db->id); | ||
| if (keyremoved) notifyKeyspaceEvent(NOTIFY_GENERIC, "del", c->argv[1], c->db->id); | ||
| server.dirty += deleted; | ||
| } | ||
| } | ||
|
|
||
| void hlenCommand(client *c) { | ||
| robj *o; | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.