From 552eb5407a49cf6b604230d1994a5e441ba10f5c Mon Sep 17 00:00:00 2001 From: antirez Date: Fri, 28 Mar 2014 12:11:36 +0100 Subject: [PATCH] HLLSELFTEST command implemented. To test the bitfield array of counters set/get macros from the Redis Tcl suite is hard, so a specialized command that is able to test the internals was developed. --- src/Makefile | 2 +- src/hyperloglog.c | 55 +++++++++++++++++++++++++++++++++++++++++------ src/redis.c | 3 ++- src/redis.h | 1 + 4 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/Makefile b/src/Makefile index c7fdf211e..289371666 100644 --- a/src/Makefile +++ b/src/Makefile @@ -107,7 +107,7 @@ endif REDIS_SERVER_NAME=redis-server REDIS_SENTINEL_NAME=redis-sentinel -REDIS_SERVER_OBJ=adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o +REDIS_SERVER_OBJ=adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o REDIS_CLI_NAME=redis-cli REDIS_CLI_OBJ=anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o REDIS_BENCHMARK_NAME=redis-benchmark diff --git a/src/hyperloglog.c b/src/hyperloglog.c index 01d43b01c..2b307a703 100644 --- a/src/hyperloglog.c +++ b/src/hyperloglog.c @@ -53,6 +53,7 @@ #define REDIS_HLL_REGISTERS 16384 #define REDIS_HLL_BITS 6 +#define REDIS_HLL_REGISTER_MAX ((1<> _leftshift; \ - p[byte+1] &= ~(m2 << _rightshift); \ - p[byte+1] |= val << _rightshift; \ + unsigned int m1 = 255, m2 = REDIS_HLL_REGISTER_MAX; \ + p[_byte] &= m1 << _rightshift; \ + p[_byte] |= val >> _leftshift; \ + p[_byte+1] &= ~(m2 << _rightshift); \ + p[_byte+1] |= val << _rightshift; \ } while(0) /* ========================= HyperLogLog algorithm ========================= */ /* ========================== HyperLogLog commands ========================== */ +/* This command performs a self-test of the HLL registers implementation. + * Something that is not easy to test from within the outside. + * + * The test is conceived to test that the different counters of our data + * structure are accessible and that setting their values both result in + * the correct value to be retained and not affect adjacent values. */ + +#define REDIS_HLL_TEST_CYCLES 1000 +void hllSelftestCommand(redisClient *c) { + int j, i; + sds bitcounters = sdsnewlen(NULL,REDIS_HLL_SIZE); + uint8_t bytecounters[REDIS_HLL_REGISTERS]; + + for (j = 0; j < REDIS_HLL_TEST_CYCLES; j++) { + /* Set the HLL counters and an array of unsigned byes of the + * same size to the same set of random values. */ + for (i = 0; i < REDIS_HLL_REGISTERS; i++) { + unsigned int r = rand() & REDIS_HLL_REGISTER_MAX; + + bytecounters[i] = r; + HLL_SET_REGISTER(bitcounters,i,r); + } + /* Check that we are able to retrieve the same values. */ + for (i = 0; i < REDIS_HLL_REGISTERS; i++) { + unsigned int val; + + HLL_GET_REGISTER(val,bitcounters,i); + if (val != bytecounters[i]) { + addReplyErrorFormat(c, + "TESTFAILED Register %d should be %d but is %d", + i, (int) bytecounters[i], (int) val); + goto cleanup; + } + } + } + + /* Success! */ + addReply(c,shared.ok); + +cleanup: + sdsfree(bitcounters); +} diff --git a/src/redis.c b/src/redis.c index 9e3331f7b..07ff7c201 100644 --- a/src/redis.c +++ b/src/redis.c @@ -267,7 +267,8 @@ struct redisCommand redisCommandTable[] = { {"bitop",bitopCommand,-4,"wm",0,NULL,2,-1,1,0,0}, {"bitcount",bitcountCommand,-2,"r",0,NULL,1,1,1,0,0}, {"bitpos",bitposCommand,-3,"r",0,NULL,1,1,1,0,0}, - {"wait",waitCommand,3,"rs",0,NULL,0,0,0,0,0} + {"wait",waitCommand,3,"rs",0,NULL,0,0,0,0,0}, + {"hllselftest",hllSelftestCommand,1,"r",0,NULL,0,0,0,0,0}, }; struct evictionPoolEntry *evictionPoolAlloc(void); diff --git a/src/redis.h b/src/redis.h index 14a656b36..106d22ba9 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1447,6 +1447,7 @@ void bitcountCommand(redisClient *c); void bitposCommand(redisClient *c); void replconfCommand(redisClient *c); void waitCommand(redisClient *c); +void hllSelftestCommand(redisClient *c); #if defined(__GNUC__) void *calloc(size_t count, size_t size) __attribute__ ((deprecated));