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
Expand all
Hide 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,53 +610,61 @@ 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
;
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
;
while
((
p
=
zipmapNext
(
p
,
&
field
,
&
flen
,
&
val
,
&
vlen
))
!=
NULL
)
{
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
(
rioWriteBulkString
(
r
,(
char
*
)
field
,
flen
)
==
0
)
return
0
;
if
(
rioWriteBulkString
(
r
,(
char
*
)
val
,
vlen
)
==
0
)
return
0
;
if
(
++
count
==
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
count
=
0
;
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
;
}
}
else
{
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
field
=
dictGetKey
(
de
);
robj
*
val
=
dictGetVal
(
de
);
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
--
;
}
if
(
count
==
0
)
{
int
cmd_items
=
(
items
>
REDIS_AOF_REWRITE_ITEMS_PER_CMD
)
?
REDIS_AOF_REWRITE_ITEMS_PER_CMD
:
items
;
hashTypeReleaseIterator
(
hi
);
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
...
...
@@ -636,8 +636,9 @@ void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
redisLog
(
REDIS_WARNING
,
"
\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
"
" 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
)))
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
,
*
decval
;
/* 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
);
}
/* Load remaining fields and values into the hash table */
while
(
o
->
encoding
==
REDIS_ENCODING_HT
&&
len
>
0
)
{
robj
*
field
,
*
value
;
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
:
o
->
type
=
REDIS_HASH
;
o
->
encoding
=
REDIS_ENCODING_ZIPMAP
;
if
(
zipmapLen
(
o
->
ptr
)
>
server
.
hash_max_zipmap_entries
)
convertToRealHash
(
o
);
/* 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_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
This diff is collapsed.
Click to expand it.
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