Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
8ca3e9d1
Commit
8ca3e9d1
authored
Apr 15, 2010
by
antirez
Browse files
Active rehashing
parent
5413c40d
Changes
4
Hide whitespace changes
Inline
Side-by-side
dict.c
View file @
8ca3e9d1
...
@@ -41,6 +41,7 @@
...
@@ -41,6 +41,7 @@
#include <stdarg.h>
#include <stdarg.h>
#include <assert.h>
#include <assert.h>
#include <limits.h>
#include <limits.h>
#include <sys/time.h>
#include "dict.h"
#include "dict.h"
#include "zmalloc.h"
#include "zmalloc.h"
...
@@ -237,6 +238,25 @@ int dictRehash(dict *d, int n) {
...
@@ -237,6 +238,25 @@ int dictRehash(dict *d, int n) {
return
1
;
return
1
;
}
}
long
long
timeInMilliseconds
(
void
)
{
struct
timeval
tv
;
gettimeofday
(
&
tv
,
NULL
);
return
(((
long
long
)
tv
.
tv_sec
)
*
1000
)
+
(
tv
.
tv_usec
/
1000
);
}
/* Rehash for an amount of time between ms milliseconds and ms+1 milliseconds */
int
dictRehashMilliseconds
(
dict
*
d
,
int
ms
)
{
long
long
start
=
timeInMilliseconds
();
int
rehashes
=
0
;
while
(
dictRehash
(
d
,
100
))
{
rehashes
+=
100
;
if
(
timeInMilliseconds
()
-
start
>
ms
)
break
;
}
return
rehashes
;
}
/* This function performs just a step of rehashing, and only if there are
/* This function performs just a step of rehashing, and only if there are
* not iterators bound to our hash table. When we have iterators in the middle
* not iterators bound to our hash table. When we have iterators in the middle
* of a rehashing we can't mess with the two hash tables otherwise some element
* of a rehashing we can't mess with the two hash tables otherwise some element
...
@@ -527,7 +547,7 @@ static unsigned long _dictNextPower(unsigned long size)
...
@@ -527,7 +547,7 @@ static unsigned long _dictNextPower(unsigned long size)
* index is always returned in the context of the second (new) hash table. */
* index is always returned in the context of the second (new) hash table. */
static
int
_dictKeyIndex
(
dict
*
d
,
const
void
*
key
)
static
int
_dictKeyIndex
(
dict
*
d
,
const
void
*
key
)
{
{
unsigned
int
h
,
h1
,
h2
;
unsigned
int
h
,
idx
,
table
;
dictEntry
*
he
;
dictEntry
*
he
;
/* Expand the hashtable if needed */
/* Expand the hashtable if needed */
...
@@ -535,24 +555,18 @@ static int _dictKeyIndex(dict *d, const void *key)
...
@@ -535,24 +555,18 @@ static int _dictKeyIndex(dict *d, const void *key)
return
-
1
;
return
-
1
;
/* Compute the key hash value */
/* Compute the key hash value */
h
=
dictHashKey
(
d
,
key
);
h
=
dictHashKey
(
d
,
key
);
h1
=
h
&
d
->
ht
[
0
].
sizemask
;
for
(
table
=
0
;
table
<=
1
;
table
++
)
{
h2
=
h
&
d
->
ht
[
1
].
sizemask
;
idx
=
h
&
d
->
ht
[
table
].
sizemask
;
/* Search if this slot does not already contain the given key */
/* Search if this slot does not already contain the given key */
he
=
d
->
ht
[
0
].
table
[
h1
];
he
=
d
->
ht
[
table
].
table
[
idx
];
while
(
he
)
{
while
(
he
)
{
if
(
dictCompareHashKeys
(
d
,
key
,
he
->
key
))
if
(
dictCompareHashKeys
(
d
,
key
,
he
->
key
))
return
-
1
;
return
-
1
;
he
=
he
->
next
;
he
=
he
->
next
;
}
}
if
(
!
dictIsRehashing
(
d
))
return
h1
;
if
(
!
dictIsRehashing
(
d
))
break
;
/* Check the second hash table */
he
=
d
->
ht
[
1
].
table
[
h2
];
while
(
he
)
{
if
(
dictCompareHashKeys
(
d
,
key
,
he
->
key
))
return
-
1
;
he
=
he
->
next
;
}
}
return
h2
;
return
idx
;
}
}
void
dictEmpty
(
dict
*
d
)
{
void
dictEmpty
(
dict
*
d
)
{
...
...
dict.h
View file @
8ca3e9d1
...
@@ -122,24 +122,25 @@ typedef struct dictIterator {
...
@@ -122,24 +122,25 @@ typedef struct dictIterator {
/* API */
/* API */
dict
*
dictCreate
(
dictType
*
type
,
void
*
privDataPtr
);
dict
*
dictCreate
(
dictType
*
type
,
void
*
privDataPtr
);
int
dictExpand
(
dict
*
ht
,
unsigned
long
size
);
int
dictExpand
(
dict
*
d
,
unsigned
long
size
);
int
dictAdd
(
dict
*
ht
,
void
*
key
,
void
*
val
);
int
dictAdd
(
dict
*
d
,
void
*
key
,
void
*
val
);
int
dictReplace
(
dict
*
ht
,
void
*
key
,
void
*
val
);
int
dictReplace
(
dict
*
d
,
void
*
key
,
void
*
val
);
int
dictDelete
(
dict
*
ht
,
const
void
*
key
);
int
dictDelete
(
dict
*
d
,
const
void
*
key
);
int
dictDeleteNoFree
(
dict
*
ht
,
const
void
*
key
);
int
dictDeleteNoFree
(
dict
*
d
,
const
void
*
key
);
void
dictRelease
(
dict
*
ht
);
void
dictRelease
(
dict
*
d
);
dictEntry
*
dictFind
(
dict
*
ht
,
const
void
*
key
);
dictEntry
*
dictFind
(
dict
*
d
,
const
void
*
key
);
int
dictResize
(
dict
*
ht
);
int
dictResize
(
dict
*
d
);
dictIterator
*
dictGetIterator
(
dict
*
ht
);
dictIterator
*
dictGetIterator
(
dict
*
d
);
dictEntry
*
dictNext
(
dictIterator
*
iter
);
dictEntry
*
dictNext
(
dictIterator
*
iter
);
void
dictReleaseIterator
(
dictIterator
*
iter
);
void
dictReleaseIterator
(
dictIterator
*
iter
);
dictEntry
*
dictGetRandomKey
(
dict
*
ht
);
dictEntry
*
dictGetRandomKey
(
dict
*
d
);
void
dictPrintStats
(
dict
*
ht
);
void
dictPrintStats
(
dict
*
d
);
unsigned
int
dictGenHashFunction
(
const
unsigned
char
*
buf
,
int
len
);
unsigned
int
dictGenHashFunction
(
const
unsigned
char
*
buf
,
int
len
);
void
dictEmpty
(
dict
*
ht
);
void
dictEmpty
(
dict
*
d
);
void
dictEnableResize
(
void
);
void
dictEnableResize
(
void
);
void
dictDisableResize
(
void
);
void
dictDisableResize
(
void
);
int
dictRehash
(
dict
*
d
,
int
n
);
int
dictRehash
(
dict
*
d
,
int
n
);
int
dictRehashMilliseconds
(
dict
*
d
,
int
ms
);
/* Hash table types */
/* Hash table types */
extern
dictType
dictTypeHeapStringCopyKey
;
extern
dictType
dictTypeHeapStringCopyKey
;
...
...
redis.c
View file @
8ca3e9d1
...
@@ -91,7 +91,7 @@
...
@@ -91,7 +91,7 @@
#define REDIS_CONFIGLINE_MAX 1024
#define REDIS_CONFIGLINE_MAX 1024
#define REDIS_OBJFREELIST_MAX 1000000
/* Max number of objects to cache */
#define REDIS_OBJFREELIST_MAX 1000000
/* Max number of objects to cache */
#define REDIS_MAX_SYNC_TIME 60
/* Slave can't take more to sync */
#define REDIS_MAX_SYNC_TIME 60
/* Slave can't take more to sync */
#define REDIS_EXPIRELOOKUPS_PER_CRON 10
/*
try to expire 10 keys/
loop */
#define REDIS_EXPIRELOOKUPS_PER_CRON 10
/*
lookup 10 expires per
loop */
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256)
/* max bytes in inline command */
...
@@ -379,6 +379,7 @@ struct redisServer {
...
@@ -379,6 +379,7 @@ struct redisServer {
char
*
requirepass
;
char
*
requirepass
;
int
shareobjects
;
int
shareobjects
;
int
rdbcompression
;
int
rdbcompression
;
int
activerehashing
;
/* Replication related */
/* Replication related */
int
isslave
;
int
isslave
;
char
*
masterauth
;
char
*
masterauth
;
...
@@ -1208,6 +1209,21 @@ static void tryResizeHashTables(void) {
...
@@ -1208,6 +1209,21 @@ static void tryResizeHashTables(void) {
}
}
}
}
/* Our hash table implementation performs rehashing incrementally while
* we write/read from the hash table. Still if the server is idle, the hash
* table will use two tables for a long time. So we try to use 1 millisecond
* of CPU time at every serverCron() loop in order to rehash some key. */
static
void
incrementallyRehash
(
void
)
{
int
j
;
for
(
j
=
0
;
j
<
server
.
dbnum
;
j
++
)
{
if
(
dictIsRehashing
(
server
.
db
[
j
].
dict
))
{
dictRehashMilliseconds
(
server
.
db
[
j
].
dict
,
1
);
break
;
/* already used our millisecond for this loop... */
}
}
}
/* A background saving child (BGSAVE) terminated its work. Handle this. */
/* A background saving child (BGSAVE) terminated its work. Handle this. */
void
backgroundSaveDoneHandler
(
int
statloc
)
{
void
backgroundSaveDoneHandler
(
int
statloc
)
{
int
exitcode
=
WEXITSTATUS
(
statloc
);
int
exitcode
=
WEXITSTATUS
(
statloc
);
...
@@ -1337,10 +1353,9 @@ static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientD
...
@@ -1337,10 +1353,9 @@ static int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientD
* if we resize the HT while there is the saving child at work actually
* if we resize the HT while there is the saving child at work actually
* a lot of memory movements in the parent will cause a lot of pages
* a lot of memory movements in the parent will cause a lot of pages
* copied. */
* copied. */
if
(
server
.
bgsavechildpid
==
-
1
&&
server
.
bgrewritechildpid
==
-
1
&&
if
(
server
.
bgsavechildpid
==
-
1
&&
server
.
bgrewritechildpid
==
-
1
)
{
!
(
loops
%
10
))
if
(
!
(
loops
%
10
))
tryResizeHashTables
();
{
if
(
server
.
activerehashing
)
incrementallyRehash
();
tryResizeHashTables
();
}
}
/* Show information about connected clients */
/* Show information about connected clients */
...
@@ -1568,6 +1583,7 @@ static void initServerConfig() {
...
@@ -1568,6 +1583,7 @@ static void initServerConfig() {
server
.
requirepass
=
NULL
;
server
.
requirepass
=
NULL
;
server
.
shareobjects
=
0
;
server
.
shareobjects
=
0
;
server
.
rdbcompression
=
1
;
server
.
rdbcompression
=
1
;
server
.
activerehashing
=
1
;
server
.
maxclients
=
0
;
server
.
maxclients
=
0
;
server
.
blpop_blocked_clients
=
0
;
server
.
blpop_blocked_clients
=
0
;
server
.
maxmemory
=
0
;
server
.
maxmemory
=
0
;
...
@@ -1801,6 +1817,10 @@ static void loadServerConfig(char *filename) {
...
@@ -1801,6 +1817,10 @@ static void loadServerConfig(char *filename) {
if
((
server
.
rdbcompression
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
if
((
server
.
rdbcompression
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"activerehashing"
)
&&
argc
==
2
)
{
if
((
server
.
activerehashing
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"daemonize"
)
&&
argc
==
2
)
{
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"daemonize"
)
&&
argc
==
2
)
{
if
((
server
.
daemonize
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
if
((
server
.
daemonize
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
...
...
redis.conf
View file @
8ca3e9d1
...
@@ -262,6 +262,26 @@ glueoutputbuf yes
...
@@ -262,6 +262,26 @@ glueoutputbuf yes
hash
-
max
-
zipmap
-
entries
64
hash
-
max
-
zipmap
-
entries
64
hash
-
max
-
zipmap
-
value
512
hash
-
max
-
zipmap
-
value
512
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into an hash table
# that is rhashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
# The default is to use this millisecond 10 times every second in order to
# active rehashing the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply form time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
activerehashing
yes
################################## INCLUDES ###################################
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# Include one or more other config files here. This is useful if you
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment