Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1837922
  • 博文数量: 184
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2388
  • 用 户 组: 普通用户
  • 注册时间: 2016-12-21 22:26
个人简介

90后空巢老码农

文章分类

全部博文(184)

文章存档

2021年(26)

2020年(56)

2019年(54)

2018年(47)

2017年(1)

我的朋友

分类: NOSQL

2019-05-02 17:11:36

一觉醒来才发现,刚刚的一篇文章,貌似忘了写这个东西,补上,顺便给自己增增速,
bitfield命令起始同之前的bitops的操作差不多,只不过它是提供了针对同一个值的不同段,一次性做多个操作,最终返回一个数组作为结果,其命令形式如下:
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL]
由上面的命令可知,BITFIELD命令供支持三种自命令,并设置了溢出处理方式:
1. GET type offset,在指定的偏移量,拿出指定类型的数据
2. SET type offset value, 在指定的偏移量,设置指定类型的数据
3. INCRBY type offset increment,在指定的偏移量,为指定类型增加increment
4. OVERFLOW WRAP|SAT|FAIL, 处理溢出的方式:回环(默认),满足,失败;
具体操作示例如下:


理解了其命令之后,下面来看看代码:
bitfield是将每一个子命令都保存到一个对应的结构当中去,结构如下:

点击(此处)折叠或打开

  1. /* BITFIELD key subcommmand-1 arg ... subcommand-2 arg ... subcommand-N ...
  2.  *
  3.  * Supported subcommands:
  4.  *
  5.  * GET <type> <offset>
  6.  * SET <type> <offset> <value>
  7.  * INCRBY <type> <offset> <increment>
  8.  * OVERFLOW [WRAP|SAT|FAIL]
  9.  */

  10. struct bitfieldOp {
  11.     uint64_t offset; /* Bitfield offset. */
  12.     int64_t i64; /* Increment amount (INCRBY) or SET value */
  13.     int opcode; /* Operation id. */
  14.     int owtype; /* Overflow type to use. */
  15.     int bits; /* Integer bitfield bits width. */
  16.     int sign; /* True if signed, otherwise unsigned op. */
  17. };


执行逻辑也就明了,先解析出子命令,然后在key对应的value上进行相应操作,遇到溢出要按照指示处理,主要代码如下:

点击(此处)折叠或打开

  1. void bitfieldCommand(client *c) {
  2.     robj *o;
  3.     size_t bitoffset;
  4.     int j, numops = 0, changes = 0;
  5.     struct bitfieldOp *ops = NULL; /* Array of ops to execute at end. */
  6.     int owtype = BFOVERFLOW_WRAP; /* Overflow type. */
  7.     int readonly = 1;
  8.     size_t higest_write_offset = 0;

  9.     for (j = 2; j < c->argc; j++) {
  10.         int remargs = c->argc-j-1; /* Remaining args other than current. */
  11.         char *subcmd = c->argv[j]->ptr; /* Current command name. */
  12.         int opcode; /* Current operation code. */
  13.         long long i64 = 0; /* Signed SET value. */
  14.         int sign = 0; /* Signed or unsigned type? */
  15.         int bits = 0; /* Bitfield width in bits. */

  16.         if (!strcasecmp(subcmd,"get") && remargs >= 2)
  17.             opcode = BITFIELDOP_GET;
  18.         else if (!strcasecmp(subcmd,"set") && remargs >= 3)
  19.             opcode = BITFIELDOP_SET;
  20.         else if (!strcasecmp(subcmd,"incrby") && remargs >= 3)
  21.             opcode = BITFIELDOP_INCRBY;
  22.         else if (!strcasecmp(subcmd,"overflow") && remargs >= 1) {
  23.             char *owtypename = c->argv[j+1]->ptr;
  24.             j++;
  25.             if (!strcasecmp(owtypename,"wrap"))
  26.                 owtype = BFOVERFLOW_WRAP;
  27.             else if (!strcasecmp(owtypename,"sat"))
  28.                 owtype = BFOVERFLOW_SAT;
  29.             else if (!strcasecmp(owtypename,"fail"))
  30.                 owtype = BFOVERFLOW_FAIL;
  31.             else {
  32.                 addReplyError(c,"Invalid OVERFLOW type specified");
  33.                 zfree(ops);
  34.                 return;
  35.             }
  36.             continue;
  37.         } else {
  38.             addReply(c,shared.syntaxerr);
  39.             zfree(ops);
  40.             return;
  41.         }

  42.         /* Get the type and offset arguments, common to all the ops. */
  43.         if (getBitfieldTypeFromArgument(c,c->argv[j+1],&sign,&bits) != C_OK) {
  44.             zfree(ops);
  45.             return;
  46.         }

  47.         if (getBitOffsetFromArgument(c,c->argv[j+2],&bitoffset,1,bits) != C_OK){
  48.             zfree(ops);
  49.             return;
  50.         }

  51.         if (opcode != BITFIELDOP_GET) {
  52.             readonly = 0;
  53.             if (higest_write_offset < bitoffset + bits - 1)
  54.                 higest_write_offset = bitoffset + bits - 1;
  55.             /* INCRBY and SET require another argument. */
  56.             if (getLongLongFromObjectOrReply(c,c->argv[j+3],&i64,NULL) != C_OK){
  57.                 zfree(ops);
  58.                 return;
  59.             }
  60.         }

  61.         /* Populate the array of operations we'll process. */
  62.         ops = zrealloc(ops,sizeof(*ops)*(numops+1));
  63.         ops[numops].offset = bitoffset;
  64.         ops[numops].i64 = i64;
  65.         ops[numops].opcode = opcode;
  66.         ops[numops].owtype = owtype;
  67.         ops[numops].bits = bits;
  68.         ops[numops].sign = sign;
  69.         numops++;

  70.         j += 3 - (opcode == BITFIELDOP_GET);
  71.     }

  72.     if (readonly) {
  73.         /* Lookup for read is ok if key doesn't exit, but errors
  74.          * if it's not a string. */
  75.         o = lookupKeyRead(c->db,c->argv[1]);
  76.         if (o != NULL && checkType(c,o,OBJ_STRING)) return;
  77.     } else {
  78.         /* Lookup by making room up to the farest bit reached by
  79.          * this operation. */
  80.         if ((o = lookupStringForBitCommand(c,
  81.             higest_write_offset)) == NULL) return;
  82.     }

  83.     addReplyMultiBulkLen(c,numops);

  84.     /* Actually process the operations. */
  85.     for (j = 0; j < numops; j++) {
  86.         struct bitfieldOp *thisop = ops+j;

  87.         /* Execute the operation. */
  88.         if (thisop->opcode == BITFIELDOP_SET ||
  89.             thisop->opcode == BITFIELDOP_INCRBY)
  90.         {
  91.             /* SET and INCRBY: We handle both with the same code path
  92.              * for simplicity. SET return value is the previous value so
  93.              * we need fetch & store as well. */

  94.             /* We need two different but very similar code paths for signed
  95.              * and unsigned operations, since the set of functions to get/set
  96.              * the integers and the used variables types are different. */
  97.             if (thisop->sign) {
  98.                 int64_t oldval, newval, wrapped, retval;
  99.                 int overflow;

  100.                 oldval = getSignedBitfield(o->ptr,thisop->offset,
  101.                         thisop->bits);

  102.                 if (thisop->opcode == BITFIELDOP_INCRBY) {
  103.                     newval = oldval + thisop->i64;
  104.                     overflow = checkSignedBitfieldOverflow(oldval,
  105.                             thisop->i64,thisop->bits,thisop->owtype,&wrapped);
  106.                     if (overflow) newval = wrapped;
  107.                     retval = newval;
  108.                 } else {
  109.                     newval = thisop->i64;
  110.                     overflow = checkSignedBitfieldOverflow(newval,
  111.                             0,thisop->bits,thisop->owtype,&wrapped);
  112.                     if (overflow) newval = wrapped;
  113.                     retval = oldval;
  114.                 }

  115.                 /* On overflow of type is "FAIL", don't write and return
  116.                  * NULL to signal the condition. */
  117.                 if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
  118.                     addReplyLongLong(c,retval);
  119.                     setSignedBitfield(o->ptr,thisop->offset,
  120.                                       thisop->bits,newval);
  121.                 } else {
  122.                     addReply(c,shared.nullbulk);
  123.                 }
  124.             } else {
  125.                 uint64_t oldval, newval, wrapped, retval;
  126.                 int overflow;

  127.                 oldval = getUnsignedBitfield(o->ptr,thisop->offset,
  128.                         thisop->bits);

  129.                 if (thisop->opcode == BITFIELDOP_INCRBY) {
  130.                     newval = oldval + thisop->i64;
  131.                     overflow = checkUnsignedBitfieldOverflow(oldval,
  132.                             thisop->i64,thisop->bits,thisop->owtype,&wrapped);
  133.                     if (overflow) newval = wrapped;
  134.                     retval = newval;
  135.                 } else {
  136.                     newval = thisop->i64;
  137.                     overflow = checkUnsignedBitfieldOverflow(newval,
  138.                             0,thisop->bits,thisop->owtype,&wrapped);
  139.                     if (overflow) newval = wrapped;
  140.                     retval = oldval;
  141.                 }
  142.                 /* On overflow of type is "FAIL", don't write and return
  143.                  * NULL to signal the condition. */
  144.                 if (!(overflow && thisop->owtype == BFOVERFLOW_FAIL)) {
  145.                     addReplyLongLong(c,retval);
  146.                     setUnsignedBitfield(o->ptr,thisop->offset,
  147.                                         thisop->bits,newval);
  148.                 } else {
  149.                     addReply(c,shared.nullbulk);
  150.                 }
  151.             }
  152.             changes++;
  153.         } else {
  154.             /* GET */
  155.             unsigned char buf[9];
  156.             long strlen = 0;
  157.             unsigned char *src = NULL;
  158.             char llbuf[LONG_STR_SIZE];

  159.             if (o != NULL)
  160.                 src = getObjectReadOnlyString(o,&strlen,llbuf);

  161.             /* For GET we use a trick: before executing the operation
  162.              * copy up to 9 bytes to a local buffer, so that we can easily
  163.              * execute up to 64 bit operations that are at actual string
  164.              * object boundaries. */
  165.             memset(buf,0,9);
  166.             int i;
  167.             size_t byte = thisop->offset >> 3;
  168.             for (i = 0; i < 9; i++) {
  169.                 if (src == NULL || i+byte >= (size_t)strlen) break;
  170.                 buf[i] = src[i+byte];
  171.             }

  172.             /* Now operate on the copied buffer which is guaranteed
  173.              * to be zero-padded. */
  174.             if (thisop->sign) {
  175.                 int64_t val = getSignedBitfield(buf,thisop->offset-(byte*8),
  176.                                             thisop->bits);
  177.                 addReplyLongLong(c,val);
  178.             } else {
  179.                 uint64_t val = getUnsignedBitfield(buf,thisop->offset-(byte*8),
  180.                                             thisop->bits);
  181.                 addReplyLongLong(c,val);
  182.             }
  183.         }
  184.     }

  185.     if (changes) {
  186.         signalModifiedKey(c->db,c->argv[1]);
  187.         notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
  188.         server.dirty += changes;
  189.     }
  190.     zfree(ops);
  191. }



阅读(2754) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~