<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      簡介

      REDIS有非常豐富的數(shù)據(jù)結(jié)構(gòu) 以及建立在這數(shù)據(jù)結(jié)構(gòu)上的操作,在源文件中主要集中在 T_hash.c /T_list.c /T_string.c/T_zset.c

      可以說讀懂了這4個源文件  大部分?jǐn)?shù)據(jù)結(jié)構(gòu)命令都比較清楚了。 先從T_string.c源文件開始讀起:

      T_string.c  SET命令

      命令簡介

      SET key value [EX seconds] [PX milliseconds] [NX|XX]   1)設(shè)置了Key Value的時間  有2種單位: 第一: EX  對應(yīng)的是秒 第2: PX  是毫秒

        命令源碼分解
      1. void setCommand(redisClient *c) {
      2. int j;
      3.     robj *expire = NULL;
      4. int unit = UNIT_SECONDS;
      5. int flags = REDIS_SET_NO_FLAGS;
      6. for (j = 3; j < c->argc; j++) {
      7. char *a = c->argv[j]->ptr;
      8.         robj *next = (j == c->argc-1) ? NULL : c->argv[j+1];
      9. if ((a[0] == 'n' || a[0] == 'N') &&
      10.             (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
      11.             flags |= REDIS_SET_NX;
      12.         } else if ((a[0] == 'x' || a[0] == 'X') &&
      13.                    (a[1] == 'x' || a[1] == 'X') && a[2] == '\0') {
      14.             flags |= REDIS_SET_XX;
      15.         } else if ((a[0] == 'e' || a[0] == 'E') &&
      16.                    (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
      17.             unit = UNIT_SECONDS;
      18.             expire = next;
      19.             j++;
      20.         } else if ((a[0] == 'p' || a[0] == 'P') &&
      21.                    (a[1] == 'x' || a[1] == 'X') && a[2] == '\0' && next) {
      22.             unit = UNIT_MILLISECONDS;
      23.             expire = next;
      24.             j++;
      25.         } else {
      26.             addReply(c,shared.syntaxerr);
      27. return;
      28.         }
      29.     }
      30.     c->argv[2] = tryObjectEncoding(c->argv[2]);
      31.     setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);
      32. }

       

      解析:line 8: a獲取每個分割的命令參數(shù)的頭指針  j從3開始, 如果命令如:

      set key value 這種  中間的循環(huán)就不會做了, line 3-5變量的設(shè)置就是原始值

      如果做了中間的循環(huán):

      首先由2種可能: ex 和Px 但是在寫代碼的時候  他就會注意到, 后面還會不會接其他的命令

      最終就解析出來了   line33主要是防止Object Value是一個數(shù)字  看看能不能進行重新編碼

      Line 34:就調(diào)用通用的SetCommand。 這里實現(xiàn)了所有SET命令版本的入口

      1. void setGenericCommand(redisClient *c, int flags, robj *key, robj *val, robj *expire, int unit, robj *ok_reply, robj *abort_reply) {
      2. long long milliseconds = 0; /* initialized to avoid any harmness warning */
      3. if (expire) {
      4. if (getLongLongFromObjectOrReply(c, expire, &milliseconds, NULL) != REDIS_OK)
      5. return;
      6. if (milliseconds <= 0) {
      7.             addReplyError(c,"invalid expire time in SETEX");
      8. return;
      9.         }
      10. if (unit == UNIT_SECONDS) milliseconds *= 1000;
      11.     }
      12. if ((flags & REDIS_SET_NX && lookupKeyWrite(c->db,key) != NULL) ||
      13.         (flags & REDIS_SET_XX && lookupKeyWrite(c->db,key) == NULL))
      14.     {
      15.         addReply(c, abort_reply ? abort_reply : shared.nullbulk);
      16. return;
      17.     }
      18.     setKey(c->db,key,val);
      19.     server.dirty++;
      20. if (expire) setExpire(c->db,key,mstime()+milliseconds);
      21.     addReply(c, ok_reply ? ok_reply : shared.ok);

       

      line 4到line 11 :是計算出需要多長時間 

      line 14- 15:  lookupKeyWrite(c->db,key) != NULL) 查看是否有這個key 如果沒有就寫入 

      同樣的:lookupKeyWrite(c->db,key) == NULL)  查看是否有這個key 如果有就寫入

      line 20: 調(diào)用db.c/setKey函數(shù),就把相應(yīng)的Key和value插入到dict[]中去了

      line 21: dirty重新賦值

      line22:調(diào)用db.c/setExpire函數(shù) 把時間鍵值插入到這個expire字典里了。 mstime()是計算出當(dāng)前時間的長整形秒數(shù)。 至此 整個SET命令完成了~!

      T_string.c  GET命令  難度【*】

      1. int getGenericCommand(redisClient *c) {
      2.     robj *o;
      3. if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL)
      4. return REDIS_OK;
      5. if (o->type != REDIS_STRING) {
      6.         addReply(c,shared.wrongtypeerr);
      7. return REDIS_ERR;
      8.     } else {
      9.         addReplyBulk(c,o);
      10. return REDIS_OK;
      11.     }
      12. }

       

      get命名從Line 1 進入:  調(diào)用DB.C里的lookupKeyReadOrReply函數(shù) 如果不存在  直接返回OK。

      如果不是REDIS_STRING類型: 則返回一個錯誤。

      如果完全正確 Line 11:把結(jié)果返回給客戶端

      T_string.c  GETSET/INCR命令   難度【*】

          這2個命令非常的實用

      1. void getsetCommand(redisClient *c) {
      2. if (getGenericCommand(c) == REDIS_ERR) return;
      3.     c->argv[2] = tryObjectEncoding(c->argv[2]);
      4.     setKey(c->db,c->argv[1],c->argv[2]);
      5.     server.dirty++;
      6. }

       

      這里可以看到 Line 2:  先調(diào)用get命令 

      然后line 4:進行setKey  覆蓋掉以前的old key

      這個命令可以完成那種復(fù)位計數(shù)器的功能:獲得當(dāng)前某個變量值 然后置空

      INCR命令                                                                                                                                                   難度【**】

      對key 存儲的數(shù)字加1  當(dāng)然他的key必須要存儲的是數(shù)字哦

      1. void incrDecrCommand(redisClient *c, long long incr) {
      2. long long value, oldvalue;
      3.     robj *o, *new;
      4.     o = lookupKeyWrite(c->db,c->argv[1]);
      5. if (o != NULL && checkType(c,o,REDIS_STRING)) return;
      6. if (getLongLongFromObjectOrReply(c,o,&value,NULL) != REDIS_OK) return;
      7.     oldvalue = value;
      8. if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||
      9.         (incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {
      10.         addReplyError(c,"increment or decrement would overflow");
      11. return;
      12.     }
      13.     value += incr;
      14. new = createStringObjectFromLongLong(value);
      15. if (o)
      16.         dbOverwrite(c->db,c->argv[1],new);
      17. else
      18.         dbAdd(c->db,c->argv[1],new);
      19.     signalModifiedKey(c->db,c->argv[1]);
      20.     server.dirty++;
      21.     addReply(c,shared.colon);
      22.     addReply(c,new);
      23.     addReply(c,shared.crlf);
      24. }
      25. void incrCommand(redisClient *c) {
      26.     incrDecrCommand(c,1);
      27. }

       

      line28:命令入口 然后進入Line1:

      line 5: 先找到key對應(yīng)的value  先判斷是不是STRING 是撤回, 然后判斷能否轉(zhuǎn)換成Longlong型數(shù) 如果能轉(zhuǎn)換 就繼續(xù)下面的工作: 如果遞增 會導(dǎo)致數(shù)量越界  就返回。

      修改了具體的數(shù)值

      注意點: 如果o為NULL,則沒有這個key  那么就會采用這個方案:dbAdd,如果含有 則改寫

      最后一個命令:line 21: 需要通知下 相關(guān)的被watch的Key, 如果被watched的key里有這個key  則那個key的相應(yīng)標(biāo)記位需要置為臟。 但不影響這里的操作

      題外話 : 引入INCR的原因

          試想 如果N客戶端 都想對某個變量做自增的一個操作  如果沒有INCR的話 只能是取回 在本地加一  然后在傳上去  但是這樣必須進行原子鎖  所以是不行的  如果這樣的事情交給服務(wù)器做,就可以避免這樣的問題,對于客戶端來講只需要提供INCR命令,剩下的都是redis 進行流水線操作  就絕對能保持其自增效果   對于這個INCR在我們實驗室的爬蟲部分 關(guān)于多臺主機爬取信息 怎么根據(jù)ID自增來插入表格 是一個非常好的解決方案~!

      T_string.c  APPEND命令       難度【**】

          如果已經(jīng)存在 就講value加到key的末尾  如果不存在  就是簡單的set key value

      1. void appendCommand(redisClient *c) {
      2.     size_t totlen;
      3.     robj *o, *append;
      4.     o = lookupKeyWrite(c->db,c->argv[1]);
      5. if (o == NULL) {
      6. /* Create the key */
      7.         c->argv[2] = tryObjectEncoding(c->argv[2]);
      8.         dbAdd(c->db,c->argv[1],c->argv[2]);
      9.         incrRefCount(c->argv[2]);
      10.         totlen = stringObjectLen(c->argv[2]);
      11.     } else {
      12. /* Key exists, check type */
      13. if (checkType(c,o,REDIS_STRING))
      14. return;
      15. /* "append" is an argument, so always an sds */
      16.         append = c->argv[2];
      17.         totlen = stringObjectLen(o)+sdslen(append->ptr);
      18. if (checkStringLength(c,totlen) != REDIS_OK)
      19. return;
      20. /* If the object is shared or encoded, we have to make a copy */
      21. if (o->refcount != 1 || o->encoding != REDIS_ENCODING_RAW) {
      22.             robj *decoded = getDecodedObject(o);
      23.             o = createStringObject(decoded->ptr, sdslen(decoded->ptr));
      24.             decrRefCount(decoded);
      25.             dbOverwrite(c->db,c->argv[1],o);
      26.         }
      27. /* Append the value */
      28.         o->ptr = sdscatlen(o->ptr,append->ptr,sdslen(append->ptr));
      29.         totlen = sdslen(o->ptr);
      30.     }
      31.     signalModifiedKey(c->db,c->argv[1]);
      32.     server.dirty++;
      33.     addReplyLongLong(c,totlen);
      34. }

       

           分2種: 如果沒有含key 就直接加入

          如果沒有含key  則重新分配

          line 32:sdscatlen() 將o->ptr的內(nèi)容分配到append->ptr里。

      T_string.c  MSET/MGET命令

      簡介:

          一次性進行多次插入和取操作命令   是一個原子操作

      void msetGenericCommand(redisClient *c, int nx) {

      1. int j, busykeys = 0;
      2. if ((c->argc % 2) == 0) {
      3.         addReplyError(c,"wrong number of arguments for MSET");
      4. return;
      5.     }
      6. /* Handle the NX flag. The MSETNX semantic is to return zero and don't
      7.      * set nothing at all if at least one already key exists. */
      8. if (nx) {
      9. for (j = 1; j < c->argc; j += 2) {
      10. if (lookupKeyWrite(c->db,c->argv[j]) != NULL) {
      11.                 busykeys++;
      12.             }
      13.         }
      14. if (busykeys) {
      15.             addReply(c, shared.czero);
      16. return;
      17.         }
      18.     }
      19. for (j = 1; j < c->argc; j += 2) {
      20.         c->argv[j+1] = tryObjectEncoding(c->argv[j+1]);
      21.         setKey(c->db,c->argv[j],c->argv[j+1]);
      22.     }
      23.     server.dirty += (c->argc-1)/2;
      24.     addReply(c, nx ? shared.cone : shared.ok);
      25. }
      26. void msetCommand(redisClient *c) {
      27.     msetGenericCommand(c,0);
      28. }

       

      同樣 入口是line 29 很簡單:

          進入line msetGenericCommand之后, Line 3 先看下是不是有參數(shù)錯了, 如果所有參數(shù)和是個偶數(shù) 就證明錯了

          line 9-14: 如果是msetnx就是key不存在的時候能插入  如果存在不讓插入  nx=1的話 就是調(diào)用msetnx命令

              注意點:這里是原子操作,要么全面插入成功 要么全部失敗,也就是說:如果中間有一個key存在  msetnx直接從17返回了

          Line21-26:這里是真正的插入信息 每2個作為一組進行插入  然后就講dirty更新

      MGET命令基本上是一樣的原理  再次忽略

      t_string.c 基本上就是這些命令 ,但是奇怪的是getbit setbit的源碼不在,這個bit 2進制數(shù)組需要在其他的文件中應(yīng)該會出現(xiàn),出現(xiàn)在其他源文件中放在其他文件中分析。

      下篇預(yù)告: List操作  這個是實驗室項目用的最多的,所以必須要很好的分析。

       

       

      posted on 2014-08-30 16:33  fuck_shit  閱讀(653)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 风韵丰满熟妇啪啪区老熟熟女| 在线观看AV永久免费| 国产亚洲欧洲AⅤ综合一区| 久视频久免费视频久免费| 免费av网站| 成全影视大全在线观看| 丁香婷婷在线观看| 久久精品蜜芽亚洲国产AV| 国产黄大片在线观看画质优化| 苍溪县| 久久se精品一区精品二区 | 国模一区二区三区私拍视频| 在线日韩一区二区| 亚洲中文精品一区二区| 欧美三级欧美成人高清| 在线观看亚洲精品国产| 中文字幕无码av不卡一区| 色av专区无码影音先锋| 挺进粗大尤物人妻中文字幕| 99久久婷婷国产综合精品青草漫画| 2021亚洲va在线va天堂va国产| 日本午夜精品一区二区三区电影| 久久国产一区二区三区| 人妻精品中文字幕av| A级孕妇高清免费毛片| 一卡2卡三卡4卡免费网站| 亚洲永久精品免费在线看| 凹凸国产熟女精品视频| a男人的天堂久久a毛片| 四虎国产精品成人| 久久精品国产精品亚洲蜜月| 日韩精品亚洲精品第一页| 99中文字幕精品国产| 蜜臀av一区二区三区精品 | 午夜精品福利一区二区三| 伊人久久大香线蕉综合影院首页| 国产精品午夜福利片国产| 久久天天躁综合夜夜黑人鲁色| 亚洲精品尤物av在线网站| 一本色道久久东京热| 日韩一区在线中文字幕|