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
0f999784
Commit
0f999784
authored
Mar 24, 2012
by
antirez
Browse files
Merge remote-tracking branch 'origin/unstable' into unstable
parents
74f10793
1b247d13
Changes
42
Show whitespace changes
Inline
Side-by-side
00-RELEASENOTES
View file @
0f999784
...
...
@@ -22,6 +22,12 @@ but it is better to keep them in mind:
starting with '#'. All the major clients should be already fixed to work
with the new INFO format.
Also the following redis.conf and CONFIG GET / SET parameters changed name:
* hash-max-zipmap-entries, now replaced by hash-max-ziplist-entries
* hash-max-zipmap-value, now replaced by hash-max-ziplist-value
* glueoutputbuf was no completely removed as it does not make sense
---------
CHANGELOG
---------
...
...
redis.conf
View file @
0f999784
...
...
@@ -93,6 +93,21 @@ save 900 1
save
300
10
save
60
10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in an hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# distater will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usually even if there are problems with disk,
# permissions, and so forth.
stop
-
writes
-
on
-
bgsave
-
error
yes
# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
...
...
@@ -141,6 +156,22 @@ dir ./
#
slave
-
serve
-
stale
-
data
yes
# You can configure a slave instance to accept writes or not. Writing against
# a slave instance may be useful to store some ephemeral data (because data
# written on a slave will be easily deleted after resync with the master) but
# may also cause problems if clients are writing to it because of a
# misconfiguration.
#
# Since Redis 2.6 by default slaves are read-only.
#
# Note: read only slaves are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only slave exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extend you can improve
# security of read only slaves using 'rename-command' to shadow all the
# administrative / dangerous commands.
slave
-
read
-
only
yes
# Slaves send PINGs to server in a predefined interval. It's possible to change
# this interval with the repl_ping_slave_period option. The default value is 10
# seconds.
...
...
@@ -231,7 +262,7 @@ slave-serve-stale-data yes
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-
>
random -> remove a random key, any key
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
...
...
@@ -406,12 +437,11 @@ slowlog-max-len 1024
############################### ADVANCED CONFIG ###############################
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash
-
max
-
zipmap
-
entries
512
hash
-
max
-
zipmap
-
value
64
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash
-
max
-
ziplist
-
entries
512
hash
-
max
-
ziplist
-
value
64
# Similarly to hashes, small lists are also encoded in a special way in order
# to save a lot of space. The special representation is only used when
...
...
src/Makefile
View file @
0f999784
...
...
@@ -73,7 +73,7 @@ QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR
QUIET_LINK
=
@printf
' %b %b\n'
$(LINKCOLOR)
LINK
$(ENDCOLOR)
$(BINCOLOR)$@$(ENDCOLOR)
;
endif
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
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
BENCHOBJ
=
ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
CLIOBJ
=
anet.o sds.o adlist.o redis-cli.o zmalloc.o release.o
CHECKDUMPOBJ
=
redis-check-dump.o lzf_c.o lzf_d.o
...
...
@@ -98,35 +98,39 @@ ae_kqueue.o: ae_kqueue.c
ae_select.o
:
ae_select.c
anet.o
:
anet.c fmacros.h anet.h
aof.o
:
aof.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h bio.h
bio.o
:
bio.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h bio.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
bio.h
cluster.o
:
cluster.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h
\
rio.h
config.o
:
config.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
crc16.o
:
crc16.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
db.o
:
db.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
debug.o
:
debug.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h sha1.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
sha1.h
dict.o
:
dict.c fmacros.h dict.h zmalloc.h
endianconv.o
:
endianconv.c
intset.o
:
intset.c intset.h zmalloc.h endianconv.h
lzf_c.o
:
lzf_c.c lzfP.h
lzf_d.o
:
lzf_d.c lzfP.h
multi.o
:
multi.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
networking.o
:
networking.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h
\
rio.h
object.o
:
object.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
pqsort.o
:
pqsort.c
pubsub.o
:
pubsub.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h rio.h
rand.o
:
rand.c
rdb.o
:
rdb.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h lzf.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h rio.h lzf.h
\
zipmap.h
redis-benchmark.o
:
redis-benchmark.c fmacros.h ae.h
\
../deps/hiredis/hiredis.h sds.h adlist.h zmalloc.h
redis-check-aof.o
:
redis-check-aof.c fmacros.h config.h
...
...
@@ -134,34 +138,37 @@ redis-check-dump.o: redis-check-dump.c lzf.h
redis-cli.o
:
redis-cli.c fmacros.h version.h ../deps/hiredis/hiredis.h
\
sds.h zmalloc.h ../deps/linenoise/linenoise.h help.h
redis.o
:
redis.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
slowlog
.h
\
bio.h asciilogo.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio
.h
\
slowlog.h
bio.h asciilogo.h
release.o
:
release.c release.h
replication.o
:
replication.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h
\
rio.h
rio.o
:
rio.c fmacros.h rio.h sds.h util.h
scripting.o
:
scripting.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
\
sha1.h rand.h
rio.o
:
rio.c sds.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h
\
rio.h sha1.h rand.h
sds.o
:
sds.c sds.h zmalloc.h
sha1.o
:
sha1.c sha1.h config.h
slowlog.o
:
slowlog.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
\
slowlog.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h
\
rio.h
slowlog.h
sort.o
:
sort.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h pqsort.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h rio.h
\
pqsort.h
syncio.o
:
syncio.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
t_hash.o
:
t_hash.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
t_list.o
:
t_list.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
t_set.o
:
t_set.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
t_string.o
:
t_string.c redis.h fmacros.h config.h ae.h sds.h dict.h
\
adlist.h zmalloc.h anet.h zipmap.h ziplist.h intset.h version.h util.h
adlist.h zmalloc.h anet.h ziplist.h intset.h version.h util.h rdb.h
\
rio.h
t_zset.o
:
t_zset.c redis.h fmacros.h config.h ae.h sds.h dict.h adlist.h
\
zmalloc.h anet.h
zipmap.h
ziplist.h intset.h version.h util.h
zmalloc.h anet.h ziplist.h intset.h version.h util.h
rdb.h rio.h
util.o
:
util.c fmacros.h util.h
ziplist.o
:
ziplist.c zmalloc.h util.h ziplist.h endianconv.h
zipmap.o
:
zipmap.c zmalloc.h endianconv.h
...
...
src/adlist.c
View file @
0f999784
...
...
@@ -323,3 +323,19 @@ listNode *listIndex(list *list, long index) {
}
return
n
;
}
/* Rotate the list removing the tail node and inserting it to the head. */
void
listRotate
(
list
*
list
)
{
listNode
*
tail
=
list
->
tail
;
if
(
listLength
(
list
)
<=
1
)
return
;
/* Detatch current tail */
list
->
tail
=
tail
->
prev
;
list
->
tail
->
next
=
NULL
;
/* Move it as head */
list
->
head
->
prev
=
tail
;
tail
->
prev
=
NULL
;
tail
->
next
=
list
->
head
;
list
->
head
=
tail
;
}
src/adlist.h
View file @
0f999784
...
...
@@ -84,6 +84,7 @@ listNode *listSearchKey(list *list, void *key);
listNode
*
listIndex
(
list
*
list
,
long
index
);
void
listRewind
(
list
*
list
,
listIter
*
li
);
void
listRewindTail
(
list
*
list
,
listIter
*
li
);
void
listRotate
(
list
*
list
);
/* Directions for iterators */
#define AL_START_HEAD 0
...
...
src/anet.c
View file @
0f999784
...
...
@@ -353,7 +353,12 @@ int anetPeerToString(int fd, char *ip, int *port) {
struct
sockaddr_in
sa
;
socklen_t
salen
=
sizeof
(
sa
);
if
(
getpeername
(
fd
,(
struct
sockaddr
*
)
&
sa
,
&
salen
)
==
-
1
)
return
-
1
;
if
(
getpeername
(
fd
,(
struct
sockaddr
*
)
&
sa
,
&
salen
)
==
-
1
)
{
*
port
=
0
;
ip
[
0
]
=
'?'
;
ip
[
1
]
=
'\0'
;
return
-
1
;
}
if
(
ip
)
strcpy
(
ip
,
inet_ntoa
(
sa
.
sin_addr
));
if
(
port
)
*
port
=
ntohs
(
sa
.
sin_port
);
return
0
;
...
...
src/aof.c
View file @
0f999784
...
...
@@ -287,6 +287,7 @@ struct redisClient *createFakeClient(void) {
selectDb
(
c
,
0
);
c
->
fd
=
-
1
;
c
->
querybuf
=
sdsempty
();
c
->
querybuf_peak
=
0
;
c
->
argc
=
0
;
c
->
argv
=
NULL
;
c
->
bufpos
=
0
;
...
...
@@ -609,17 +610,44 @@ int rewriteSortedSetObject(rio *r, robj *key, robj *o) {
return
1
;
}
/* Write either the key or the value of the currently selected item of an hash.
* The 'hi' argument passes a valid Redis hash iterator.
* The 'what' filed specifies if to write a key or a value and can be
* either REDIS_HASH_KEY or REDIS_HASH_VALUE.
*
* The function returns 0 on error, non-zero on success. */
static
int
rioWriteHashIteratorCursor
(
rio
*
r
,
hashTypeIterator
*
hi
,
int
what
)
{
if
(
hi
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
unsigned
char
*
vstr
=
NULL
;
unsigned
int
vlen
=
UINT_MAX
;
long
long
vll
=
LLONG_MAX
;
hashTypeCurrentFromZiplist
(
hi
,
what
,
&
vstr
,
&
vlen
,
&
vll
);
if
(
vstr
)
{
return
rioWriteBulkString
(
r
,
(
char
*
)
vstr
,
vlen
);
}
else
{
return
rioWriteBulkLongLong
(
r
,
vll
);
}
}
else
if
(
hi
->
encoding
==
REDIS_ENCODING_HT
)
{
robj
*
value
;
hashTypeCurrentFromHashTable
(
hi
,
what
,
&
value
);
return
rioWriteBulkObject
(
r
,
value
);
}
redisPanic
(
"Unknown hash encoding"
);
return
0
;
}
/* Emit the commands needed to rebuild a hash object.
* The function returns 0 on error, 1 on success. */
int
rewriteHashObject
(
rio
*
r
,
robj
*
key
,
robj
*
o
)
{
hashTypeIterator
*
hi
;
long
long
count
=
0
,
items
=
hashTypeLength
(
o
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
p
=
zipmapRewind
(
o
->
ptr
);
unsigned
char
*
field
,
*
val
;
unsigned
int
flen
,
vlen
;
while
((
p
=
zipmapNext
(
p
,
&
field
,
&
flen
,
&
val
,
&
vlen
))
!=
NULL
)
{
hi
=
hashTypeInitIterator
(
o
);
while
(
hashTypeNext
(
hi
)
!=
REDIS_ERR
)
{
if
(
count
==
0
)
{
int
cmd_items
=
(
items
>
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
?
REDIS_AOF_REWRITE_ITEMS_PER_CMD
:
items
;
...
...
@@ -628,34 +656,15 @@ int rewriteHashObject(rio *r, robj *key, robj *o) {
if
(
rioWriteBulkString
(
r
,
"HMSET"
,
5
)
==
0
)
return
0
;
if
(
rioWriteBulkObject
(
r
,
key
)
==
0
)
return
0
;
}
if
(
rioWriteBulkString
(
r
,(
char
*
)
field
,
flen
)
==
0
)
return
0
;
if
(
rioWriteBulkString
(
r
,(
char
*
)
val
,
vlen
)
==
0
)
return
0
;
if
(
rioWriteHashIteratorCursor
(
r
,
hi
,
REDIS_HASH_KEY
)
==
0
)
return
0
;
if
(
rioWriteHashIteratorCursor
(
r
,
hi
,
REDIS_HASH_VALUE
)
==
0
)
return
0
;
if
(
++
count
==
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
count
=
0
;
items
--
;
}
}
else
{
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
field
=
dictGetKey
(
de
);
robj
*
val
=
dictGetVal
(
de
);
hashTypeReleaseIterator
(
hi
);
if
(
count
==
0
)
{
int
cmd_items
=
(
items
>
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
?
REDIS_AOF_REWRITE_ITEMS_PER_CMD
:
items
;
if
(
rioWriteBulkCount
(
r
,
'*'
,
2
+
cmd_items
*
2
)
==
0
)
return
0
;
if
(
rioWriteBulkString
(
r
,
"HMSET"
,
5
)
==
0
)
return
0
;
if
(
rioWriteBulkObject
(
r
,
key
)
==
0
)
return
0
;
}
if
(
rioWriteBulkObject
(
r
,
field
)
==
0
)
return
0
;
if
(
rioWriteBulkObject
(
r
,
val
)
==
0
)
return
0
;
if
(
++
count
==
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
count
=
0
;
items
--
;
}
dictReleaseIterator
(
di
);
}
return
1
;
}
...
...
src/cluster.c
View file @
0f999784
...
...
@@ -19,20 +19,6 @@ int clusterAddSlot(clusterNode *n, int slot);
* Initialization
* -------------------------------------------------------------------------- */
void
clusterGetRandomName
(
char
*
p
)
{
FILE
*
fp
=
fopen
(
"/dev/urandom"
,
"r"
);
char
*
charset
=
"0123456789abcdef"
;
int
j
;
if
(
fp
==
NULL
||
fread
(
p
,
REDIS_CLUSTER_NAMELEN
,
1
,
fp
)
==
0
)
{
for
(
j
=
0
;
j
<
REDIS_CLUSTER_NAMELEN
;
j
++
)
p
[
j
]
=
rand
();
}
for
(
j
=
0
;
j
<
REDIS_CLUSTER_NAMELEN
;
j
++
)
p
[
j
]
=
charset
[
p
[
j
]
&
0x0F
];
fclose
(
fp
);
}
int
clusterLoadConfig
(
char
*
filename
)
{
FILE
*
fp
=
fopen
(
filename
,
"r"
);
char
*
line
;
...
...
@@ -304,7 +290,7 @@ clusterNode *createClusterNode(char *nodename, int flags) {
if
(
nodename
)
memcpy
(
node
->
name
,
nodename
,
REDIS_CLUSTER_NAMELEN
);
else
clusterGetRandomName
(
node
->
name
);
getRandomHexChars
(
node
->
name
,
REDIS_CLUSTER_NAMELEN
);
node
->
flags
=
flags
;
memset
(
node
->
slots
,
0
,
sizeof
(
node
->
slots
));
node
->
numslaves
=
0
;
...
...
src/config.c
View file @
0f999784
...
...
@@ -202,8 +202,10 @@ void loadServerConfigFromString(char *config) {
if
((
server
.
repl_serve_stale_data
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"glueoutputbuf"
))
{
redisLog
(
REDIS_WARNING
,
"Deprecated configuration directive:
\"
%s
\"
"
,
argv
[
0
]);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"slave-read-only"
)
&&
argc
==
2
)
{
if
((
server
.
repl_slave_ro
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"rdbcompression"
)
&&
argc
==
2
)
{
if
((
server
.
rdb_compression
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
...
...
@@ -262,10 +264,10 @@ void loadServerConfigFromString(char *config) {
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"dbfilename"
)
&&
argc
==
2
)
{
zfree
(
server
.
rdb_filename
);
server
.
rdb_filename
=
zstrdup
(
argv
[
1
]);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"hash-max-zip
map
-entries"
)
&&
argc
==
2
)
{
server
.
hash_max_zip
map
_entries
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"hash-max-zip
map
-value"
)
&&
argc
==
2
)
{
server
.
hash_max_zip
map
_value
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"hash-max-zip
list
-entries"
)
&&
argc
==
2
)
{
server
.
hash_max_zip
list
_entries
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"hash-max-zip
list
-value"
)
&&
argc
==
2
)
{
server
.
hash_max_zip
list
_value
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"list-max-ziplist-entries"
)
&&
argc
==
2
){
server
.
list_max_ziplist_entries
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"list-max-ziplist-value"
)
&&
argc
==
2
)
{
...
...
@@ -336,6 +338,11 @@ void loadServerConfigFromString(char *config) {
server
.
client_obuf_limits
[
class
].
hard_limit_bytes
=
hard
;
server
.
client_obuf_limits
[
class
].
soft_limit_bytes
=
soft
;
server
.
client_obuf_limits
[
class
].
soft_limit_seconds
=
soft_seconds
;
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"stop-writes-on-bgsave-error"
)
&&
argc
==
2
)
{
if
((
server
.
stop_writes_on_bgsave_err
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
{
err
=
"Bad directive or wrong number of arguments"
;
goto
loaderr
;
}
...
...
@@ -511,17 +518,22 @@ void configSetCommand(redisClient *c) {
if
(
yn
==
-
1
)
goto
badfmt
;
server
.
repl_serve_stale_data
=
yn
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"slave-read-only"
))
{
int
yn
=
yesnotoi
(
o
->
ptr
);
if
(
yn
==
-
1
)
goto
badfmt
;
server
.
repl_slave_ro
=
yn
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"dir"
))
{
if
(
chdir
((
char
*
)
o
->
ptr
)
==
-
1
)
{
addReplyErrorFormat
(
c
,
"Changing directory: %s"
,
strerror
(
errno
));
return
;
}
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"hash-max-zip
map
-entries"
))
{
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"hash-max-zip
list
-entries"
))
{
if
(
getLongLongFromObject
(
o
,
&
ll
)
==
REDIS_ERR
||
ll
<
0
)
goto
badfmt
;
server
.
hash_max_zip
map
_entries
=
ll
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"hash-max-zip
map
-value"
))
{
server
.
hash_max_zip
list
_entries
=
ll
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"hash-max-zip
list
-value"
))
{
if
(
getLongLongFromObject
(
o
,
&
ll
)
==
REDIS_ERR
||
ll
<
0
)
goto
badfmt
;
server
.
hash_max_zip
map
_value
=
ll
;
server
.
hash_max_zip
list
_value
=
ll
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"list-max-ziplist-entries"
))
{
if
(
getLongLongFromObject
(
o
,
&
ll
)
==
REDIS_ERR
||
ll
<
0
)
goto
badfmt
;
server
.
list_max_ziplist_entries
=
ll
;
...
...
@@ -604,7 +616,17 @@ void configSetCommand(redisClient *c) {
server
.
client_obuf_limits
[
class
].
soft_limit_seconds
=
soft_seconds
;
}
sdsfreesplitres
(
v
,
vlen
);
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"stop-writes-on-bgsave-error"
))
{
int
yn
=
yesnotoi
(
o
->
ptr
);
if
(
yn
==
-
1
)
goto
badfmt
;
server
.
stop_writes_on_bgsave_err
=
yn
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"repl-ping-slave-period"
))
{
if
(
getLongLongFromObject
(
o
,
&
ll
)
==
REDIS_ERR
||
ll
<=
0
)
goto
badfmt
;
server
.
repl_ping_slave_period
=
ll
;
}
else
if
(
!
strcasecmp
(
c
->
argv
[
2
]
->
ptr
,
"repl-timeout"
))
{
if
(
getLongLongFromObject
(
o
,
&
ll
)
==
REDIS_ERR
||
ll
<=
0
)
goto
badfmt
;
server
.
repl_timeout
=
ll
;
}
else
{
addReplyErrorFormat
(
c
,
"Unsupported CONFIG parameter: %s"
,
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
...
...
@@ -619,6 +641,31 @@ badfmt: /* Bad format errors */
(
char
*
)
c
->
argv
[
2
]
->
ptr
);
}
#define config_get_string_field(_name,_var) do { \
if (stringmatch(pattern,_name,0)) { \
addReplyBulkCString(c,_name); \
addReplyBulkCString(c,_var ? _var : ""); \
matches++; \
} \
} while(0);
#define config_get_bool_field(_name,_var) do { \
if (stringmatch(pattern,_name,0)) { \
addReplyBulkCString(c,_name); \
addReplyBulkCString(c,_var ? "yes" : "no"); \
matches++; \
} \
} while(0);
#define config_get_numerical_field(_name,_var) do { \
if (stringmatch(pattern,_name,0)) { \
ll2string(buf,sizeof(buf),_var); \
addReplyBulkCString(c,_name); \
addReplyBulkCString(c,buf); \
matches++; \
} \
} while(0);
void
configGetCommand
(
redisClient
*
c
)
{
robj
*
o
=
c
->
argv
[
2
];
void
*
replylen
=
addDeferredMultiBulkLength
(
c
);
...
...
@@ -627,6 +674,68 @@ void configGetCommand(redisClient *c) {
int
matches
=
0
;
redisAssertWithInfo
(
c
,
o
,
o
->
encoding
==
REDIS_ENCODING_RAW
);
/* String values */
config_get_string_field
(
"dbfilename"
,
server
.
rdb_filename
);
config_get_string_field
(
"requirepass"
,
server
.
requirepass
);
config_get_string_field
(
"masterauth"
,
server
.
requirepass
);
config_get_string_field
(
"bind"
,
server
.
bindaddr
);
config_get_string_field
(
"unixsocket"
,
server
.
unixsocket
);
config_get_string_field
(
"logfile"
,
server
.
logfile
);
config_get_string_field
(
"pidfile"
,
server
.
pidfile
);
/* Numerical values */
config_get_numerical_field
(
"maxmemory"
,
server
.
maxmemory
);
config_get_numerical_field
(
"maxmemory-samples"
,
server
.
maxmemory_samples
);
config_get_numerical_field
(
"timeout"
,
server
.
maxidletime
);
config_get_numerical_field
(
"auto-aof-rewrite-percentage"
,
server
.
aof_rewrite_perc
);
config_get_numerical_field
(
"auto-aof-rewrite-min-size"
,
server
.
aof_rewrite_min_size
);
config_get_numerical_field
(
"hash-max-ziplist-entries"
,
server
.
hash_max_ziplist_entries
);
config_get_numerical_field
(
"hash-max-ziplist-value"
,
server
.
hash_max_ziplist_value
);
config_get_numerical_field
(
"list-max-ziplist-entries"
,
server
.
list_max_ziplist_entries
);
config_get_numerical_field
(
"list-max-ziplist-value"
,
server
.
list_max_ziplist_value
);
config_get_numerical_field
(
"set-max-intset-entries"
,
server
.
set_max_intset_entries
);
config_get_numerical_field
(
"zset-max-ziplist-entries"
,
server
.
zset_max_ziplist_entries
);
config_get_numerical_field
(
"zset-max-ziplist-value"
,
server
.
zset_max_ziplist_value
);
config_get_numerical_field
(
"lua-time-limit"
,
server
.
lua_time_limit
);
config_get_numerical_field
(
"slowlog-log-slower-than"
,
server
.
slowlog_log_slower_than
);
config_get_numerical_field
(
"slowlog-max-len"
,
server
.
slowlog_max_len
);
config_get_numerical_field
(
"port"
,
server
.
port
);
config_get_numerical_field
(
"databases"
,
server
.
dbnum
);
config_get_numerical_field
(
"repl-ping-slave-period"
,
server
.
repl_ping_slave_period
);
config_get_numerical_field
(
"repl-timeout"
,
server
.
repl_timeout
);
config_get_numerical_field
(
"maxclients"
,
server
.
maxclients
);
/* Bool (yes/no) values */
config_get_bool_field
(
"no-appendfsync-on-rewrite"
,
server
.
aof_no_fsync_on_rewrite
);
config_get_bool_field
(
"slave-serve-stale-data"
,
server
.
repl_serve_stale_data
);
config_get_bool_field
(
"slave-read-only"
,
server
.
repl_slave_ro
);
config_get_bool_field
(
"stop-writes-on-bgsave-error"
,
server
.
stop_writes_on_bgsave_err
);
config_get_bool_field
(
"daemonize"
,
server
.
daemonize
);
config_get_bool_field
(
"rdbcompression"
,
server
.
rdb_compression
);
config_get_bool_field
(
"activerehashing"
,
server
.
activerehashing
);
/* Everything we can't handle with macros follows. */
if
(
stringmatch
(
pattern
,
"appendonly"
,
0
))
{
addReplyBulkCString
(
c
,
"appendonly"
);
addReplyBulkCString
(
c
,
server
.
aof_state
==
REDIS_AOF_OFF
?
"no"
:
"yes"
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"dir"
,
0
))
{
char
buf
[
1024
];
...
...
@@ -637,27 +746,6 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"dbfilename"
,
0
))
{
addReplyBulkCString
(
c
,
"dbfilename"
);
addReplyBulkCString
(
c
,
server
.
rdb_filename
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"requirepass"
,
0
))
{
addReplyBulkCString
(
c
,
"requirepass"
);
addReplyBulkCString
(
c
,
server
.
requirepass
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"masterauth"
,
0
))
{
addReplyBulkCString
(
c
,
"masterauth"
);
addReplyBulkCString
(
c
,
server
.
masterauth
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"maxmemory"
,
0
))
{
ll2string
(
buf
,
sizeof
(
buf
),
server
.
maxmemory
);
addReplyBulkCString
(
c
,
"maxmemory"
);
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"maxmemory-policy"
,
0
))
{
char
*
s
;
...
...
@@ -674,28 +762,6 @@ void configGetCommand(redisClient *c) {
addReplyBulkCString
(
c
,
s
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"maxmemory-samples"
,
0
))
{
ll2string
(
buf
,
sizeof
(
buf
),
server
.
maxmemory_samples
);
addReplyBulkCString
(
c
,
"maxmemory-samples"
);
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"timeout"
,
0
))
{
ll2string
(
buf
,
sizeof
(
buf
),
server
.
maxidletime
);
addReplyBulkCString
(
c
,
"timeout"
);
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"appendonly"
,
0
))
{
addReplyBulkCString
(
c
,
"appendonly"
);
addReplyBulkCString
(
c
,
server
.
aof_state
==
REDIS_AOF_OFF
?
"no"
:
"yes"
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"no-appendfsync-on-rewrite"
,
0
))
{
addReplyBulkCString
(
c
,
"no-appendfsync-on-rewrite"
);
addReplyBulkCString
(
c
,
server
.
aof_no_fsync_on_rewrite
?
"yes"
:
"no"
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"appendfsync"
,
0
))
{
char
*
policy
;
...
...
@@ -725,71 +791,6 @@ void configGetCommand(redisClient *c) {
sdsfree
(
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"auto-aof-rewrite-percentage"
,
0
))
{
addReplyBulkCString
(
c
,
"auto-aof-rewrite-percentage"
);
addReplyBulkLongLong
(
c
,
server
.
aof_rewrite_perc
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"auto-aof-rewrite-min-size"
,
0
))
{
addReplyBulkCString
(
c
,
"auto-aof-rewrite-min-size"
);
addReplyBulkLongLong
(
c
,
server
.
aof_rewrite_min_size
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"slave-serve-stale-data"
,
0
))
{
addReplyBulkCString
(
c
,
"slave-serve-stale-data"
);
addReplyBulkCString
(
c
,
server
.
repl_serve_stale_data
?
"yes"
:
"no"
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"hash-max-zipmap-entries"
,
0
))
{
addReplyBulkCString
(
c
,
"hash-max-zipmap-entries"
);
addReplyBulkLongLong
(
c
,
server
.
hash_max_zipmap_entries
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"hash-max-zipmap-value"
,
0
))
{
addReplyBulkCString
(
c
,
"hash-max-zipmap-value"
);
addReplyBulkLongLong
(
c
,
server
.
hash_max_zipmap_value
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"list-max-ziplist-entries"
,
0
))
{
addReplyBulkCString
(
c
,
"list-max-ziplist-entries"
);
addReplyBulkLongLong
(
c
,
server
.
list_max_ziplist_entries
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"list-max-ziplist-value"
,
0
))
{
addReplyBulkCString
(
c
,
"list-max-ziplist-value"
);
addReplyBulkLongLong
(
c
,
server
.
list_max_ziplist_value
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"set-max-intset-entries"
,
0
))
{
addReplyBulkCString
(
c
,
"set-max-intset-entries"
);
addReplyBulkLongLong
(
c
,
server
.
set_max_intset_entries
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"zset-max-ziplist-entries"
,
0
))
{
addReplyBulkCString
(
c
,
"zset-max-ziplist-entries"
);
addReplyBulkLongLong
(
c
,
server
.
zset_max_ziplist_entries
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"zset-max-ziplist-value"
,
0
))
{
addReplyBulkCString
(
c
,
"zset-max-ziplist-value"
);
addReplyBulkLongLong
(
c
,
server
.
zset_max_ziplist_value
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"lua-time-limit"
,
0
))
{
addReplyBulkCString
(
c
,
"lua-time-limit"
);
addReplyBulkLongLong
(
c
,
server
.
lua_time_limit
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"slowlog-log-slower-than"
,
0
))
{
addReplyBulkCString
(
c
,
"slowlog-log-slower-than"
);
addReplyBulkLongLong
(
c
,
server
.
slowlog_log_slower_than
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"slowlog-max-len"
,
0
))
{
addReplyBulkCString
(
c
,
"slowlog-max-len"
);
addReplyBulkLongLong
(
c
,
server
.
slowlog_max_len
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"loglevel"
,
0
))
{
char
*
s
;
...
...
@@ -822,6 +823,25 @@ void configGetCommand(redisClient *c) {
sdsfree
(
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"unixsocketperm"
,
0
))
{
char
buf
[
32
];
snprintf
(
buf
,
sizeof
(
buf
),
"%o"
,
server
.
unixsocketperm
);
addReplyBulkCString
(
c
,
"unixsocketperm"
);
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
if
(
stringmatch
(
pattern
,
"slaveof"
,
0
))
{
char
buf
[
256
];
addReplyBulkCString
(
c
,
"slaveof"
);
if
(
server
.
masterhost
)
snprintf
(
buf
,
sizeof
(
buf
),
"%s %d"
,
server
.
masterhost
,
server
.
masterport
);
else
buf
[
0
]
=
'\0'
;
addReplyBulkCString
(
c
,
buf
);
matches
++
;
}
setDeferredMultiBulkLength
(
c
,
replylen
,
matches
*
2
);
}
...
...
src/debug.c
View file @
0f999784
...
...
@@ -638,6 +638,7 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
"
\n
=== REDIS BUG REPORT END. Make sure to include from START to END. ===
\n\n
"
" Please report the crash opening an issue on github:
\n\n
"
" http://github.com/antirez/redis/issues
\n\n
"
" Suspect RAM error? Use redis-server --test-memory to veryfy it.
\n\n
"
);
/* free(messages); Don't call free() with possibly corrupted memory. */
if
(
server
.
daemonize
)
unlink
(
server
.
pidfile
);
...
...
src/memtest.c
0 → 100644
View file @
0f999784
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#include <errno.h>
#include <termios.h>
#include <sys/ioctl.h>
#if (ULONG_MAX == 4294967295UL)
#define MEMTEST_32BIT
#elif (ULONG_MAX == 18446744073709551615ULL)
#define MEMTEST_64BIT
#else
#error "ULONG_MAX value not supported."
#endif
#ifdef MEMTEST_32BIT
#define ULONG_ONEZERO 0xaaaaaaaaaaaaaaaaUL
#define ULONG_ZEROONE 0x5555555555555555UL
#else
#define ULONG_ONEZERO 0xaaaaaaaaUL
#define ULONG_ZEROONE 0x55555555UL
#endif
static
struct
winsize
ws
;
size_t
progress_printed
;
/* Printed chars in screen-wide progress bar. */
size_t
progress_full
;
/* How many chars to write to fill the progress bar. */
void
memtest_progress_start
(
char
*
title
,
int
pass
)
{
int
j
;
printf
(
"
\x1b
[H
\x1b
[2J"
);
/* Cursor home, clear screen. */
/* Fill with dots. */
for
(
j
=
0
;
j
<
ws
.
ws_col
*
(
ws
.
ws_row
-
2
);
j
++
)
printf
(
"."
);
printf
(
"Please keep the test running several minutes per GB of memory.
\n
"
);
printf
(
"Also check http://www.memtest86.com/ and http://pyropus.ca/software/memtester/"
);
printf
(
"
\x1b
[H
\x1b
[2K"
);
/* Cursor home, clear current line. */
printf
(
"%s [%d]
\n
"
,
title
,
pass
);
/* Print title. */
progress_printed
=
0
;
progress_full
=
ws
.
ws_col
*
(
ws
.
ws_row
-
3
);
fflush
(
stdout
);
}
void
memtest_progress_end
(
void
)
{
printf
(
"
\x1b
[H
\x1b
[2J"
);
/* Cursor home, clear screen. */
}
void
memtest_progress_step
(
size_t
curr
,
size_t
size
,
char
c
)
{
size_t
chars
=
(
curr
*
progress_full
)
/
size
,
j
;
for
(
j
=
0
;
j
<
chars
-
progress_printed
;
j
++
)
{
printf
(
"%c"
,
c
);
progress_printed
++
;
}
fflush
(
stdout
);
}
/* Test that addressing is fine. Every location is populated with its own
* address, and finally verified. This test is very fast but may detect
* ASAP big issues with the memory subsystem. */
void
memtest_addressing
(
unsigned
long
*
l
,
size_t
bytes
)
{
unsigned
long
words
=
bytes
/
sizeof
(
unsigned
long
);
unsigned
long
j
,
*
p
;
/* Fill */
p
=
l
;
for
(
j
=
0
;
j
<
words
;
j
++
)
{
*
p
=
(
unsigned
long
)
p
;
p
++
;
if
((
j
&
0xffff
)
==
0
)
memtest_progress_step
(
j
,
words
*
2
,
'A'
);
}
/* Test */
p
=
l
;
for
(
j
=
0
;
j
<
words
;
j
++
)
{
if
(
*
p
!=
(
unsigned
long
)
p
)
{
printf
(
"
\n
*** MEMORY ADDRESSING ERROR: %p contains %lu
\n
"
,
(
void
*
)
p
,
*
p
);
exit
(
1
);
}
p
++
;
if
((
j
&
0xffff
)
==
0
)
memtest_progress_step
(
j
+
words
,
words
*
2
,
'A'
);
}
}
/* Fill words stepping a single page at every write, so we continue to
* touch all the pages in the smallest amount of time reducing the
* effectiveness of caches, and making it hard for the OS to transfer
* pages on the swap. */
void
memtest_fill_random
(
unsigned
long
*
l
,
size_t
bytes
)
{
unsigned
long
step
=
4096
/
sizeof
(
unsigned
long
);
unsigned
long
words
=
bytes
/
sizeof
(
unsigned
long
)
/
2
;
unsigned
long
iwords
=
words
/
step
;
/* words per iteration */
unsigned
long
off
,
w
,
*
l1
,
*
l2
;
assert
((
bytes
&
4095
)
==
0
);
for
(
off
=
0
;
off
<
step
;
off
++
)
{
l1
=
l
+
off
;
l2
=
l1
+
words
;
for
(
w
=
0
;
w
<
iwords
;
w
++
)
{
#ifdef MEMTEST_32BIT
*
l1
=
*
l2
=
((
unsigned
long
)
(
rand
()
&
0xffff
))
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
16
);
#else
*
l1
=
*
l2
=
((
unsigned
long
)
(
rand
()
&
0xffff
))
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
16
)
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
32
)
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
48
);
#endif
l1
+=
step
;
l2
+=
step
;
if
((
w
&
0xffff
)
==
0
)
memtest_progress_step
(
w
+
iwords
*
off
,
words
,
'R'
);
}
}
}
/* Like memtest_fill_random() but uses the two specified values to fill
* memory, in an alternated way (v1|v2|v1|v2|...) */
void
memtest_fill_value
(
unsigned
long
*
l
,
size_t
bytes
,
unsigned
long
v1
,
unsigned
long
v2
,
char
sym
)
{
unsigned
long
step
=
4096
/
sizeof
(
unsigned
long
);
unsigned
long
words
=
bytes
/
sizeof
(
unsigned
long
)
/
2
;
unsigned
long
iwords
=
words
/
step
;
/* words per iteration */
unsigned
long
off
,
w
,
*
l1
,
*
l2
,
v
;
assert
((
bytes
&
4095
)
==
0
);
for
(
off
=
0
;
off
<
step
;
off
++
)
{
l1
=
l
+
off
;
l2
=
l1
+
words
;
v
=
(
off
&
1
)
?
v2
:
v1
;
for
(
w
=
0
;
w
<
iwords
;
w
++
)
{
#ifdef MEMTEST_32BIT
*
l1
=
*
l2
=
((
unsigned
long
)
(
rand
()
&
0xffff
))
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
16
);
#else
*
l1
=
*
l2
=
((
unsigned
long
)
(
rand
()
&
0xffff
))
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
16
)
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
32
)
|
(((
unsigned
long
)
(
rand
()
&
0xffff
))
<<
48
);
#endif
l1
+=
step
;
l2
+=
step
;
if
((
w
&
0xffff
)
==
0
)
memtest_progress_step
(
w
+
iwords
*
off
,
words
,
sym
);
}
}
}
void
memtest_compare
(
unsigned
long
*
l
,
size_t
bytes
)
{
unsigned
long
words
=
bytes
/
sizeof
(
unsigned
long
)
/
2
;
unsigned
long
w
,
*
l1
,
*
l2
;
assert
((
bytes
&
4095
)
==
0
);
l1
=
l
;
l2
=
l1
+
words
;
for
(
w
=
0
;
w
<
words
;
w
++
)
{
if
(
*
l1
!=
*
l2
)
{
printf
(
"
\n
*** MEMORY ERROR DETECTED: %p != %p (%lu vs %lu)
\n
"
,
(
void
*
)
l1
,
(
void
*
)
l2
,
*
l1
,
*
l2
);
exit
(
1
);
}
l1
++
;
l2
++
;
if
((
w
&
0xffff
)
==
0
)
memtest_progress_step
(
w
,
words
,
'='
);
}
}
void
memtest_compare_times
(
unsigned
long
*
m
,
size_t
bytes
,
int
pass
,
int
times
)
{
int
j
;
for
(
j
=
0
;
j
<
times
;
j
++
)
{
memtest_progress_start
(
"Compare"
,
pass
);
memtest_compare
(
m
,
bytes
);
memtest_progress_end
();
}
}
void
memtest_test
(
size_t
megabytes
,
int
passes
)
{
size_t
bytes
=
megabytes
*
1024
*
1024
;
unsigned
long
*
m
=
malloc
(
bytes
);
int
pass
=
0
;
if
(
m
==
NULL
)
{
fprintf
(
stderr
,
"Unable to allocate %zu megabytes: %s"
,
megabytes
,
strerror
(
errno
));
exit
(
1
);
}
while
(
pass
!=
passes
)
{
pass
++
;
memtest_progress_start
(
"Addressing test"
,
pass
);
memtest_addressing
(
m
,
bytes
);
memtest_progress_end
();
memtest_progress_start
(
"Random fill"
,
pass
);
memtest_fill_random
(
m
,
bytes
);
memtest_progress_end
();
memtest_compare_times
(
m
,
bytes
,
pass
,
4
);
memtest_progress_start
(
"Solid fill"
,
pass
);
memtest_fill_value
(
m
,
bytes
,
0
,(
unsigned
long
)
-
1
,
'S'
);
memtest_progress_end
();
memtest_compare_times
(
m
,
bytes
,
pass
,
4
);
memtest_progress_start
(
"Checkerboard fill"
,
pass
);
memtest_fill_value
(
m
,
bytes
,
ULONG_ONEZERO
,
ULONG_ZEROONE
,
'C'
);
memtest_progress_end
();
memtest_compare_times
(
m
,
bytes
,
pass
,
4
);
}
}
void
memtest
(
size_t
megabytes
,
int
passes
)
{
if
(
ioctl
(
1
,
TIOCGWINSZ
,
&
ws
)
==
-
1
)
{
ws
.
ws_col
=
80
;
ws
.
ws_row
=
20
;
}
memtest_test
(
megabytes
,
passes
);
printf
(
"
\n
Your memory passed this test.
\n
"
);
printf
(
"Please if you are still in doubt use the following two tools:
\n
"
);
printf
(
"1) memtest86: http://www.memtest86.com/
\n
"
);
printf
(
"2) memtester: http://pyropus.ca/software/memtester/
\n
"
);
exit
(
0
);
}
src/multi.c
View file @
0f999784
...
...
@@ -40,6 +40,13 @@ void queueMultiCommand(redisClient *c) {
c
->
mstate
.
count
++
;
}
void
discardTransaction
(
redisClient
*
c
)
{
freeClientMultiState
(
c
);
initClientMultiState
(
c
);
c
->
flags
&=
~
(
REDIS_MULTI
|
REDIS_DIRTY_CAS
);;
unwatchAllKeys
(
c
);
}
void
multiCommand
(
redisClient
*
c
)
{
if
(
c
->
flags
&
REDIS_MULTI
)
{
addReplyError
(
c
,
"MULTI calls can not be nested"
);
...
...
@@ -54,11 +61,7 @@ void discardCommand(redisClient *c) {
addReplyError
(
c
,
"DISCARD without MULTI"
);
return
;
}
freeClientMultiState
(
c
);
initClientMultiState
(
c
);
c
->
flags
&=
~
(
REDIS_MULTI
|
REDIS_DIRTY_CAS
);;
unwatchAllKeys
(
c
);
discardTransaction
(
c
);
addReply
(
c
,
shared
.
ok
);
}
...
...
src/networking.c
View file @
0f999784
...
...
@@ -22,7 +22,6 @@ int listMatchObjects(void *a, void *b) {
redisClient
*
createClient
(
int
fd
)
{
redisClient
*
c
=
zmalloc
(
sizeof
(
redisClient
));
c
->
bufpos
=
0
;
/* passing -1 as fd it is possible to create a non connected client.
* This is useful since all the Redis commands needs to be executed
...
...
@@ -42,7 +41,9 @@ redisClient *createClient(int fd) {
selectDb
(
c
,
0
);
c
->
fd
=
fd
;
c
->
bufpos
=
0
;
c
->
querybuf
=
sdsempty
();
c
->
querybuf_peak
=
0
;
c
->
reqtype
=
0
;
c
->
argc
=
0
;
c
->
argv
=
NULL
;
...
...
@@ -51,7 +52,7 @@ redisClient *createClient(int fd) {
c
->
bulklen
=
-
1
;
c
->
sentlen
=
0
;
c
->
flags
=
0
;
c
->
lastinteraction
=
time
(
NULL
);
c
->
ctime
=
c
->
lastinteraction
=
time
(
NULL
);
c
->
authenticated
=
0
;
c
->
replstate
=
REDIS_REPL_NONE
;
c
->
reply
=
listCreate
();
...
...
@@ -751,34 +752,6 @@ void resetClient(redisClient *c) {
if
(
!
(
c
->
flags
&
REDIS_MULTI
))
c
->
flags
&=
(
~
REDIS_ASKING
);
}
void
closeTimedoutClients
(
void
)
{
redisClient
*
c
;
listNode
*
ln
;
time_t
now
=
time
(
NULL
);
listIter
li
;
listRewind
(
server
.
clients
,
&
li
);
while
((
ln
=
listNext
(
&
li
))
!=
NULL
)
{
c
=
listNodeValue
(
ln
);
if
(
server
.
maxidletime
&&
!
(
c
->
flags
&
REDIS_SLAVE
)
&&
/* no timeout for slaves */
!
(
c
->
flags
&
REDIS_MASTER
)
&&
/* no timeout for masters */
!
(
c
->
flags
&
REDIS_BLOCKED
)
&&
/* no timeout for BLPOP */
dictSize
(
c
->
pubsub_channels
)
==
0
&&
/* no timeout for pubsub */
listLength
(
c
->
pubsub_patterns
)
==
0
&&
(
now
-
c
->
lastinteraction
>
server
.
maxidletime
))
{
redisLog
(
REDIS_VERBOSE
,
"Closing idle client"
);
freeClient
(
c
);
}
else
if
(
c
->
flags
&
REDIS_BLOCKED
)
{
if
(
c
->
bpop
.
timeout
!=
0
&&
c
->
bpop
.
timeout
<
now
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
unblockClientWaitingData
(
c
);
}
}
}
}
int
processInlineBuffer
(
redisClient
*
c
)
{
char
*
newline
=
strstr
(
c
->
querybuf
,
"
\r\n
"
);
int
argc
,
j
;
...
...
@@ -1026,6 +999,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
}
qblen
=
sdslen
(
c
->
querybuf
);
if
(
c
->
querybuf_peak
<
qblen
)
c
->
querybuf_peak
=
qblen
;
c
->
querybuf
=
sdsMakeRoomFor
(
c
->
querybuf
,
readlen
);
nread
=
read
(
fd
,
c
->
querybuf
+
qblen
,
readlen
);
if
(
nread
==
-
1
)
{
...
...
@@ -1087,11 +1061,7 @@ sds getClientInfoString(redisClient *client) {
time_t
now
=
time
(
NULL
);
int
emask
;
if
(
anetPeerToString
(
client
->
fd
,
ip
,
&
port
)
==
-
1
)
{
ip
[
0
]
=
'?'
;
ip
[
1
]
=
'\0'
;
port
=
0
;
}
anetPeerToString
(
client
->
fd
,
ip
,
&
port
);
p
=
flags
;
if
(
client
->
flags
&
REDIS_SLAVE
)
{
if
(
client
->
flags
&
REDIS_MONITOR
)
...
...
@@ -1115,14 +1085,16 @@ sds getClientInfoString(redisClient *client) {
if
(
emask
&
AE_WRITABLE
)
*
p
++
=
'w'
;
*
p
=
'\0'
;
return
sdscatprintf
(
sdsempty
(),
"addr=%s:%d fd=%d idle=%ld flags=%s db=%d sub=%d psub=%d qbuf=%lu obl=%lu oll=%lu omem=%lu events=%s cmd=%s"
,
"addr=%s:%d fd=%d
age=%ld
idle=%ld flags=%s db=%d sub=%d psub=%d qbuf=%lu
qbuf-free=%lu
obl=%lu oll=%lu omem=%lu events=%s cmd=%s"
,
ip
,
port
,
client
->
fd
,
(
long
)(
now
-
client
->
ctime
),
(
long
)(
now
-
client
->
lastinteraction
),
flags
,
client
->
db
->
id
,
(
int
)
dictSize
(
client
->
pubsub_channels
),
(
int
)
listLength
(
client
->
pubsub_patterns
),
(
unsigned
long
)
sdslen
(
client
->
querybuf
),
(
unsigned
long
)
sdsavail
(
client
->
querybuf
),
(
unsigned
long
)
client
->
bufpos
,
(
unsigned
long
)
listLength
(
client
->
reply
),
getClientOutputBufferMemoryUsage
(
client
),
...
...
src/object.c
View file @
0f999784
...
...
@@ -56,7 +56,16 @@ robj *createStringObjectFromLongDouble(long double value) {
* that is "non surprising" for the user (that is, most small decimal
* numbers will be represented in a way that when converted back into
* a string are exactly the same as what the user typed.) */
len
=
snprintf
(
buf
,
sizeof
(
buf
),
"%.17Lg"
,
value
);
len
=
snprintf
(
buf
,
sizeof
(
buf
),
"%.17Lf"
,
value
);
/* Now remove trailing zeroes after the '.' */
if
(
strchr
(
buf
,
'.'
)
!=
NULL
)
{
char
*
p
=
buf
+
len
-
1
;
while
(
*
p
==
'0'
)
{
p
--
;
len
--
;
}
if
(
*
p
==
'.'
)
len
--
;
}
return
createStringObject
(
buf
,
len
);
}
...
...
@@ -95,12 +104,9 @@ robj *createIntsetObject(void) {
}
robj
*
createHashObject
(
void
)
{
/* All the Hashes start as zipmaps. Will be automatically converted
* into hash tables if there are enough elements or big elements
* inside. */
unsigned
char
*
zm
=
zipmapNew
();
robj
*
o
=
createObject
(
REDIS_HASH
,
zm
);
o
->
encoding
=
REDIS_ENCODING_ZIPMAP
;
unsigned
char
*
zl
=
ziplistNew
();
robj
*
o
=
createObject
(
REDIS_HASH
,
zl
);
o
->
encoding
=
REDIS_ENCODING_ZIPLIST
;
return
o
;
}
...
...
@@ -176,7 +182,7 @@ void freeHashObject(robj *o) {
case
REDIS_ENCODING_HT
:
dictRelease
((
dict
*
)
o
->
ptr
);
break
;
case
REDIS_ENCODING_ZIP
MAP
:
case
REDIS_ENCODING_ZIP
LIST
:
zfree
(
o
->
ptr
);
break
;
default:
...
...
@@ -492,7 +498,6 @@ char *strEncoding(int encoding) {
case
REDIS_ENCODING_RAW
:
return
"raw"
;
case
REDIS_ENCODING_INT
:
return
"int"
;
case
REDIS_ENCODING_HT
:
return
"hashtable"
;
case
REDIS_ENCODING_ZIPMAP
:
return
"zipmap"
;
case
REDIS_ENCODING_LINKEDLIST
:
return
"linkedlist"
;
case
REDIS_ENCODING_ZIPLIST
:
return
"ziplist"
;
case
REDIS_ENCODING_INTSET
:
return
"intset"
;
...
...
src/rdb.c
View file @
0f999784
#include "redis.h"
#include "lzf.h"
/* LZF compression library */
#include "zipmap.h"
#include <math.h>
#include <sys/types.h>
...
...
@@ -424,8 +425,8 @@ int rdbSaveObjectType(rio *rdb, robj *o) {
else
redisPanic
(
"Unknown sorted set encoding"
);
case
REDIS_HASH
:
if
(
o
->
encoding
==
REDIS_ENCODING_ZIP
MAP
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_HASH_ZIP
MAP
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIP
LIST
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_HASH_ZIP
LIST
);
else
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_HASH
);
else
...
...
@@ -530,12 +531,13 @@ int rdbSaveObject(rio *rdb, robj *o) {
}
}
else
if
(
o
->
type
==
REDIS_HASH
)
{
/* Save a hash value */
if
(
o
->
encoding
==
REDIS_ENCODING_ZIP
MAP
)
{
size_t
l
=
zip
map
BlobLen
((
unsigned
char
*
)
o
->
ptr
);
if
(
o
->
encoding
==
REDIS_ENCODING_ZIP
LIST
)
{
size_t
l
=
zip
list
BlobLen
((
unsigned
char
*
)
o
->
ptr
);
if
((
n
=
rdbSaveRawString
(
rdb
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
{
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
{
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
...
...
@@ -552,7 +554,11 @@ int rdbSaveObject(rio *rdb, robj *o) {
nwritten
+=
n
;
}
dictReleaseIterator
(
di
);
}
else
{
redisPanic
(
"Unknown hash encoding"
);
}
}
else
{
redisPanic
(
"Unknown object type"
);
}
...
...
@@ -610,7 +616,7 @@ int rdbSave(char *filename) {
}
rioInitWithFile
(
&
rdb
,
fp
);
if
(
rdbWriteRaw
(
&
rdb
,
"REDIS000
3
"
,
9
)
==
-
1
)
goto
werr
;
if
(
rdbWriteRaw
(
&
rdb
,
"REDIS000
4
"
,
9
)
==
-
1
)
goto
werr
;
for
(
j
=
0
;
j
<
server
.
dbnum
;
j
++
)
{
redisDb
*
db
=
server
.
db
+
j
;
...
...
@@ -656,6 +662,7 @@ int rdbSave(char *filename) {
redisLog
(
REDIS_NOTICE
,
"DB saved on disk"
);
server
.
dirty
=
0
;
server
.
lastsave
=
time
(
NULL
);
server
.
lastbgsave_status
=
REDIS_OK
;
return
REDIS_OK
;
werr:
...
...
@@ -824,55 +831,74 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
maxelelen
<=
server
.
zset_max_ziplist_value
)
zsetConvert
(
o
,
REDIS_ENCODING_ZIPLIST
);
}
else
if
(
rdbtype
==
REDIS_RDB_TYPE_HASH
)
{
size_t
hashlen
;
size_t
len
;
int
ret
;
len
=
rdbLoadLen
(
rdb
,
NULL
);
if
(
len
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
hashlen
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
o
=
createHashObject
();
/* Too many entries? Use an hash table. */
if
(
hashlen
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
/* Load every key/value, then set it into the zipmap or hash
* table, as needed. */
while
(
hashlen
--
)
{
robj
*
key
,
*
val
;
if
((
key
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
if
((
val
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
/* If we are using a zipmap and there are too big values
* the object is converted to real hash table encoding. */
if
(
o
->
encoding
!=
REDIS_ENCODING_HT
&&
((
key
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
key
->
ptr
)
>
server
.
hash_max_zipmap_value
)
||
(
val
->
encoding
==
REDIS_ENCODING_RAW
&&
sdslen
(
val
->
ptr
)
>
server
.
hash_max_zipmap_value
)))
/* Too many entries? Use an hash table. */
if
(
len
>
server
.
hash_max_ziplist_entries
)
hashTypeConvert
(
o
,
REDIS_ENCODING_HT
);
/* Load every field and value into the ziplist */
while
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
&&
len
>
0
)
{
robj
*
field
,
*
value
;
len
--
;
/* Load raw strings */
field
=
rdbLoadStringObject
(
rdb
);
if
(
field
==
NULL
)
return
NULL
;
redisAssert
(
field
->
encoding
==
REDIS_ENCODING_RAW
);
value
=
rdbLoadStringObject
(
rdb
);
if
(
value
==
NULL
)
return
NULL
;
redisAssert
(
field
->
encoding
==
REDIS_ENCODING_RAW
);
/* Add pair to ziplist */
o
->
ptr
=
ziplistPush
(
o
->
ptr
,
field
->
ptr
,
sdslen
(
field
->
ptr
),
ZIPLIST_TAIL
);
o
->
ptr
=
ziplistPush
(
o
->
ptr
,
value
->
ptr
,
sdslen
(
value
->
ptr
),
ZIPLIST_TAIL
);
/* Convert to hash table if size threshold is exceeded */
if
(
sdslen
(
field
->
ptr
)
>
server
.
hash_max_ziplist_value
||
sdslen
(
value
->
ptr
)
>
server
.
hash_max_ziplist_value
)
{
convertToRealHash
(
o
);
decrRefCount
(
field
);
decrRefCount
(
value
);
hashTypeConvert
(
o
,
REDIS_ENCODING_HT
);
break
;
}
decrRefCount
(
field
);
decrRefCount
(
value
);
}
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
unsigned
char
*
zm
=
o
->
ptr
;
robj
*
deckey
,
*
dec
val
;
/* Load remaining fields and values into the hash table */
while
(
o
->
encoding
==
REDIS_ENCODING_HT
&&
len
>
0
)
{
robj
*
field
,
*
val
ue
;
/* We need raw string objects to add them to the zipmap */
deckey
=
getDecodedObject
(
key
);
decval
=
getDecodedObject
(
val
);
zm
=
zipmapSet
(
zm
,
deckey
->
ptr
,
sdslen
(
deckey
->
ptr
),
decval
->
ptr
,
sdslen
(
decval
->
ptr
),
NULL
);
o
->
ptr
=
zm
;
decrRefCount
(
deckey
);
decrRefCount
(
decval
);
decrRefCount
(
key
);
decrRefCount
(
val
);
}
else
{
key
=
tryObjectEncoding
(
key
);
val
=
tryObjectEncoding
(
val
);
dictAdd
((
dict
*
)
o
->
ptr
,
key
,
val
);
}
len
--
;
/* Load encoded strings */
field
=
rdbLoadEncodedStringObject
(
rdb
);
if
(
field
==
NULL
)
return
NULL
;
value
=
rdbLoadEncodedStringObject
(
rdb
);
if
(
value
==
NULL
)
return
NULL
;
field
=
tryObjectEncoding
(
field
);
value
=
tryObjectEncoding
(
value
);
/* Add pair to hash table */
ret
=
dictAdd
((
dict
*
)
o
->
ptr
,
field
,
value
);
redisAssert
(
ret
==
REDIS_OK
);
}
/* All pairs should be read by now */
redisAssert
(
len
==
0
);
}
else
if
(
rdbtype
==
REDIS_RDB_TYPE_HASH_ZIPMAP
||
rdbtype
==
REDIS_RDB_TYPE_LIST_ZIPLIST
||
rdbtype
==
REDIS_RDB_TYPE_SET_INTSET
||
rdbtype
==
REDIS_RDB_TYPE_ZSET_ZIPLIST
)
rdbtype
==
REDIS_RDB_TYPE_ZSET_ZIPLIST
||
rdbtype
==
REDIS_RDB_TYPE_HASH_ZIPLIST
)
{
robj
*
aux
=
rdbLoadStringObject
(
rdb
);
...
...
@@ -890,10 +916,33 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
* converted. */
switch
(
rdbtype
)
{
case
REDIS_RDB_TYPE_HASH_ZIPMAP
:
/* Convert to ziplist encoded hash. This must be deprecated
* when loading dumps created by Redis 2.4 gets deprecated. */
{
unsigned
char
*
zl
=
ziplistNew
();
unsigned
char
*
zi
=
zipmapRewind
(
o
->
ptr
);
unsigned
char
*
fstr
,
*
vstr
;
unsigned
int
flen
,
vlen
;
unsigned
int
maxlen
=
0
;
while
((
zi
=
zipmapNext
(
zi
,
&
fstr
,
&
flen
,
&
vstr
,
&
vlen
))
!=
NULL
)
{
if
(
flen
>
maxlen
)
maxlen
=
flen
;
if
(
vlen
>
maxlen
)
maxlen
=
vlen
;
zl
=
ziplistPush
(
zl
,
fstr
,
flen
,
ZIPLIST_TAIL
);
zl
=
ziplistPush
(
zl
,
vstr
,
vlen
,
ZIPLIST_TAIL
);
}
zfree
(
o
->
ptr
);
o
->
ptr
=
zl
;
o
->
type
=
REDIS_HASH
;
o
->
encoding
=
REDIS_ENCODING_ZIPMAP
;
if
(
zipmapLen
(
o
->
ptr
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
o
->
encoding
=
REDIS_ENCODING_ZIPLIST
;
if
(
hashTypeLength
(
o
)
>
server
.
hash_max_ziplist_entries
||
maxlen
>
server
.
hash_max_ziplist_value
)
{
hashTypeConvert
(
o
,
REDIS_ENCODING_HT
);
}
}
break
;
case
REDIS_RDB_TYPE_LIST_ZIPLIST
:
o
->
type
=
REDIS_LIST
;
...
...
@@ -913,6 +962,12 @@ robj *rdbLoadObject(int rdbtype, rio *rdb) {
if
(
zsetLength
(
o
)
>
server
.
zset_max_ziplist_entries
)
zsetConvert
(
o
,
REDIS_ENCODING_SKIPLIST
);
break
;
case
REDIS_RDB_TYPE_HASH_ZIPLIST
:
o
->
type
=
REDIS_HASH
;
o
->
encoding
=
REDIS_ENCODING_ZIPLIST
;
if
(
hashTypeLength
(
o
)
>
server
.
hash_max_ziplist_entries
)
hashTypeConvert
(
o
,
REDIS_ENCODING_HT
);
break
;
default:
redisPanic
(
"Unknown encoding"
);
break
;
...
...
@@ -973,7 +1028,7 @@ int rdbLoad(char *filename) {
return
REDIS_ERR
;
}
rdbver
=
atoi
(
buf
+
5
);
if
(
rdbver
<
1
||
rdbver
>
3
)
{
if
(
rdbver
<
1
||
rdbver
>
4
)
{
fclose
(
fp
);
redisLog
(
REDIS_WARNING
,
"Can't handle RDB format version %d"
,
rdbver
);
errno
=
EINVAL
;
...
...
@@ -1061,12 +1116,15 @@ void backgroundSaveDoneHandler(int exitcode, int bysignal) {
"Background saving terminated with success"
);
server
.
dirty
=
server
.
dirty
-
server
.
dirty_before_bgsave
;
server
.
lastsave
=
time
(
NULL
);
server
.
lastbgsave_status
=
REDIS_OK
;
}
else
if
(
!
bysignal
&&
exitcode
!=
0
)
{
redisLog
(
REDIS_WARNING
,
"Background saving error"
);
server
.
lastbgsave_status
=
REDIS_ERR
;
}
else
{
redisLog
(
REDIS_WARNING
,
"Background saving terminated by signal %d"
,
bysignal
);
rdbRemoveTempFile
(
server
.
rdb_child_pid
);
server
.
lastbgsave_status
=
REDIS_ERR
;
}
server
.
rdb_child_pid
=
-
1
;
/* Possibly there are slaves waiting for a BGSAVE in order to be served
...
...
src/rdb.h
View file @
0f999784
...
...
@@ -47,6 +47,7 @@
#define REDIS_RDB_TYPE_LIST_ZIPLIST 10
#define REDIS_RDB_TYPE_SET_INTSET 11
#define REDIS_RDB_TYPE_ZSET_ZIPLIST 12
#define REDIS_RDB_TYPE_HASH_ZIPLIST 13
/* Test if a type is an object type. */
#define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 12))
...
...
src/redis-check-dump.c
View file @
0f999784
...
...
@@ -20,6 +20,7 @@
#define REDIS_LIST_ZIPLIST 10
#define REDIS_SET_INTSET 11
#define REDIS_ZSET_ZIPLIST 12
#define REDIS_HASH_ZIPLIST 13
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The 'encoding' field of the object
...
...
@@ -136,7 +137,7 @@ int processHeader() {
}
dump_version
=
(
int
)
strtol
(
buf
+
5
,
NULL
,
10
);
if
(
dump_version
<
1
||
dump_version
>
2
)
{
if
(
dump_version
<
1
||
dump_version
>
4
)
{
ERROR
(
"Unknown RDB format version: %d
\n
"
,
dump_version
);
}
return
1
;
...
...
@@ -384,6 +385,7 @@ int loadPair(entry *e) {
case
REDIS_LIST_ZIPLIST
:
case
REDIS_SET_INTSET
:
case
REDIS_ZSET_ZIPLIST
:
case
REDIS_HASH_ZIPLIST
:
if
(
!
processStringObject
(
NULL
))
{
SHIFT_ERROR
(
offset
,
"Error reading entry value"
);
return
0
;
...
...
src/redis-cli.c
View file @
0f999784
...
...
@@ -49,6 +49,10 @@
#define REDIS_NOTUSED(V) ((void) V)
#define OUTPUT_STANDARD 0
#define OUTPUT_RAW 1
#define OUTPUT_CSV 2
static
redisContext
*
context
;
static
struct
config
{
char
*
hostip
;
...
...
@@ -64,9 +68,10 @@ static struct config {
int
latency_mode
;
int
cluster_mode
;
int
cluster_reissue_command
;
int
slave_mode
;
int
stdinarg
;
/* get last arg from stdin. (-x option) */
char
*
auth
;
int
raw_
output
;
/* output mode
per command
*/
int
output
;
/* output mode
, see OUTPUT_* defines
*/
sds
mb_delim
;
char
prompt
[
128
];
char
*
eval
;
...
...
@@ -434,10 +439,46 @@ static sds cliFormatReplyRaw(redisReply *r) {
return
out
;
}
static
sds
cliFormatReplyCSV
(
redisReply
*
r
)
{
unsigned
int
i
;
sds
out
=
sdsempty
();
switch
(
r
->
type
)
{
case
REDIS_REPLY_ERROR
:
out
=
sdscat
(
out
,
"ERROR,"
);
out
=
sdscatrepr
(
out
,
r
->
str
,
strlen
(
r
->
str
));
break
;
case
REDIS_REPLY_STATUS
:
out
=
sdscatrepr
(
out
,
r
->
str
,
r
->
len
);
break
;
case
REDIS_REPLY_INTEGER
:
out
=
sdscatprintf
(
out
,
"%lld"
,
r
->
integer
);
break
;
case
REDIS_REPLY_STRING
:
out
=
sdscatrepr
(
out
,
r
->
str
,
r
->
len
);
break
;
case
REDIS_REPLY_NIL
:
out
=
sdscat
(
out
,
"NIL
\n
"
);
break
;
case
REDIS_REPLY_ARRAY
:
for
(
i
=
0
;
i
<
r
->
elements
;
i
++
)
{
sds
tmp
=
cliFormatReplyCSV
(
r
->
element
[
i
]);
out
=
sdscatlen
(
out
,
tmp
,
sdslen
(
tmp
));
if
(
i
!=
r
->
elements
-
1
)
out
=
sdscat
(
out
,
","
);
sdsfree
(
tmp
);
}
break
;
default:
fprintf
(
stderr
,
"Unknown reply type: %d
\n
"
,
r
->
type
);
exit
(
1
);
}
return
out
;
}
static
int
cliReadReply
(
int
output_raw_strings
)
{
void
*
_reply
;
redisReply
*
reply
;
sds
out
;
sds
out
=
NULL
;
int
output
=
1
;
if
(
redisGetReply
(
context
,
&
_reply
)
!=
REDIS_OK
)
{
...
...
@@ -457,7 +498,8 @@ static int cliReadReply(int output_raw_strings) {
reply
=
(
redisReply
*
)
_reply
;
/* Check if we need to connect to a different node and reissue the request. */
/* Check if we need to connect to a different node and reissue the
* request. */
if
(
config
.
cluster_mode
&&
reply
->
type
==
REDIS_REPLY_ERROR
&&
(
!
strncmp
(
reply
->
str
,
"MOVED"
,
5
)
||
!
strcmp
(
reply
->
str
,
"ASK"
)))
{
...
...
@@ -489,11 +531,14 @@ static int cliReadReply(int output_raw_strings) {
if
(
output_raw_strings
)
{
out
=
cliFormatReplyRaw
(
reply
);
}
else
{
if
(
config
.
raw_
output
)
{
if
(
config
.
output
==
OUTPUT_RAW
)
{
out
=
cliFormatReplyRaw
(
reply
);
out
=
sdscat
(
out
,
"
\n
"
);
}
else
{
}
else
if
(
config
.
output
==
OUTPUT_STANDARD
)
{
out
=
cliFormatReplyTTY
(
reply
,
""
);
}
else
if
(
config
.
output
==
OUTPUT_CSV
)
{
out
=
cliFormatReplyCSV
(
reply
);
out
=
sdscat
(
out
,
"
\n
"
);
}
}
fwrite
(
out
,
sdslen
(
out
),
1
,
stdout
);
...
...
@@ -545,7 +590,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
}
if
(
config
.
pubsub_mode
)
{
if
(
!
config
.
raw_
output
)
if
(
config
.
output
!=
OUTPUT_RAW
)
printf
(
"Reading messages... (press Ctrl-C to quit)
\n
"
);
while
(
1
)
{
if
(
cliReadReply
(
output_raw
)
!=
REDIS_OK
)
exit
(
1
);
...
...
@@ -603,9 +648,13 @@ static int parseOptions(int argc, char **argv) {
}
else
if
(
!
strcmp
(
argv
[
i
],
"-a"
)
&&
!
lastarg
)
{
config
.
auth
=
argv
[
++
i
];
}
else
if
(
!
strcmp
(
argv
[
i
],
"--raw"
))
{
config
.
raw_output
=
1
;
config
.
output
=
OUTPUT_RAW
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--csv"
))
{
config
.
output
=
OUTPUT_CSV
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--latency"
))
{
config
.
latency_mode
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--slave"
))
{
config
.
slave_mode
=
1
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"--eval"
)
&&
!
lastarg
)
{
config
.
eval
=
argv
[
++
i
];
}
else
if
(
!
strcmp
(
argv
[
i
],
"-c"
))
{
...
...
@@ -661,6 +710,7 @@ static void usage() {
" -c Enable cluster mode (follow -ASK and -MOVED redirections)
\n
"
" --raw Use raw formatting for replies (default when STDOUT is not a tty)
\n
"
" --latency Enter a special mode continuously sampling latency.
\n
"
" --slave Simulate a slave showing commands received from the master.
\n
"
" --eval <file> Send an EVAL command using the Lua script at <file>.
\n
"
" --help Output this help and exit
\n
"
" --version Output version and exit
\n
"
...
...
@@ -866,6 +916,54 @@ static void latencyMode(void) {
}
}
static
void
slaveMode
(
void
)
{
/* To start we need to send the SYNC command and return the payload.
* The hiredis client lib does not understand this part of the protocol
* and we don't want to mess with its buffers, so everything is performed
* using direct low-level I/O. */
int
fd
=
context
->
fd
;
char
buf
[
1024
],
*
p
;
ssize_t
nread
;
unsigned
long
long
payload
;
/* Send the SYNC command. */
if
(
write
(
fd
,
"SYNC
\r\n
"
,
6
)
!=
6
)
{
fprintf
(
stderr
,
"Error writing to master
\n
"
);
exit
(
1
);
}
/* Read $<payload>\r\n, making sure to read just up to "\n" */
p
=
buf
;
while
(
1
)
{
nread
=
read
(
fd
,
p
,
1
);
if
(
nread
<=
0
)
{
fprintf
(
stderr
,
"Error reading bulk length while SYNCing
\n
"
);
exit
(
1
);
}
if
(
*
p
==
'\n'
)
break
;
p
++
;
}
*
p
=
'\0'
;
payload
=
strtoull
(
buf
+
1
,
NULL
,
10
);
fprintf
(
stderr
,
"SYNC with master, discarding %lld bytes of bulk tranfer...
\n
"
,
payload
);
/* Discard the payload. */
while
(
payload
)
{
nread
=
read
(
fd
,
buf
,(
payload
>
sizeof
(
buf
))
?
sizeof
(
buf
)
:
payload
);
if
(
nread
<=
0
)
{
fprintf
(
stderr
,
"Error reading RDB payload while SYNCing
\n
"
);
exit
(
1
);
}
payload
-=
nread
;
}
fprintf
(
stderr
,
"SYNC done. Logging commands from master.
\n
"
);
/* Now we can use the hiredis to read the incoming protocol. */
config
.
output
=
OUTPUT_CSV
;
while
(
cliReadReply
(
0
)
==
REDIS_OK
);
}
int
main
(
int
argc
,
char
**
argv
)
{
int
firstarg
;
...
...
@@ -884,7 +982,10 @@ int main(int argc, char **argv) {
config
.
stdinarg
=
0
;
config
.
auth
=
NULL
;
config
.
eval
=
NULL
;
config
.
raw_output
=
!
isatty
(
fileno
(
stdout
))
&&
(
getenv
(
"FAKETTY"
)
==
NULL
);
if
(
!
isatty
(
fileno
(
stdout
))
&&
(
getenv
(
"FAKETTY"
)
==
NULL
))
config
.
output
=
OUTPUT_RAW
;
else
config
.
output
=
OUTPUT_STANDARD
;
config
.
mb_delim
=
sdsnew
(
"
\n
"
);
cliInitHelp
();
...
...
@@ -898,6 +999,12 @@ int main(int argc, char **argv) {
latencyMode
();
}
/* Start in slave mode if appropriate */
if
(
config
.
slave_mode
)
{
cliConnect
(
0
);
slaveMode
();
}
/* Start interactive mode when no command is provided */
if
(
argc
==
0
&&
!
config
.
eval
)
{
/* Note that in repl mode we don't abort on connection error.
...
...
src/redis.c
View file @
0f999784
...
...
@@ -211,7 +211,7 @@ struct redisCommand redisCommandTable[] = {
{
"lastsave"
,
lastsaveCommand
,
1
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"type"
,
typeCommand
,
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"multi"
,
multiCommand
,
1
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
"
wm
s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"exec"
,
execCommand
,
1
,
"s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"discard"
,
discardCommand
,
1
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"sync"
,
syncCommand
,
1
,
"ars"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"flushdb"
,
flushdbCommand
,
1
,
"w"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
...
...
@@ -223,13 +223,13 @@ struct redisCommand redisCommandTable[] = {
{
"pttl"
,
pttlCommand
,
2
,
"r"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"persist"
,
persistCommand
,
2
,
"w"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"slaveof"
,
slaveofCommand
,
3
,
"aws"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
"a
w
s"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"debug"
,
debugCommand
,
-
2
,
"as"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"config"
,
configCommand
,
-
2
,
"ar"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"subscribe"
,
subscribeCommand
,
-
2
,
"rps"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"unsubscribe"
,
unsubscribeCommand
,
-
1
,
"rps"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"psubscribe"
,
psubscribeCommand
,
-
2
,
"rps"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"punsubscribe"
,
punsubscribeCommand
,
-
1
,
"rps"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
"
r
pf"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"publish"
,
publishCommand
,
3
,
"pf"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"watch"
,
watchCommand
,
-
2
,
"rs"
,
0
,
noPreloadGetKeys
,
1
,
-
1
,
1
,
0
,
0
},
{
"unwatch"
,
unwatchCommand
,
1
,
"rs"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"cluster"
,
clusterCommand
,
-
2
,
"ar"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
...
...
@@ -239,10 +239,11 @@ struct redisCommand redisCommandTable[] = {
{
"dump"
,
dumpCommand
,
2
,
"ar"
,
0
,
NULL
,
1
,
1
,
1
,
0
,
0
},
{
"object"
,
objectCommand
,
-
2
,
"r"
,
0
,
NULL
,
2
,
2
,
2
,
0
,
0
},
{
"client"
,
clientCommand
,
-
2
,
"ar"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"eval"
,
evalCommand
,
-
3
,
"
wm
s"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"evalsha"
,
evalShaCommand
,
-
3
,
"
wm
s"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"eval"
,
evalCommand
,
-
3
,
"s"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"evalsha"
,
evalShaCommand
,
-
3
,
"s"
,
0
,
zunionInterGetKeys
,
0
,
0
,
0
,
0
,
0
},
{
"slowlog"
,
slowlogCommand
,
-
2
,
"r"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"script"
,
scriptCommand
,
-
2
,
"ras"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
{
"script"
,
scriptCommand
,
-
2
,
"ras"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
},
{
"time"
,
timeCommand
,
1
,
"rR"
,
0
,
NULL
,
0
,
0
,
0
,
0
,
0
}
};
/*============================ Utility functions ============================ */
...
...
@@ -615,6 +616,110 @@ void updateLRUClock(void) {
REDIS_LRU_CLOCK_MAX
;
}
/* Add a sample to the operations per second array of samples. */
void
trackOperationsPerSecond
(
void
)
{
long
long
t
=
mstime
()
-
server
.
ops_sec_last_sample_time
;
long
long
ops
=
server
.
stat_numcommands
-
server
.
ops_sec_last_sample_ops
;
long
long
ops_sec
;
ops_sec
=
t
>
0
?
(
ops
*
1000
/
t
)
:
0
;
server
.
ops_sec_samples
[
server
.
ops_sec_idx
]
=
ops_sec
;
server
.
ops_sec_idx
=
(
server
.
ops_sec_idx
+
1
)
%
REDIS_OPS_SEC_SAMPLES
;
server
.
ops_sec_last_sample_time
=
mstime
();
server
.
ops_sec_last_sample_ops
=
server
.
stat_numcommands
;
}
/* Return the mean of all the samples. */
long
long
getOperationsPerSecond
(
void
)
{
int
j
;
long
long
sum
=
0
;
for
(
j
=
0
;
j
<
REDIS_OPS_SEC_SAMPLES
;
j
++
)
sum
+=
server
.
ops_sec_samples
[
j
];
return
sum
/
REDIS_OPS_SEC_SAMPLES
;
}
/* Check for timeouts. Returns non-zero if the client was terminated */
int
clientsCronHandleTimeout
(
redisClient
*
c
)
{
time_t
now
=
server
.
unixtime
;
if
(
server
.
maxidletime
&&
!
(
c
->
flags
&
REDIS_SLAVE
)
&&
/* no timeout for slaves */
!
(
c
->
flags
&
REDIS_MASTER
)
&&
/* no timeout for masters */
!
(
c
->
flags
&
REDIS_BLOCKED
)
&&
/* no timeout for BLPOP */
dictSize
(
c
->
pubsub_channels
)
==
0
&&
/* no timeout for pubsub */
listLength
(
c
->
pubsub_patterns
)
==
0
&&
(
now
-
c
->
lastinteraction
>
server
.
maxidletime
))
{
redisLog
(
REDIS_VERBOSE
,
"Closing idle client"
);
freeClient
(
c
);
return
1
;
}
else
if
(
c
->
flags
&
REDIS_BLOCKED
)
{
if
(
c
->
bpop
.
timeout
!=
0
&&
c
->
bpop
.
timeout
<
now
)
{
addReply
(
c
,
shared
.
nullmultibulk
);
unblockClientWaitingData
(
c
);
}
}
return
0
;
}
/* The client query buffer is an sds.c string that can end with a lot of
* free space not used, this function reclaims space if needed.
*
* The funciton always returns 0 as it never terminates the client. */
int
clientsCronResizeQueryBuffer
(
redisClient
*
c
)
{
size_t
querybuf_size
=
sdsAllocSize
(
c
->
querybuf
);
time_t
idletime
=
server
.
unixtime
-
c
->
lastinteraction
;
/* There are two conditions to resize the query buffer:
* 1) Query buffer is > BIG_ARG and too big for latest peak.
* 2) Client is inactive and the buffer is bigger than 1k. */
if
(((
querybuf_size
>
REDIS_MBULK_BIG_ARG
)
&&
(
querybuf_size
/
(
c
->
querybuf_peak
+
1
))
>
2
)
||
(
querybuf_size
>
1024
&&
idletime
>
2
))
{
/* Only resize the query buffer if it is actually wasting space. */
if
(
sdsavail
(
c
->
querybuf
)
>
1024
)
{
c
->
querybuf
=
sdsRemoveFreeSpace
(
c
->
querybuf
);
}
}
/* Reset the peak again to capture the peak memory usage in the next
* cycle. */
c
->
querybuf_peak
=
0
;
return
0
;
}
void
clientsCron
(
void
)
{
/* Make sure to process at least 1/100 of clients per call.
* Since this function is called 10 times per second we are sure that
* in the worst case we process all the clients in 10 seconds.
* In normal conditions (a reasonable number of clients) we process
* all the clients in a shorter time. */
int
numclients
=
listLength
(
server
.
clients
);
int
iterations
=
numclients
/
100
;
if
(
iterations
<
50
)
iterations
=
(
numclients
<
50
)
?
numclients
:
50
;
while
(
listLength
(
server
.
clients
)
&&
iterations
--
)
{
redisClient
*
c
;
listNode
*
head
;
/* Rotate the list, take the current head, process.
* This way if the client must be removed from the list it's the
* first element and we don't incur into O(N) computation. */
listRotate
(
server
.
clients
);
head
=
listFirst
(
server
.
clients
);
c
=
listNodeValue
(
head
);
/* The following functions do different service checks on the client.
* The protocol is that they return non-zero if the client was
* terminated. */
if
(
clientsCronHandleTimeout
(
c
))
continue
;
if
(
clientsCronResizeQueryBuffer
(
c
))
continue
;
}
}
int
serverCron
(
struct
aeEventLoop
*
eventLoop
,
long
long
id
,
void
*
clientData
)
{
int
j
,
loops
=
server
.
cronloops
;
REDIS_NOTUSED
(
eventLoop
);
...
...
@@ -627,6 +732,8 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
* To access a global var is faster than calling time(NULL) */
server
.
unixtime
=
time
(
NULL
);
trackOperationsPerSecond
();
/* We have just 22 bits per object for LRU information.
* So we use an (eventually wrapping) LRU clock with 10 seconds resolution.
* 2^22 bits with 10 seconds resoluton is more or less 1.5 years.
...
...
@@ -684,9 +791,8 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
zmalloc_used_memory
());
}
/* Close connections of timedout clients */
if
((
server
.
maxidletime
&&
!
(
loops
%
100
))
||
server
.
bpop_blocked_clients
)
closeTimedoutClients
();
/* We need to do a few operations on clients asynchronously. */
clientsCron
();
/* Start a scheduled AOF rewrite if this was requested by the user while
* a BGSAVE was in progress. */
...
...
@@ -832,6 +938,12 @@ void createSharedObjects(void) {
"-LOADING Redis is loading the dataset in memory
\r\n
"
));
shared
.
slowscripterr
=
createObject
(
REDIS_STRING
,
sdsnew
(
"-BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
\r\n
"
));
shared
.
bgsaveerr
=
createObject
(
REDIS_STRING
,
sdsnew
(
"-MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
\r\n
"
));
shared
.
roslaveerr
=
createObject
(
REDIS_STRING
,
sdsnew
(
"-READONLY You can't write against a read only slave.
\r\n
"
));
shared
.
oomerr
=
createObject
(
REDIS_STRING
,
sdsnew
(
"-OOM command not allowed when used memory > 'maxmemory'.
\r\n
"
));
shared
.
space
=
createObject
(
REDIS_STRING
,
sdsnew
(
" "
));
shared
.
colon
=
createObject
(
REDIS_STRING
,
sdsnew
(
":"
));
shared
.
plus
=
createObject
(
REDIS_STRING
,
sdsnew
(
"+"
));
...
...
@@ -852,6 +964,8 @@ void createSharedObjects(void) {
shared
.
psubscribebulk
=
createStringObject
(
"$10
\r\n
psubscribe
\r\n
"
,
17
);
shared
.
punsubscribebulk
=
createStringObject
(
"$12
\r\n
punsubscribe
\r\n
"
,
19
);
shared
.
del
=
createStringObject
(
"DEL"
,
3
);
shared
.
rpop
=
createStringObject
(
"RPOP"
,
4
);
shared
.
lpop
=
createStringObject
(
"LPOP"
,
4
);
for
(
j
=
0
;
j
<
REDIS_SHARED_INTEGERS
;
j
++
)
{
shared
.
integers
[
j
]
=
createObject
(
REDIS_STRING
,(
void
*
)(
long
)
j
);
shared
.
integers
[
j
]
->
encoding
=
REDIS_ENCODING_INT
;
...
...
@@ -865,6 +979,8 @@ void createSharedObjects(void) {
}
void
initServerConfig
()
{
getRandomHexChars
(
server
.
runid
,
REDIS_RUN_ID_SIZE
);
server
.
runid
[
REDIS_RUN_ID_SIZE
]
=
'\0'
;
server
.
arch_bits
=
(
sizeof
(
long
)
==
8
)
?
64
:
32
;
server
.
port
=
REDIS_SERVERPORT
;
server
.
bindaddr
=
NULL
;
...
...
@@ -905,8 +1021,8 @@ void initServerConfig() {
server
.
maxmemory
=
0
;
server
.
maxmemory_policy
=
REDIS_MAXMEMORY_VOLATILE_LRU
;
server
.
maxmemory_samples
=
3
;
server
.
hash_max_zip
map
_entries
=
REDIS_HASH_MAX_ZIP
MAP
_ENTRIES
;
server
.
hash_max_zip
map
_value
=
REDIS_HASH_MAX_ZIP
MAP
_VALUE
;
server
.
hash_max_zip
list
_entries
=
REDIS_HASH_MAX_ZIP
LIST
_ENTRIES
;
server
.
hash_max_zip
list
_value
=
REDIS_HASH_MAX_ZIP
LIST
_VALUE
;
server
.
list_max_ziplist_entries
=
REDIS_LIST_MAX_ZIPLIST_ENTRIES
;
server
.
list_max_ziplist_value
=
REDIS_LIST_MAX_ZIPLIST_VALUE
;
server
.
set_max_intset_entries
=
REDIS_SET_MAX_INTSET_ENTRIES
;
...
...
@@ -936,6 +1052,7 @@ void initServerConfig() {
server
.
repl_state
=
REDIS_REPL_NONE
;
server
.
repl_syncio_timeout
=
REDIS_REPL_SYNCIO_TIMEOUT
;
server
.
repl_serve_stale_data
=
1
;
server
.
repl_slave_ro
=
1
;
server
.
repl_down_since
=
-
1
;
/* Client output buffer limits */
...
...
@@ -962,6 +1079,7 @@ void initServerConfig() {
populateCommandTable
();
server
.
delCommand
=
lookupCommandByCString
(
"del"
);
server
.
multiCommand
=
lookupCommandByCString
(
"multi"
);
server
.
lpushCommand
=
lookupCommandByCString
(
"lpush"
);
/* Slow log */
server
.
slowlog_log_slower_than
=
REDIS_SLOWLOG_LOG_SLOWER_THAN
;
...
...
@@ -1083,7 +1201,13 @@ void initServer() {
server
.
stat_peak_memory
=
0
;
server
.
stat_fork_time
=
0
;
server
.
stat_rejected_conn
=
0
;
memset
(
server
.
ops_sec_samples
,
0
,
sizeof
(
server
.
ops_sec_samples
));
server
.
ops_sec_idx
=
0
;
server
.
ops_sec_last_sample_time
=
mstime
();
server
.
ops_sec_last_sample_ops
=
0
;
server
.
unixtime
=
time
(
NULL
);
server
.
lastbgsave_status
=
REDIS_OK
;
server
.
stop_writes_on_bgsave_err
=
1
;
aeCreateTimeEvent
(
server
.
el
,
1
,
serverCron
,
NULL
,
NULL
);
if
(
server
.
ipfd
>
0
&&
aeCreateFileEvent
(
server
.
el
,
server
.
ipfd
,
AE_READABLE
,
acceptTcpHandler
,
NULL
)
==
AE_ERR
)
oom
(
"creating file event"
);
...
...
@@ -1160,6 +1284,43 @@ void resetCommandTableStats(void) {
}
}
/* ========================== Redis OP Array API ============================ */
void
redisOpArrayInit
(
redisOpArray
*
oa
)
{
oa
->
ops
=
NULL
;
oa
->
numops
=
0
;
}
int
redisOpArrayAppend
(
redisOpArray
*
oa
,
struct
redisCommand
*
cmd
,
int
dbid
,
robj
**
argv
,
int
argc
,
int
target
)
{
redisOp
*
op
;
oa
->
ops
=
zrealloc
(
oa
->
ops
,
sizeof
(
redisOp
)
*
(
oa
->
numops
+
1
));
op
=
oa
->
ops
+
oa
->
numops
;
op
->
cmd
=
cmd
;
op
->
dbid
=
dbid
;
op
->
argv
=
argv
;
op
->
argc
=
argc
;
op
->
target
=
target
;
oa
->
numops
++
;
return
oa
->
numops
;
}
void
redisOpArrayFree
(
redisOpArray
*
oa
)
{
while
(
oa
->
numops
)
{
int
j
;
redisOp
*
op
;
oa
->
numops
--
;
op
=
oa
->
ops
+
oa
->
numops
;
for
(
j
=
0
;
j
<
op
->
argc
;
j
++
)
decrRefCount
(
op
->
argv
[
j
]);
zfree
(
op
->
argv
);
}
zfree
(
oa
->
ops
);
}
/* ====================== Commands lookup and execution ===================== */
struct
redisCommand
*
lookupCommand
(
sds
name
)
{
...
...
@@ -1175,10 +1336,42 @@ struct redisCommand *lookupCommandByCString(char *s) {
return
cmd
;
}
/* Propagate the specified command (in the context of the specified database id)
* to AOF, Slaves and Monitors.
*
* flags are an xor between:
* + REDIS_PROPAGATE_NONE (no propagation of command at all)
* + REDIS_PROPAGATE_AOF (propagate into the AOF file if is enabled)
* + REDIS_PROPAGATE_REPL (propagate into the replication link)
*/
void
propagate
(
struct
redisCommand
*
cmd
,
int
dbid
,
robj
**
argv
,
int
argc
,
int
flags
)
{
if
(
server
.
aof_state
!=
REDIS_AOF_OFF
&&
flags
&
REDIS_PROPAGATE_AOF
)
feedAppendOnlyFile
(
cmd
,
dbid
,
argv
,
argc
);
if
(
flags
&
REDIS_PROPAGATE_REPL
&&
listLength
(
server
.
slaves
))
replicationFeedSlaves
(
server
.
slaves
,
dbid
,
argv
,
argc
);
}
/* Used inside commands to schedule the propagation of additional commands
* after the current command is propagated to AOF / Replication. */
void
alsoPropagate
(
struct
redisCommand
*
cmd
,
int
dbid
,
robj
**
argv
,
int
argc
,
int
target
)
{
redisOpArrayAppend
(
&
server
.
also_propagate
,
cmd
,
dbid
,
argv
,
argc
,
target
);
}
/* Call() is the core of Redis execution of a command */
void
call
(
redisClient
*
c
,
int
flags
)
{
long
long
dirty
,
start
=
ustime
(),
duration
;
/* Sent the command to clients in MONITOR mode, only if the commands are
* not geneated from reading an AOF. */
if
(
listLength
(
server
.
monitors
)
&&
!
server
.
loading
)
replicationFeedMonitors
(
c
,
server
.
monitors
,
c
->
db
->
id
,
c
->
argv
,
c
->
argc
);
/* Call the command. */
redisOpArrayInit
(
&
server
.
also_propagate
);
dirty
=
server
.
dirty
;
c
->
cmd
->
proc
(
c
);
dirty
=
server
.
dirty
-
dirty
;
...
...
@@ -1189,20 +1382,37 @@ void call(redisClient *c, int flags) {
if
(
server
.
loading
&&
c
->
flags
&
REDIS_LUA_CLIENT
)
flags
&=
~
(
REDIS_CALL_SLOWLOG
|
REDIS_CALL_STATS
);
/* Log the command into the Slow log if needed, and populate the
* per-command statistics that we show in INFO commandstats. */
if
(
flags
&
REDIS_CALL_SLOWLOG
)
slowlogPushEntryIfNeeded
(
c
->
argv
,
c
->
argc
,
duration
);
if
(
flags
&
REDIS_CALL_STATS
)
{
c
->
cmd
->
microseconds
+=
duration
;
c
->
cmd
->
calls
++
;
}
/* Propagate the command into the AOF and replication link */
if
(
flags
&
REDIS_CALL_PROPAGATE
)
{
if
(
server
.
aof_state
!=
REDIS_AOF_OFF
&&
dirty
>
0
)
feedAppendOnlyFile
(
c
->
cmd
,
c
->
db
->
id
,
c
->
argv
,
c
->
argc
);
if
((
dirty
>
0
||
c
->
cmd
->
flags
&
REDIS_CMD_FORCE_REPLICATION
)
&&
listLength
(
server
.
slaves
))
replicationFeedSlaves
(
server
.
slaves
,
c
->
db
->
id
,
c
->
argv
,
c
->
argc
);
if
(
listLength
(
server
.
monitors
))
replicationFeedMonitors
(
server
.
monitors
,
c
->
db
->
id
,
c
->
argv
,
c
->
argc
);
int
flags
=
REDIS_PROPAGATE_NONE
;
if
(
c
->
cmd
->
flags
&
REDIS_CMD_FORCE_REPLICATION
)
flags
|=
REDIS_PROPAGATE_REPL
;
if
(
dirty
)
flags
|=
(
REDIS_PROPAGATE_REPL
|
REDIS_PROPAGATE_AOF
);
if
(
flags
!=
REDIS_PROPAGATE_NONE
)
propagate
(
c
->
cmd
,
c
->
db
->
id
,
c
->
argv
,
c
->
argc
,
flags
);
}
/* Commands such as LPUSH or BRPOPLPUSH may propagate an additional
* PUSH command. */
if
(
server
.
also_propagate
.
numops
)
{
int
j
;
redisOp
*
rop
;
for
(
j
=
0
;
j
<
server
.
also_propagate
.
numops
;
j
++
)
{
rop
=
&
server
.
also_propagate
.
ops
[
j
];
propagate
(
rop
->
cmd
,
rop
->
dbid
,
rop
->
argv
,
rop
->
argc
,
rop
->
target
);
}
redisOpArrayFree
(
&
server
.
also_propagate
);
}
server
.
stat_numcommands
++
;
}
...
...
@@ -1278,10 +1488,29 @@ int processCommand(redisClient *c) {
if
(
server
.
maxmemory
)
{
int
retval
=
freeMemoryIfNeeded
();
if
((
c
->
cmd
->
flags
&
REDIS_CMD_DENYOOM
)
&&
retval
==
REDIS_ERR
)
{
addReplyError
(
c
,
"command not allowed when used memory > 'maxmemory'"
);
addReply
(
c
,
shared
.
oomerr
);
return
REDIS_OK
;
}
}
/* Don't accept write commands if there are problems persisting on disk. */
if
(
server
.
stop_writes_on_bgsave_err
&&
server
.
saveparamslen
>
0
&&
server
.
lastbgsave_status
==
REDIS_ERR
&&
c
->
cmd
->
flags
&
REDIS_CMD_WRITE
)
{
addReply
(
c
,
shared
.
bgsaveerr
);
return
REDIS_OK
;
}
/* Don't accept wirte commands if this is a read only slave. But
* accept write commands if this is our master. */
if
(
server
.
masterhost
&&
server
.
repl_slave_ro
&&
!
(
c
->
flags
&
REDIS_MASTER
)
&&
c
->
cmd
->
flags
&
REDIS_CMD_WRITE
)
{
addReply
(
c
,
shared
.
roslaveerr
);
return
REDIS_OK
;
}
/* Only allow SUBSCRIBE and UNSUBSCRIBE in the context of Pub/Sub */
...
...
@@ -1416,6 +1645,17 @@ void echoCommand(redisClient *c) {
addReplyBulk
(
c
,
c
->
argv
[
1
]);
}
void
timeCommand
(
redisClient
*
c
)
{
struct
timeval
tv
;
/* gettimeofday() can only fail if &tv is a bad addresss so we
* don't check for errors. */
gettimeofday
(
&
tv
,
NULL
);
addReplyMultiBulkLen
(
c
,
2
);
addReplyBulkLongLong
(
c
,
tv
.
tv_sec
);
addReplyBulkLongLong
(
c
,
tv
.
tv_usec
);
}
/* Convert an amount of bytes into a human readable string in the form
* of 100B, 2G, 100M, 4K, and so forth. */
void
bytesToHuman
(
char
*
s
,
unsigned
long
long
n
)
{
...
...
@@ -1470,6 +1710,7 @@ sds genRedisInfoString(char *section) {
"multiplexing_api:%s
\r\n
"
"gcc_version:%d.%d.%d
\r\n
"
"process_id:%ld
\r\n
"
"run_id:%s
\r\n
"
"tcp_port:%d
\r\n
"
"uptime_in_seconds:%ld
\r\n
"
"uptime_in_days:%ld
\r\n
"
...
...
@@ -1485,6 +1726,7 @@ sds genRedisInfoString(char *section) {
0
,
0
,
0
,
#endif
(
long
)
getpid
(),
server
.
runid
,
server
.
port
,
uptime
,
uptime
/
(
3600
*
24
),
...
...
@@ -1544,12 +1786,14 @@ sds genRedisInfoString(char *section) {
"changes_since_last_save:%lld
\r\n
"
"bgsave_in_progress:%d
\r\n
"
"last_save_time:%ld
\r\n
"
"last_bgsave_status:%s
\r\n
"
"bgrewriteaof_in_progress:%d
\r\n
"
,
server
.
loading
,
server
.
aof_state
!=
REDIS_AOF_OFF
,
server
.
dirty
,
server
.
rdb_child_pid
!=
-
1
,
server
.
lastsave
,
server
.
lastbgsave_status
==
REDIS_OK
?
"ok"
:
"err"
,
server
.
aof_child_pid
!=
-
1
);
if
(
server
.
aof_state
!=
REDIS_AOF_OFF
)
{
...
...
@@ -1605,6 +1849,7 @@ sds genRedisInfoString(char *section) {
"# Stats
\r\n
"
"total_connections_received:%lld
\r\n
"
"total_commands_processed:%lld
\r\n
"
"instantaneous_ops_per_sec:%lld
\r\n
"
"rejected_connections:%lld
\r\n
"
"expired_keys:%lld
\r\n
"
"evicted_keys:%lld
\r\n
"
...
...
@@ -1615,6 +1860,7 @@ sds genRedisInfoString(char *section) {
"latest_fork_usec:%lld
\r\n
"
,
server
.
stat_numconnections
,
server
.
stat_numcommands
,
getOperationsPerSecond
(),
server
.
stat_rejected_conn
,
server
.
stat_expiredkeys
,
server
.
stat_evictedkeys
,
...
...
@@ -1990,8 +2236,8 @@ void daemonize(void) {
}
void
version
()
{
printf
(
"Redis server v
ersion %s (%s:%d)
\n
"
,
REDIS_VERSION
,
redisGitSHA1
(),
atoi
(
redisGitDirty
())
>
0
);
printf
(
"Redis server v
=%s sha=%s:%d malloc=%s
\n
"
,
REDIS_VERSION
,
redisGitSHA1
(),
atoi
(
redisGitDirty
())
>
0
,
ZMALLOC_LIB
);
exit
(
0
);
}
...
...
@@ -1999,7 +2245,8 @@ void usage() {
fprintf
(
stderr
,
"Usage: ./redis-server [/path/to/redis.conf] [options]
\n
"
);
fprintf
(
stderr
,
" ./redis-server - (read config from stdin)
\n
"
);
fprintf
(
stderr
,
" ./redis-server -v or --version
\n
"
);
fprintf
(
stderr
,
" ./redis-server -h or --help
\n\n
"
);
fprintf
(
stderr
,
" ./redis-server -h or --help
\n
"
);
fprintf
(
stderr
,
" ./redis-server --test-memory <megabytes>
\n\n
"
);
fprintf
(
stderr
,
"Examples:
\n
"
);
fprintf
(
stderr
,
" ./redis-server (run the server with default conf)
\n
"
);
fprintf
(
stderr
,
" ./redis-server /etc/redis/6379.conf
\n
"
);
...
...
@@ -2055,6 +2302,8 @@ void setupSignalHandlers(void) {
return
;
}
void
memtest
(
size_t
megabytes
,
int
passes
);
int
main
(
int
argc
,
char
**
argv
)
{
long
long
start
;
struct
timeval
tv
;
...
...
@@ -2076,6 +2325,17 @@ int main(int argc, char **argv) {
strcmp
(
argv
[
1
],
"--version"
)
==
0
)
version
();
if
(
strcmp
(
argv
[
1
],
"--help"
)
==
0
||
strcmp
(
argv
[
1
],
"-h"
)
==
0
)
usage
();
if
(
strcmp
(
argv
[
1
],
"--test-memory"
)
==
0
)
{
if
(
argc
==
3
)
{
memtest
(
atoi
(
argv
[
2
]),
50
);
exit
(
0
);
}
else
{
fprintf
(
stderr
,
"Please specify the amount of memory to test in megabytes.
\n
"
);
fprintf
(
stderr
,
"Example: ./redis-server --test-memory 4096
\n\n
"
);
exit
(
1
);
}
}
/* First argument is the config file name? */
if
(
argv
[
j
][
0
]
!=
'-'
||
argv
[
j
][
1
]
!=
'-'
)
configfile
=
argv
[
j
++
];
...
...
src/redis.h
View file @
0f999784
...
...
@@ -28,7 +28,6 @@
#include "adlist.h"
/* Linked lists */
#include "zmalloc.h"
/* total memory usage aware version of malloc/free */
#include "anet.h"
/* Networking the easy way */
#include "zipmap.h"
/* Compact string -> string data structure */
#include "ziplist.h"
/* Compact list data structure */
#include "intset.h"
/* Compact integer set structure */
#include "version.h"
/* Version macro */
...
...
@@ -58,6 +57,9 @@
#define REDIS_REPL_TIMEOUT 60
#define REDIS_REPL_PING_SLAVE_PERIOD 10
#define REDIS_RUN_ID_SIZE 40
#define REDIS_OPS_SEC_SAMPLES 16
/* Protocol and I/O related defines */
#define REDIS_MAX_QUERYBUF_LEN (1024*1024*1024)
/* 1GB max query buffer. */
#define REDIS_IOBUF_LEN (1024*16)
/* Generic I/O buffer size */
...
...
@@ -205,8 +207,8 @@
#define AOF_FSYNC_EVERYSEC 2
/* Zip structure related defaults */
#define REDIS_HASH_MAX_ZIP
MAP
_ENTRIES 512
#define REDIS_HASH_MAX_ZIP
MAP
_VALUE 64
#define REDIS_HASH_MAX_ZIP
LIST
_ENTRIES 512
#define REDIS_HASH_MAX_ZIP
LIST
_VALUE 64
#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 512
#define REDIS_LIST_MAX_ZIPLIST_VALUE 64
#define REDIS_SET_MAX_INTSET_ENTRIES 512
...
...
@@ -245,6 +247,11 @@
#define REDIS_CALL_PROPAGATE 4
#define REDIS_CALL_FULL (REDIS_CALL_SLOWLOG | REDIS_CALL_STATS | REDIS_CALL_PROPAGATE)
/* Command propagation flags, see propagate() function */
#define REDIS_PROPAGATE_NONE 0
#define REDIS_PROPAGATE_AOF 1
#define REDIS_PROPAGATE_REPL 2
/* We can print the stacktrace, so our assert is defined this way: */
#define redisAssertWithInfo(_c,_o,_e) ((_e)?(void)0 : (_redisAssertWithInfo(_c,_o,#_e,__FILE__,__LINE__),_exit(1)))
#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
...
...
@@ -316,6 +323,7 @@ typedef struct redisClient {
redisDb
*
db
;
int
dictid
;
sds
querybuf
;
size_t
querybuf_peak
;
/* Recent (100ms or more) peak of querybuf size */
int
argc
;
robj
**
argv
;
struct
redisCommand
*
cmd
,
*
lastcmd
;
...
...
@@ -325,6 +333,7 @@ typedef struct redisClient {
list
*
reply
;
unsigned
long
reply_bytes
;
/* Tot bytes of objects in reply list */
int
sentlen
;
time_t
ctime
;
/* Client creation time */
time_t
lastinteraction
;
/* time of the last interaction, used for timeout */
time_t
obuf_soft_limit_reached_time
;
int
flags
;
/* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
...
...
@@ -356,11 +365,11 @@ struct sharedObjectsStruct {
robj
*
crlf
,
*
ok
,
*
err
,
*
emptybulk
,
*
czero
,
*
cone
,
*
cnegone
,
*
pong
,
*
space
,
*
colon
,
*
nullbulk
,
*
nullmultibulk
,
*
queued
,
*
emptymultibulk
,
*
wrongtypeerr
,
*
nokeyerr
,
*
syntaxerr
,
*
sameobjecterr
,
*
outofrangeerr
,
*
noscripterr
,
*
loadingerr
,
*
slowscripterr
,
*
plus
,
*
select0
,
*
select1
,
*
select2
,
*
select3
,
*
select4
,
*
select5
,
*
select6
,
*
select7
,
*
select8
,
*
select9
,
*
outofrangeerr
,
*
noscripterr
,
*
loadingerr
,
*
slowscripterr
,
*
bgsaveerr
,
*
roslaveerr
,
*
oomerr
,
*
plus
,
*
select0
,
*
select1
,
*
select2
,
*
select3
,
*
select4
,
*
select5
,
*
select6
,
*
select7
,
*
select8
,
*
select9
,
*
messagebulk
,
*
pmessagebulk
,
*
subscribebulk
,
*
unsubscribebulk
,
*
psubscribebulk
,
*
punsubscribebulk
,
*
del
,
*
psubscribebulk
,
*
punsubscribebulk
,
*
del
,
*
rpop
,
*
lpop
,
*
integers
[
REDIS_SHARED_INTEGERS
],
*
mbulkhdr
[
REDIS_SHARED_BULKHDR_LEN
],
/* "*<value>\r\n" */
*
bulkhdr
[
REDIS_SHARED_BULKHDR_LEN
];
/* "$<value>\r\n" */
...
...
@@ -394,6 +403,30 @@ typedef struct clientBufferLimitsConfig {
time_t
soft_limit_seconds
;
}
clientBufferLimitsConfig
;
/* The redisOp structure defines a Redis Operation, that is an instance of
* a command with an argument vector, database ID, propagation target
* (REDIS_PROPAGATE_*), and command pointer.
*
* Currently only used to additionally propagate more commands to AOF/Replication
* after the propagation of the executed command. */
typedef
struct
redisOp
{
robj
**
argv
;
int
argc
,
dbid
,
target
;
struct
redisCommand
*
cmd
;
}
redisOp
;
/* Defines an array of Redis operations. There is an API to add to this
* structure in a easy way.
*
* redisOpArrayInit();
* redisOpArrayAppend();
* redisOpArrayFree();
*/
typedef
struct
redisOpArray
{
redisOp
*
ops
;
int
numops
;
}
redisOpArray
;
/*-----------------------------------------------------------------------------
* Redis cluster data structures
*----------------------------------------------------------------------------*/
...
...
@@ -538,6 +571,8 @@ struct redisServer {
char
*
requirepass
;
/* Pass for AUTH command, or NULL */
char
*
pidfile
;
/* PID file path */
int
arch_bits
;
/* 32 or 64 depending on sizeof(long) */
int
cronloops
;
/* Number of times the cron function run */
char
runid
[
REDIS_RUN_ID_SIZE
+
1
];
/* ID always different at every exec. */
/* Networking */
int
port
;
/* TCP listening port */
char
*
bindaddr
;
/* Bind address or NULL */
...
...
@@ -557,9 +592,7 @@ struct redisServer {
off_t
loading_loaded_bytes
;
time_t
loading_start_time
;
/* Fast pointers to often looked up command */
struct
redisCommand
*
delCommand
,
*
multiCommand
;
int
cronloops
;
/* Number of times the cron function run */
time_t
lastsave
;
/* Unix time of last save succeeede */
struct
redisCommand
*
delCommand
,
*
multiCommand
,
*
lpushCommand
;
/* Fields used only for stats */
time_t
stat_starttime
;
/* Server start time */
long
long
stat_numcommands
;
/* Number of processed commands */
...
...
@@ -575,6 +608,12 @@ struct redisServer {
long
long
slowlog_entry_id
;
/* SLOWLOG current entry ID */
long
long
slowlog_log_slower_than
;
/* SLOWLOG time limit (to get logged) */
unsigned
long
slowlog_max_len
;
/* SLOWLOG max number of items logged */
/* The following two are used to track instantaneous "load" in terms
* of operations per second. */
long
long
ops_sec_last_sample_time
;
/* Timestamp of last sample (in ms) */
long
long
ops_sec_last_sample_ops
;
/* numcommands in last sample */
long
long
ops_sec_samples
[
REDIS_OPS_SEC_SAMPLES
];
int
ops_sec_idx
;
/* Configuration */
int
verbosity
;
/* Loglevel in redis.conf */
int
maxidletime
;
/* Client timeout in seconds */
...
...
@@ -607,6 +646,11 @@ struct redisServer {
int
saveparamslen
;
/* Number of saving points */
char
*
rdb_filename
;
/* Name of RDB file */
int
rdb_compression
;
/* Use compression in RDB? */
time_t
lastsave
;
/* Unix time of last save succeeede */
int
lastbgsave_status
;
/* REDIS_OK or REDIS_ERR */
int
stop_writes_on_bgsave_err
;
/* Don't allow writes if can't BGSAVE */
/* Propagation of commands in AOF / replication */
redisOpArray
also_propagate
;
/* Additional command to propagate. */
/* Logging */
char
*
logfile
;
/* Path of log file */
int
syslog_enabled
;
/* Is syslog enabled? */
...
...
@@ -627,6 +671,7 @@ struct redisServer {
char
*
repl_transfer_tmpfile
;
/* Slave-> master SYNC temp file name */
time_t
repl_transfer_lastio
;
/* Unix time of the latest read, for timeout */
int
repl_serve_stale_data
;
/* Serve stale data when link is down? */
int
repl_slave_ro
;
/* Slave is read only? */
time_t
repl_down_since
;
/* Unix time at which link with master went down */
/* Limits */
unsigned
int
maxclients
;
/* Max number of simultaneous clients */
...
...
@@ -643,8 +688,8 @@ struct redisServer {
int
sort_alpha
;
int
sort_bypattern
;
/* Zip structure config, see redis.conf for more information */
size_t
hash_max_zip
map
_entries
;
size_t
hash_max_zip
map
_value
;
size_t
hash_max_zip
list
_entries
;
size_t
hash_max_zip
list
_value
;
size_t
list_max_ziplist_entries
;
size_t
list_max_ziplist_value
;
size_t
set_max_intset_entries
;
...
...
@@ -748,10 +793,10 @@ typedef struct {
* not both are required, store pointers in the iterator to avoid
* unnecessary memory allocation for fields/values. */
typedef
struct
{
robj
*
subject
;
int
encoding
;
unsigned
char
*
zi
;
unsigned
char
*
zk
,
*
zv
;
unsigned
int
zklen
,
zvlen
;
unsigned
char
*
fptr
,
*
vptr
;
dictIterator
*
di
;
dictEntry
*
de
;
...
...
@@ -780,6 +825,7 @@ dictType hashDictType;
/* Utils */
long
long
ustime
(
void
);
long
long
mstime
(
void
);
void
getRandomHexChars
(
char
*
p
,
unsigned
int
len
);
/* networking.c -- Networking and Client related operations */
redisClient
*
createClient
(
int
fd
);
...
...
@@ -856,6 +902,7 @@ void freeClientMultiState(redisClient *c);
void
queueMultiCommand
(
redisClient
*
c
);
void
touchWatchedKey
(
redisDb
*
db
,
robj
*
key
);
void
touchWatchedKeysOnFlush
(
int
dbid
);
void
discardTransaction
(
redisClient
*
c
);
/* Redis object implementation */
void
decrRefCount
(
void
*
o
);
...
...
@@ -901,7 +948,7 @@ int syncReadLine(int fd, char *ptr, ssize_t size, int timeout);
/* Replication */
void
replicationFeedSlaves
(
list
*
slaves
,
int
dictid
,
robj
**
argv
,
int
argc
);
void
replicationFeedMonitors
(
list
*
monitors
,
int
dictid
,
robj
**
argv
,
int
argc
);
void
replicationFeedMonitors
(
redisClient
*
c
,
list
*
monitors
,
int
dictid
,
robj
**
argv
,
int
argc
);
void
updateSlavesWaitingBgsave
(
int
bgsaveerr
);
void
replicationCron
(
void
);
...
...
@@ -950,6 +997,8 @@ void setupSignalHandlers(void);
struct
redisCommand
*
lookupCommand
(
sds
name
);
struct
redisCommand
*
lookupCommandByCString
(
char
*
s
);
void
call
(
redisClient
*
c
,
int
flags
);
void
propagate
(
struct
redisCommand
*
cmd
,
int
dbid
,
robj
**
argv
,
int
argc
,
int
flags
);
void
alsoPropagate
(
struct
redisCommand
*
cmd
,
int
dbid
,
robj
**
argv
,
int
argc
,
int
target
);
int
prepareForShutdown
();
void
redisLog
(
int
level
,
const
char
*
fmt
,
...);
void
redisLogRaw
(
int
level
,
const
char
*
msg
);
...
...
@@ -974,10 +1023,9 @@ unsigned long setTypeSize(robj *subject);
void
setTypeConvert
(
robj
*
subject
,
int
enc
);
/* Hash data type */
void
convertToRealHash
(
robj
*
o
);
void
hashTypeConvert
(
robj
*
o
,
int
enc
);
void
hashTypeTryConversion
(
robj
*
subject
,
robj
**
argv
,
int
start
,
int
end
);
void
hashTypeTryObjectEncoding
(
robj
*
subject
,
robj
**
o1
,
robj
**
o2
);
int
hashTypeGet
(
robj
*
o
,
robj
*
key
,
robj
**
objval
,
unsigned
char
**
v
,
unsigned
int
*
vlen
);
robj
*
hashTypeGetObject
(
robj
*
o
,
robj
*
key
);
int
hashTypeExists
(
robj
*
o
,
robj
*
key
);
int
hashTypeSet
(
robj
*
o
,
robj
*
key
,
robj
*
value
);
...
...
@@ -986,7 +1034,11 @@ unsigned long hashTypeLength(robj *o);
hashTypeIterator
*
hashTypeInitIterator
(
robj
*
subject
);
void
hashTypeReleaseIterator
(
hashTypeIterator
*
hi
);
int
hashTypeNext
(
hashTypeIterator
*
hi
);
int
hashTypeCurrent
(
hashTypeIterator
*
hi
,
int
what
,
robj
**
objval
,
unsigned
char
**
v
,
unsigned
int
*
vlen
);
void
hashTypeCurrentFromZiplist
(
hashTypeIterator
*
hi
,
int
what
,
unsigned
char
**
vstr
,
unsigned
int
*
vlen
,
long
long
*
vll
);
void
hashTypeCurrentFromHashTable
(
hashTypeIterator
*
hi
,
int
what
,
robj
**
dst
);
robj
*
hashTypeCurrentObject
(
hashTypeIterator
*
hi
,
int
what
);
robj
*
hashTypeLookupWriteOrCreate
(
redisClient
*
c
,
robj
*
key
);
...
...
@@ -1185,6 +1237,7 @@ void clientCommand(redisClient *c);
void
evalCommand
(
redisClient
*
c
);
void
evalShaCommand
(
redisClient
*
c
);
void
scriptCommand
(
redisClient
*
c
);
void
timeCommand
(
redisClient
*
c
);
#if defined(__GNUC__)
void
*
calloc
(
size_t
count
,
size_t
size
)
__attribute__
((
deprecated
));
...
...
Prev
1
2
3
Next
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