Commit 70b4b320 authored by Pieter Noordhuis's avatar Pieter Noordhuis
Browse files

check if the list encoding needs to be changed on LPUSHX, RPUSHX, LINSERT

parent 244b873b
...@@ -4926,7 +4926,7 @@ static void listTypePush(robj *subject, robj *value, int where) { ...@@ -4926,7 +4926,7 @@ static void listTypePush(robj *subject, robj *value, int where) {
/* Check if we need to convert the ziplist */ /* Check if we need to convert the ziplist */
listTypeTryConversion(subject,value); listTypeTryConversion(subject,value);
if (subject->encoding == REDIS_ENCODING_ZIPLIST && if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
ziplistLen(subject->ptr) > server.list_max_ziplist_entries) ziplistLen(subject->ptr) >= server.list_max_ziplist_entries)
listTypeConvert(subject,REDIS_ENCODING_LIST); listTypeConvert(subject,REDIS_ENCODING_LIST);
if (subject->encoding == REDIS_ENCODING_ZIPLIST) { if (subject->encoding == REDIS_ENCODING_ZIPLIST) {
...@@ -5214,6 +5214,7 @@ static void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int whe ...@@ -5214,6 +5214,7 @@ static void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int whe
robj *subject; robj *subject;
listTypeIterator *iter; listTypeIterator *iter;
listTypeEntry entry; listTypeEntry entry;
int inserted = 0;
if ((subject = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL || if ((subject = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
checkType(c,subject,REDIS_LIST)) return; checkType(c,subject,REDIS_LIST)) return;
...@@ -5227,20 +5228,36 @@ static void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int whe ...@@ -5227,20 +5228,36 @@ static void pushxGenericCommand(redisClient *c, robj *refval, robj *val, int whe
* last argument of the multi-bulk LINSERT. */ * last argument of the multi-bulk LINSERT. */
redisAssert(refval->encoding == REDIS_ENCODING_RAW); redisAssert(refval->encoding == REDIS_ENCODING_RAW);
/* We're not sure if this value can be inserted yet, but we cannot
* convert the list inside the iterator. We don't want to loop over
* the list twice (once to see if the value can be inserted and once
* to do the actual insert), so we assume this value can be inserted
* and convert the ziplist to a regular list if necessary. */
listTypeTryConversion(subject,val);
/* Seek refval from head to tail */ /* Seek refval from head to tail */
iter = listTypeInitIterator(subject,0,REDIS_TAIL); iter = listTypeInitIterator(subject,0,REDIS_TAIL);
while (listTypeNext(iter,&entry)) { while (listTypeNext(iter,&entry)) {
if (listTypeEqual(&entry,refval)) { if (listTypeEqual(&entry,refval)) {
listTypeInsert(&entry,val,where); listTypeInsert(&entry,val,where);
inserted = 1;
break; break;
} }
} }
listTypeReleaseIterator(iter); listTypeReleaseIterator(iter);
if (inserted) {
/* Check if the length exceeds the ziplist length threshold. */
if (subject->encoding == REDIS_ENCODING_ZIPLIST &&
ziplistLen(subject->ptr) > server.list_max_ziplist_entries)
listTypeConvert(subject,REDIS_ENCODING_LIST);
server.dirty++;
}
} else { } else {
listTypePush(subject,val,where); listTypePush(subject,val,where);
server.dirty++;
} }
server.dirty++;
addReplyUlong(c,listTypeLength(subject)); addReplyUlong(c,listTypeLength(subject));
} }
......
...@@ -52,17 +52,50 @@ start_server { ...@@ -52,17 +52,50 @@ start_server {
assert_equal $large_value [r lindex mylist2 2] assert_equal $large_value [r lindex mylist2 2]
} }
test {LPUSHX, RPUSHX, LPUSHXAFTER, RPUSHXAFTER - ziplist} { test {DEL a list - ziplist} {
assert_equal 1 [r del myziplist2]
assert_equal 0 [r exists myziplist2]
assert_equal 0 [r llen myziplist2]
}
test {DEL a list - regular list} {
assert_equal 1 [r del mylist2]
assert_equal 0 [r exists mylist2]
assert_equal 0 [r llen mylist2]
}
proc create_ziplist {key entries} {
r del $key
foreach entry $entries { r rpush $key $entry }
assert_encoding ziplist $key
}
proc create_list {key entries} {
r del $key
r rpush $key "aaaaaaaaaaaaaaaaa"
foreach entry $entries { r rpush $key $entry }
assert_equal "aaaaaaaaaaaaaaaaa" [r lpop $key]
assert_encoding list $key
}
test {LPUSHX, RPUSHX - generic} {
r del xlist r del xlist
assert_equal 0 [r lpushx xlist a] assert_equal 0 [r lpushx xlist a]
assert_equal 0 [r llen xlist]
assert_equal 0 [r rpushx xlist a] assert_equal 0 [r rpushx xlist a]
assert_equal 1 [r rpush xlist b] assert_equal 0 [r llen xlist]
assert_equal 2 [r rpush xlist c] }
foreach type {ziplist list} {
test "LPUSHX, RPUSHX - $type" {
create_$type xlist {b c}
assert_equal 3 [r rpushx xlist d] assert_equal 3 [r rpushx xlist d]
assert_equal 4 [r lpushx xlist a] assert_equal 4 [r lpushx xlist a]
assert_encoding ziplist xlist assert_equal {a b c d} [r lrange xlist 0 -1]
assert_equal {a b c d} [r lrange xlist 0 10] }
test "LINSERT - $type" {
create_$type xlist {a b c d}
assert_equal 5 [r linsert xlist before c zz] assert_equal 5 [r linsert xlist before c zz]
assert_equal {a b zz c d} [r lrange xlist 0 10] assert_equal {a b zz c d} [r lrange xlist 0 10]
assert_equal 6 [r linsert xlist after c yy] assert_equal 6 [r linsert xlist after c yy]
...@@ -73,61 +106,59 @@ start_server { ...@@ -73,61 +106,59 @@ start_server {
assert_equal 8 [r linsert xlist before a aa] assert_equal 8 [r linsert xlist before a aa]
assert_equal 8 [r linsert xlist before bad aaa] assert_equal 8 [r linsert xlist before bad aaa]
assert_equal {aa a b zz c yy d dd} [r lrange xlist 0 10] assert_equal {aa a b zz c yy d dd} [r lrange xlist 0 10]
# check inserting integer encoded value
assert_equal 9 [r linsert xlist before aa 42] assert_equal 9 [r linsert xlist before aa 42]
assert_equal 42 [r lrange xlist 0 0] assert_equal 42 [r lrange xlist 0 0]
} }
}
test {LPUSHX, RPUSHX, LPUSHXAFTER, RPUSHXAFTER - regular list} { test {LPUSHX, RPUSHX convert from ziplist to list} {
set large_value "aaaaaaaaaaaaaaaaa" set large_value "aaaaaaaaaaaaaaaaa"
r del xlist # convert when a large value is pushed
assert_equal 0 [r lpushx xlist a] create_ziplist xlist a
assert_equal 0 [r rpushx xlist a] assert_equal 2 [r rpushx xlist $large_value]
assert_equal 1 [r rpush xlist $large_value] assert_encoding list xlist
assert_equal 2 [r rpush xlist c] create_ziplist xlist a
assert_equal 3 [r rpushx xlist d] assert_equal 2 [r lpushx xlist $large_value]
assert_equal 4 [r lpushx xlist a]
assert_encoding list xlist assert_encoding list xlist
assert_equal {a aaaaaaaaaaaaaaaaa c d} [r lrange xlist 0 10]
assert_equal 5 [r linsert xlist before c zz] # convert when the length threshold is exceeded
assert_equal {a aaaaaaaaaaaaaaaaa zz c d} [r lrange xlist 0 10] create_ziplist xlist [lrepeat 256 a]
assert_equal 6 [r linsert xlist after c yy] assert_equal 257 [r rpushx xlist b]
assert_equal {a aaaaaaaaaaaaaaaaa zz c yy d} [r lrange xlist 0 10] assert_encoding list xlist
assert_equal 7 [r linsert xlist after d dd] create_ziplist xlist [lrepeat 256 a]
assert_equal 7 [r linsert xlist after bad ddd] assert_equal 257 [r lpushx xlist b]
assert_equal {a aaaaaaaaaaaaaaaaa zz c yy d dd} [r lrange xlist 0 10] assert_encoding list xlist
assert_equal 8 [r linsert xlist before a aa]
assert_equal 8 [r linsert xlist before bad aaa]
assert_equal {aa a aaaaaaaaaaaaaaaaa zz c yy d dd} [r lrange xlist 0 10]
assert_equal 9 [r linsert xlist before aa 42]
assert_equal 42 [r lrange xlist 0 0]
} }
test {DEL a list - ziplist} { test {LINSERT convert from ziplist to list} {
assert_equal 1 [r del myziplist2] set large_value "aaaaaaaaaaaaaaaaa"
assert_equal 0 [r exists myziplist2]
assert_equal 0 [r llen myziplist2]
}
test {DEL a list - regular list} { # convert when a large value is inserted
assert_equal 1 [r del mylist2] create_ziplist xlist a
assert_equal 0 [r exists mylist2] assert_equal 2 [r linsert xlist before a $large_value]
assert_equal 0 [r llen mylist2] assert_encoding list xlist
} create_ziplist xlist a
assert_equal 2 [r linsert xlist after a $large_value]
assert_encoding list xlist
proc create_ziplist {key entries} { # convert when the length threshold is exceeded
r del $key create_ziplist xlist [lrepeat 256 a]
foreach entry $entries { r rpush $key $entry } assert_equal 257 [r linsert xlist before a a]
assert_encoding ziplist $key assert_encoding list xlist
} create_ziplist xlist [lrepeat 256 a]
assert_equal 257 [r linsert xlist after a a]
assert_encoding list xlist
proc create_list {key entries} { # don't convert when the value could not be inserted
r del $key create_ziplist xlist [lrepeat 256 a]
r rpush $key "aaaaaaaaaaaaaaaaa" assert_equal 256 [r linsert xlist before foo a]
foreach entry $entries { r rpush $key $entry } assert_encoding ziplist xlist
assert_equal "aaaaaaaaaaaaaaaaa" [r lpop $key] create_ziplist xlist [lrepeat 256 a]
assert_encoding list $key assert_equal 256 [r linsert xlist after foo a]
assert_encoding ziplist xlist
} }
foreach {type num} {ziplist 250 list 500} { foreach {type num} {ziplist 250 list 500} {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment