From 7e41200b98ecf1ac79fb342c6486e5a270729f85 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 21 Jan 2015 18:48:08 +0100 Subject: [PATCH 1/4] Cluster test initialization: use transaction for reset + set-config-epoch. Otherwise between the two commands other nodes may contact us making the next SET-CONFIG-EPOCH call impossible. --- tests/cluster/tests/includes/init-tests.tcl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cluster/tests/includes/init-tests.tcl b/tests/cluster/tests/includes/init-tests.tcl index 65fc806e..117f7920 100644 --- a/tests/cluster/tests/includes/init-tests.tcl +++ b/tests/cluster/tests/includes/init-tests.tcl @@ -28,8 +28,10 @@ test "Cluster nodes are reachable" { test "Cluster nodes hard reset" { foreach_redis_id id { catch {R $id flushall} ; # May fail for readonly slaves. + R $id MULTI R $id cluster reset hard R $id cluster set-config-epoch [expr {$id+1}] + R $id EXEC R $id config set cluster-node-timeout 3000 R $id config set cluster-slave-validity-factor 10 R $id config rewrite From b25154a387261a41c0f1a81eba58426dc72ae373 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 21 Jan 2015 23:19:37 +0100 Subject: [PATCH 2/4] getRandomHexChars(): use /dev/urandom just to seed. On Darwin /dev/urandom depletes terribly fast. This is not an issue normally, but with Redis Cluster we generate a lot of unique IDs, for example during nodes handshakes. Our IDs need just to be unique without other strong crypto requirements, so this commit turns the function into something that gets a 20 bytes seed from /dev/urandom, and produces the rest of the output just using SHA1 in counter mode. --- src/util.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/util.c b/src/util.c index 80242ff7..e29c7862 100644 --- a/src/util.c +++ b/src/util.c @@ -40,6 +40,7 @@ #include #include "util.h" +#include "sha1.h" /* Glob-style pattern matching. */ int stringmatchlen(const char *pattern, int patternLen, @@ -428,11 +429,42 @@ int d2string(char *buf, size_t len, double value) { * having run_id == A, and you reconnect and it has run_id == B, you can be * sure that it is either a different instance or it was restarted. */ void getRandomHexChars(char *p, unsigned int len) { - FILE *fp = fopen("/dev/urandom","r"); char *charset = "0123456789abcdef"; unsigned int j; + static int seed_initialized = 0; + unsigned char seed[20]; /* A seed to have a different sequence each run. */ + uint64_t counter = 0; /* The counter we hash together with the seed. */ - if (fp == NULL || fread(p,len,1,fp) == 0) { + if (!seed_initialized) { + /* Initialize a seed and use SHA1 in counter mode, where we hash + * the same seed with a progressive counter. For the goals of this + * function we just need non-colliding strings, there are no + * cryptographic security needs. */ + FILE *fp = fopen("/dev/urandom","r"); + if (fp && fread(seed,sizeof(seed),1,fp) == 1) + seed_initialized = 1; + if (fp) fclose(fp); + } + + if (seed_initialized) { + while(len) { + unsigned char digest[20]; + SHA1_CTX ctx; + unsigned int copylen = len > 20 ? 20 : len; + + SHA1Init(&ctx); + SHA1Update(&ctx, seed, sizeof(seed)); + SHA1Update(&ctx, (unsigned char*)&counter,sizeof(counter)); + SHA1Final(digest, &ctx); + counter++; + + memcpy(p,digest,copylen); + /* Convert to hex digits. */ + for (j = 0; j < copylen; j++) p[j] = charset[p[j] & 0x0F]; + len -= copylen; + p += copylen; + } + } else { /* If we can't read from /dev/urandom, do some reasonable effort * in order to create some entropy, since this function is used to * generate run_id and cluster instance IDs */ @@ -459,14 +491,12 @@ void getRandomHexChars(char *p, unsigned int len) { x += sizeof(pid); } /* Finally xor it with rand() output, that was already seeded with - * time() at startup. */ - for (j = 0; j < len; j++) + * time() at startup, and convert to hex digits. */ + for (j = 0; j < len; j++) { p[j] ^= rand(); + p[j] = charset[p[j] & 0x0F]; + } } - /* Turn it into hex digits taking just 4 bits out of 8 for every byte. */ - for (j = 0; j < len; j++) - p[j] = charset[p[j] & 0x0F]; - if (fp) fclose(fp); } /* Given the filename, return the absolute path as an SDS string, or NULL From 4e73b305f0fb49a6293c8ade98a6cae3db7939d8 Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 22 Jan 2015 11:00:26 +0100 Subject: [PATCH 3/4] counter must be static in getRandomHexChars(). --- src/util.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/util.c b/src/util.c index e29c7862..6ea16678 100644 --- a/src/util.c +++ b/src/util.c @@ -431,9 +431,11 @@ int d2string(char *buf, size_t len, double value) { void getRandomHexChars(char *p, unsigned int len) { char *charset = "0123456789abcdef"; unsigned int j; - static int seed_initialized = 0; unsigned char seed[20]; /* A seed to have a different sequence each run. */ - uint64_t counter = 0; /* The counter we hash together with the seed. */ + + /* Global state. */ + static int seed_initialized = 0; + static uint64_t counter = 0; /* The counter we hash with the seed. */ if (!seed_initialized) { /* Initialize a seed and use SHA1 in counter mode, where we hash From 71da1b15c89d8623985f85b7deae5cfcb727ed4a Mon Sep 17 00:00:00 2001 From: antirez Date: Thu, 22 Jan 2015 11:10:43 +0100 Subject: [PATCH 4/4] The seed must be static in getRandomHexChars(). --- src/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.c b/src/util.c index 6ea16678..c5386f3a 100644 --- a/src/util.c +++ b/src/util.c @@ -431,10 +431,10 @@ int d2string(char *buf, size_t len, double value) { void getRandomHexChars(char *p, unsigned int len) { char *charset = "0123456789abcdef"; unsigned int j; - unsigned char seed[20]; /* A seed to have a different sequence each run. */ /* Global state. */ static int seed_initialized = 0; + static unsigned char seed[20]; /* The SHA1 seed, from /dev/urandom. */ static uint64_t counter = 0; /* The counter we hash with the seed. */ if (!seed_initialized) {