Redis源碼分析(三十五)--- redis.c服務端的實現分析(2)

來源:互聯網
上載者:User

標籤:nosql資料庫   源碼   記憶體資料庫   

       在Redis服務端的代碼量真的是比較大,如果一個一個API的學習怎麼實現,無疑是一種效率很低的做法,所以我今天對服務端的實現代碼的學習,重在他的執行流程上,而對於他的模組設計在上一篇中我已經分析過了,不明白的同學可以接著看上篇。所以我學習分析redis服務端的實現也是主要從main函數開始。在分析main執行流程之前,Redis的作者在這裡聲明了幾個變數,這個我們有必要知道一下。

/* Our shared "common" objects *//* 共用的對象 */struct sharedObjectsStruct shared;/* Global vars that are actually used as constants. The following double * values are used for double on-disk serialization, and are initialized * at runtime to avoid strange compiler optimizations. *//* 全域的double類型常量 */double R_Zero, R_PosInf, R_NegInf, R_Nan;/*================================= Globals ================================= *//* Global vars *//* 全域的RedisServer */struct redisServer server; /* server global state *//* Our command table. * * Every entry is composed of the following fields: * * name: a string representing the command name. * function: pointer to the C function implementing the command. * arity: number of arguments, it is possible to use -N to say >= N * sflags: command flags as string. See below for a table of flags. * flags: flags as bitmask. Computed by Redis using the 'sflags' field. * get_keys_proc: an optional function to get key arguments from a command. *                This is only used when the following three fields are not *                enough to specify what arguments are keys. * first_key_index: first argument that is a key * last_key_index: last argument that is a key * key_step: step to get all the keys from first to last argument. For instance *           in MSET the step is two since arguments are key,val,key,val,... * microseconds: microseconds of total execution time for this command. * calls: total number of calls of this command. * * The flags, microseconds and calls fields are computed by Redis and should * always be set to zero. * * Command flags are expressed using strings where every character represents * a flag. Later the populateCommandTable() function will take care of * populating the real 'flags' field using this characters. * * This is the meaning of the flags: * * w: write command (may modify the key space). * r: read command  (will never modify the key space). * m: may increase memory usage once called. Don't allow if out of memory. * a: admin command, like SAVE or SHUTDOWN. * p: Pub/Sub related command. * f: force replication of this command, regardless of server.dirty. * s: command not allowed in scripts. * R: random command. Command is not deterministic, that is, the same command *    with the same arguments, with the same key space, may have different *    results. For instance SPOP and RANDOMKEY are two random commands. * S: Sort command output array if called from script, so that the output *    is deterministic. * l: Allow command while loading the database. * t: Allow command while a slave has stale data but is not allowed to *    server this data. Normally no command is accepted in this condition *    but just a few. * M: Do not automatically propagate the command on MONITOR. * F: Fast command: O(1) or O(log(N)) command that should never delay *    its execution as long as the kernel scheduler is giving us time. *    Note that commands that may trigger a DEL as a side effect (like SET) *    are not fast commands. *//* redis命令表格對應關係 */struct redisCommand redisCommandTable[] = {    {"get",getCommand,2,"rF",0,NULL,1,1,1,0,0},    {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},    {"setnx",setnxCommand,3,"wmF",0,NULL,1,1,1,0,0},    {"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},.....
這個命令表相當多,省略了,基本是囊括了所有的可能命令。畢竟服務端都是以上這些命令的響應實現嘛。下面是重點要學習的了,在服務端的執行主程式中,是如何執行的呢,來一個流程框圖:


具體的代碼實現為如下:

int main(int argc, char **argv) {    struct timeval tv;    /* We need to initialize our libraries, and the server configuration. */#ifdef INIT_SETPROCTITLE_REPLACEMENT    spt_init(argc, argv);#endif    setlocale(LC_COLLATE,"");//啟用安全執行緒模式    zmalloc_enable_thread_safeness();    //啟用當發生記憶體溢出時的handler方法    zmalloc_set_oom_handler(redisOutOfMemoryHandler);    srand(time(NULL)^getpid());    //擷取目前時間    gettimeofday(&tv,NULL);    dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());    server.sentinel_mode = checkForSentinelMode(argc,argv);    //初始化服務端的配置    initServerConfig();    /* We need to init sentinel right now as parsing the configuration file     * in sentinel mode will have the effect of populating the sentinel     * data structures with master nodes to monitor. */    //初始化服務端的模式    if (server.sentinel_mode) {        initSentinelConfig();        initSentinel();    }    if (argc >= 2) {        int j = 1; /* First option to parse in argv[] */        sds options = sdsempty();        char *configfile = NULL;        /* Handle special options --help and --version */        if (strcmp(argv[1], "-v") == 0 ||            strcmp(argv[1], "--version") == 0) version();        if (strcmp(argv[1], "--help") == 0 ||            strcmp(argv[1], "-h") == 0) usage();        if (strcmp(argv[1], "--test-memory") == 0) {            if (argc == 3) {                memtest(atoi(argv[2]),50);                exit(0);            } else {                fprintf(stderr,"Please specify the amount of memory to test in megabytes.\n");                fprintf(stderr,"Example: ./redis-server --test-memory 4096\n\n");                exit(1);            }        }        /* First argument is the config file name? */        if (argv[j][0] != '-' || argv[j][1] != '-')            configfile = argv[j++];        /* All the other options are parsed and conceptually appended to the         * configuration file. For instance --port 6380 will generate the         * string "port 6380\n" to be parsed after the actual file name         * is parsed, if any. */        while(j != argc) {            if (argv[j][0] == '-' && argv[j][1] == '-') {                /* Option name */                if (sdslen(options)) options = sdscat(options,"\n");                options = sdscat(options,argv[j]+2);                options = sdscat(options," ");            } else {                /* Option argument */                options = sdscatrepr(options,argv[j],strlen(argv[j]));                options = sdscat(options," ");            }            j++;        }        if (server.sentinel_mode && configfile && *configfile == '-') {            redisLog(REDIS_WARNING,                "Sentinel config from STDIN not allowed.");            redisLog(REDIS_WARNING,                "Sentinel needs config file on disk to save state.  Exiting...");            exit(1);        }        if (configfile) server.configfile = getAbsolutePath(configfile);        resetServerSaveParams();        //載入服務端的配置,根據config設定檔來載入        loadServerConfig(configfile,options);        sdsfree(options);    } else {        redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");    }    //是否開啟守護進程    if (server.daemonize) daemonize();    initServer();    if (server.daemonize) createPidFile();    redisSetProcTitle(argv[0]);    redisAsciiArt();    if (!server.sentinel_mode) {        /* Things not needed when running in Sentinel mode. */        redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION);    #ifdef __linux__        linuxOvercommitMemoryWarning();    #endif        loadDataFromDisk();        if (server.ipfd_count > 0)            redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);        if (server.sofd > 0)            redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);    } else {        sentinelIsRunning();    }    /* Warning the user about suspicious maxmemory setting. */    if (server.maxmemory > 0 && server.maxmemory < 1024*1024) {        redisLog(REDIS_WARNING,"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory);    }//事件載入之前調用的beforeSleep方法    aeSetBeforeSleepProc(server.el,beforeSleep);    //開啟事件驅動迴圈    aeMain(server.el);    aeDeleteEventLoop(server.el);    return 0;}
方法非常簡單命令,有人估計比較納悶了,為什麼沒有串連操作呢,Client和Server不是要有串連操作的嘛,在這裡為什麼會沒有呢,因為那些是用戶端的主動進行的操作,所以服務端的main操作相對簡單很多。

Redis源碼分析(三十五)--- redis.c服務端的實現分析(2)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.