Redisのデータベースはソースコードの読み取りを実現する

13318 ワード

lookupKey:指定したキーを検索し、対応する値を返す場合
robj *lookupKey(redisDb *db, robj *key) {

    //      
    dictEntry *de = dictFind(db->dict,key->ptr);

    //     
    if (de) {
        

        //    
        robj *val = dictGetVal(de);

        /* Update the access time for the ageing algorithm.
         * Don't do it if we have a saving child, as this will trigger
         * a copy on write madness. */
        //       (           ,     copy-on-write   )
        if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
            val->lru = LRU_CLOCK();

        //    
        return val;
    } else {

        //      

        return NULL;
    }
}

lookupKeyRead:まずkeyが期限切れであるかどうかを確認し、データベースから値を取り出し、ヒット/不明情報を更新します.
robj *lookupKeyRead(redisDb *db, robj *key) {
    robj *val;

    //    key       
    expireIfNeeded(db,key);

    //           
    val = lookupKey(db,key);

    //     /     
    if (val == NULL)
        server.stat_keyspace_misses++;
    else
        server.stat_keyspace_hits++;

    //    
    return val;
}

lookupKeyWrite
robj *lookupKeyWrite(redisDb *db, robj *key) {

    //      
    expireIfNeeded(db,key);

    //       key     
    return lookupKey(db,key);
}

lookupKeyReadOrReply:読み込み操作を実行するためにデータベースからキーを返す値を検索します.
robj *lookupKeyReadOrReply(redisClient *c, robj *key, robj *reply) {

    //   
    robj *o = lookupKeyRead(c->db, key);

    //         
    if (!o) addReply(c,reply);

    return o;
}

lookupKeyWriteOrReply:書き込み操作を実行するためにデータベースからキーを返す値を検索します.
robj *lookupKeyWriteOrReply(redisClient *c, robj *key, robj *reply) {

    robj *o = lookupKeyWrite(c->db, key);

    if (!o) addReply(c,reply);

    return o;
}

dbAdd:キー値対keyとvalをデータベースに追加してみます.
void dbAdd(redisDb *db, robj *key, robj *val) {

    //     
    sds copy = sdsdup(key->ptr);

    //        
    int retval = dictAdd(db->dict, copy, val);

    //        ,    
    redisAssertWithInfo(NULL,key,retval == REDIS_OK);

    //          ,          
    if (server.cluster_enabled) slotToKeyAdd(key);
 }

setKey:高レベルのSET操作関数.
void setKey(redisDb *db, robj *key, robj *val) {

    //              
    if (lookupKeyWrite(db,key) == NULL) {
        dbAdd(db,key,val);
    } else {
        dbOverwrite(db,key,val);
    }

    incrRefCount(val);

    //         
    removeExpire(db,key);

    //        
    signalModifiedKey(db,key);
}

dbExists:キーキーキーがデータベースに存在するか、戻り1が存在するか、戻り0が存在しないかを確認します.
int dbExists(redisDb *db, robj *key) {
    return dictFind(db->dict,key->ptr) != NULL;
}

dbRandomKey:ランダムにデータベースからキーを取り出し、文字列オブジェクトとしてこのキーを返します.
robj *dbRandomKey(redisDb *db) {
    dictEntry *de;

    while(1) {
        sds key;
        robj *keyobj;

        //               
        de = dictGetRandomKey(db->dict);

        //      
        if (de == NULL) return NULL;

        //    
        key = dictGetKey(de);
        //            ,         
        keyobj = createStringObject(key,sdslen(key));
        //            
        if (dictFind(db->expires,key)) {
            //        ,      ,        
            if (expireIfNeeded(db,keyobj)) {
                decrRefCount(keyobj);
                continue; /* search for another key. This expired. */
            }
        }

        //         (   )
        return keyobj;
    }
}

dbDelete:指定したキー、キーの値、およびキーの有効期限をデータベースから削除します.
int dbDelete(redisDb *db, robj *key) {

    /* Deleting an entry from the expires dict will not free the sds of
     * the key, because it is shared with the main dictionary. */
    //         
    if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);

    //      
    if (dictDelete(db->dict,key->ptr) == DICT_OK) {
        //          ,           
        if (server.cluster_enabled) slotToKeyDel(key);
        return 1;
    } else {
        //     
        return 0;
    }
}

EmptyDb:サーバのすべてのデータを空にします.
long long emptyDb(void(callback)(void*)) {
    int j;
    long long removed = 0;

    //        
    for (j = 0; j < server.dbnum; j++) {

        //          
        removed += dictSize(server.db[j].dict);

        //        
        dictEmpty(server.db[j].dict,callback);
        //           
        dictEmpty(server.db[j].expires,callback);
    }

    //          ,         
    if (server.cluster_enabled) slotToKeyFlush();

    //       
    return removed;
}

selectDb:クライアントのターゲットデータベースをidで指定したデータベースに切り替える
int selectDb(redisClient *c, int id) {

    //    id       
    if (id < 0 || id >= server.dbnum)
        return REDIS_ERR;

    //      (    )
    c->db = &server.db[id];

    return REDIS_OK;
}

SignalModifiedKey:データベース内のキーが変更されるたびに、signalModifiedKey()関数が呼び出されます.
void signalModifiedKey(redisDb *db, robj *key) {
    touchWatchedKey(db,key);
}

SignalFlushedDb:データベースが空になるたびにsignalFlushDb()が呼び出されます.
void signalFlushedDb(int dbid) {
    touchWatchedKeysOnFlush(dbid);
}

flushdbCommand:クライアントが指定したデータベースを空にする
void flushdbCommand(redisClient *c) {

    server.dirty += dictSize(c->db->dict);

    //     
    signalFlushedDb(c->db->id);

    //           dict   expires   
    dictEmpty(c->db->dict,NULL);
    dictEmpty(c->db->expires,NULL);

    //          ,         
    if (server.cluster_enabled) slotToKeyFlush();

    addReply(c,shared.ok);
}

flushallCommand:サーバ内のすべてのデータベースを空にします.
void flushallCommand(redisClient *c) {

    //     
    signalFlushedDb(-1);

    //        
    server.dirty += emptyDb(NULL);
    addReply(c,shared.ok);

    //          RDB ,        
    if (server.rdb_child_pid != -1) {
        kill(server.rdb_child_pid,SIGUSR1);
        rdbRemoveTempFile(server.rdb_child_pid);
    }

    //    RDB   
    if (server.saveparamslen > 0) {
        /* Normally rdbSave() will reset dirty, but we don't want this here
         * as otherwise FLUSHALL will not be replicated nor put into the AOF. */
        // rdbSave()         dirty   
        //       FLUSHALL         ,
        //          rdbSave()            dirty   
        int saved_dirty = server.dirty;

        rdbSave(server.rdb_filename);

        server.dirty = saved_dirty;
    }

    server.dirty++;
}

delCommand:クライアントが指定したキーを削除する
void delCommand(redisClient *c) {
    int deleted = 0, j;

    //        
    for (j = 1; j < c->argc; j++) {

        //        
        expireIfNeeded(c->db,c->argv[j]);

        //      
        if (dbDelete(c->db,c->argv[j])) {

            //      ,    

            signalModifiedKey(c->db,c->argv[j]);
            notifyKeyspaceEvent(REDIS_NOTIFY_GENERIC,
                "del",c->argv[j],c->db->id);

            server.dirty++;

            //         deleted      
            deleted++;
        }
    }

    //          
    addReplyLongLong(c,deleted);
}

existsCommand:キーが存在するかどうかを確認します
void existsCommand(redisClient *c) {

    //          ,       ,      
    //                 
    expireIfNeeded(c->db,c->argv[1]);

    //        
    if (dbExists(c->db,c->argv[1])) {
        addReply(c, shared.cone);
    } else {
        addReply(c, shared.czero);
    }
}

selectCommand:クライアントの現在のデータベースを変更する
void selectCommand(redisClient *c) {
    long id;

    //          
    if (getLongFromObjectOrReply(c, c->argv[1], &id,
        "invalid DB index") != REDIS_OK)
        return;

    if (server.cluster_enabled && id != 0) {
        addReplyError(c,"SELECT is not allowed in cluster mode");
        return;
    }

    //      
    if (selectDb(c,id) == REDIS_ERR) {
        addReplyError(c,"invalid DB index");
    } else {
        addReply(c,shared.ok);
    }
}

randomkeyCommand:キーを返します
void randomkeyCommand(redisClient *c) {
    robj *key;

    //      
    if ((key = dbRandomKey(c->db)) == NULL) {
        addReply(c,shared.nullbulk);
        return;
    }

    addReplyBulk(c,key);
    decrRefCount(key);
}

keysCommand:クライアントが指定したモードに一致するすべてのキーを返します.
void keysCommand(redisClient *c) {
    dictIterator *di;
    dictEntry *de;

    //   
    sds pattern = c->argv[1]->ptr;

    int plen = sdslen(pattern), allkeys;
    unsigned long numkeys = 0;
    void *replylen = addDeferredMultiBulkLength(c);

    //        ,  (  )       
    di = dictGetSafeIterator(c->db->dict);
    allkeys = (pattern[0] == '*' && pattern[1] == '\0');
    while((de = dictNext(di)) != NULL) {
        sds key = dictGetKey(de);
        robj *keyobj;

        //           
        if (allkeys || stringmatchlen(pattern,plen,key,sdslen(key),0)) {

            //                
            keyobj = createStringObject(key,sdslen(key));

            //       
            if (expireIfNeeded(c->db,keyobj) == 0) {
                addReplyBulk(c,keyobj);
                numkeys++;
            }

            decrRefCount(keyobj);
        }
    }
    dictReleaseIterator(di);

    setDeferredMultiBulkLength(c,replylen,numkeys);
}

removeExpire:キーキーの削除の有効期限
int removeExpire(redisDb *db, robj *key) {
    /* An expire may only be removed if there is a corresponding entry in the
     * main dict. Otherwise, the key will never be freed. */
    //          
    redisAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);

    //       
    return dictDelete(db->expires,key->ptr) == DICT_OK;
}

setExpire:キーキーの有効期限をwhenに設定
void setExpire(redisDb *db, robj *key, long long when) {

    dictEntry *kde, *de;

    /* Reuse the sds from the main dict in the expire dict */
    //    
    kde = dictFind(db->dict,key->ptr);

    redisAssertWithInfo(NULL,key,kde != NULL);

    //            
    de = dictReplaceRaw(db->expires,dictGetKey(kde));

    //         
    //                  ,    INT     String   
    dictSetSignedIntegerVal(de,when);
}

getExpire:指定したkeyの有効期限を返します.
long long getExpire(redisDb *db, robj *key) {
    dictEntry *de;

    /* No expire? return ASAP */
    //         
    //          ,      
    if (dictSize(db->expires) == 0 ||
       (de = dictFind(db->expires,key->ptr)) == NULL) return -1;

    /* The entry was found in the expire dict, this means it should also
     * be present in the main dict (safety check). */
    redisAssertWithInfo(NULL,key,dictFind(db->dict,key->ptr) != NULL);

    //       
    return dictGetSignedIntegerVal(de);
}

propagateExpire:期限切れを付属ノードとAOFファイルに伝播します.
void propagateExpire(redisDb *db, robj *key) {
    robj *argv[2];

    //      DEL key   
    argv[0] = shared.del;
    argv[1] = key;
    incrRefCount(argv[0]);
    incrRefCount(argv[1]);

    //     AOF 
    if (server.aof_state != REDIS_AOF_OFF)
        feedAppendOnlyFile(server.delCommand,db->id,argv,2);

    //          
    replicationFeedSlaves(server.slaves,db->id,argv,2);

    decrRefCount(argv[0]);
    decrRefCount(argv[1]);
}

expireIfNeeded:keyが期限切れになっているかどうかを確認し、そうであればデータベースから削除します.
int expireIfNeeded(redisDb *db, robj *key) {

    //         
    mstime_t when = getExpire(db,key);
    mstime_t now;

    //       
    if (when < 0) return 0; /* No expire for this key */

    /* Don't expire anything while loading. It will be done later. */
    //            ,           
    if (server.loading) return 0;

    /* If we are in the context of a Lua script, we claim that time is
     * blocked to when the Lua script started. This way a key can expire
     * only the first time it is accessed and not in the middle of the
     * script execution, making propagation to slaves / AOF consistent.
     * See issue #1525 on Github for more information. */
    now = server.lua_caller ? server.lua_time_start : mstime();

    /* If we are running in the context of a slave, return ASAP:
     * the slave key expiration is controlled by the master that will
     * send us synthesized DEL operations for expired keys.
     *
     * Still we try to return the right information to the caller, 
     * that is, 0 if we think the key should be still valid, 1 if
     * we think the key is expired at this time. */
    //         replication    
    //            key
    //                
    //                        
    //          
    if (server.masterhost != NULL) return now > when;

    //      ,         ,         

    /* Return when this key has not expired */
    //      ,   0
    if (now <= when) return 0;

    /* Delete the key */
    server.stat_expiredkeys++;

    //   AOF              
    propagateExpire(db,key);

    //       
    notifyKeyspaceEvent(REDIS_NOTIFY_EXPIRED,
        "expired",key,db->id);

    //            
    return dbDelete(db,key);
}