summaryrefslogtreecommitdiff
path: root/src/redis-check-rdb.c
diff options
context:
space:
mode:
authorGreg Femec <gfemec@users.noreply.github.com>2020-12-23 05:52:07 -0800
committerGitHub <noreply@github.com>2020-12-23 15:52:07 +0200
commit266949c7fcfab9d10f81314fd7480a00638ced80 (patch)
treecee4dcce6eb376f1ed358587e5667a1b9c9ca92b /src/redis-check-rdb.c
parent2426aaa099e5dfee29cce17af39298d0ce14cc2a (diff)
downloadredis-266949c7fcfab9d10f81314fd7480a00638ced80.tar.gz
Fix random element selection for large hash tables. (#8133)
When a database on a 64 bit build grows past 2^31 keys, the underlying hash table expands to 2^32 buckets. After this point, the algorithms for selecting random elements only return elements from half of the available buckets because they use random() which has a range of 0 to 2^31 - 1. This causes problems for eviction policies which use dictGetSomeKeys or dictGetRandomKey. Over time they cause the hash table to become unbalanced because, while new keys are spread out evenly across all buckets, evictions come from only half of the available buckets. Eventually this half of the table starts to run out of keys and it takes longer and longer to find candidates for eviction. This continues until no more evictions can happen. This solution addresses this by using a 64 bit PRNG instead of libc random(). Co-authored-by: Greg Femec <gfemec@google.com>
Diffstat (limited to 'src/redis-check-rdb.c')
-rw-r--r--src/redis-check-rdb.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/src/redis-check-rdb.c b/src/redis-check-rdb.c
index 79dbf3229..335e35189 100644
--- a/src/redis-check-rdb.c
+++ b/src/redis-check-rdb.c
@@ -27,10 +27,13 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include "mt19937-64.h"
#include "server.h"
#include "rdb.h"
#include <stdarg.h>
+#include <sys/time.h>
+#include <unistd.h>
void createSharedObjects(void);
void rdbLoadProgressCallback(rio *r, const void *buf, size_t len);
@@ -362,10 +365,16 @@ err:
* Otherwise if called with a non NULL fp, the function returns C_OK or
* C_ERR depending on the success or failure. */
int redis_check_rdb_main(int argc, char **argv, FILE *fp) {
+ struct timeval tv;
+
if (argc != 2 && fp == NULL) {
fprintf(stderr, "Usage: %s <rdb-file-name>\n", argv[0]);
exit(1);
}
+
+ gettimeofday(&tv, NULL);
+ init_genrand64(((long long) tv.tv_sec * 1000000 + tv.tv_usec) ^ getpid());
+
/* In order to call the loading functions we need to create the shared
* integer objects, however since this function may be called from
* an already initialized Redis instance, check if we really need to. */