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

Code before:
        } else if (ob->type == OBJ_STREAM && ob->encoding == OBJ_ENCODING_STREAM) {
            return scanLaterStreamListpacks(ob, cursor, endtime);
        } else if (ob->type == OBJ_MODULE) {
            /* Fun fact (and a bug since forever): The key is passed to
             * moduleLateDefrag as an sds string, but the parameter is declared
             * to be an robj and it's passed as such to the module type defrag
             * callbacks. Nobody can ever have used this, i.e. accessed the key
             * name in the defrag module type callback. */
            void *sds_key_passed_as_robj = objectGetKey(ob);
            long long endtimeWallClock = ustime() + (endtime - getMonotonicUs());
            return moduleLateDefrag(sds_key_passed_as_robj, ob, cursor, endtimeWallClock, dbid);
        } else {
            *cursor = 0; /* object type/encoding may have changed since we schedule it for later */
        }
    } else {
        *cursor = 0; /* object may have been deleted already */
    }
    return 0;
}


// A kvstoreHelperPreContinueFn
static doneStatus defragLaterStep(monotime endtime, void *privdata) {
    defragKeysCtx *ctx = privdata;

    unsigned int iterations = 0;
    unsigned long long prev_defragged = server.stat_active_defrag_hits;
    unsigned long long prev_scanned = server.stat_active_defrag_scanned;

    while (defrag_later && listLength(defrag_later) > 0) {
        listNode *head = listFirst(defrag_later);
        sds key = head->value;
        void *found = NULL;
        kvstoreHashtableFind(ctx->kvstate.kvs, ctx->kvstate.slot, key, &found);
        robj *ob = found;

        long long key_defragged = server.stat_active_defrag_hits;
        bool timeout = (defragLaterItem(ob, &defrag_later_cursor, endtime, ctx->dbid) == 1);
        if (key_defragged != server.stat_active_defrag_hits) {
            server.stat_active_defrag_key_hits++;
        } else {
            server.stat_active_defrag_key_misses++;
        }

        if (timeout) break;

        if (defrag_later_cursor == 0) {
            // the item is finished, move on
            listDelNode(defrag_later, head);
        }


Review comment (refactor):
This, and all the changes in `defrag.c` look good to me.  I'll defer to Viktor's comments re: the other refactoring.

Code after:
 * and 1 if time is up and more work is needed. */
static int defragLaterItem(robj *ob, unsigned long *cursor, monotime endtime, int dbid) {
    if (ob) {
        if (ob->type == OBJ_LIST && ob->encoding == OBJ_ENCODING_QUICKLIST) {
            return scanLaterList(ob, cursor, endtime);
        } else if (ob->type == OBJ_SET && ob->encoding == OBJ_ENCODING_HASHTABLE) {
            scanLaterSet(ob, cursor);
        } else if (ob->type == OBJ_ZSET && ob->encoding == OBJ_ENCODING_SKIPLIST) {
            scanLaterZset(ob, cursor);
        } else if (ob->type == OBJ_HASH && ob->encoding == OBJ_ENCODING_HASHTABLE) {
            scanLaterHash(ob, cursor);
        } else if (ob->type == OBJ_STREAM && ob->encoding == OBJ_ENCODING_STREAM) {
            return scanLaterStreamListpacks(ob, cursor, endtime);
        } else if (ob->type == OBJ_MODULE) {
            /* Fun fact (and a bug since forever): The key is passed to
             * moduleLateDefrag as an sds string, but the parameter is declared
             * to be an robj and it's passed as such to the module type defrag
             * callbacks. Nobody can ever have used this, i.e. accessed the key
             * name in the defrag module type callback. */
            void *sds_key_passed_as_robj = objectGetKey(ob);
            long long endtimeWallClock = ustime() + (endtime - getMonotonicUs());
            return moduleLateDefrag(sds_key_passed_as_robj, ob, cursor, endtimeWallClock, dbid);
        } else {
            *cursor = 0; /* object type/encoding may have changed since we schedule it for later */
        }
    } else {
        *cursor = 0; /* object may have been deleted already */
    }
    return 0;
}


// A kvstoreHelperPreContinueFn
static doneStatus defragLaterStep(monotime endtime, void *privdata) {
    defragKeysCtx *ctx = privdata;

    unsigned int iterations = 0;
    unsigned long long prev_defragged = server.stat_active_defrag_hits;
    unsigned long long prev_scanned = server.stat_active_defrag_scanned;

    while (defrag_later && listLength(defrag_later) > 0) {
        listNode *head = listFirst(defrag_later);
        sds key = head->value;
        void *found = NULL;
        kvstoreHashtableFind(ctx->kvstate.kvs, ctx->kvstate.slot, key, &found);
        robj *ob = found;

        long long key_defragged = server.stat_active_defrag_hits;
        bool timeout = (defragLaterItem(ob, &defrag_later_cursor, endtime, ctx->dbid) == 1);
        if (key_defragged != server.stat_active_defrag_hits) {
            server.stat_active_defrag_key_hits++;