-
Notifications
You must be signed in to change notification settings - Fork 947
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
base: unstable
Are you sure you want to change the base?
Changes from 3 commits
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,59 @@ void hdelCommand(client *c) { | |
| addReplyLongLong(c, deleted); | ||
| } | ||
|
|
||
| void hgetdelCommand(client *c) { | ||
| int fields_index = 4; | ||
|
Contributor
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 add a small comment like this to explain why 4. |
||
| 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)) { | ||
| addReplyErrorObject(c, shared.syntaxerr); | ||
roshkhatri marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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; | ||
|
|
||
| /* Reply with array of values */ | ||
| addReplyArrayLen(c, num_fields); | ||
| for (i = fields_index; i < c->argc; i++) { | ||
| addHashFieldToReply(c, o, c->argv[i]->ptr); | ||
| } | ||
|
|
||
| /* If hash doesn't exist, we're done as we have already replied with NULLs */ | ||
| if (o == NULL) return; | ||
|
|
||
| /* Now delete the fields. */ | ||
| bool hash_volatile_items = hashTypeHasVolatileFields(o); | ||
| for (i = fields_index; i < c->argc; i++) { | ||
| if (hashTypeDelete(o, c->argv[i]->ptr)) { | ||
| deleted++; | ||
| if (hashTypeLength(o) == 0) { | ||
| if (hash_volatile_items) dbUntrackKeyWithVolatileItems(c->db, o); | ||
| dbDelete(c->db, c->argv[1]); | ||
| keyremoved = true; | ||
| break; | ||
| } | ||
| } | ||
| } | ||
roshkhatri marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| if (deleted) { | ||
| if (!keyremoved && hash_volatile_items != hashTypeHasVolatileFields(o)) { | ||
| dbUpdateObjectWithVolatileItemsTracking(c->db, o); | ||
| } | ||
| signalModifiedKey(c, c->db, c->argv[1]); | ||
| notifyKeyspaceEvent(NOTIFY_HASH, "hgetdel", 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; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally I agree this should be O(N), but we should then fix the inconsistency, since for other commands we marked them as O(1) following PR review (eg httl, hpttl, hsetex etc...) HOWEVER for HMGET we did use O(N), so lets decide on the correct form and align all command docs. @valkey-io/core-team FYI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe it needs to be O(N) as we will be looping over the number of fields.