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

Code before:
    }

    /* Also fire the end event. Note that this event will fire almost
     * immediately after the start event if the flush is asynchronous. */
    moduleFireServerEvent(VALKEYMODULE_EVENT_FLUSHDB, VALKEYMODULE_SUBEVENT_FLUSHDB_END, &fi);

    return removed;
}

/* Initialize temporary db on replica for use during diskless replication. */
serverDb *initTempDb(void) {
    int slot_count_bits = 0;
    int flags = KVSTORE_ALLOCATE_HASHTABLES_ON_DEMAND;
    if (server.cluster_enabled) {
        slot_count_bits = CLUSTER_SLOT_MASK_BITS;
        flags |= KVSTORE_FREE_EMPTY_HASHTABLES;
    }
    serverDb *tempDb = zcalloc(sizeof(serverDb) * server.dbnum);
    for (int i = 0; i < server.dbnum; i++) {
        tempDb[i].id = i;
        tempDb[i].keys = kvstoreCreate(&kvstoreKeysHashtableType, slot_count_bits, flags);
        tempDb[i].expires = kvstoreCreate(&kvstoreExpiresHashtableType, slot_count_bits, flags);
    }

    return tempDb;
}

void freeServerdb(serverDb *db) {
    if (db == NULL) return;
    kvstoreRelease(db->keys);
    kvstoreRelease(db->expires);
    zfree(db);
}

/* Discard tempDb, it's always async. */
void discardTempDb(serverDb **tempDb) {
    /* Release temp DBs. */
    emptyDbStructure(tempDb, -1, 1, NULL);
    for (int i = 0; i < server.dbnum; i++) {
        freeServerdb(tempDb[i]);
    }
    zfree(tempDb);
}

int selectDb(client *c, int id) {
    if (id < 0 || id >= server.dbnum) return C_ERR;
    initDatabase(id);
    c->db = server.db[id];
    return C_OK;
}


Review comment (suggestion):
This seems strange and incomplete. if we are writing a dedicated function to free a DB we need to make sure ALL it's fields are being reclaimed (or assert if they are in use). What about the watched keys? blocked keys? etc...

Code after:
        functionsLibCtxClearCurrent(async, (void (*)(dict *))callback);
    }

    /* Also fire the end event. Note that this event will fire almost
     * immediately after the start event if the flush is asynchronous. */
    moduleFireServerEvent(VALKEYMODULE_EVENT_FLUSHDB, VALKEYMODULE_SUBEVENT_FLUSHDB_END, &fi);

    return removed;
}

/* Discard tempDb array. It's always async. */
void discardTempDb(serverDb **tempDb) {
    /* Release temp DBs. */
    emptyDbStructure(tempDb, -1, 1, NULL);
    for (int i = 0; i < server.dbnum; i++) {
        if (tempDb[i]) {
            kvstoreRelease(tempDb[i]->keys);
            kvstoreRelease(tempDb[i]->expires);

            /* These are expected to be empty on temporary databases */
            serverAssert(dictSize(tempDb[i]->blocking_keys) == 0);
            serverAssert(dictSize(tempDb[i]->blocking_keys_unblock_on_nokey) == 0);
            serverAssert(dictSize(tempDb[i]->ready_keys) == 0);
            serverAssert(dictSize(tempDb[i]->watched_keys) == 0);

            dictRelease(tempDb[i]->blocking_keys);
            dictRelease(tempDb[i]->blocking_keys_unblock_on_nokey);
            dictRelease(tempDb[i]->ready_keys);
            dictRelease(tempDb[i]->watched_keys);
            zfree(tempDb[i]);
            tempDb[i] = NULL;
        }
    }
    zfree(tempDb);
}

int selectDb(client *c, int id) {
    if (id < 0 || id >= server.dbnum) return C_ERR;
    c->db = createDatabaseIfNeeded(id);
    return C_OK;
}

long long dbTotalServerKeyCount(void) {
    long long total = 0;
    int j;
    for (j = 0; j < server.dbnum; j++) {
        if (dbHasNoKeys(j)) continue;
        total += kvstoreSize(server.db[j]->keys);
    }
    return total;
}