mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
Merge branch 'hincrby' of git://github.com/pietern/redis
This commit is contained in:
commit
570e43c828
@ -150,6 +150,7 @@ static struct redisCommand cmdTable[] = {
|
||||
{"exec",1,REDIS_CMD_INLINE},
|
||||
{"discard",1,REDIS_CMD_INLINE},
|
||||
{"hset",4,REDIS_CMD_MULTIBULK},
|
||||
{"hincrby",4,REDIS_CMD_INLINE},
|
||||
{"hget",3,REDIS_CMD_BULK},
|
||||
{"hdel",3,REDIS_CMD_BULK},
|
||||
{"hlen",2,REDIS_CMD_INLINE},
|
||||
|
76
redis.c
76
redis.c
@ -697,6 +697,7 @@ static void hvalsCommand(redisClient *c);
|
||||
static void hgetallCommand(redisClient *c);
|
||||
static void hexistsCommand(redisClient *c);
|
||||
static void configCommand(redisClient *c);
|
||||
static void hincrbyCommand(redisClient *c);
|
||||
|
||||
/*================================= Globals ================================= */
|
||||
|
||||
@ -756,6 +757,7 @@ static struct redisCommand cmdTable[] = {
|
||||
{"zrank",zrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
|
||||
{"zrevrank",zrevrankCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
|
||||
{"hset",hsetCommand,4,REDIS_CMD_BULK|REDIS_CMD_DENYOOM,NULL,1,1,1},
|
||||
{"hincrby",hincrbyCommand,4,REDIS_CMD_INLINE|REDIS_CMD_DENYOOM,NULL,1,1,1},
|
||||
{"hget",hgetCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
|
||||
{"hdel",hdelCommand,3,REDIS_CMD_BULK,NULL,1,1,1},
|
||||
{"hlen",hlenCommand,2,REDIS_CMD_INLINE,NULL,1,1,1},
|
||||
@ -5955,6 +5957,80 @@ static void hsetCommand(redisClient *c) {
|
||||
addReplySds(c,sdscatprintf(sdsempty(),":%d\r\n",update == 0));
|
||||
}
|
||||
|
||||
static void hincrbyCommand(redisClient *c) {
|
||||
int update = 0;
|
||||
long long value = 0, incr = 0;
|
||||
robj *o = lookupKeyWrite(c->db,c->argv[1]);
|
||||
|
||||
if (o == NULL) {
|
||||
o = createHashObject();
|
||||
dictAdd(c->db->dict,c->argv[1],o);
|
||||
incrRefCount(c->argv[1]);
|
||||
} else {
|
||||
if (o->type != REDIS_HASH) {
|
||||
addReply(c,shared.wrongtypeerr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
robj *o_incr = getDecodedObject(c->argv[3]);
|
||||
incr = strtoll(o_incr->ptr, NULL, 10);
|
||||
decrRefCount(o_incr);
|
||||
|
||||
if (o->encoding == REDIS_ENCODING_ZIPMAP) {
|
||||
unsigned char *zm = o->ptr;
|
||||
unsigned char *zval;
|
||||
unsigned int zvlen;
|
||||
|
||||
/* Find value if already present in hash */
|
||||
if (zipmapGet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
|
||||
&zval,&zvlen)) {
|
||||
/* strtoll needs the char* to have a trailing \0, but
|
||||
* the zipmap doesn't include them. */
|
||||
sds szval = sdsnewlen(zval, zvlen);
|
||||
value = strtoll(szval,NULL,10);
|
||||
sdsfree(szval);
|
||||
}
|
||||
|
||||
value += incr;
|
||||
sds svalue = sdscatprintf(sdsempty(),"%lld",value);
|
||||
zm = zipmapSet(zm,c->argv[2]->ptr,sdslen(c->argv[2]->ptr),
|
||||
(unsigned char*)svalue,sdslen(svalue),&update);
|
||||
sdsfree(svalue);
|
||||
o->ptr = zm;
|
||||
|
||||
/* Check if the zipmap needs to be converted
|
||||
* if this was not an update. */
|
||||
if (!update && zipmapLen(zm) > server.hash_max_zipmap_entries)
|
||||
convertToRealHash(o);
|
||||
} else {
|
||||
robj *hval;
|
||||
dictEntry *de;
|
||||
|
||||
/* Find value if already present in hash */
|
||||
de = dictFind(o->ptr,c->argv[2]);
|
||||
if (de != NULL) {
|
||||
hval = dictGetEntryVal(de);
|
||||
if (hval->encoding == REDIS_ENCODING_RAW)
|
||||
value = strtoll(hval->ptr,NULL,10);
|
||||
else if (hval->encoding == REDIS_ENCODING_INT)
|
||||
value = (long)hval->ptr;
|
||||
else
|
||||
redisAssert(1 != 1);
|
||||
}
|
||||
|
||||
value += incr;
|
||||
hval = createObject(REDIS_STRING,sdscatprintf(sdsempty(),"%lld",value));
|
||||
tryObjectEncoding(hval);
|
||||
if (dictReplace(o->ptr,c->argv[2],hval)) {
|
||||
incrRefCount(c->argv[2]);
|
||||
}
|
||||
}
|
||||
|
||||
server.dirty++;
|
||||
addReplyLong(c, value);
|
||||
}
|
||||
|
||||
static void hgetCommand(redisClient *c) {
|
||||
robj *o;
|
||||
|
||||
|
@ -1697,6 +1697,53 @@ proc main {server port} {
|
||||
$r debug object smallhash
|
||||
} {*hashtable*}
|
||||
|
||||
test {HINCRBY against non existing database key} {
|
||||
$r del htest
|
||||
list [$r hincrby htest foo 2]
|
||||
} {2}
|
||||
|
||||
test {HINCRBY against non existing hash key} {
|
||||
set rv {}
|
||||
$r hdel smallhash tmp
|
||||
$r hdel bighash tmp
|
||||
lappend rv [$r hincrby smallhash tmp 2]
|
||||
lappend rv [$r hget smallhash tmp]
|
||||
lappend rv [$r hincrby bighash tmp 2]
|
||||
lappend rv [$r hget bighash tmp]
|
||||
} {2 2 2 2}
|
||||
|
||||
test {HINCRBY against hash key created by hincrby itself} {
|
||||
set rv {}
|
||||
lappend rv [$r hincrby smallhash tmp 3]
|
||||
lappend rv [$r hget smallhash tmp]
|
||||
lappend rv [$r hincrby bighash tmp 3]
|
||||
lappend rv [$r hget bighash tmp]
|
||||
} {5 5 5 5}
|
||||
|
||||
test {HINCRBY against hash key originally set with HSET} {
|
||||
$r hset smallhash tmp 100
|
||||
$r hset bighash tmp 100
|
||||
list [$r hincrby smallhash tmp 2] [$r hincrby bighash tmp 2]
|
||||
} {102 102}
|
||||
|
||||
test {HINCRBY over 32bit value} {
|
||||
$r hset smallhash tmp 17179869184
|
||||
$r hset bighash tmp 17179869184
|
||||
list [$r hincrby smallhash tmp 1] [$r hincrby bighash tmp 1]
|
||||
} {17179869185 17179869185}
|
||||
|
||||
test {HINCRBY over 32bit value with over 32bit increment} {
|
||||
$r hset smallhash tmp 17179869184
|
||||
$r hset bighash tmp 17179869184
|
||||
list [$r hincrby smallhash tmp 17179869184] [$r hincrby bighash tmp 17179869184]
|
||||
} {34359738368 34359738368}
|
||||
|
||||
test {HINCRBY against key with spaces (no integer encoded)} {
|
||||
$r hset smallhash tmp " 11 "
|
||||
$r hset bighash tmp " 11 "
|
||||
list [$r hincrby smallhash tmp 1] [$r hincrby bighash tmp 1]
|
||||
} {12 12}
|
||||
|
||||
# TODO:
|
||||
# Randomized test, small and big
|
||||
# .rdb / AOF consistency test should include hashes
|
||||
|
Loading…
Reference in New Issue
Block a user