diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 49a1e5b4b..ee9ac1bbf 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: make - run: make + run: make REDIS_CFLAGS='-Werror -DREDIS_TEST' - name: test run: | sudo apt-get install tcl8.6 @@ -28,6 +28,8 @@ jobs: run: ./runtest-sentinel - name: cluster tests run: ./runtest-cluster + - name: unittest + run: ./src/redis-server test all test-ubuntu-libc-malloc: runs-on: ubuntu-latest @@ -76,7 +78,7 @@ jobs: - name: make run: | sudo apt-get update && sudo apt-get install libc6-dev-i386 - make 32bit + make 32bit REDIS_CFLAGS='-Werror -DREDIS_TEST' - name: test run: | sudo apt-get install tcl8.6 @@ -89,6 +91,8 @@ jobs: run: ./runtest-sentinel - name: cluster tests run: ./runtest-cluster + - name: unittest + run: ./src/redis-server test all test-ubuntu-tls: runs-on: ubuntu-latest @@ -142,7 +146,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: make - run: make valgrind + run: make valgrind REDIS_CFLAGS='-Werror -DREDIS_TEST' - name: test run: | sudo apt-get update @@ -150,6 +154,10 @@ jobs: ./runtest --valgrind --verbose --clients 1 --dump-logs - name: module api test run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1 + - name: unittest + run: | + valgrind --track-origins=yes --suppressions=./src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full --log-file=err.txt ./src/redis-server test all + if grep -q 0x err.txt; then cat err.txt; exit 1; fi test-valgrind-no-malloc-usable-size: runs-on: ubuntu-latest diff --git a/src/Makefile b/src/Makefile index ecd69295f..591a06ad5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -351,9 +351,6 @@ $(REDIS_CLI_NAME): $(REDIS_CLI_OBJ) $(REDIS_BENCHMARK_NAME): $(REDIS_BENCHMARK_OBJ) $(REDIS_LD) -o $@ $^ ../deps/hiredis/libhiredis.a ../deps/hdr_histogram/hdr_histogram.o $(FINAL_LIBS) -dict-benchmark: dict.c zmalloc.c sds.c siphash.c mt19937-64.c - $(REDIS_CC) $(FINAL_CFLAGS) $^ -D DICT_BENCHMARK_MAIN -o $@ $(FINAL_LIBS) - DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ:%.o=%.d) -include $(DEP) @@ -364,7 +361,7 @@ DEP = $(REDIS_SERVER_OBJ:%.o=%.d) $(REDIS_CLI_OBJ:%.o=%.d) $(REDIS_BENCHMARK_OBJ $(REDIS_CC) -MMD -o $@ -c $< clean: - rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep dict-benchmark + rm -rf $(REDIS_SERVER_NAME) $(REDIS_SENTINEL_NAME) $(REDIS_CLI_NAME) $(REDIS_BENCHMARK_NAME) $(REDIS_CHECK_RDB_NAME) $(REDIS_CHECK_AOF_NAME) *.o *.gcda *.gcno *.gcov redis.info lcov-html Makefile.dep rm -f $(DEP) .PHONY: clean diff --git a/src/crc64.c b/src/crc64.c index 6c9432c4a..d4db4158e 100644 --- a/src/crc64.c +++ b/src/crc64.c @@ -127,9 +127,10 @@ uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l) { #include #define UNUSED(x) (void)(x) -int crc64Test(int argc, char *argv[]) { +int crc64Test(int argc, char *argv[], int accurate) { UNUSED(argc); UNUSED(argv); + UNUSED(accurate); crc64_init(); printf("[calcula]: e9c6d914c4b8d9ca == %016" PRIx64 "\n", (uint64_t)_crc64(0, "123456789", 9)); diff --git a/src/crc64.h b/src/crc64.h index 60c42345f..38b0b6387 100644 --- a/src/crc64.h +++ b/src/crc64.h @@ -7,7 +7,7 @@ void crc64_init(void); uint64_t crc64(uint64_t crc, const unsigned char *s, uint64_t l); #ifdef REDIS_TEST -int crc64Test(int argc, char *argv[]); +int crc64Test(int argc, char *argv[], int accurate); #endif #endif diff --git a/src/dict.c b/src/dict.c index 4a9f3fb0a..21c616e6f 100644 --- a/src/dict.c +++ b/src/dict.c @@ -45,11 +45,7 @@ #include "dict.h" #include "zmalloc.h" -#ifndef DICT_BENCHMARK_MAIN #include "redisassert.h" -#else -#include -#endif /* Using dictEnableResize() / dictDisableResize() we make possible to * enable/disable resizing of the hash table as needed. This is very important @@ -1175,20 +1171,18 @@ void dictGetStats(char *buf, size_t bufsize, dict *d) { /* ------------------------------- Benchmark ---------------------------------*/ -#ifdef DICT_BENCHMARK_MAIN - -#include "sds.h" +#ifdef REDIS_TEST uint64_t hashCallback(const void *key) { - return dictGenHashFunction((unsigned char*)key, sdslen((char*)key)); + return dictGenHashFunction((unsigned char*)key, strlen((char*)key)); } int compareCallback(void *privdata, const void *key1, const void *key2) { int l1,l2; DICT_NOTUSED(privdata); - l1 = sdslen((sds)key1); - l2 = sdslen((sds)key2); + l1 = strlen((char*)key1); + l2 = strlen((char*)key2); if (l1 != l2) return 0; return memcmp(key1, key2, l1) == 0; } @@ -1196,7 +1190,19 @@ int compareCallback(void *privdata, const void *key1, const void *key2) { void freeCallback(void *privdata, void *val) { DICT_NOTUSED(privdata); - sdsfree(val); + zfree(val); +} + +char *stringFromLongLong(long long value) { + char buf[32]; + int len; + char *s; + + len = sprintf(buf,"%lld",value); + s = zmalloc(len+1); + memcpy(s, buf, len); + s[len] = '\0'; + return s; } dictType BenchmarkDictType = { @@ -1215,22 +1221,26 @@ dictType BenchmarkDictType = { printf(msg ": %ld items in %lld ms\n", count, elapsed); \ } while(0) -/* dict-benchmark [count] */ -int main(int argc, char **argv) { +/* ./redis-server test dict [ | --accurate] */ +int dictTest(int argc, char **argv, int accurate) { long j; long long start, elapsed; dict *dict = dictCreate(&BenchmarkDictType,NULL); long count = 0; - if (argc == 2) { - count = strtol(argv[1],NULL,10); + if (argc == 4) { + if (accurate) { + count = 5000000; + } else { + count = strtol(argv[3],NULL,10); + } } else { - count = 5000000; + count = 5000; } start_benchmark(); for (j = 0; j < count; j++) { - int retval = dictAdd(dict,sdsfromlonglong(j),(void*)j); + int retval = dictAdd(dict,stringFromLongLong(j),(void*)j); assert(retval == DICT_OK); } end_benchmark("Inserting"); @@ -1243,28 +1253,28 @@ int main(int argc, char **argv) { start_benchmark(); for (j = 0; j < count; j++) { - sds key = sdsfromlonglong(j); + char *key = stringFromLongLong(j); dictEntry *de = dictFind(dict,key); assert(de != NULL); - sdsfree(key); + zfree(key); } end_benchmark("Linear access of existing elements"); start_benchmark(); for (j = 0; j < count; j++) { - sds key = sdsfromlonglong(j); + char *key = stringFromLongLong(j); dictEntry *de = dictFind(dict,key); assert(de != NULL); - sdsfree(key); + zfree(key); } end_benchmark("Linear access of existing elements (2nd round)"); start_benchmark(); for (j = 0; j < count; j++) { - sds key = sdsfromlonglong(rand() % count); + char *key = stringFromLongLong(rand() % count); dictEntry *de = dictFind(dict,key); assert(de != NULL); - sdsfree(key); + zfree(key); } end_benchmark("Random access of existing elements"); @@ -1277,17 +1287,17 @@ int main(int argc, char **argv) { start_benchmark(); for (j = 0; j < count; j++) { - sds key = sdsfromlonglong(rand() % count); + char *key = stringFromLongLong(rand() % count); key[0] = 'X'; dictEntry *de = dictFind(dict,key); assert(de == NULL); - sdsfree(key); + zfree(key); } end_benchmark("Accessing missing"); start_benchmark(); for (j = 0; j < count; j++) { - sds key = sdsfromlonglong(j); + char *key = stringFromLongLong(j); int retval = dictDelete(dict,key); assert(retval == DICT_OK); key[0] += 17; /* Change first number to letter. */ @@ -1295,5 +1305,7 @@ int main(int argc, char **argv) { assert(retval == DICT_OK); } end_benchmark("Removing and adding"); + dictRelease(dict); + return 0; } #endif diff --git a/src/dict.h b/src/dict.h index bd57f859e..7e2258960 100644 --- a/src/dict.h +++ b/src/dict.h @@ -201,4 +201,8 @@ extern dictType dictTypeHeapStringCopyKey; extern dictType dictTypeHeapStrings; extern dictType dictTypeHeapStringCopyKeyValue; +#ifdef REDIS_TEST +int dictTest(int argc, char *argv[], int accurate); +#endif + #endif /* __DICT_H */ diff --git a/src/endianconv.c b/src/endianconv.c index 918844e25..98ed405a5 100644 --- a/src/endianconv.c +++ b/src/endianconv.c @@ -105,11 +105,12 @@ uint64_t intrev64(uint64_t v) { #include #define UNUSED(x) (void)(x) -int endianconvTest(int argc, char *argv[]) { +int endianconvTest(int argc, char *argv[], int accurate) { char buf[32]; UNUSED(argc); UNUSED(argv); + UNUSED(accurate); sprintf(buf,"ciaoroma"); memrev16(buf); diff --git a/src/endianconv.h b/src/endianconv.h index 475f72b08..004749786 100644 --- a/src/endianconv.h +++ b/src/endianconv.h @@ -72,7 +72,7 @@ uint64_t intrev64(uint64_t v); #endif #ifdef REDIS_TEST -int endianconvTest(int argc, char *argv[]); +int endianconvTest(int argc, char *argv[], int accurate); #endif #endif diff --git a/src/intset.c b/src/intset.c index 74de87acb..5498227f4 100644 --- a/src/intset.c +++ b/src/intset.c @@ -392,7 +392,7 @@ static void checkConsistency(intset *is) { } #define UNUSED(x) (void)(x) -int intsetTest(int argc, char **argv) { +int intsetTest(int argc, char **argv, int accurate) { uint8_t success; int i; intset *is; @@ -400,6 +400,7 @@ int intsetTest(int argc, char **argv) { UNUSED(argc); UNUSED(argv); + UNUSED(accurate); printf("Value encodings: "); { assert(_intsetValueEncoding(-32768) == INTSET_ENC_INT16); @@ -424,6 +425,7 @@ int intsetTest(int argc, char **argv) { is = intsetAdd(is,4,&success); assert(success); is = intsetAdd(is,4,&success); assert(!success); ok(); + zfree(is); } printf("Large number of random adds: "); { @@ -436,6 +438,7 @@ int intsetTest(int argc, char **argv) { assert(intrev32ifbe(is->length) == inserts); checkConsistency(is); ok(); + zfree(is); } printf("Upgrade from int16 to int32: "); { @@ -447,6 +450,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,32)); assert(intsetFind(is,65535)); checkConsistency(is); + zfree(is); is = intsetNew(); is = intsetAdd(is,32,NULL); @@ -457,6 +461,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,-65535)); checkConsistency(is); ok(); + zfree(is); } printf("Upgrade from int16 to int64: "); { @@ -468,6 +473,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,32)); assert(intsetFind(is,4294967295)); checkConsistency(is); + zfree(is); is = intsetNew(); is = intsetAdd(is,32,NULL); @@ -478,6 +484,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,-4294967295)); checkConsistency(is); ok(); + zfree(is); } printf("Upgrade from int32 to int64: "); { @@ -489,6 +496,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,65535)); assert(intsetFind(is,4294967295)); checkConsistency(is); + zfree(is); is = intsetNew(); is = intsetAdd(is,65535,NULL); @@ -499,6 +507,7 @@ int intsetTest(int argc, char **argv) { assert(intsetFind(is,-4294967295)); checkConsistency(is); ok(); + zfree(is); } printf("Stress lookups: "); { @@ -512,6 +521,7 @@ int intsetTest(int argc, char **argv) { for (i = 0; i < num; i++) intsetSearch(is,rand() % ((1<len == 0 && !errors) { - OK; return errors; } @@ -1690,8 +1687,6 @@ static int _ql_verify(quicklist *ql, uint32_t len, uint32_t count, } } - if (!errors) - OK; return errors; } @@ -1703,9 +1698,10 @@ static char *genstr(char *prefix, int i) { } /* main test, but callable from other files */ -int quicklistTest(int argc, char *argv[]) { +int quicklistTest(int argc, char *argv[], int accurate) { UNUSED(argc); UNUSED(argv); + UNUSED(accurate); unsigned int err = 0; int optimize_start = @@ -1714,11 +1710,14 @@ int quicklistTest(int argc, char *argv[]) { printf("Starting optimization offset at: %d\n", optimize_start); int options[] = {0, 1, 2, 3, 4, 5, 6, 10}; + int fills[] = {-5, -4, -3, -2, -1, 0, + 1, 2, 32, 66, 128, 999}; size_t option_count = sizeof(options) / sizeof(*options); + int fill_count = (int)(sizeof(fills) / sizeof(*fills)); long long runtime[option_count]; for (int _i = 0; _i < (int)option_count; _i++) { - printf("Testing Option %d\n", options[_i]); + printf("Testing Compression option %d\n", options[_i]); long long start = mstime(); TEST("create list") { @@ -1743,57 +1742,53 @@ int quicklistTest(int argc, char *argv[]) { quicklistRelease(ql); } - for (int f = optimize_start; f < 32; f++) { - TEST_DESC("add to tail 5x at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("add to tail 5x at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 5; i++) quicklistPushTail(ql, genstr("hello", i), 32); if (ql->count != 5) ERROR; - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 5, 5, 5); quicklistRelease(ql); } } - for (int f = optimize_start; f < 32; f++) { - TEST_DESC("add to head 5x at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("add to head 5x at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 5; i++) quicklistPushHead(ql, genstr("hello", i), 32); if (ql->count != 5) ERROR; - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 5, 5, 5); quicklistRelease(ql); } } - for (int f = optimize_start; f < 512; f++) { - TEST_DESC("add to tail 500x at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("add to tail 500x at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushTail(ql, genstr("hello", i), 64); if (ql->count != 500) ERROR; - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 16, 500, 32, 20); quicklistRelease(ql); } } - for (int f = optimize_start; f < 512; f++) { - TEST_DESC("add to head 500x at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("add to head 500x at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushHead(ql, genstr("hello", i), 32); if (ql->count != 500) ERROR; - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 16, 500, 20, 32); quicklistRelease(ql); } @@ -1806,9 +1801,9 @@ int quicklistTest(int argc, char *argv[]) { quicklistRelease(ql); } - for (int f = optimize_start; f < 32; f++) { - TEST("rotate one val once") { - quicklist *ql = quicklistNew(f, options[_i]); + TEST("rotate one val once") { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); quicklistPushHead(ql, "hello", 6); quicklistRotate(ql); /* Ignore compression verify because ziplist is @@ -1818,10 +1813,9 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 3; f++) { - TEST_DESC("rotate 500 val 5000 times at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("rotate 500 val 5000 times at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); quicklistPushHead(ql, "900", 3); quicklistPushHead(ql, "7000", 4); quicklistPushHead(ql, "-1200", 5); @@ -1833,11 +1827,11 @@ int quicklistTest(int argc, char *argv[]) { ql_info(ql); quicklistRotate(ql); } - if (f == 1) + if (fills[f] == 1) ql_verify(ql, 504, 504, 1, 1); - else if (f == 2) + else if (fills[f] == 2) ql_verify(ql, 252, 504, 2, 2); - else if (f == 32) + else if (fills[f] == 32) ql_verify(ql, 16, 504, 32, 24); quicklistRelease(ql); } @@ -2014,11 +2008,10 @@ int quicklistTest(int argc, char *argv[]) { quicklistRelease(ql); } - for (int f = optimize_start; f < 12; f++) { - TEST_DESC("insert once in elements while iterating at fill %d at " - "compress %d\n", - f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("insert once in elements while iterating at compress %d", + options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); quicklistPushTail(ql, "abc", 3); quicklistSetFill(ql, 1); quicklistPushTail(ql, "def", 3); /* force to unique node */ @@ -2070,12 +2063,10 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 1024; f++) { - TEST_DESC( - "insert [before] 250 new in middle of 500 elements at fill" - " %d at compress %d", - f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("insert [before] 250 new in middle of 500 elements at compress %d", + options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushTail(ql, genstr("hello", i), 32); for (int i = 0; i < 250; i++) { @@ -2083,17 +2074,16 @@ int quicklistTest(int argc, char *argv[]) { quicklistIndex(ql, 250, &entry); quicklistInsertBefore(ql, &entry, genstr("abc", i), 32); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 25, 750, 32, 20); quicklistRelease(ql); } } - for (int f = optimize_start; f < 1024; f++) { - TEST_DESC("insert [after] 250 new in middle of 500 elements at " - "fill %d at compress %d", - f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("insert [after] 250 new in middle of 500 elements at compress %d", + options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushHead(ql, genstr("hello", i), 32); for (int i = 0; i < 250; i++) { @@ -2105,7 +2095,7 @@ int quicklistTest(int argc, char *argv[]) { if (ql->count != 750) ERR("List size not 750, but rather %ld", ql->count); - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 26, 750, 20, 32); quicklistRelease(ql); } @@ -2143,70 +2133,58 @@ int quicklistTest(int argc, char *argv[]) { quicklistRelease(copy); } - for (int f = optimize_start; f < 512; f++) { + for (int f = 0; f < fill_count; f++) { TEST_DESC("index 1,200 from 500 list at fill %d at compress %d", f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushTail(ql, genstr("hello", i + 1), 32); quicklistEntry entry; quicklistIndex(ql, 1, &entry); - if (!strcmp((char *)entry.value, "hello2")) - OK; - else + if (strcmp((char *)entry.value, "hello2") != 0) ERR("Value: %s", entry.value); quicklistIndex(ql, 200, &entry); - if (!strcmp((char *)entry.value, "hello201")) - OK; - else + if (strcmp((char *)entry.value, "hello201") != 0) ERR("Value: %s", entry.value); quicklistRelease(ql); } - TEST_DESC("index -1,-2 from 500 list at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("index -1,-2 from 500 list at fill %d at compress %d", + fills[f], options[_i]) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushTail(ql, genstr("hello", i + 1), 32); quicklistEntry entry; quicklistIndex(ql, -1, &entry); - if (!strcmp((char *)entry.value, "hello500")) - OK; - else + if (strcmp((char *)entry.value, "hello500") != 0) ERR("Value: %s", entry.value); quicklistIndex(ql, -2, &entry); - if (!strcmp((char *)entry.value, "hello499")) - OK; - else + if (strcmp((char *)entry.value, "hello499") != 0) ERR("Value: %s", entry.value); quicklistRelease(ql); } - TEST_DESC("index -100 from 500 list at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("index -100 from 500 list at fill %d at compress %d", + fills[f], options[_i]) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 500; i++) quicklistPushTail(ql, genstr("hello", i + 1), 32); quicklistEntry entry; quicklistIndex(ql, -100, &entry); - if (!strcmp((char *)entry.value, "hello401")) - OK; - else + if (strcmp((char *)entry.value, "hello401") != 0) ERR("Value: %s", entry.value); quicklistRelease(ql); } TEST_DESC("index too big +1 from 50 list at fill %d at compress %d", - f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + fills[f], options[_i]) { + quicklist *ql = quicklistNew(fills[f], options[_i]); for (int i = 0; i < 50; i++) quicklistPushTail(ql, genstr("hello", i + 1), 32); quicklistEntry entry; if (quicklistIndex(ql, 50, &entry)) ERR("Index found at 50 with 50 list: %.*s", entry.sz, entry.value); - else - OK; quicklistRelease(ql); } } @@ -2378,12 +2356,11 @@ int quicklistTest(int argc, char *argv[]) { quicklistReplaceAtIndex(ql, 1, "foo", 3); quicklistReplaceAtIndex(ql, -1, "bar", 3); quicklistRelease(ql); - OK; } - for (int f = optimize_start; f < 16; f++) { - TEST_DESC("lrem test at fill %d at compress %d", f, options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("lrem test at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); char *words[] = {"abc", "foo", "bar", "foobar", "foobared", "zap", "bar", "test", "foo"}; char *result[] = {"abc", "foo", "foobar", "foobared", @@ -2408,14 +2385,12 @@ int quicklistTest(int argc, char *argv[]) { /* check result of lrem 0 bar */ iter = quicklistGetIterator(ql, AL_START_HEAD); i = 0; - int ok = 1; while (quicklistNext(iter, &entry)) { /* Result must be: abc, foo, foobar, foobared, zap, test, * foo */ if (strncmp((char *)entry.value, result[i], entry.sz)) { ERR("No match at position %d, got %.*s instead of %s", i, entry.sz, entry.value, result[i]); - ok = 0; } i++; } @@ -2452,23 +2427,18 @@ int quicklistTest(int argc, char *argv[]) { entry.sz)) { ERR("No match at position %d, got %.*s instead of %s", i, entry.sz, entry.value, resultB[resB - 1 - i]); - ok = 0; } i++; } quicklistReleaseIterator(iter); - /* final result of all tests */ - if (ok) - OK; quicklistRelease(ql); } } - for (int f = optimize_start; f < 16; f++) { - TEST_DESC("iterate reverse + delete at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("iterate reverse + delete at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); quicklistPushTail(ql, "abc", 3); quicklistPushTail(ql, "def", 3); quicklistPushTail(ql, "hij", 3); @@ -2505,10 +2475,9 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 800; f++) { - TEST_DESC("iterator at index test at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("iterator at index test at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); char num[32]; long long nums[5000]; for (int i = 0; i < 760; i++) { @@ -2532,10 +2501,9 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 40; f++) { - TEST_DESC("ltrim test A at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("ltrim test A at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); char num[32]; long long nums[5000]; for (int i = 0; i < 32; i++) { @@ -2543,7 +2511,7 @@ int quicklistTest(int argc, char *argv[]) { int sz = ll2string(num, sizeof(num), nums[i]); quicklistPushTail(ql, num, sz); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 32, 32, 32); /* ltrim 25 53 (keep [25,32] inclusive = 7 remaining) */ quicklistDelRange(ql, 0, 25); @@ -2556,18 +2524,17 @@ int quicklistTest(int argc, char *argv[]) { "%lld", entry.longval, nums[25 + i]); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 7, 7, 7); quicklistRelease(ql); } } - for (int f = optimize_start; f < 40; f++) { - TEST_DESC("ltrim test B at fill %d at compress %d", f, - options[_i]) { + TEST_DESC("ltrim test B at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { /* Force-disable compression because our 33 sequential * integers don't compress and the check always fails. */ - quicklist *ql = quicklistNew(f, QUICKLIST_NOCOMPRESS); + quicklist *ql = quicklistNew(fills[f], QUICKLIST_NOCOMPRESS); char num[32]; long long nums[5000]; for (int i = 0; i < 33; i++) { @@ -2575,24 +2542,20 @@ int quicklistTest(int argc, char *argv[]) { int sz = ll2string(num, sizeof(num), nums[i]); quicklistPushTail(ql, num, sz); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 2, 33, 32, 1); /* ltrim 5 16 (keep [5,16] inclusive = 12 remaining) */ quicklistDelRange(ql, 0, 5); quicklistDelRange(ql, -16, 16); - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 12, 12, 12); quicklistEntry entry; quicklistIndex(ql, 0, &entry); if (entry.longval != 5) ERR("A: longval not 5, but %lld", entry.longval); - else - OK; quicklistIndex(ql, -1, &entry); if (entry.longval != 16) ERR("B! got instead: %lld", entry.longval); - else - OK; quicklistPushTail(ql, "bobobob", 7); quicklistIndex(ql, -1, &entry); if (strncmp((char *)entry.value, "bobobob", 7)) @@ -2609,10 +2572,9 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 40; f++) { - TEST_DESC("ltrim test C at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("ltrim test C at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); char num[32]; long long nums[5000]; for (int i = 0; i < 33; i++) { @@ -2620,28 +2582,25 @@ int quicklistTest(int argc, char *argv[]) { int sz = ll2string(num, sizeof(num), nums[i]); quicklistPushTail(ql, num, sz); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 2, 33, 32, 1); /* ltrim 3 3 (keep [3,3] inclusive = 1 remaining) */ quicklistDelRange(ql, 0, 3); quicklistDelRange(ql, -29, 4000); /* make sure not loop forever */ - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 1, 1, 1, 1); quicklistEntry entry; quicklistIndex(ql, 0, &entry); if (entry.longval != -5157318210846258173) ERROR; - else - OK; quicklistRelease(ql); } } - for (int f = optimize_start; f < 40; f++) { - TEST_DESC("ltrim test D at fill %d at compress %d", f, - options[_i]) { - quicklist *ql = quicklistNew(f, options[_i]); + TEST_DESC("ltrim test D at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { + quicklist *ql = quicklistNew(fills[f], options[_i]); char num[32]; long long nums[5000]; for (int i = 0; i < 33; i++) { @@ -2649,7 +2608,7 @@ int quicklistTest(int argc, char *argv[]) { int sz = ll2string(num, sizeof(num), nums[i]); quicklistPushTail(ql, num, sz); } - if (f == 32) + if (fills[f] == 32) ql_verify(ql, 2, 33, 32, 1); quicklistDelRange(ql, -12, 3); if (ql->count != 30) @@ -2659,9 +2618,8 @@ int quicklistTest(int argc, char *argv[]) { } } - for (int f = optimize_start; f < 72; f++) { - TEST_DESC("create quicklist from ziplist at fill %d at compress %d", - f, options[_i]) { + TEST_DESC("create quicklist from ziplist at compress %d", options[_i]) { + for (int f = 0; f < fill_count; f++) { unsigned char *zl = ziplistNew(); long long nums[64]; char num[64]; @@ -2675,12 +2633,12 @@ int quicklistTest(int argc, char *argv[]) { zl = ziplistPush(zl, (unsigned char *)genstr("hello", i), 32, ZIPLIST_TAIL); } - quicklist *ql = quicklistCreateFromZiplist(f, options[_i], zl); - if (f == 1) + quicklist *ql = quicklistCreateFromZiplist(fills[f], options[_i], zl); + if (fills[f] == 1) ql_verify(ql, 66, 66, 1, 1); - else if (f == 32) + else if (fills[f] == 32) ql_verify(ql, 3, 66, 32, 2); - else if (f == 66) + else if (fills[f] == 66) ql_verify(ql, 1, 66, 66, 66); quicklistRelease(ql); } @@ -2693,16 +2651,14 @@ int quicklistTest(int argc, char *argv[]) { /* Run a longer test of compression depth outside of primary test loop. */ int list_sizes[] = {250, 251, 500, 999, 1000}; long long start = mstime(); - for (int list = 0; list < (int)(sizeof(list_sizes) / sizeof(*list_sizes)); - list++) { - for (int f = optimize_start; f < 128; f++) { - for (int depth = 1; depth < 40; depth++) { - /* skip over many redundant test cases */ - TEST_DESC("verify specific compression of interior nodes with " - "%d list " - "at fill %d at compress %d", - list_sizes[list], f, depth) { - quicklist *ql = quicklistNew(f, depth); + int list_count = accurate ? (int)(sizeof(list_sizes) / sizeof(*list_sizes)) : 1; + for (int list = 0; list < list_count; list++) { + TEST_DESC("verify specific compression of interior nodes with %d list ", + list_sizes[list]) { + for (int f = 0; f < fill_count; f++) { + for (int depth = 1; depth < 40; depth++) { + /* skip over many redundant test cases */ + quicklist *ql = quicklistNew(fills[f], depth); for (int i = 0; i < list_sizes[list]; i++) { quicklistPushTail(ql, genstr("hello TAIL", i + 1), 64); quicklistPushHead(ql, genstr("hello HEAD", i + 1), 64); @@ -2712,8 +2668,11 @@ int quicklistTest(int argc, char *argv[]) { /* test remove node */ if (step == 1) { for (int i = 0; i < list_sizes[list] / 2; i++) { - quicklistPop(ql, QUICKLIST_HEAD, NULL, NULL, NULL); - quicklistPop(ql, QUICKLIST_TAIL, NULL, NULL, NULL); + unsigned char *data; + quicklistPop(ql, QUICKLIST_HEAD, &data, NULL, NULL); + zfree(data); + quicklistPop(ql, QUICKLIST_TAIL, &data, NULL, NULL); + zfree(data); } } quicklistNode *node = ql->head; diff --git a/src/quicklist.h b/src/quicklist.h index fd9878af0..c9f493d80 100644 --- a/src/quicklist.h +++ b/src/quicklist.h @@ -199,7 +199,7 @@ quicklistNode *quicklistBookmarkFind(quicklist *ql, const char *name); void quicklistBookmarksClear(quicklist *ql); #ifdef REDIS_TEST -int quicklistTest(int argc, char *argv[]); +int quicklistTest(int argc, char *argv[], int accurate); #endif /* Directions for iterators */ diff --git a/src/sds.c b/src/sds.c index 6385ab14b..2ec3aa733 100644 --- a/src/sds.c +++ b/src/sds.c @@ -1234,9 +1234,10 @@ static sds sdsTestTemplateCallback(sds varname, void *arg) { else return NULL; } -int sdsTest(int argc, char **argv) { +int sdsTest(int argc, char **argv, int accurate) { UNUSED(argc); UNUSED(argv); + UNUSED(accurate); { sds x = sdsnew("foo"), y; diff --git a/src/sds.h b/src/sds.h index 85dc0b680..7f8710745 100644 --- a/src/sds.h +++ b/src/sds.h @@ -277,7 +277,7 @@ void *sds_realloc(void *ptr, size_t size); void sds_free(void *ptr); #ifdef REDIS_TEST -int sdsTest(int argc, char *argv[]); +int sdsTest(int argc, char *argv[], int accurate); #endif #endif diff --git a/src/server.c b/src/server.c index 26fe57499..e7c9787b1 100644 --- a/src/server.c +++ b/src/server.c @@ -6030,36 +6030,78 @@ int iAmMaster(void) { (server.cluster_enabled && nodeIsMaster(server.cluster->myself))); } +#ifdef REDIS_TEST +typedef int redisTestProc(int argc, char **argv, int accurate); +struct redisTest { + char *name; + redisTestProc *proc; + int failed; +} redisTests[] = { + {"ziplist", ziplistTest}, + {"quicklist", quicklistTest}, + {"intset", intsetTest}, + {"zipmap", zipmapTest}, + {"sha1test", sha1Test}, + {"util", utilTest}, + {"endianconv", endianconvTest}, + {"crc64", crc64Test}, + {"zmalloc", zmalloc_test}, + {"sds", sdsTest}, + {"dict", dictTest} +}; +redisTestProc *getTestProcByName(const char *name) { + int numtests = sizeof(redisTests)/sizeof(struct redisTest); + for (int j = 0; j < numtests; j++) { + if (!strcasecmp(name,redisTests[j].name)) { + return redisTests[j].proc; + } + } + return NULL; +} +#endif + int main(int argc, char **argv) { struct timeval tv; int j; char config_from_stdin = 0; #ifdef REDIS_TEST - if (argc == 3 && !strcasecmp(argv[1], "test")) { - if (!strcasecmp(argv[2], "ziplist")) { - return ziplistTest(argc, argv); - } else if (!strcasecmp(argv[2], "quicklist")) { - quicklistTest(argc, argv); - } else if (!strcasecmp(argv[2], "intset")) { - return intsetTest(argc, argv); - } else if (!strcasecmp(argv[2], "zipmap")) { - return zipmapTest(argc, argv); - } else if (!strcasecmp(argv[2], "sha1test")) { - return sha1Test(argc, argv); - } else if (!strcasecmp(argv[2], "util")) { - return utilTest(argc, argv); - } else if (!strcasecmp(argv[2], "endianconv")) { - return endianconvTest(argc, argv); - } else if (!strcasecmp(argv[2], "crc64")) { - return crc64Test(argc, argv); - } else if (!strcasecmp(argv[2], "zmalloc")) { - return zmalloc_test(argc, argv); - } else if (!strcasecmp(argv[2], "sds")) { - return sdsTest(argc, argv); + if (argc >= 3 && !strcasecmp(argv[1], "test")) { + int accurate = 0; + for (j = 3; j < argc; j++) { + if (!strcasecmp(argv[j], "--accurate")) { + accurate = 1; + } } - return -1; /* test not found */ + if (!strcasecmp(argv[2], "all")) { + int numtests = sizeof(redisTests)/sizeof(struct redisTest); + for (j = 0; j < numtests; j++) { + redisTests[j].failed = (redisTests[j].proc(argc,argv,accurate) != 0); + } + + /* Report tests result */ + int failed_num = 0; + for (j = 0; j < numtests; j++) { + if (redisTests[j].failed) { + failed_num++; + printf("[failed] Test - %s\n", redisTests[j].name); + } else { + printf("[ok] Test - %s\n", redisTests[j].name); + } + } + + printf("%d tests, %d passed, %d failed\n", numtests, + numtests-failed_num, failed_num); + + return failed_num == 0 ? 0 : 1; + } else { + redisTestProc *proc = getTestProcByName(argv[2]); + if (!proc) return -1; /* test not found */ + return proc(argc,argv,accurate); + } + + return 0; } #endif diff --git a/src/sha1.c b/src/sha1.c index ce487e367..f2423c052 100644 --- a/src/sha1.c +++ b/src/sha1.c @@ -201,7 +201,7 @@ void SHA1Final(unsigned char digest[20], SHA1_CTX* context) #define BUFSIZE 4096 #define UNUSED(x) (void)(x) -int sha1Test(int argc, char **argv) +int sha1Test(int argc, char **argv, int accurate) { SHA1_CTX ctx; unsigned char hash[20], buf[BUFSIZE]; @@ -209,6 +209,7 @@ int sha1Test(int argc, char **argv) UNUSED(argc); UNUSED(argv); + UNUSED(accurate); for(i=0;i --accurate */ +int ziplistTest(int argc, char **argv, int 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 == 2) - srand(atoi(argv[1])); + if (argc >= 4) + srand(atoi(argv[3])); zl = createIntList(); ziplistRepr(zl); @@ -2339,7 +2341,8 @@ int ziplistTest(int argc, char **argv) { unsigned int slen; long long sval; - for (i = 0; i < 20000; i++) { + iteration = accurate ? 20000 : 20; + for (i = 0; i < iteration; i++) { zl = ziplistNew(); ref = listCreate(); listSetFreeMethod(ref,(void (*)(void*))sdsfree); @@ -2405,15 +2408,17 @@ int ziplistTest(int argc, char **argv) { printf("Stress with variable ziplist size:\n"); { unsigned long long start = usec(); - stress(ZIPLIST_HEAD,100000,16384,256); - stress(ZIPLIST_TAIL,100000,16384,256); + 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(); - for (int i=0; i<100000; i++) { + iteration = accurate ? 100000 : 100; + for (int i=0; i %d:%.*s\n", klen, klen, key, vlen, vlen, value); } } + zfree(zm); return 0; } #endif diff --git a/src/zipmap.h b/src/zipmap.h index daf8430a0..1b34a32ae 100644 --- a/src/zipmap.h +++ b/src/zipmap.h @@ -48,7 +48,7 @@ void zipmapRepr(unsigned char *p); int zipmapValidateIntegrity(unsigned char *zm, size_t size, int deep); #ifdef REDIS_TEST -int zipmapTest(int argc, char *argv[]); +int zipmapTest(int argc, char *argv[], int accurate); #endif #endif diff --git a/src/zmalloc.c b/src/zmalloc.c index e212583a4..77eeea174 100644 --- a/src/zmalloc.c +++ b/src/zmalloc.c @@ -675,11 +675,12 @@ size_t zmalloc_get_memory_size(void) { #ifdef REDIS_TEST #define UNUSED(x) ((void)(x)) -int zmalloc_test(int argc, char **argv) { +int zmalloc_test(int argc, char **argv, int accurate) { void *ptr; UNUSED(argc); UNUSED(argv); + UNUSED(accurate); printf("Malloc prefix size: %d\n", (int) PREFIX_SIZE); printf("Initial used memory: %zu\n", zmalloc_used_memory()); ptr = zmalloc(123); diff --git a/src/zmalloc.h b/src/zmalloc.h index 3c0ba95d4..bb4cbddbb 100644 --- a/src/zmalloc.h +++ b/src/zmalloc.h @@ -135,7 +135,7 @@ size_t zmalloc_usable_size(void *ptr); #endif #ifdef REDIS_TEST -int zmalloc_test(int argc, char **argv); +int zmalloc_test(int argc, char **argv, int accurate); #endif #endif /* __ZMALLOC_H */