Repository: valkey-io/valkey
File: src/t_hash.c (C)

Code before:
            int j = 0;

            // First argument: command
            rewrite_argv[j++] = c->argv[0];
            incrRefCount(c->argv[0]);

            // Second argument: hash
            rewrite_argv[j++] = c->argv[1];
            incrRefCount(c->argv[1]);

            // Copy all field/value pairs, skipping NX/XX/FNX/FXX flags
            for (int i = fields_index; i < c->argc; i++) {
                // Skip NX/XX/FNX/FXX flags
                if (strcmp(c->argv[i]->ptr, "NX") &&
                    strcmp(c->argv[i]->ptr, "XX") &&
                    strcmp(c->argv[i]->ptr, "FNX") &&
                    strcmp(c->argv[i]->ptr, "FXX")) {
                    rewrite_argv[j++] = c->argv[i];
                    incrRefCount(c->argv[i]);
                }
            }

            // Replace client command vector
            replaceClientCommandVector(c, j, rewrite_argv);
        }

        signalModifiedKey(c, c->db, c->argv[1]);
        /* Delete the object in case it was left empty */
        if (hashTypeLength(o) == 0) {
            dbDelete(c->db, c->argv[1]);
            notifyKeyspaceEvent(NOTIFY_GENERIC, "del", c->argv[1], c->db->id);
        }
        server.dirty += changes;
    } else {
        /* If no changes were done we still need to free the new argv array and the refcount of the first argument. */
        if (set_expired)
            decrRefCount(c->argv[1]);
        if (new_argv) zfree(new_argv);
    }
    addReplyLongLong(c, changes == num_fields ? 1 : 0);
}

/* High-Level Algorithm of HGETEX Command:
 *
 * - Parses the command for optional arguments, including expiration options,
 *   persistence flags, and the list of hash fields to retrieve.
 *
 * - Verifies that the number of fields specified matches the actual arguments,
 *   and ensures the key exists and is a valid hash type.
 *
 * - Computes the expiration behavior:

Review comment (performance):
I think this might work, but it is somewhat wasteful. For example, when we are expiring elements (eg expiration time is zero) we already managing a separate argv. I think maybe it would be better to simply use and manage a new_argv when we are doing the hashTypeSet. We can optimize by not adding the parameters when the new_argv is NULL.

Code after:
        }
    }


    if (changes) {
        if (has_volatile_fields != hashTypeHasVolatileFields(o)) {
            dbUpdateObjectWithVolatileItemsTracking(c->db, o);
        }
        if (set_expired) {
            replaceClientCommandVector(c, new_argc, new_argv);
            /* We would like to reduce the number of hexpired events in case there are potential many expired fields. */
            notifyKeyspaceEvent(NOTIFY_HASH, "hexpired", c->argv[1], c->db->id);
        } else {
            notifyKeyspaceEvent(NOTIFY_HASH, "hset", c->argv[1], c->db->id);
            if (need_rewrite_argv) {
                replaceClientCommandVector(c, new_argc, new_argv);
            }
            if (expire) {
                notifyKeyspaceEvent(NOTIFY_HASH, "hexpire", c->argv[1], c->db->id);
            }
        }
        signalModifiedKey(c, c->db, c->argv[1]);
        /* Delete the object in case it was left empty */
        if (hashTypeLength(o) == 0) {
            dbDelete(c->db, c->argv[1]);
            notifyKeyspaceEvent(NOTIFY_GENERIC, "del", c->argv[1], c->db->id);
        }
        server.dirty += changes;
    } else {
        /* If no changes were done we still need to free the new argv array and the refcount of the first argument. */
        if (set_expired)
            decrRefCount(c->argv[1]);
        if (new_argv) zfree(new_argv);
    }
    addReplyLongLong(c, changes == num_fields ? 1 : 0);
}

/* High-Level Algorithm of HGETEX Command:
 *
 * - Parses the command for optional arguments, including expiration options,
 *   persistence flags, and the list of hash fields to retrieve.
 *
 * - Verifies that the number of fields specified matches the actual arguments,
 *   and ensures the key exists and is a valid hash type.
 *
 * - Computes the expiration behavior:
 *   - If `PERSIST` is provided, removes the expiration from the fields.
 *   - If an expiration time is specified, calculates it relative or absolute.
 *     - If already expired, deletes the fields immediately.
 *     - Otherwise, schedules new expiration timestamps.
 *