Migrate ziplist.c unit tests to new framework (#486)

Issue #428.

Moved the SERVER_TEST block from ziplist.c into unit tests in
test_ziplist.c. I left the benchmark related tasks alone in their own
test, as I am not sure what to do with them.

Some of the assertions are a little vague/useless, but I will try to
refine them.

---------

Signed-off-by: Mason Hall <hallmason17@gmail.com>
This commit is contained in:
Mason Hall 2024-05-21 20:54:09 -04:00 committed by GitHub
parent 005a018db6
commit 72538622ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 1087 additions and 984 deletions

View File

@ -6929,7 +6929,6 @@ struct serverTest {
serverTestProc *proc;
int failed;
} serverTests[] = {
{"ziplist", ziplistTest},
{"quicklist", quicklistTest},
{"zipmap", zipmapTest},
{"dict", dictTest},

View File

@ -30,6 +30,42 @@ int test_ll2string(int argc, char **argv, int flags);
int test_ld2string(int argc, char **argv, int flags);
int test_fixedpoint_d2string(int argc, char **argv, int flags);
int test_reclaimFilePageCache(int argc, char **argv, int flags);
int test_ziplistCreateIntList(int argc, char **argv, int flags);
int test_ziplistPop(int argc, char **argv, int flags);
int test_ziplistGetElementAtIndex3(int argc, char **argv, int flags);
int test_ziplistGetElementOutOfRange(int argc, char **argv, int flags);
int test_ziplistGetLastElement(int argc, char **argv, int flags);
int test_ziplistGetFirstElement(int argc, char **argv, int flags);
int test_ziplistGetElementOutOfRangeReverse(int argc, char **argv, int flags);
int test_ziplistIterateThroughFullList(int argc, char **argv, int flags);
int test_ziplistIterateThroughListFrom1ToEnd(int argc, char **argv, int flags);
int test_ziplistIterateThroughListFrom2ToEnd(int argc, char **argv, int flags);
int test_ziplistIterateThroughStartOutOfRange(int argc, char **argv, int flags);
int test_ziplistIterateBackToFront(int argc, char **argv, int flags);
int test_ziplistIterateBackToFrontDeletingAllItems(int argc, char **argv, int flags);
int test_ziplistDeleteInclusiveRange0To0(int argc, char **argv, int flags);
int test_ziplistDeleteInclusiveRange0To1(int argc, char **argv, int flags);
int test_ziplistDeleteInclusiveRange1To2(int argc, char **argv, int flags);
int test_ziplistDeleteWithStartIndexOutOfRange(int argc, char **argv, int flags);
int test_ziplistDeleteWithNumOverflow(int argc, char **argv, int flags);
int test_ziplistDeleteFooWhileIterating(int argc, char **argv, int flags);
int test_ziplistReplaceWithSameSize(int argc, char **argv, int flags);
int test_ziplistReplaceWithDifferentSize(int argc, char **argv, int flags);
int test_ziplistRegressionTestForOver255ByteStrings(int argc, char **argv, int flags);
int test_ziplistRegressionTestDeleteNextToLastEntries(int argc, char **argv, int flags);
int test_ziplistCreateLongListAndCheckIndices(int argc, char **argv, int flags);
int test_ziplistCompareStringWithZiplistEntries(int argc, char **argv, int flags);
int test_ziplistMergeTest(int argc, char **argv, int flags);
int test_ziplistStressWithRandomPayloadsOfDifferentEncoding(int argc, char **argv, int flags);
int test_ziplistCascadeUpdateEdgeCases(int argc, char **argv, int flags);
int test_ziplistInsertEdgeCase(int argc, char **argv, int flags);
int test_ziplistStressWithVariableSize(int argc, char **argv, int flags);
int test_BenchmarkziplistFind(int argc, char **argv, int flags);
int test_BenchmarkziplistIndex(int argc, char **argv, int flags);
int test_BenchmarkziplistValidateIntegrity(int argc, char **argv, int flags);
int test_BenchmarkziplistCompareWithString(int argc, char **argv, int flags);
int test_BenchmarkziplistCompareWithNumber(int argc, char **argv, int flags);
int test_ziplistStress__ziplistCascadeUpdate(int argc, char **argv, int flags);
int test_zmallocInitialUsedMemory(int argc, char **argv, int flags);
int test_zmallocAllocReallocCallocAndFree(int argc, char **argv, int flags);
int test_zmallocAllocZeroByteAndFree(int argc, char **argv, int flags);
@ -42,6 +78,7 @@ unitTest __test_kvstore_c[] = {{"test_kvstoreAdd16Keys", test_kvstoreAdd16Keys},
unitTest __test_sds_c[] = {{"test_sds", test_sds}, {NULL, NULL}};
unitTest __test_sha1_c[] = {{"test_sha1", test_sha1}, {NULL, NULL}};
unitTest __test_util_c[] = {{"test_string2ll", test_string2ll}, {"test_string2l", test_string2l}, {"test_ll2string", test_ll2string}, {"test_ld2string", test_ld2string}, {"test_fixedpoint_d2string", test_fixedpoint_d2string}, {"test_reclaimFilePageCache", test_reclaimFilePageCache}, {NULL, NULL}};
unitTest __test_ziplist_c[] = {{"test_ziplistCreateIntList", test_ziplistCreateIntList}, {"test_ziplistPop", test_ziplistPop}, {"test_ziplistGetElementAtIndex3", test_ziplistGetElementAtIndex3}, {"test_ziplistGetElementOutOfRange", test_ziplistGetElementOutOfRange}, {"test_ziplistGetLastElement", test_ziplistGetLastElement}, {"test_ziplistGetFirstElement", test_ziplistGetFirstElement}, {"test_ziplistGetElementOutOfRangeReverse", test_ziplistGetElementOutOfRangeReverse}, {"test_ziplistIterateThroughFullList", test_ziplistIterateThroughFullList}, {"test_ziplistIterateThroughListFrom1ToEnd", test_ziplistIterateThroughListFrom1ToEnd}, {"test_ziplistIterateThroughListFrom2ToEnd", test_ziplistIterateThroughListFrom2ToEnd}, {"test_ziplistIterateThroughStartOutOfRange", test_ziplistIterateThroughStartOutOfRange}, {"test_ziplistIterateBackToFront", test_ziplistIterateBackToFront}, {"test_ziplistIterateBackToFrontDeletingAllItems", test_ziplistIterateBackToFrontDeletingAllItems}, {"test_ziplistDeleteInclusiveRange0To0", test_ziplistDeleteInclusiveRange0To0}, {"test_ziplistDeleteInclusiveRange0To1", test_ziplistDeleteInclusiveRange0To1}, {"test_ziplistDeleteInclusiveRange1To2", test_ziplistDeleteInclusiveRange1To2}, {"test_ziplistDeleteWithStartIndexOutOfRange", test_ziplistDeleteWithStartIndexOutOfRange}, {"test_ziplistDeleteWithNumOverflow", test_ziplistDeleteWithNumOverflow}, {"test_ziplistDeleteFooWhileIterating", test_ziplistDeleteFooWhileIterating}, {"test_ziplistReplaceWithSameSize", test_ziplistReplaceWithSameSize}, {"test_ziplistReplaceWithDifferentSize", test_ziplistReplaceWithDifferentSize}, {"test_ziplistRegressionTestForOver255ByteStrings", test_ziplistRegressionTestForOver255ByteStrings}, {"test_ziplistRegressionTestDeleteNextToLastEntries", test_ziplistRegressionTestDeleteNextToLastEntries}, {"test_ziplistCreateLongListAndCheckIndices", test_ziplistCreateLongListAndCheckIndices}, {"test_ziplistCompareStringWithZiplistEntries", test_ziplistCompareStringWithZiplistEntries}, {"test_ziplistMergeTest", test_ziplistMergeTest}, {"test_ziplistStressWithRandomPayloadsOfDifferentEncoding", test_ziplistStressWithRandomPayloadsOfDifferentEncoding}, {"test_ziplistCascadeUpdateEdgeCases", test_ziplistCascadeUpdateEdgeCases}, {"test_ziplistInsertEdgeCase", test_ziplistInsertEdgeCase}, {"test_ziplistStressWithVariableSize", test_ziplistStressWithVariableSize}, {"test_BenchmarkziplistFind", test_BenchmarkziplistFind}, {"test_BenchmarkziplistIndex", test_BenchmarkziplistIndex}, {"test_BenchmarkziplistValidateIntegrity", test_BenchmarkziplistValidateIntegrity}, {"test_BenchmarkziplistCompareWithString", test_BenchmarkziplistCompareWithString}, {"test_BenchmarkziplistCompareWithNumber", test_BenchmarkziplistCompareWithNumber}, {"test_ziplistStress__ziplistCascadeUpdate", test_ziplistStress__ziplistCascadeUpdate}, {NULL, NULL}};
unitTest __test_zmalloc_c[] = {{"test_zmallocInitialUsedMemory", test_zmallocInitialUsedMemory}, {"test_zmallocAllocReallocCallocAndFree", test_zmallocAllocReallocCallocAndFree}, {"test_zmallocAllocZeroByteAndFree", test_zmallocAllocZeroByteAndFree}, {NULL, NULL}};
struct unitTestSuite {
@ -56,5 +93,6 @@ struct unitTestSuite {
{"test_sds.c", __test_sds_c},
{"test_sha1.c", __test_sha1_c},
{"test_util.c", __test_util_c},
{"test_ziplist.c", __test_ziplist_c},
{"test_zmalloc.c", __test_zmalloc_c},
};

1049
src/unit/test_ziplist.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1687,982 +1687,3 @@ unsigned int ziplistRandomPairsUnique(unsigned char *zl, unsigned int count, zip
}
return picked;
}
#ifdef SERVER_TEST
#include <sys/time.h>
#include "adlist.h"
#include "sds.h"
#include "testhelp.h"
#define debug(f, ...) { if (DEBUG) printf(f, __VA_ARGS__); }
static unsigned char *createList(void) {
unsigned char *zl = ziplistNew();
zl = ziplistPush(zl, (unsigned char*)"foo", 3, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"quux", 4, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"hello", 5, ZIPLIST_HEAD);
zl = ziplistPush(zl, (unsigned char*)"1024", 4, ZIPLIST_TAIL);
return zl;
}
static unsigned char *createIntList(void) {
unsigned char *zl = ziplistNew();
char buf[32];
snprintf(buf, sizeof(buf), "100");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_TAIL);
snprintf(buf, sizeof(buf), "128000");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_TAIL);
snprintf(buf, sizeof(buf), "-100");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_HEAD);
snprintf(buf, sizeof(buf), "4294967296");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_HEAD);
snprintf(buf, sizeof(buf), "non integer");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_TAIL);
snprintf(buf,sizeof(buf), "much much longer non integer");
zl = ziplistPush(zl, (unsigned char*)buf, strlen(buf), ZIPLIST_TAIL);
return zl;
}
static long long usec(void) {
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
}
static void stress(int pos, int num, int maxsize, int dnum) {
int i,j,k;
unsigned char *zl;
char posstr[2][5] = { "HEAD", "TAIL" };
long long start;
for (i = 0; i < maxsize; i+=dnum) {
zl = ziplistNew();
for (j = 0; j < i; j++) {
zl = ziplistPush(zl,(unsigned char*)"quux",4,ZIPLIST_TAIL);
}
/* Do num times a push+pop from pos */
start = usec();
for (k = 0; k < num; k++) {
zl = ziplistPush(zl,(unsigned char*)"quux",4,pos);
zl = ziplistDeleteRange(zl,0,1);
}
printf("List size: %8d, bytes: %8d, %dx push+pop (%s): %6lld usec\n",
i,intrev32ifbe(ZIPLIST_BYTES(zl)),num,posstr[pos],usec()-start);
zfree(zl);
}
}
static unsigned char *pop(unsigned char *zl, int where) {
unsigned char *p, *vstr;
unsigned int vlen;
long long vlong = 0;
p = ziplistIndex(zl,where == ZIPLIST_HEAD ? 0 : -1);
if (ziplistGet(p,&vstr,&vlen,&vlong)) {
if (where == ZIPLIST_HEAD)
printf("Pop head: ");
else
printf("Pop tail: ");
if (vstr) {
if (vlen && fwrite(vstr,vlen,1,stdout) == 0) perror("fwrite");
}
else {
printf("%lld", vlong);
}
printf("\n");
return ziplistDelete(zl,&p);
} else {
printf("ERROR: Could not pop\n");
exit(1);
}
}
static int randstring(char *target, unsigned int min, unsigned int max) {
int p = 0;
int len = min+rand()%(max-min+1);
int minval, maxval;
switch(rand() % 3) {
case 0:
minval = 0;
maxval = 255;
break;
case 1:
minval = 48;
maxval = 122;
break;
case 2:
minval = 48;
maxval = 52;
break;
default:
assert(NULL);
}
while(p < len)
target[p++] = minval+rand()%(maxval-minval+1);
return len;
}
static void verify(unsigned char *zl, zlentry *e) {
int len = ziplistLen(zl);
zlentry _e;
ZIPLIST_ENTRY_ZERO(&_e);
for (int i = 0; i < len; i++) {
memset(&e[i], 0, sizeof(zlentry));
zipEntry(ziplistIndex(zl, i), &e[i]);
memset(&_e, 0, sizeof(zlentry));
zipEntry(ziplistIndex(zl, -len+i), &_e);
assert(memcmp(&e[i], &_e, sizeof(zlentry)) == 0);
}
}
static unsigned char *insertHelper(unsigned char *zl, char ch, size_t len, unsigned char *pos) {
assert(len <= ZIP_BIG_PREVLEN);
unsigned char data[ZIP_BIG_PREVLEN] = {0};
memset(data, ch, len);
return ziplistInsert(zl, pos, data, len);
}
static int compareHelper(unsigned char *zl, char ch, size_t len, int index) {
assert(len <= ZIP_BIG_PREVLEN);
unsigned char data[ZIP_BIG_PREVLEN] = {0};
memset(data, ch, len);
unsigned char *p = ziplistIndex(zl, index);
assert(p != NULL);
return ziplistCompare(p, data, len);
}
static size_t strEntryBytesSmall(size_t slen) {
return slen + zipStorePrevEntryLength(NULL, 0) + zipStoreEntryEncoding(NULL, 0, slen);
}
static size_t strEntryBytesLarge(size_t slen) {
return slen + zipStorePrevEntryLength(NULL, ZIP_BIG_PREVLEN) + zipStoreEntryEncoding(NULL, 0, slen);
}
/* ./valkey-server test ziplist <randomseed> */
int ziplistTest(int argc, char **argv, int flags) {
int accurate = (flags & TEST_ACCURATE);
unsigned char *zl, *p;
unsigned char *entry;
unsigned int elen;
long long value;
int iteration;
/* If an argument is given, use it as the random seed. */
if (argc >= 4)
srand(atoi(argv[3]));
zl = createIntList();
ziplistRepr(zl);
zfree(zl);
zl = createList();
ziplistRepr(zl);
zl = pop(zl,ZIPLIST_TAIL);
ziplistRepr(zl);
zl = pop(zl,ZIPLIST_HEAD);
ziplistRepr(zl);
zl = pop(zl,ZIPLIST_TAIL);
ziplistRepr(zl);
zl = pop(zl,ZIPLIST_TAIL);
ziplistRepr(zl);
zfree(zl);
printf("Get element at index 3:\n");
{
zl = createList();
p = ziplistIndex(zl, 3);
if (!ziplistGet(p, &entry, &elen, &value)) {
printf("ERROR: Could not access index 3\n");
return 1;
}
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
printf("\n");
} else {
printf("%lld\n", value);
}
printf("\n");
zfree(zl);
}
printf("Get element at index 4 (out of range):\n");
{
zl = createList();
p = ziplistIndex(zl, 4);
if (p == NULL) {
printf("No entry\n");
} else {
printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", (long)(p-zl));
return 1;
}
printf("\n");
zfree(zl);
}
printf("Get element at index -1 (last element):\n");
{
zl = createList();
p = ziplistIndex(zl, -1);
if (!ziplistGet(p, &entry, &elen, &value)) {
printf("ERROR: Could not access index -1\n");
return 1;
}
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
printf("\n");
} else {
printf("%lld\n", value);
}
printf("\n");
zfree(zl);
}
printf("Get element at index -4 (first element):\n");
{
zl = createList();
p = ziplistIndex(zl, -4);
if (!ziplistGet(p, &entry, &elen, &value)) {
printf("ERROR: Could not access index -4\n");
return 1;
}
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
printf("\n");
} else {
printf("%lld\n", value);
}
printf("\n");
zfree(zl);
}
printf("Get element at index -5 (reverse out of range):\n");
{
zl = createList();
p = ziplistIndex(zl, -5);
if (p == NULL) {
printf("No entry\n");
} else {
printf("ERROR: Out of range index should return NULL, returned offset: %ld\n", (long)(p-zl));
return 1;
}
printf("\n");
zfree(zl);
}
printf("Iterate list from 0 to end:\n");
{
zl = createList();
p = ziplistIndex(zl, 0);
while (ziplistGet(p, &entry, &elen, &value)) {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
} else {
printf("%lld", value);
}
p = ziplistNext(zl,p);
printf("\n");
}
printf("\n");
zfree(zl);
}
printf("Iterate list from 1 to end:\n");
{
zl = createList();
p = ziplistIndex(zl, 1);
while (ziplistGet(p, &entry, &elen, &value)) {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
} else {
printf("%lld", value);
}
p = ziplistNext(zl,p);
printf("\n");
}
printf("\n");
zfree(zl);
}
printf("Iterate list from 2 to end:\n");
{
zl = createList();
p = ziplistIndex(zl, 2);
while (ziplistGet(p, &entry, &elen, &value)) {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
} else {
printf("%lld", value);
}
p = ziplistNext(zl,p);
printf("\n");
}
printf("\n");
zfree(zl);
}
printf("Iterate starting out of range:\n");
{
zl = createList();
p = ziplistIndex(zl, 4);
if (!ziplistGet(p, &entry, &elen, &value)) {
printf("No entry\n");
} else {
printf("ERROR\n");
}
printf("\n");
zfree(zl);
}
printf("Iterate from back to front:\n");
{
zl = createList();
p = ziplistIndex(zl, -1);
while (ziplistGet(p, &entry, &elen, &value)) {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
} else {
printf("%lld", value);
}
p = ziplistPrev(zl,p);
printf("\n");
}
printf("\n");
zfree(zl);
}
printf("Iterate from back to front, deleting all items:\n");
{
zl = createList();
p = ziplistIndex(zl, -1);
while (ziplistGet(p, &entry, &elen, &value)) {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0) perror("fwrite");
} else {
printf("%lld", value);
}
zl = ziplistDelete(zl,&p);
p = ziplistPrev(zl,p);
printf("\n");
}
printf("\n");
zfree(zl);
}
printf("Delete inclusive range 0,0:\n");
{
zl = createList();
zl = ziplistDeleteRange(zl, 0, 1);
ziplistRepr(zl);
zfree(zl);
}
printf("Delete inclusive range 0,1:\n");
{
zl = createList();
zl = ziplistDeleteRange(zl, 0, 2);
ziplistRepr(zl);
zfree(zl);
}
printf("Delete inclusive range 1,2:\n");
{
zl = createList();
zl = ziplistDeleteRange(zl, 1, 2);
ziplistRepr(zl);
zfree(zl);
}
printf("Delete with start index out of range:\n");
{
zl = createList();
zl = ziplistDeleteRange(zl, 5, 1);
ziplistRepr(zl);
zfree(zl);
}
printf("Delete with num overflow:\n");
{
zl = createList();
zl = ziplistDeleteRange(zl, 1, 5);
ziplistRepr(zl);
zfree(zl);
}
printf("Delete foo while iterating:\n");
{
zl = createList();
p = ziplistIndex(zl,0);
while (ziplistGet(p,&entry,&elen,&value)) {
if (entry && strncmp("foo",(char*)entry,elen) == 0) {
printf("Delete foo\n");
zl = ziplistDelete(zl,&p);
} else {
printf("Entry: ");
if (entry) {
if (elen && fwrite(entry,elen,1,stdout) == 0)
perror("fwrite");
} else {
printf("%lld",value);
}
p = ziplistNext(zl,p);
printf("\n");
}
}
printf("\n");
ziplistRepr(zl);
zfree(zl);
}
printf("Replace with same size:\n");
{
zl = createList(); /* "hello", "foo", "quux", "1024" */
unsigned char *orig_zl = zl;
p = ziplistIndex(zl, 0);
zl = ziplistReplace(zl, p, (unsigned char*)"zoink", 5);
p = ziplistIndex(zl, 3);
zl = ziplistReplace(zl, p, (unsigned char*)"yy", 2);
p = ziplistIndex(zl, 1);
zl = ziplistReplace(zl, p, (unsigned char*)"65536", 5);
p = ziplistIndex(zl, 0);
assert(!memcmp((char*)p,
"\x00\x05zoink"
"\x07\xf0\x00\x00\x01" /* 65536 as int24 */
"\x05\x04quux" "\x06\x02yy" "\xff",
23));
assert(zl == orig_zl); /* no reallocations have happened */
zfree(zl);
printf("SUCCESS\n\n");
}
printf("Replace with different size:\n");
{
zl = createList(); /* "hello", "foo", "quux", "1024" */
p = ziplistIndex(zl, 1);
zl = ziplistReplace(zl, p, (unsigned char*)"squirrel", 8);
p = ziplistIndex(zl, 0);
assert(!strncmp((char*)p,
"\x00\x05hello" "\x07\x08squirrel" "\x0a\x04quux"
"\x06\xc0\x00\x04" "\xff",
28));
zfree(zl);
printf("SUCCESS\n\n");
}
printf("Regression test for >255 byte strings:\n");
{
char v1[257] = {0}, v2[257] = {0};
memset(v1,'x',256);
memset(v2,'y',256);
zl = ziplistNew();
zl = ziplistPush(zl,(unsigned char*)v1,strlen(v1),ZIPLIST_TAIL);
zl = ziplistPush(zl,(unsigned char*)v2,strlen(v2),ZIPLIST_TAIL);
/* Pop values again and compare their value. */
p = ziplistIndex(zl,0);
assert(ziplistGet(p,&entry,&elen,&value));
assert(strncmp(v1,(char*)entry,elen) == 0);
p = ziplistIndex(zl,1);
assert(ziplistGet(p,&entry,&elen,&value));
assert(strncmp(v2,(char*)entry,elen) == 0);
printf("SUCCESS\n\n");
zfree(zl);
}
printf("Regression test deleting next to last entries:\n");
{
char v[3][257] = {{0}};
zlentry e[3] = {{.prevrawlensize = 0, .prevrawlen = 0, .lensize = 0,
.len = 0, .headersize = 0, .encoding = 0, .p = NULL}};
size_t i;
for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) {
memset(v[i], 'a' + i, sizeof(v[0]));
}
v[0][256] = '\0';
v[1][ 1] = '\0';
v[2][256] = '\0';
zl = ziplistNew();
for (i = 0; i < (sizeof(v)/sizeof(v[0])); i++) {
zl = ziplistPush(zl, (unsigned char *) v[i], strlen(v[i]), ZIPLIST_TAIL);
}
verify(zl, e);
assert(e[0].prevrawlensize == 1);
assert(e[1].prevrawlensize == 5);
assert(e[2].prevrawlensize == 1);
/* Deleting entry 1 will increase `prevrawlensize` for entry 2 */
unsigned char *p = e[1].p;
zl = ziplistDelete(zl, &p);
verify(zl, e);
assert(e[0].prevrawlensize == 1);
assert(e[1].prevrawlensize == 5);
printf("SUCCESS\n\n");
zfree(zl);
}
printf("Create long list and check indices:\n");
{
unsigned long long start = usec();
zl = ziplistNew();
char buf[32];
int i,len;
for (i = 0; i < 1000; i++) {
len = snprintf(buf,sizeof(buf),"%d",i);
zl = ziplistPush(zl,(unsigned char*)buf,len,ZIPLIST_TAIL);
}
for (i = 0; i < 1000; i++) {
p = ziplistIndex(zl,i);
assert(ziplistGet(p,NULL,NULL,&value));
assert(i == value);
p = ziplistIndex(zl,-i-1);
assert(ziplistGet(p,NULL,NULL,&value));
assert(999-i == value);
}
printf("SUCCESS. usec=%lld\n\n", usec()-start);
zfree(zl);
}
printf("Compare strings with ziplist entries:\n");
{
zl = createList();
p = ziplistIndex(zl,0);
if (!ziplistCompare(p,(unsigned char*)"hello",5)) {
printf("ERROR: not \"hello\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"hella",5)) {
printf("ERROR: \"hella\"\n");
return 1;
}
p = ziplistIndex(zl,3);
if (!ziplistCompare(p,(unsigned char*)"1024",4)) {
printf("ERROR: not \"1024\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"1025",4)) {
printf("ERROR: \"1025\"\n");
return 1;
}
printf("SUCCESS\n\n");
zfree(zl);
}
printf("Merge test:\n");
{
/* create list gives us: [hello, foo, quux, 1024] */
zl = createList();
unsigned char *zl2 = createList();
unsigned char *zl3 = ziplistNew();
unsigned char *zl4 = ziplistNew();
if (ziplistMerge(&zl4, &zl4)) {
printf("ERROR: Allowed merging of one ziplist into itself.\n");
return 1;
}
/* Merge two empty ziplists, get empty result back. */
zl4 = ziplistMerge(&zl3, &zl4);
ziplistRepr(zl4);
if (ziplistLen(zl4)) {
printf("ERROR: Merging two empty ziplists created entries.\n");
return 1;
}
zfree(zl4);
zl2 = ziplistMerge(&zl, &zl2);
/* merge gives us: [hello, foo, quux, 1024, hello, foo, quux, 1024] */
ziplistRepr(zl2);
if (ziplistLen(zl2) != 8) {
printf("ERROR: Merged length not 8, but: %u\n", ziplistLen(zl2));
return 1;
}
p = ziplistIndex(zl2,0);
if (!ziplistCompare(p,(unsigned char*)"hello",5)) {
printf("ERROR: not \"hello\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"hella",5)) {
printf("ERROR: \"hella\"\n");
return 1;
}
p = ziplistIndex(zl2,3);
if (!ziplistCompare(p,(unsigned char*)"1024",4)) {
printf("ERROR: not \"1024\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"1025",4)) {
printf("ERROR: \"1025\"\n");
return 1;
}
p = ziplistIndex(zl2,4);
if (!ziplistCompare(p,(unsigned char*)"hello",5)) {
printf("ERROR: not \"hello\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"hella",5)) {
printf("ERROR: \"hella\"\n");
return 1;
}
p = ziplistIndex(zl2,7);
if (!ziplistCompare(p,(unsigned char*)"1024",4)) {
printf("ERROR: not \"1024\"\n");
return 1;
}
if (ziplistCompare(p,(unsigned char*)"1025",4)) {
printf("ERROR: \"1025\"\n");
return 1;
}
printf("SUCCESS\n\n");
zfree(zl);
}
printf("Stress with random payloads of different encoding:\n");
{
unsigned long long start = usec();
int i,j,len,where;
unsigned char *p;
char buf[1024];
int buflen;
list *ref;
listNode *refnode;
/* Hold temp vars from ziplist */
unsigned char *sstr;
unsigned int slen;
long long sval;
iteration = accurate ? 20000 : 20;
for (i = 0; i < iteration; i++) {
zl = ziplistNew();
ref = listCreate();
listSetFreeMethod(ref,(void (*)(void*))sdsfree);
len = rand() % 256;
/* Create lists */
for (j = 0; j < len; j++) {
where = (rand() & 1) ? ZIPLIST_HEAD : ZIPLIST_TAIL;
if (rand() % 2) {
buflen = randstring(buf,1,sizeof(buf)-1);
} else {
switch(rand() % 3) {
case 0:
buflen = snprintf(buf,sizeof(buf),"%lld",(0LL + rand()) >> 20);
break;
case 1:
buflen = snprintf(buf,sizeof(buf),"%lld",(0LL + rand()));
break;
case 2:
buflen = snprintf(buf,sizeof(buf),"%lld",(0LL + rand()) << 20);
break;
default:
assert(NULL);
}
}
/* Add to ziplist */
zl = ziplistPush(zl, (unsigned char*)buf, buflen, where);
/* Add to reference list */
if (where == ZIPLIST_HEAD) {
listAddNodeHead(ref,sdsnewlen(buf, buflen));
} else if (where == ZIPLIST_TAIL) {
listAddNodeTail(ref,sdsnewlen(buf, buflen));
} else {
assert(NULL);
}
}
assert(listLength(ref) == ziplistLen(zl));
for (j = 0; j < len; j++) {
/* Naive way to get elements, but similar to the stresser
* executed from the Tcl test suite. */
p = ziplistIndex(zl,j);
refnode = listIndex(ref,j);
assert(ziplistGet(p,&sstr,&slen,&sval));
if (sstr == NULL) {
buflen = snprintf(buf,sizeof(buf),"%lld",sval);
} else {
buflen = slen;
memcpy(buf,sstr,buflen);
buf[buflen] = '\0';
}
assert(memcmp(buf,listNodeValue(refnode),buflen) == 0);
}
zfree(zl);
listRelease(ref);
}
printf("Done. usec=%lld\n\n", usec()-start);
}
printf("Stress with variable ziplist size:\n");
{
unsigned long long start = usec();
int maxsize = accurate ? 16384 : 16;
stress(ZIPLIST_HEAD,100000,maxsize,256);
stress(ZIPLIST_TAIL,100000,maxsize,256);
printf("Done. usec=%lld\n\n", usec()-start);
}
/* Benchmarks */
{
zl = ziplistNew();
iteration = accurate ? 100000 : 100;
for (int i=0; i<iteration; i++) {
char buf[4096] = "asdf";
zl = ziplistPush(zl, (unsigned char*)buf, 4, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)buf, 40, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)buf, 400, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)buf, 4000, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"1", 1, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"10", 2, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"100", 3, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"1000", 4, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"10000", 5, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"100000", 6, ZIPLIST_TAIL);
}
printf("Benchmark ziplistFind:\n");
{
unsigned long long start = usec();
for (int i = 0; i < 2000; i++) {
unsigned char *fptr = ziplistIndex(zl, ZIPLIST_HEAD);
fptr = ziplistFind(zl, fptr, (unsigned char*)"nothing", 7, 1);
}
printf("%lld\n", usec()-start);
}
printf("Benchmark ziplistIndex:\n");
{
unsigned long long start = usec();
for (int i = 0; i < 2000; i++) {
ziplistIndex(zl, 99999);
}
printf("%lld\n", usec()-start);
}
printf("Benchmark ziplistValidateIntegrity:\n");
{
unsigned long long start = usec();
for (int i = 0; i < 2000; i++) {
ziplistValidateIntegrity(zl, ziplistBlobLen(zl), 1, NULL, NULL);
}
printf("%lld\n", usec()-start);
}
printf("Benchmark ziplistCompare with string\n");
{
unsigned long long start = usec();
for (int i = 0; i < 2000; i++) {
unsigned char *eptr = ziplistIndex(zl,0);
while (eptr != NULL) {
ziplistCompare(eptr,(unsigned char*)"nothing",7);
eptr = ziplistNext(zl,eptr);
}
}
printf("Done. usec=%lld\n", usec()-start);
}
printf("Benchmark ziplistCompare with number\n");
{
unsigned long long start = usec();
for (int i = 0; i < 2000; i++) {
unsigned char *eptr = ziplistIndex(zl,0);
while (eptr != NULL) {
ziplistCompare(eptr,(unsigned char*)"99999",5);
eptr = ziplistNext(zl,eptr);
}
}
printf("Done. usec=%lld\n", usec()-start);
}
zfree(zl);
}
printf("Stress __ziplistCascadeUpdate:\n");
{
char data[ZIP_BIG_PREVLEN];
zl = ziplistNew();
iteration = accurate ? 100000 : 100;
for (int i = 0; i < iteration; i++) {
zl = ziplistPush(zl, (unsigned char*)data, ZIP_BIG_PREVLEN-4, ZIPLIST_TAIL);
}
unsigned long long start = usec();
zl = ziplistPush(zl, (unsigned char*)data, ZIP_BIG_PREVLEN-3, ZIPLIST_HEAD);
printf("Done. usec=%lld\n\n", usec()-start);
zfree(zl);
}
printf("Edge cases of __ziplistCascadeUpdate:\n");
{
/* Inserting a entry with data length greater than ZIP_BIG_PREVLEN-4
* will leads to cascade update. */
size_t s1 = ZIP_BIG_PREVLEN-4, s2 = ZIP_BIG_PREVLEN-3;
zl = ziplistNew();
zlentry e[4] = {{.prevrawlensize = 0, .prevrawlen = 0, .lensize = 0,
.len = 0, .headersize = 0, .encoding = 0, .p = NULL}};
zl = insertHelper(zl, 'a', s1, ZIPLIST_ENTRY_HEAD(zl));
verify(zl, e);
assert(e[0].prevrawlensize == 1 && e[0].prevrawlen == 0);
assert(compareHelper(zl, 'a', s1, 0));
ziplistRepr(zl);
/* No expand. */
zl = insertHelper(zl, 'b', s1, ZIPLIST_ENTRY_HEAD(zl));
verify(zl, e);
assert(e[0].prevrawlensize == 1 && e[0].prevrawlen == 0);
assert(compareHelper(zl, 'b', s1, 0));
assert(e[1].prevrawlensize == 1 && e[1].prevrawlen == strEntryBytesSmall(s1));
assert(compareHelper(zl, 'a', s1, 1));
ziplistRepr(zl);
/* Expand(tail included). */
zl = insertHelper(zl, 'c', s2, ZIPLIST_ENTRY_HEAD(zl));
verify(zl, e);
assert(e[0].prevrawlensize == 1 && e[0].prevrawlen == 0);
assert(compareHelper(zl, 'c', s2, 0));
assert(e[1].prevrawlensize == 5 && e[1].prevrawlen == strEntryBytesSmall(s2));
assert(compareHelper(zl, 'b', s1, 1));
assert(e[2].prevrawlensize == 5 && e[2].prevrawlen == strEntryBytesLarge(s1));
assert(compareHelper(zl, 'a', s1, 2));
ziplistRepr(zl);
/* Expand(only previous head entry). */
zl = insertHelper(zl, 'd', s2, ZIPLIST_ENTRY_HEAD(zl));
verify(zl, e);
assert(e[0].prevrawlensize == 1 && e[0].prevrawlen == 0);
assert(compareHelper(zl, 'd', s2, 0));
assert(e[1].prevrawlensize == 5 && e[1].prevrawlen == strEntryBytesSmall(s2));
assert(compareHelper(zl, 'c', s2, 1));
assert(e[2].prevrawlensize == 5 && e[2].prevrawlen == strEntryBytesLarge(s2));
assert(compareHelper(zl, 'b', s1, 2));
assert(e[3].prevrawlensize == 5 && e[3].prevrawlen == strEntryBytesLarge(s1));
assert(compareHelper(zl, 'a', s1, 3));
ziplistRepr(zl);
/* Delete from mid. */
unsigned char *p = ziplistIndex(zl, 2);
zl = ziplistDelete(zl, &p);
verify(zl, e);
assert(e[0].prevrawlensize == 1 && e[0].prevrawlen == 0);
assert(compareHelper(zl, 'd', s2, 0));
assert(e[1].prevrawlensize == 5 && e[1].prevrawlen == strEntryBytesSmall(s2));
assert(compareHelper(zl, 'c', s2, 1));
assert(e[2].prevrawlensize == 5 && e[2].prevrawlen == strEntryBytesLarge(s2));
assert(compareHelper(zl, 'a', s1, 2));
ziplistRepr(zl);
zfree(zl);
}
printf("__ziplistInsert nextdiff == -4 && reqlen < 4 (issue #7170):\n");
{
zl = ziplistNew();
/* We set some values to almost reach the critical point - 254 */
char A_252[253] = {0}, A_250[251] = {0};
memset(A_252, 'A', 252);
memset(A_250, 'A', 250);
/* After the rpush, the list look like: [one two A_252 A_250 three 10] */
zl = ziplistPush(zl, (unsigned char*)"one", 3, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"two", 3, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)A_252, strlen(A_252), ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)A_250, strlen(A_250), ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"three", 5, ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)"10", 2, ZIPLIST_TAIL);
ziplistRepr(zl);
p = ziplistIndex(zl, 2);
if (!ziplistCompare(p, (unsigned char*)A_252, strlen(A_252))) {
printf("ERROR: not \"A_252\"\n");
return 1;
}
/* When we remove A_252, the list became: [one two A_250 three 10]
* A_250's prev node became node two, because node two quite small
* So A_250's prevlenSize shrink to 1, A_250's total size became 253(1+2+250)
* The prev node of node three is still node A_250.
* We will not shrink the node three's prevlenSize, keep it at 5 bytes */
zl = ziplistDelete(zl, &p);
ziplistRepr(zl);
p = ziplistIndex(zl, 3);
if (!ziplistCompare(p, (unsigned char*)"three", 5)) {
printf("ERROR: not \"three\"\n");
return 1;
}
/* We want to insert a node after A_250, the list became: [one two A_250 10 three 10]
* Because the new node is quite small, node three prevlenSize will shrink to 1 */
zl = ziplistInsert(zl, p, (unsigned char*)"10", 2);
ziplistRepr(zl);
/* Last element should equal 10 */
p = ziplistIndex(zl, -1);
if (!ziplistCompare(p, (unsigned char*)"10", 2)) {
printf("ERROR: not \"10\"\n");
return 1;
}
zfree(zl);
}
printf("ALL TESTS PASSED!\n");
return 0;
}
#endif

View File

@ -67,8 +67,4 @@ void ziplistRandomPairs(unsigned char *zl, unsigned int count, ziplistEntry *key
unsigned int ziplistRandomPairsUnique(unsigned char *zl, unsigned int count, ziplistEntry *keys, ziplistEntry *vals);
int ziplistSafeToAdd(unsigned char* zl, size_t add);
#ifdef SERVER_TEST
int ziplistTest(int argc, char *argv[], int flags);
#endif
#endif /* _ZIPLIST_H */