順風車運營研發團隊 施洪寶html
getbit, getrange, blpop, brpop, rpopredis
一. getbit
1.命令說明
使用方式: getbit key offsetide
功能: 對key對應value的值, 取對應偏移量上的值。ui
返回值: key不存在, offset比字符串長度大時, 返回0, 不然返回對應位上的值。this
時間複雜度: O(1)spa
2.源碼實現
源碼實現的步驟能夠分爲兩步: 1. 獲取偏移量所在字節數。 2. 獲取偏移量所在字節的bit。code
void getbitCommand(client *c) { robj *o; char llbuf[32]; size_t bitoffset; size_t byte, bit; size_t bitval = 0; //讀取參數 if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset,0,0) != C_OK) return; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || checkType(c,o,OBJ_STRING)) return; //獲取offset對應的字節位置以及對應的bit byte = bitoffset >> 3; bit = 7 - (bitoffset & 0x7); //讀取結果並返回 if (sdsEncodedObject(o)) { if (byte < sdslen(o->ptr)) bitval = ((uint8_t*)o->ptr)[byte] & (1 << bit); } else { if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr)) bitval = llbuf[byte] & (1 << bit); } addReply(c, bitval ? shared.cone : shared.czero); }
3. 參考
http://doc.redisfans.com/stri...orm
二. getrange
1.命名說明
使用方式:getrange key start endserver
功能: 返回key中字符串值得子字符串,字符串截取位置由start, end決定htm
返回值: 截取的子字符串,超過範圍自動截取
時間複雜度: O(n)
2.源碼實現
void getrangeCommand(client *c) { robj *o; long long start, end; char *str, llbuf[32]; size_t strlen; //獲取參數 if (getLongLongFromObjectOrReply(c,c->argv[2],&start,NULL) != C_OK) return; if (getLongLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK) return; if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptybulk)) == NULL || checkType(c,o,OBJ_STRING)) return; //獲取值對應的字符串 if (o->encoding == OBJ_ENCODING_INT) { str = llbuf; strlen = ll2string(llbuf,sizeof(llbuf),(long)o->ptr); } else { str = o->ptr; strlen = sdslen(str); } //start, end處理 /* Convert negative indexes */ if (start < 0 && end < 0 && start > end) { addReply(c,shared.emptybulk); return; } if (start < 0) start = strlen+start; if (end < 0) end = strlen+end; if (start < 0) start = 0; if (end < 0) end = 0; if ((unsigned long long)end >= strlen) end = strlen-1; /* Precondition: end >= 0 && end < strlen, so the only condition where * nothing can be returned is: start > end. */ if (start > end || strlen == 0) { addReply(c,shared.emptybulk); } else { addReplyBulkCBuffer(c,(char*)str+start,end-start+1); } }
3.參考
http://doc.redisfans.com/stri...
三. blpop
1.命令說明
使用方法: blpop key [key...] timeout
功能: 從給定的key中,找到一個非空列表,返回頭元素。查找順序按照給定的key順序。若是全部key對應的列表都是空的,則操做被阻塞,阻塞時間可由timeout設置
時間複雜度: O(n), n爲key的個數(沒有被阻塞的狀況下)
返回值: 返回key以及列表的元素
2.源碼實現
void blockingPopGenericCommand(client *c, int where) { robj *o; mstime_t timeout; int j; //獲取超時時間 if (getTimeoutFromObjectOrReply(c,c->argv[c->argc-1],&timeout,UNIT_SECONDS) != C_OK) return; //依次遍歷全部給定的key for (j = 1; j < c->argc-1; j++) { //獲取key對應的value o = lookupKeyWrite(c->db,c->argv[j]); if (o != NULL) { if (o->type != OBJ_LIST) { addReply(c,shared.wrongtypeerr); return; } else { if (listTypeLength(o) != 0) { /* Non empty list, this is like a non normal [LR]POP. */ char *event = (where == LIST_HEAD) ? "lpop" : "rpop"; robj *value = listTypePop(o,where); //從列表中彈出一個元素,位置由where決定, 頭部或者尾部。 serverAssert(value != NULL); //返回結果 addReplyMultiBulkLen(c,2); addReplyBulk(c,c->argv[j]); addReplyBulk(c,value); decrRefCount(value); //發送鍵空間事件通知(pub, sub) notifyKeyspaceEvent(NOTIFY_LIST,event, c->argv[j],c->db->id); if (listTypeLength(o) == 0) { dbDelete(c->db,c->argv[j]); notifyKeyspaceEvent(NOTIFY_GENERIC,"del", c->argv[j],c->db->id); } //通知正在watch這個key的client, 具體實現爲將client的flags開啓CLIENT_DIRTY_CAS signalModifiedKey(c->db,c->argv[j]); server.dirty++; /* Replicate it as an [LR]POP instead of B[LR]POP. */ //由於已經在一個key上找到元素,故而能夠將blpop, brpop改寫爲lpop, rpop rewriteClientCommandVector(c,2, (where == LIST_HEAD) ? shared.lpop : shared.rpop, c->argv[j]); return; } } } } /* If we are inside a MULTI/EXEC and the list is empty the only thing * we can do is treating it as a timeout (even with timeout 0). */ //Redis正在執行事務 if (c->flags & CLIENT_MULTI) { addReply(c,shared.nullmultibulk); return; } /* If the list is empty or the key does not exists we must block */ //列表爲空或者key不存在 blockForKeys(c, c->argv + 1, c->argc - 2, timeout, NULL); }
3. 參考
http://doc.redisfans.com/list...
四. brpop
1.命令說明
使用方法: rlpop key [key...] timeout
功能: 從給定的key中,找到一個非空列表,返回尾部元素。查找順序按照給定的key順序。若是全部key對應的列表都是空的,則操做被阻塞,阻塞時間可由timeout設置
時間複雜度: O(n), n爲key的個數(沒有被阻塞的狀況下)
返回值: 返回key以及列表的元素
2.源碼實現
與blpop相同,兩者都是經過調用blockingPopGenericCommand來實現的,惟一的區別再與,blpop彈出首部(blockingPopGenericCommand的where參數爲LIST_HEAD),brpop彈出尾部元素(blockingPopGenericCommand的where參數爲LIST_TAIL)
3. 參考
http://doc.redisfans.com/list...
五. rpop
1.命令說明
使用方法: rpop key
功能: 移除並返回列表的尾部元素。
返回值: 返回列表的尾部元素,不存在時返回nil
時間複雜度: O(1)
2. 源碼實現
void popGenericCommand(client *c, int where) { robj *o = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk); //查找key if (o == NULL || checkType(c,o,OBJ_LIST)) return; robj *value = listTypePop(o,where); if (value == NULL) { addReply(c,shared.nullbulk); //value中沒有元素 } else { char *event = (where == LIST_HEAD) ? "lpop" : "rpop"; addReplyBulk(c,value); //返回結果 decrRefCount(value); notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id); //鍵空間通知 if (listTypeLength(o) == 0) { notifyKeyspaceEvent(NOTIFY_GENERIC,"del", c->argv[1],c->db->id); dbDelete(c->db,c->argv[1]); } signalModifiedKey(c->db,c->argv[1]); //通知正在監聽這個key的client, 具體實現爲將client的flags開啓CLIENT_DIRTY_CAS server.dirty++; //髒標誌加1 } }