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

Code before:
    server.clients_hz = 1000 / delay_ms;
    server.el_cron_duration += elapsedUs(start_time);
    return delay_ms;
}

/* This function handles 'background' operations we are required to do
 * incrementally in the databases, such as active key expiring, resizing,
 * rehashing. */
void databasesCron(void) {
    /* Expire keys by random sampling. Not required for replicas
     * as primary will synthesize DELs for us. */
    if (server.active_expire_enabled) {
        if (!iAmPrimary()) {
            expireReplicaKeys();
        } else if (!server.import_mode) {
            activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
            /* If this node was previously a writable replica
             * and replicaKeysWithExpire is not empty,
             * it needs to be cleaned up;
             * otherwise, it may lead to memory leaks. */
            size_t replica_key_count = getReplicaKeyWithExpireCount();
            if (replica_key_count > 0) {
                flushReplicaKeysWithExpireList(1); /* Asynchronous cleanup */
            }
        }
    }

    /* Start active defrag cycle or adjust defrag CPU if needed. */
    monitorActiveDefrag();

    /* Perform hash tables rehashing if needed, but only if there are no
     * other processes saving the DB on disk. Otherwise rehashing is bad
     * as will cause a lot of copy-on-write of memory pages. */
    if (!hasActiveChildProcess()) {
        /* We use global counters so if we stop the computation at a given
         * DB we'll be able to start from the successive in the next
         * cron loop iteration. */
        static unsigned int resize_db = 0;
        static unsigned int rehash_db = 0;
        int dbs_per_call = CRON_DBS_PER_CALL;
        int j;

        /* Don't test more DBs than we have. */
        if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;

        for (j = 0; j < dbs_per_call; j++) {
            serverDb *db = server.db[resize_db % server.dbnum];
            resize_db++;
            if (db == NULL) continue;
            kvstoreTryResizeHashtables(db->keys, CRON_DICTS_PER_DB);
            kvstoreTryResizeHashtables(db->expires, CRON_DICTS_PER_DB);

Review comment (bug):
I guess that since "import mode" is temporal, it will probably get here after we leave import mode and some edge case drove us to have the leak as an "importing primary". I just feel like maybe this could have been separated from the import logic?

Code after:
    server.clients_hz = 1000 / delay_ms;
    server.el_cron_duration += elapsedUs(start_time);
    return delay_ms;
}

/* This function handles 'background' operations we are required to do
 * incrementally in the databases, such as active key expiring, resizing,
 * rehashing. */
void databasesCron(void) {
    /* Expire keys by random sampling. Not required for replicas
     * as primary will synthesize DELs for us. */
    if (server.active_expire_enabled) {
        if (!iAmPrimary()) {
            expireReplicaKeys();
        } else {
            if (!server.import_mode) {
                activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);
            }
            /* If this node was previously a writable replica
             * and replicaKeysWithExpire is not empty,
             * it needs to be cleaned up;
             * otherwise, it may lead to memory leaks. */
            size_t replica_key_count = getReplicaKeyWithExpireCount();
            if (replica_key_count > 0) {
                flushReplicaKeysWithExpireList(1);
            }
        }
    }

    /* Start active defrag cycle or adjust defrag CPU if needed. */
    monitorActiveDefrag();

    /* Perform hash tables rehashing if needed, but only if there are no
     * other processes saving the DB on disk. Otherwise rehashing is bad
     * as will cause a lot of copy-on-write of memory pages. */
    if (!hasActiveChildProcess()) {
        /* We use global counters so if we stop the computation at a given
         * DB we'll be able to start from the successive in the next
         * cron loop iteration. */
        static unsigned int resize_db = 0;
        static unsigned int rehash_db = 0;
        int dbs_per_call = CRON_DBS_PER_CALL;
        int j;

        /* Don't test more DBs than we have. */
        if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum;

        for (j = 0; j < dbs_per_call; j++) {
            serverDb *db = server.db[resize_db % server.dbnum];
            resize_db++;
            if (db == NULL) continue;