如下爲我的筆記redis
/** * process_command 在memcached中是用來處理用戶發送的命令的, * 包括get set,add,delete,replace,stats,flush_all等經常使用的和不經常使用的命令,全在這進行處理的。 * 一共有兩個參數,conn *c 和字符串指針 char *command ; * 關於conn結構體就先不說了,反正它是整個memcached中最重要的結構體就好了,等之後研究明白了再說,先從總體上領會精神吧。 * 這裏我想說一下的是, memcached 和 redis 在處理命令上的想法仍是有很大差異的, * 在 redis 裏面,你要是想看一下一共支持多少命令,每一個命令對應的函數,很方便,都在一個名叫 redisCommandTable 的結構體數組裏面,一目瞭然; * 可是 memcached 卻不是這樣,我剛開始也是按照看 redis 源碼的方式去找 memcached 中的,可是找了好久也沒有發現,緣由就是做者把支持的全部命令都散落在下面這個函數中了。 * 先說一下 memcached 是怎麼從 command 字符串中分解出具體的命令和對應的參數的。 * 在函數中用到了一個結構體數組: tokens[MAX_TOKENS] ,它實際上是用來存放分析完的 command 結果用的,分析工做在函數 tokenize_command 中進行。 * 如:有一個命令 "get aaaaaaaaaa" ,分析完之後存在tokens中的就是 * tokens[3] = {{value:"get",length:3},{value:"aaaaaaaaaa",length:10},{value:NULL,length:0}}; * 函數 tokenize_command 返回的是一個int型數據 ntokens,記錄了 tokens 的大小,表示從 command 命令中分解出了幾條數據, * 固然 ntokens 的值會比實際中 command 中包含的數據多1,由於字符串結尾的'\0'也要佔同樣。 * * 下面說說以 "get aaaaaaaaaa" 命令爲例,具體的命令分析和函數調用過程: * 當一條命令 "get aaaaaaaaaa" 傳到 process_command 中以後,先調用負責解析命令的函數tokenize_command, * 將解析後的命令存儲在tokens數組中,結果如上面的tokens[3],並返回ntokens,說明command中包含幾個字段(這裏獲得的是3), * 而後根據字段的數目進行判斷應該到哪一個條件語句去進行比對,當確認以後,就會跳到對應的條件語句中 * 因此這裏應該到 tokenize_command 下面的第一個if語句中,而後使用tokens[0].value,也就是tokens數組中存儲的get命令和字符串"get"進行比較, * 匹配,則調用對應的函數,這裏調用process_get_command(c, tokens, ntokens, false); * 而後 process_command 的使命就結束了。 * 如下代碼在memcached-1.4.22/memcached.c */ static void process_command(conn *c, char *command) { token_t tokens[MAX_TOKENS]; size_t ntokens; int comm; assert(c != NULL); MEMCACHED_PROCESS_COMMAND_START(c->sfd, c->rcurr, c->rbytes); if (settings.verbose > 1) fprintf(stderr, "<%d %s\n", c->sfd, command); /* * for commands set/add/replace, we build an item and read the data * directly into it, then continue in nread_complete(). */ c->msgcurr = 0; c->msgused = 0; c->iovused = 0; if (add_msghdr(c) != 0) { out_of_memory(c, "SERVER_ERROR out of memory preparing response"); return; } ntokens = tokenize_command(command, tokens, MAX_TOKENS); if (ntokens >= 3 && ((strcmp(tokens[COMMAND_TOKEN].value, "get") == 0) || (strcmp(tokens[COMMAND_TOKEN].value, "bget") == 0))) { process_get_command(c, tokens, ntokens, false); } else if ((ntokens == 6 || ntokens == 7) && ((strcmp(tokens[COMMAND_TOKEN].value, "add") == 0 && (comm = NREAD_ADD)) || (strcmp(tokens[COMMAND_TOKEN].value, "set") == 0 && (comm = NREAD_SET)) || (strcmp(tokens[COMMAND_TOKEN].value, "replace") == 0 && (comm = NREAD_REPLACE)) || (strcmp(tokens[COMMAND_TOKEN].value, "prepend") == 0 && (comm = NREAD_PREPEND)) || (strcmp(tokens[COMMAND_TOKEN].value, "append") == 0 && (comm = NREAD_APPEND)) )) { process_update_command(c, tokens, ntokens, comm, false); } else if ((ntokens == 7 || ntokens == 8) && (strcmp(tokens[COMMAND_TOKEN].value, "cas") == 0 && (comm = NREAD_CAS))) { process_update_command(c, tokens, ntokens, comm, true); } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "incr") == 0)) { process_arithmetic_command(c, tokens, ntokens, 1); } else if (ntokens >= 3 && (strcmp(tokens[COMMAND_TOKEN].value, "gets") == 0)) { process_get_command(c, tokens, ntokens, true); } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "decr") == 0)) { process_arithmetic_command(c, tokens, ntokens, 0); } else if (ntokens >= 3 && ntokens <= 5 && (strcmp(tokens[COMMAND_TOKEN].value, "delete") == 0)) { process_delete_command(c, tokens, ntokens); } else if ((ntokens == 4 || ntokens == 5) && (strcmp(tokens[COMMAND_TOKEN].value, "touch") == 0)) { process_touch_command(c, tokens, ntokens); } else if (ntokens >= 2 && (strcmp(tokens[COMMAND_TOKEN].value, "stats") == 0)) { process_stat(c, tokens, ntokens); } else if (ntokens >= 2 && ntokens <= 4 && (strcmp(tokens[COMMAND_TOKEN].value, "flush_all") == 0)) { time_t exptime = 0; set_noreply_maybe(c, tokens, ntokens); pthread_mutex_lock(&c->thread->stats.mutex); c->thread->stats.flush_cmds++; pthread_mutex_unlock(&c->thread->stats.mutex); if (!settings.flush_enabled) { // flush_all is not allowed but we log it on stats out_string(c, "CLIENT_ERROR flush_all not allowed"); return; } if(ntokens == (c->noreply ? 3 : 2)) { settings.oldest_live = current_time - 1; item_flush_expired(); out_string(c, "OK"); return; } exptime = strtol(tokens[1].value, NULL, 10); if(errno == ERANGE) { out_string(c, "CLIENT_ERROR bad command line format"); return; } /* If exptime is zero realtime() would return zero too, and realtime(exptime) - 1 would overflow to the max unsigned value. So we process exptime == 0 the same way we do when no delay is given at all. */ if (exptime > 0) settings.oldest_live = realtime(exptime) - 1; else /* exptime == 0 */ settings.oldest_live = current_time - 1; item_flush_expired(); out_string(c, "OK"); return; } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "version") == 0)) { out_string(c, "VERSION " VERSION); } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "quit") == 0)) { conn_set_state(c, conn_closing); } else if (ntokens == 2 && (strcmp(tokens[COMMAND_TOKEN].value, "shutdown") == 0)) { if (settings.shutdown_command) { conn_set_state(c, conn_closing); raise(SIGINT); } else { out_string(c, "ERROR: shutdown not enabled"); } } else if (ntokens > 1 && strcmp(tokens[COMMAND_TOKEN].value, "slabs") == 0) { if (ntokens == 5 && strcmp(tokens[COMMAND_TOKEN + 1].value, "reassign") == 0) { int src, dst, rv; if (settings.slab_reassign == false) { out_string(c, "CLIENT_ERROR slab reassignment disabled"); return; } src = strtol(tokens[2].value, NULL, 10); dst = strtol(tokens[3].value, NULL, 10); if (errno == ERANGE) { out_string(c, "CLIENT_ERROR bad command line format"); return; } rv = slabs_reassign(src, dst); switch (rv) { case REASSIGN_OK: out_string(c, "OK"); break; case REASSIGN_RUNNING: out_string(c, "BUSY currently processing reassign request"); break; case REASSIGN_BADCLASS: out_string(c, "BADCLASS invalid src or dst class id"); break; case REASSIGN_NOSPARE: out_string(c, "NOSPARE source class has no spare pages"); break; case REASSIGN_SRC_DST_SAME: out_string(c, "SAME src and dst class are identical"); break; } return; } else if (ntokens == 4 && (strcmp(tokens[COMMAND_TOKEN + 1].value, "automove") == 0)) { process_slabs_automove_command(c, tokens, ntokens); } else { out_string(c, "ERROR"); } } else if (ntokens > 1 && strcmp(tokens[COMMAND_TOKEN].value, "lru_crawler") == 0) { if (ntokens == 4 && strcmp(tokens[COMMAND_TOKEN + 1].value, "crawl") == 0) { int rv; if (settings.lru_crawler == false) { out_string(c, "CLIENT_ERROR lru crawler disabled"); return; } rv = lru_crawler_crawl(tokens[2].value); switch(rv) { case CRAWLER_OK: out_string(c, "OK"); break; case CRAWLER_RUNNING: out_string(c, "BUSY currently processing crawler request"); break; case CRAWLER_BADCLASS: out_string(c, "BADCLASS invalid class id"); break; } return; } else if (ntokens == 4 && strcmp(tokens[COMMAND_TOKEN + 1].value, "tocrawl") == 0) { uint32_t tocrawl; if (!safe_strtoul(tokens[2].value, &tocrawl)) { out_string(c, "CLIENT_ERROR bad command line format"); return; } settings.lru_crawler_tocrawl = tocrawl; out_string(c, "OK"); return; } else if (ntokens == 4 && strcmp(tokens[COMMAND_TOKEN + 1].value, "sleep") == 0) { uint32_t tosleep; if (!safe_strtoul(tokens[2].value, &tosleep)) { out_string(c, "CLIENT_ERROR bad command line format"); return; } if (tosleep > 1000000) { out_string(c, "CLIENT_ERROR sleep must be one second or less"); return; } settings.lru_crawler_sleep = tosleep; out_string(c, "OK"); return; } else if (ntokens == 3) { if ((strcmp(tokens[COMMAND_TOKEN + 1].value, "enable") == 0)) { if (start_item_crawler_thread() == 0) { out_string(c, "OK"); } else { out_string(c, "ERROR failed to start lru crawler thread"); } } else if ((strcmp(tokens[COMMAND_TOKEN + 1].value, "disable") == 0)) { if (stop_item_crawler_thread() == 0) { out_string(c, "OK"); } else { out_string(c, "ERROR failed to stop lru crawler thread"); } } else { out_string(c, "ERROR"); } return; } else { out_string(c, "ERROR"); } } else if ((ntokens == 3 || ntokens == 4) && (strcmp(tokens[COMMAND_TOKEN].value, "verbosity") == 0)) { process_verbosity_command(c, tokens, ntokens); } else { out_string(c, "ERROR"); } return; }
以上爲我的筆記數組