-
incr、decr、incrby都会调用相同的incrDecrCommand函数,里面再传进正负1或者指定的数字
void incrCommand(client *c) { incrDecrCommand(c,1); }
-
接下来主要分析incrDecrCommand函数
- 用2个long long类型的数字分别记录修改前后的值,并且用2个robj实例来记录当前redis变量。robj是redis通用元素类型,可以理解为string、list等数据结构的共同父类。
- 通过lookupKeyWrite函数从数据库中得到该实例,然后检查该实例是否是string类型还是long long类型。
- 从该实例中获取其中的value值,并和oldvalue共享。
- 判断相加减后是否溢出。
- value值进行加减操作。
- 主要判断lookup到的实例是否存在,并且引用计数器为1。如果是的话,通过ptr修改robj的值。
- 如果上述条件不成立,则根据最新的value新构建一个long long类型的实例,如果是原来不存在robj实例,则dbAdd一个实例,如果是引用计数器不为1的话,则dbOverwrite重写该实例。
void incrDecrCommand(client *c, long long incr) {
long long value, oldvalue;
robj *o, *new;
o = lookupKeyWrite(c->db,c->argv[1]);
if (checkType(c,o,OBJ_STRING)) return;
if (getLongLongFromObjectOrReply(c,o,&value,NULL) != C_OK) return;
oldvalue = value;
if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||
(incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {
addReplyError(c,"increment or decrement would overflow");
return;
}
value += incr;
if (o && o->refcount == 1 && o->encoding == OBJ_ENCODING_INT &&
(value < 0 || value >= OBJ_SHARED_INTEGERS) &&
value >= LONG_MIN && value <= LONG_MAX)
{
new = o;
o->ptr = (void*)((long)value);
} else {
new = createStringObjectFromLongLongForValue(value);
if (o) {
dbOverwrite(c->db,c->argv[1],new);
} else {
dbAdd(c->db,c->argv[1],new);
}
}
signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_STRING,"incrby",c->argv[1],c->db->id);
server.dirty++;
addReplyLongLong(c, value);
}