題記:看了《REDIS原始碼分析 – PROTOCOL》,發現作者跳過了一些簡單的地方,但這些簡單的地方正好是我沒看明白的地方,於是做點補充,也隨便做個筆記。
版本:2.04。
1.Requests格式
*參數的個數 CRLF$第一個參數的長度CRLF第一個參數CRLF...$第N個參數的長度CRLF第N個參數CRLF
如果在redis_cli裡鍵入get a,經過協議組裝後的請求為
2\r\n$3\r\nget\r\n$1\r\na\r\n
2.流程
1.readQueryFromClient從fd讀取資料:nread = read(fd, c->querybuf+qblen, readlen);
2.processInputBuffer判斷是否是telnet的請求。
2.1 c->querybuf[0] == '*' -->processMultibulkBuffer。
2.2 telnet -->processInlineBuffer。
3.processMultibulkBuffer:解析指令,分解參數到c->argc和c->argv裡面,argc表示個數,argv是
redis_object的指標數組。
4.processCommand:在redis server啟動的時候,會調用populateCommandTable,將redisCommandTable數組轉行成一個hash
table(server.commands),lookupCommand通過key(get)尋找對映的函數指標,如下:
struct redisCommand redisCommandTable[] = { {"get",getCommand,2,"r",0,NULL,1,1,1,0,0}, {"set",setCommand,3,"wm",0,noPreloadGetKeys,1,1,1,0,0},。。。。
5.call(redisClient *c, int flags):執行指令函數。個人感覺最重要的一個調用:c->cmd->proc(c)。前面的c->cmd = c->lastcmd = lookupCommand(c->argv[0]->ptr),已經為cmd賦值了一個redisCommand指標。因為是get指令。c->cmd->proc(c) ==getCommand(c)。
typedef void redisCommandProc(redisClient *c);struct redisCommand { char *name; redisCommandProc *proc; int arity; .. long long microseconds, calls;};
6.華麗的來到getCommand。
void getCommand(redisClient *c) { getGenericCommand(c);}int getGenericCommand(redisClient *c) { ... if (o->type != REDIS_STRING) { addReply(c,shared.wrongtypeerr); return REDIS_ERR; } else { addReplyBulk(c,o); return REDIS_OK; }}
7.addReplyBulk。
void addReplyBulk(redisClient *c, robj *obj) { addReplyBulkLen(c,obj); addReply(c,obj); addReply(c,shared.crlf);}
8.prepareClientToWrite:通過事件分離器轉到寫出操作:sendReplyToClient,。把c->buf的內容寫到fd。
參考資料:
1.http://www.hoterran.info/redis_protocol <<REDIS原始碼分析 – PROTOCOL>>