Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
f9c6f39b
Commit
f9c6f39b
authored
Sep 22, 2011
by
antirez
Browse files
merge conflicts resolved
parents
7c748c06
041d8e2a
Changes
9
Hide whitespace changes
Inline
Side-by-side
src/Makefile
View file @
f9c6f39b
...
...
@@ -61,7 +61,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 endian.o slowlog.o scripting.o bio.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 endian.o slowlog.o scripting.o bio.o
rio.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
...
...
@@ -130,6 +130,7 @@ replication.o: replication.c redis.h fmacros.h config.h ae.h sds.h dict.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
rio.o
:
rio.c sds.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
\
...
...
src/aof.c
View file @
f9c6f39b
#include "redis.h"
#include "bio.h"
#include "rio.h"
#include <signal.h>
#include <fcntl.h>
...
...
@@ -386,11 +387,26 @@ fmterr:
exit
(
1
);
}
/* Delegate writing an object to writing a bulk string or bulk long long.
* This is not placed in rio.c since that adds the redis.h dependency. */
int
rioWriteBulkObject
(
rio
*
r
,
robj
*
obj
)
{
/* Avoid using getDecodedObject to help copy-on-write (we are often
* in a child process when this function is called). */
if
(
obj
->
encoding
==
REDIS_ENCODING_INT
)
{
return
rioWriteBulkLongLong
(
r
,(
long
)
obj
->
ptr
);
}
else
if
(
obj
->
encoding
==
REDIS_ENCODING_RAW
)
{
return
rioWriteBulkString
(
r
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
}
else
{
redisPanic
(
"Unknown string encoding"
);
}
}
/* Write a sequence of commands able to fully rebuild the dataset into
* "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
int
rewriteAppendOnlyFile
(
char
*
filename
)
{
dictIterator
*
di
=
NULL
;
dictEntry
*
de
;
rio
aof
;
FILE
*
fp
;
char
tmpfile
[
256
];
int
j
;
...
...
@@ -404,6 +420,8 @@ int rewriteAppendOnlyFile(char *filename) {
redisLog
(
REDIS_WARNING
,
"Failed rewriting the append only file: %s"
,
strerror
(
errno
));
return
REDIS_ERR
;
}
aof
=
rioInitWithFile
(
fp
);
for
(
j
=
0
;
j
<
server
.
dbnum
;
j
++
)
{
char
selectcmd
[]
=
"*2
\r\n
$6
\r\n
SELECT
\r\n
"
;
redisDb
*
db
=
server
.
db
+
j
;
...
...
@@ -416,8 +434,8 @@ int rewriteAppendOnlyFile(char *filename) {
}
/* SELECT the new DB */
if
(
fw
rite
(
selectcmd
,
sizeof
(
selectcmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkLongLong
(
f
p
,
j
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
selectcmd
,
sizeof
(
selectcmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkLongLong
(
&
ao
f
,
j
)
==
0
)
goto
werr
;
/* Iterate this DB writing every entry */
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
...
...
@@ -435,10 +453,10 @@ int rewriteAppendOnlyFile(char *filename) {
if
(
o
->
type
==
REDIS_STRING
)
{
/* Emit a SET command */
char
cmd
[]
=
"*3
\r\n
$3
\r\n
SET
\r\n
"
;
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
/* Key and value */
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
o
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
o
)
==
0
)
goto
werr
;
}
else
if
(
o
->
type
==
REDIS_LIST
)
{
/* Emit the RPUSHes needed to rebuild the list */
char
cmd
[]
=
"*3
\r\n
$5
\r\n
RPUSH
\r\n
"
;
...
...
@@ -450,13 +468,13 @@ int rewriteAppendOnlyFile(char *filename) {
long
long
vlong
;
while
(
ziplistGet
(
p
,
&
vstr
,
&
vlen
,
&
vlong
))
{
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
vstr
)
{
if
(
fw
riteBulkString
(
f
p
,(
char
*
)
vstr
,
vlen
)
==
0
)
if
(
rioW
riteBulkString
(
&
ao
f
,(
char
*
)
vstr
,
vlen
)
==
0
)
goto
werr
;
}
else
{
if
(
fw
riteBulkLongLong
(
f
p
,
vlong
)
==
0
)
if
(
rioW
riteBulkLongLong
(
&
ao
f
,
vlong
)
==
0
)
goto
werr
;
}
p
=
ziplistNext
(
zl
,
p
);
...
...
@@ -470,9 +488,9 @@ int rewriteAppendOnlyFile(char *filename) {
while
((
ln
=
listNext
(
&
li
)))
{
robj
*
eleobj
=
listNodeValue
(
ln
);
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
eleobj
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
eleobj
)
==
0
)
goto
werr
;
}
}
else
{
redisPanic
(
"Unknown list encoding"
);
...
...
@@ -485,18 +503,18 @@ int rewriteAppendOnlyFile(char *filename) {
int
ii
=
0
;
int64_t
llval
;
while
(
intsetGet
(
o
->
ptr
,
ii
++
,
&
llval
))
{
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkLongLong
(
f
p
,
llval
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkLongLong
(
&
ao
f
,
llval
)
==
0
)
goto
werr
;
}
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
{
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
eleobj
=
dictGetEntryKey
(
de
);
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
eleobj
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
eleobj
)
==
0
)
goto
werr
;
}
dictReleaseIterator
(
di
);
}
else
{
...
...
@@ -523,14 +541,14 @@ int rewriteAppendOnlyFile(char *filename) {
redisAssert
(
ziplistGet
(
eptr
,
&
vstr
,
&
vlen
,
&
vll
));
score
=
zzlGetScore
(
sptr
);
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkDouble
(
f
p
,
score
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkDouble
(
&
ao
f
,
score
)
==
0
)
goto
werr
;
if
(
vstr
!=
NULL
)
{
if
(
fw
riteBulkString
(
f
p
,(
char
*
)
vstr
,
vlen
)
==
0
)
if
(
rioW
riteBulkString
(
&
ao
f
,(
char
*
)
vstr
,
vlen
)
==
0
)
goto
werr
;
}
else
{
if
(
fw
riteBulkLongLong
(
f
p
,
vll
)
==
0
)
if
(
rioW
riteBulkLongLong
(
&
ao
f
,
vll
)
==
0
)
goto
werr
;
}
zzlNext
(
zl
,
&
eptr
,
&
sptr
);
...
...
@@ -544,10 +562,10 @@ int rewriteAppendOnlyFile(char *filename) {
robj
*
eleobj
=
dictGetEntryKey
(
de
);
double
*
score
=
dictGetEntryVal
(
de
);
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkDouble
(
f
p
,
*
score
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
eleobj
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkDouble
(
&
ao
f
,
*
score
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
eleobj
)
==
0
)
goto
werr
;
}
dictReleaseIterator
(
di
);
}
else
{
...
...
@@ -563,11 +581,11 @@ int rewriteAppendOnlyFile(char *filename) {
unsigned
int
flen
,
vlen
;
while
((
p
=
zipmapNext
(
p
,
&
field
,
&
flen
,
&
val
,
&
vlen
))
!=
NULL
)
{
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkString
(
f
p
,(
char
*
)
field
,
flen
)
==
0
)
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkString
(
&
ao
f
,(
char
*
)
field
,
flen
)
==
0
)
goto
werr
;
if
(
fw
riteBulkString
(
f
p
,(
char
*
)
val
,
vlen
)
==
0
)
if
(
rioW
riteBulkString
(
&
ao
f
,(
char
*
)
val
,
vlen
)
==
0
)
goto
werr
;
}
}
else
{
...
...
@@ -578,10 +596,10 @@ int rewriteAppendOnlyFile(char *filename) {
robj
*
field
=
dictGetEntryKey
(
de
);
robj
*
val
=
dictGetEntryVal
(
de
);
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
field
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
val
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
field
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
val
)
==
0
)
goto
werr
;
}
dictReleaseIterator
(
di
);
}
...
...
@@ -593,9 +611,9 @@ int rewriteAppendOnlyFile(char *filename) {
char
cmd
[]
=
"*3
\r\n
$8
\r\n
EXPIREAT
\r\n
"
;
/* If this key is already expired skip it */
if
(
expiretime
<
now
)
continue
;
if
(
fw
rite
(
cmd
,
sizeof
(
cmd
)
-
1
,
1
,
fp
)
==
0
)
goto
werr
;
if
(
fw
riteBulkObject
(
f
p
,
&
key
)
==
0
)
goto
werr
;
if
(
fw
riteBulkLongLong
(
f
p
,
expiretime
)
==
0
)
goto
werr
;
if
(
rioW
rite
(
&
aof
,
cmd
,
sizeof
(
cmd
)
-
1
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkObject
(
&
ao
f
,
&
key
)
==
0
)
goto
werr
;
if
(
rioW
riteBulkLongLong
(
&
ao
f
,
expiretime
)
==
0
)
goto
werr
;
}
}
dictReleaseIterator
(
di
);
...
...
src/cluster.c
View file @
f9c6f39b
...
...
@@ -1383,11 +1383,10 @@ void clusterCommand(redisClient *c) {
/* RESTORE key ttl serialized-value */
void
restoreCommand
(
redisClient
*
c
)
{
FILE
*
fp
;
char
buf
[
64
];
robj
*
o
;
unsigned
char
*
data
;
long
ttl
;
rio
payload
;
int
type
;
robj
*
obj
;
/* Make sure this key does not already exist here... */
if
(
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
])
!=
NULL
)
{
...
...
@@ -1403,44 +1402,16 @@ void restoreCommand(redisClient *c) {
return
;
}
/* rdbLoadObject() only works against file descriptors so we need to
* dump the serialized object into a file and reload. */
snprintf
(
buf
,
sizeof
(
buf
),
"redis-restore-%d.tmp"
,
getpid
());
fp
=
fopen
(
buf
,
"w+"
);
if
(
!
fp
)
{
redisLog
(
REDIS_WARNING
,
"Can't open tmp file for RESTORE: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"RESTORE failed, tmp file creation error: %s"
,
strerror
(
errno
));
return
;
}
unlink
(
buf
);
/* Write the actual data and rewind the file */
data
=
(
unsigned
char
*
)
c
->
argv
[
3
]
->
ptr
;
if
(
fwrite
(
data
+
1
,
sdslen
((
sds
)
data
)
-
1
,
1
,
fp
)
!=
1
)
{
redisLog
(
REDIS_WARNING
,
"Can't write against tmp file for RESTORE: %s"
,
strerror
(
errno
));
addReplyError
(
c
,
"RESTORE failed, tmp file I/O error."
);
fclose
(
fp
);
return
;
}
rewind
(
fp
);
/* Finally create the object from the serialized dump and
* store it at the specified key. */
if
((
data
[
0
]
>
4
&&
data
[
0
]
<
9
)
||
data
[
0
]
>
11
||
(
o
=
rdbLoadObject
(
data
[
0
],
fp
))
==
NULL
)
payload
=
rioInitWithBuffer
(
c
->
argv
[
3
]
->
ptr
);
if
(((
type
=
rdbLoadObjectType
(
&
payload
))
==
-
1
)
||
((
obj
=
rdbLoadObject
(
type
,
&
payload
))
==
NULL
))
{
addReplyError
(
c
,
"Bad data format."
);
fclose
(
fp
);
addReplyError
(
c
,
"Bad data format"
);
return
;
}
fclose
(
fp
);
/* Create the key and set the TTL if any */
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
);
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
o
bj
);
if
(
ttl
)
setExpire
(
c
->
db
,
c
->
argv
[
1
],
time
(
NULL
)
+
ttl
);
addReply
(
c
,
shared
.
ok
);
}
...
...
@@ -1450,12 +1421,9 @@ void migrateCommand(redisClient *c) {
int
fd
;
long
timeout
;
long
dbid
;
char
buf
[
64
];
FILE
*
fp
;
time_t
ttl
;
robj
*
o
;
unsigned
char
type
;
off_t
payload_len
;
rio
cmd
,
payload
;
/* Sanity check */
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
5
],
&
timeout
,
NULL
)
!=
REDIS_OK
)
...
...
@@ -1485,54 +1453,41 @@ void migrateCommand(redisClient *c) {
return
;
}
/* Create temp file */
snprintf
(
buf
,
sizeof
(
buf
),
"redis-migrate-%d.tmp"
,
getpid
());
fp
=
fopen
(
buf
,
"w+"
);
if
(
!
fp
)
{
redisLog
(
REDIS_WARNING
,
"Can't open tmp file for MIGRATE: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"MIGRATE failed, tmp file creation error: %s."
,
strerror
(
errno
));
return
;
}
unlink
(
buf
);
/* Build the SELECT + RESTORE query writing it in our temp file. */
if
(
fwriteBulkCount
(
fp
,
'*'
,
2
)
==
0
)
goto
file_wr_err
;
if
(
fwriteBulkString
(
fp
,
"SELECT"
,
6
)
==
0
)
goto
file_wr_err
;
if
(
fwriteBulkLongLong
(
fp
,
dbid
)
==
0
)
goto
file_wr_err
;
cmd
=
rioInitWithBuffer
(
sdsempty
());
redisAssert
(
rioWriteBulkCount
(
&
cmd
,
'*'
,
2
));
redisAssert
(
rioWriteBulkString
(
&
cmd
,
"SELECT"
,
6
));
redisAssert
(
rioWriteBulkLongLong
(
&
cmd
,
dbid
));
ttl
=
getExpire
(
c
->
db
,
c
->
argv
[
3
]);
type
=
o
->
type
;
if
(
fwriteBulkCount
(
fp
,
'*'
,
4
)
==
0
)
goto
file_wr_err
;
if
(
fwriteBulkString
(
fp
,
"RESTORE"
,
7
)
==
0
)
goto
file_wr_err
;
if
(
fwriteBulkObject
(
fp
,
c
->
argv
[
3
])
==
0
)
goto
file_wr_err
;
if
(
fw
riteBulkLongLong
(
fp
,
(
ttl
==
-
1
)
?
0
:
ttl
)
==
0
)
goto
file_wr_err
;
redisAssert
(
rioWriteBulkCount
(
&
cmd
,
'*'
,
4
))
;
redisAssert
(
rioWriteBulkString
(
&
cmd
,
"RESTORE"
,
7
))
;
redisAssert
(
c
->
argv
[
3
]
->
encoding
==
REDIS_ENCODING_RAW
)
;
redisAssert
(
rioWriteBulkString
(
&
cmd
,
c
->
argv
[
3
]
->
ptr
,
sdslen
(
c
->
argv
[
3
]
->
ptr
)))
;
redisAssert
(
rioW
riteBulkLongLong
(
&
cmd
,
(
ttl
==
-
1
)
?
0
:
ttl
)
)
;
/* Finally the last argument that is the serailized object payload
* in the form: <type><rdb-serailized-object>. */
payload_len
=
rdbSavedObjectLen
(
o
);
if
(
fwriteBulkCount
(
fp
,
'$'
,
payload_len
+
1
)
==
0
)
goto
file_wr_err
;
if
(
fwrite
(
&
type
,
1
,
1
,
fp
)
==
0
)
goto
file_wr_err
;
if
(
rdbSaveObject
(
fp
,
o
)
==
-
1
)
goto
file_wr_err
;
if
(
fwrite
(
"
\r\n
"
,
2
,
1
,
fp
)
==
0
)
goto
file_wr_err
;
/* Tranfer the query to the other node */
rewind
(
fp
);
* in the form: <type><rdb-serialized-object>. */
payload
=
rioInitWithBuffer
(
sdsempty
());
redisAssert
(
rdbSaveObjectType
(
&
payload
,
o
));
redisAssert
(
rdbSaveObject
(
&
payload
,
o
)
!=
-
1
);
redisAssert
(
rioWriteBulkString
(
&
cmd
,
payload
.
io
.
buffer
.
ptr
,
sdslen
(
payload
.
io
.
buffer
.
ptr
)));
sdsfree
(
payload
.
io
.
buffer
.
ptr
);
/* Tranfer the query to the other node in 64K chunks. */
{
char
buf
[
4096
];
size_t
nread
;
while
((
nread
=
fread
(
buf
,
1
,
sizeof
(
buf
),
fp
))
!=
0
)
{
int
nwritten
;
nwritten
=
syncWrite
(
fd
,
buf
,
nread
,
timeout
);
if
(
nwritten
!=
(
signed
)
nread
)
goto
socket_wr_err
;
sds
buf
=
cmd
.
io
.
buffer
.
ptr
;
size_t
pos
=
0
,
towrite
;
int
nwritten
=
0
;
while
((
towrite
=
sdslen
(
buf
)
-
pos
)
>
0
)
{
towrite
=
(
towrite
>
(
64
*
1024
)
?
(
64
*
1024
)
:
towrite
);
nwritten
=
syncWrite
(
fd
,
buf
+
nwritten
,
towrite
,
timeout
);
if
(
nwritten
!=
(
signed
)
towrite
)
goto
socket_wr_err
;
pos
+=
nwritten
;
}
if
(
ferror
(
fp
))
goto
file_rd_err
;
}
/* Read back the reply */
/* Read back the reply
.
*/
{
char
buf1
[
1024
];
char
buf2
[
1024
];
...
...
@@ -1541,7 +1496,7 @@ void migrateCommand(redisClient *c) {
if
(
syncReadLine
(
fd
,
buf1
,
sizeof
(
buf1
),
timeout
)
<=
0
)
goto
socket_rd_err
;
if
(
syncReadLine
(
fd
,
buf2
,
sizeof
(
buf2
),
timeout
)
<=
0
)
goto
socket_rd_err
;
goto
socket_rd_err
;
if
(
buf1
[
0
]
==
'-'
||
buf2
[
0
]
==
'-'
)
{
addReplyErrorFormat
(
c
,
"Target instance replied with error: %s"
,
(
buf1
[
0
]
==
'-'
)
?
buf1
+
1
:
buf2
+
1
);
...
...
@@ -1550,25 +1505,8 @@ void migrateCommand(redisClient *c) {
addReply
(
c
,
shared
.
ok
);
}
}
fclose
(
fp
);
close
(
fd
);
return
;
file_wr_err:
redisLog
(
REDIS_WARNING
,
"Can't write on tmp file for MIGRATE: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"MIGRATE failed, tmp file write error: %s."
,
strerror
(
errno
));
fclose
(
fp
);
close
(
fd
);
return
;
file_rd_err:
redisLog
(
REDIS_WARNING
,
"Can't read from tmp file for MIGRATE: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"MIGRATE failed, tmp file read error: %s."
,
strerror
(
errno
));
fclose
(
fp
);
sdsfree
(
cmd
.
io
.
buffer
.
ptr
);
close
(
fd
);
return
;
...
...
@@ -1577,7 +1515,7 @@ socket_wr_err:
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"MIGRATE failed, writing to target node: %s."
,
strerror
(
errno
));
fclose
(
fp
);
sdsfree
(
cmd
.
io
.
buffer
.
ptr
);
close
(
fd
);
return
;
...
...
@@ -1586,7 +1524,7 @@ socket_rd_err:
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"MIGRATE failed, reading from target node: %s."
,
strerror
(
errno
));
fclose
(
fp
);
sdsfree
(
cmd
.
io
.
buffer
.
ptr
);
close
(
fd
);
return
;
}
...
...
@@ -1595,74 +1533,26 @@ socket_rd_err:
* DUMP is actually not used by Redis Cluster but it is the obvious
* complement of RESTORE and can be useful for different applications. */
void
dumpCommand
(
redisClient
*
c
)
{
char
buf
[
64
];
FILE
*
fp
;
robj
*
o
,
*
dumpobj
;
sds
dump
=
NULL
;
off_t
payload_len
;
unsigned
int
type
;
rio
payload
;
/* Check if the key is here. */
if
((
o
=
lookupKeyRead
(
c
->
db
,
c
->
argv
[
1
]))
==
NULL
)
{
addReply
(
c
,
shared
.
nullbulk
);
return
;
}
/* Create temp file */
snprintf
(
buf
,
sizeof
(
buf
),
"redis-dump-%d.tmp"
,
getpid
());
fp
=
fopen
(
buf
,
"w+"
);
if
(
!
fp
)
{
redisLog
(
REDIS_WARNING
,
"Can't open tmp file for MIGRATE: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"DUMP failed, tmp file creation error: %s."
,
strerror
(
errno
));
return
;
}
unlink
(
buf
);
/* Dump the serailized object and read it back in memory.
* We prefix it with a one byte containing the type ID.
* This is the serialization format understood by RESTORE. */
if
(
rdbSaveObject
(
fp
,
o
)
==
-
1
)
goto
file_wr_err
;
payload_len
=
ftello
(
fp
);
if
(
fseeko
(
fp
,
0
,
SEEK_SET
)
==
-
1
)
goto
file_rd_err
;
dump
=
sdsnewlen
(
NULL
,
payload_len
+
1
);
if
(
payload_len
&&
fread
(
dump
+
1
,
payload_len
,
1
,
fp
)
!=
1
)
goto
file_rd_err
;
fclose
(
fp
);
type
=
o
->
type
;
if
(
type
==
REDIS_LIST
&&
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
type
=
REDIS_LIST_ZIPLIST
;
else
if
(
type
==
REDIS_HASH
&&
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
type
=
REDIS_HASH_ZIPMAP
;
else
if
(
type
==
REDIS_SET
&&
o
->
encoding
==
REDIS_ENCODING_INTSET
)
type
=
REDIS_SET_INTSET
;
else
type
=
o
->
type
;
dump
[
0
]
=
type
;
/* Serialize the object in a RDB-like format. It consist of an object type
* byte followed by the serialized object. This is understood by RESTORE. */
payload
=
rioInitWithBuffer
(
sdsempty
());
redisAssert
(
rdbSaveObjectType
(
&
payload
,
o
));
redisAssert
(
rdbSaveObject
(
&
payload
,
o
));
/* Transfer to the client */
dumpobj
=
createObject
(
REDIS_STRING
,
dump
);
dumpobj
=
createObject
(
REDIS_STRING
,
payload
.
io
.
buffer
.
ptr
);
addReplyBulk
(
c
,
dumpobj
);
decrRefCount
(
dumpobj
);
return
;
file_wr_err:
redisLog
(
REDIS_WARNING
,
"Can't write on tmp file for DUMP: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"DUMP failed, tmp file write error: %s."
,
strerror
(
errno
));
sdsfree
(
dump
);
fclose
(
fp
);
return
;
file_rd_err:
redisLog
(
REDIS_WARNING
,
"Can't read from tmp file for DUMP: %s"
,
strerror
(
errno
));
addReplyErrorFormat
(
c
,
"DUMP failed, tmp file read error: %s."
,
strerror
(
errno
));
sdsfree
(
dump
);
fclose
(
fp
);
return
;
}
/* -----------------------------------------------------------------------------
...
...
src/rdb.c
View file @
f9c6f39b
#include "redis.h"
#include "lzf.h"
/* LZF compression library */
#include <math.h>
#include <sys/types.h>
#include <sys/time.h>
...
...
@@ -8,59 +5,99 @@
#include <sys/wait.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include "rdb.h"
#include "lzf.h"
/* LZF compression library */
/* Convenience wrapper around fwrite, that returns the number of bytes written
* to the file instead of the number of objects (see fwrite(3)) and -1 in the
* case of an error. It also supports a NULL *fp to skip writing altogether
* instead of writing to /dev/null. */
static
int
rdbWriteRaw
(
FILE
*
fp
,
void
*
p
,
size_t
len
)
{
if
(
fp
!=
NULL
&&
fwrite
(
p
,
len
,
1
,
fp
)
==
0
)
return
-
1
;
static
int
rdbWriteRaw
(
rio
*
rdb
,
void
*
p
,
size_t
len
)
{
if
(
rdb
&&
rioWrite
(
rdb
,
p
,
len
)
==
0
)
return
-
1
;
return
len
;
}
int
rdbSaveType
(
FILE
*
fp
,
unsigned
char
type
)
{
return
rdbWriteRaw
(
fp
,
&
type
,
1
);
int
rdbSaveType
(
rio
*
rdb
,
unsigned
char
type
)
{
return
rdbWriteRaw
(
rdb
,
&
type
,
1
);
}
int
rdbLoadType
(
rio
*
rdb
)
{
unsigned
char
type
;
if
(
rioRead
(
rdb
,
&
type
,
1
)
==
0
)
return
-
1
;
return
type
;
}
int
rdbSaveTime
(
FILE
*
fp
,
time_t
t
)
{
int
rdbSaveTime
(
rio
*
rdb
,
time_t
t
)
{
int32_t
t32
=
(
int32_t
)
t
;
return
rdbWriteRaw
(
fp
,
&
t32
,
4
);
return
rdbWriteRaw
(
rdb
,
&
t32
,
4
);
}
time_t
rdbLoadTime
(
rio
*
rdb
)
{
int32_t
t32
;
if
(
rioRead
(
rdb
,
&
t32
,
4
)
==
0
)
return
-
1
;
return
(
time_t
)
t32
;
}
/* check rdbLoadLen() comments for more info */
int
rdbSaveLen
(
FILE
*
fp
,
uint32_t
len
)
{
/* Saves an encoded length. The first two bits in the first byte are used to
* hold the encoding type. See the REDIS_RDB_* definitions for more information
* on the types of encoding. */
int
rdbSaveLen
(
rio
*
rdb
,
uint32_t
len
)
{
unsigned
char
buf
[
2
];
in
t
nwritten
;
size_
t
nwritten
;
if
(
len
<
(
1
<<
6
))
{
/* Save a 6 bit len */
buf
[
0
]
=
(
len
&
0xFF
)
|
(
REDIS_RDB_6BITLEN
<<
6
);
if
(
rdbWriteRaw
(
fp
,
buf
,
1
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
buf
,
1
)
==
-
1
)
return
-
1
;
nwritten
=
1
;
}
else
if
(
len
<
(
1
<<
14
))
{
/* Save a 14 bit len */
buf
[
0
]
=
((
len
>>
8
)
&
0xFF
)
|
(
REDIS_RDB_14BITLEN
<<
6
);
buf
[
1
]
=
len
&
0xFF
;
if
(
rdbWriteRaw
(
fp
,
buf
,
2
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
buf
,
2
)
==
-
1
)
return
-
1
;
nwritten
=
2
;
}
else
{
/* Save a 32 bit len */
buf
[
0
]
=
(
REDIS_RDB_32BITLEN
<<
6
);
if
(
rdbWriteRaw
(
fp
,
buf
,
1
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
buf
,
1
)
==
-
1
)
return
-
1
;
len
=
htonl
(
len
);
if
(
rdbWriteRaw
(
fp
,
&
len
,
4
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
&
len
,
4
)
==
-
4
)
return
-
1
;
nwritten
=
1
+
4
;
}
return
nwritten
;
}
/* Encode 'value' as an integer if possible (if integer will fit the
* supported range). If the function sucessful encoded the integer
* then the (up to 5 bytes) encoded representation is written in the
* string pointed by 'enc' and the length is returned. Otherwise
* 0 is returned. */
/* Load an encoded length. The "isencoded" argument is set to 1 if the length
* is not actually a length but an "encoding type". See the REDIS_RDB_ENC_*
* definitions in rdb.h for more information. */
uint32_t
rdbLoadLen
(
rio
*
rdb
,
int
*
isencoded
)
{
unsigned
char
buf
[
2
];
uint32_t
len
;
int
type
;
if
(
isencoded
)
*
isencoded
=
0
;
if
(
rioRead
(
rdb
,
buf
,
1
)
==
0
)
return
REDIS_RDB_LENERR
;
type
=
(
buf
[
0
]
&
0xC0
)
>>
6
;
if
(
type
==
REDIS_RDB_ENCVAL
)
{
/* Read a 6 bit encoding type. */
if
(
isencoded
)
*
isencoded
=
1
;
return
buf
[
0
]
&
0x3F
;
}
else
if
(
type
==
REDIS_RDB_6BITLEN
)
{
/* Read a 6 bit len. */
return
buf
[
0
]
&
0x3F
;
}
else
if
(
type
==
REDIS_RDB_14BITLEN
)
{
/* Read a 14 bit len. */
if
(
rioRead
(
rdb
,
buf
+
1
,
1
)
==
0
)
return
REDIS_RDB_LENERR
;
return
((
buf
[
0
]
&
0x3F
)
<<
8
)
|
buf
[
1
];
}
else
{
/* Read a 32 bit len. */
if
(
rioRead
(
rdb
,
&
len
,
4
)
==
0
)
return
REDIS_RDB_LENERR
;
return
ntohl
(
len
);
}
}
/* Encodes the "value" argument as integer when it fits in the supported ranges
* for encoded types. If the function successfully encodes the integer, the
* representation is stored in the buffer pointer to by "enc" and the string
* length is returned. Otherwise 0 is returned. */
int
rdbEncodeInteger
(
long
long
value
,
unsigned
char
*
enc
)
{
/* Finally check if it fits in our ranges */
if
(
value
>=
-
(
1
<<
7
)
&&
value
<=
(
1
<<
7
)
-
1
)
{
enc
[
0
]
=
(
REDIS_RDB_ENCVAL
<<
6
)
|
REDIS_RDB_ENC_INT8
;
enc
[
1
]
=
value
&
0xFF
;
...
...
@@ -82,6 +119,36 @@ int rdbEncodeInteger(long long value, unsigned char *enc) {
}
}
/* Loads an integer-encoded object with the specified encoding type "enctype".
* If the "encode" argument is set the function may return an integer-encoded
* string object, otherwise it always returns a raw string object. */
robj
*
rdbLoadIntegerObject
(
rio
*
rdb
,
int
enctype
,
int
encode
)
{
unsigned
char
enc
[
4
];
long
long
val
;
if
(
enctype
==
REDIS_RDB_ENC_INT8
)
{
if
(
rioRead
(
rdb
,
enc
,
1
)
==
0
)
return
NULL
;
val
=
(
signed
char
)
enc
[
0
];
}
else
if
(
enctype
==
REDIS_RDB_ENC_INT16
)
{
uint16_t
v
;
if
(
rioRead
(
rdb
,
enc
,
2
)
==
0
)
return
NULL
;
v
=
enc
[
0
]
|
(
enc
[
1
]
<<
8
);
val
=
(
int16_t
)
v
;
}
else
if
(
enctype
==
REDIS_RDB_ENC_INT32
)
{
uint32_t
v
;
if
(
rioRead
(
rdb
,
enc
,
4
)
==
0
)
return
NULL
;
v
=
enc
[
0
]
|
(
enc
[
1
]
<<
8
)
|
(
enc
[
2
]
<<
16
)
|
(
enc
[
3
]
<<
24
);
val
=
(
int32_t
)
v
;
}
else
{
val
=
0
;
/* anti-warning */
redisPanic
(
"Unknown RDB integer encoding type"
);
}
if
(
encode
)
return
createStringObjectFromLongLong
(
val
);
else
return
createObject
(
REDIS_STRING
,
sdsfromlonglong
(
val
));
}
/* String objects in the form "2391" "-100" without any space and with a
* range of values that can fit in an 8, 16 or 32 bit signed value can be
* encoded as integers to save space */
...
...
@@ -101,7 +168,7 @@ int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
return
rdbEncodeInteger
(
value
,
enc
);
}
int
rdbSaveLzfStringObject
(
FILE
*
fp
,
unsigned
char
*
s
,
size_t
len
)
{
int
rdbSaveLzfStringObject
(
rio
*
rdb
,
unsigned
char
*
s
,
size_t
len
)
{
size_t
comprlen
,
outlen
;
unsigned
char
byte
;
int
n
,
nwritten
=
0
;
...
...
@@ -118,16 +185,16 @@ int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
}
/* Data compressed! Let's save it on disk */
byte
=
(
REDIS_RDB_ENCVAL
<<
6
)
|
REDIS_RDB_ENC_LZF
;
if
((
n
=
rdbWriteRaw
(
fp
,
&
byte
,
1
))
==
-
1
)
goto
writeerr
;
if
((
n
=
rdbWriteRaw
(
rdb
,
&
byte
,
1
))
==
-
1
)
goto
writeerr
;
nwritten
+=
n
;
if
((
n
=
rdbSaveLen
(
fp
,
comprlen
))
==
-
1
)
goto
writeerr
;
if
((
n
=
rdbSaveLen
(
rdb
,
comprlen
))
==
-
1
)
goto
writeerr
;
nwritten
+=
n
;
if
((
n
=
rdbSaveLen
(
fp
,
len
))
==
-
1
)
goto
writeerr
;
if
((
n
=
rdbSaveLen
(
rdb
,
len
))
==
-
1
)
goto
writeerr
;
nwritten
+=
n
;
if
((
n
=
rdbWriteRaw
(
fp
,
out
,
comprlen
))
==
-
1
)
goto
writeerr
;
if
((
n
=
rdbWriteRaw
(
rdb
,
out
,
comprlen
))
==
-
1
)
goto
writeerr
;
nwritten
+=
n
;
zfree
(
out
);
...
...
@@ -138,9 +205,28 @@ writeerr:
return
-
1
;
}
robj
*
rdbLoadLzfStringObject
(
rio
*
rdb
)
{
unsigned
int
len
,
clen
;
unsigned
char
*
c
=
NULL
;
sds
val
=
NULL
;
if
((
clen
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
len
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
c
=
zmalloc
(
clen
))
==
NULL
)
goto
err
;
if
((
val
=
sdsnewlen
(
NULL
,
len
))
==
NULL
)
goto
err
;
if
(
rioRead
(
rdb
,
c
,
clen
)
==
0
)
goto
err
;
if
(
lzf_decompress
(
c
,
clen
,
val
,
len
)
==
0
)
goto
err
;
zfree
(
c
);
return
createObject
(
REDIS_STRING
,
val
);
err:
zfree
(
c
);
sdsfree
(
val
);
return
NULL
;
}
/* Save a string objet as [len][data] on disk. If the object is a string
* representation of an integer value we try to save it in a special form */
int
rdbSaveRawString
(
FILE
*
fp
,
unsigned
char
*
s
,
size_t
len
)
{
int
rdbSaveRawString
(
rio
*
rdb
,
unsigned
char
*
s
,
size_t
len
)
{
int
enclen
;
int
n
,
nwritten
=
0
;
...
...
@@ -148,7 +234,7 @@ int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
if
(
len
<=
11
)
{
unsigned
char
buf
[
5
];
if
((
enclen
=
rdbTryIntegerEncoding
((
char
*
)
s
,
len
,
buf
))
>
0
)
{
if
(
rdbWriteRaw
(
fp
,
buf
,
enclen
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
buf
,
enclen
)
==
-
1
)
return
-
1
;
return
enclen
;
}
}
...
...
@@ -156,53 +242,89 @@ int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
/* Try LZF compression - under 20 bytes it's unable to compress even
* aaaaaaaaaaaaaaaaaa so skip it */
if
(
server
.
rdbcompression
&&
len
>
20
)
{
n
=
rdbSaveLzfStringObject
(
fp
,
s
,
len
);
n
=
rdbSaveLzfStringObject
(
rdb
,
s
,
len
);
if
(
n
==
-
1
)
return
-
1
;
if
(
n
>
0
)
return
n
;
/* Return value of 0 means data can't be compressed, save the old way */
}
/* Store verbatim */
if
((
n
=
rdbSaveLen
(
fp
,
len
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
len
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
if
(
len
>
0
)
{
if
(
rdbWriteRaw
(
fp
,
s
,
len
)
==
-
1
)
return
-
1
;
if
(
rdbWriteRaw
(
rdb
,
s
,
len
)
==
-
1
)
return
-
1
;
nwritten
+=
len
;
}
return
nwritten
;
}
/* Save a long long value as either an encoded string or a string. */
int
rdbSaveLongLongAsStringObject
(
FILE
*
fp
,
long
long
value
)
{
int
rdbSaveLongLongAsStringObject
(
rio
*
rdb
,
long
long
value
)
{
unsigned
char
buf
[
32
];
int
n
,
nwritten
=
0
;
int
enclen
=
rdbEncodeInteger
(
value
,
buf
);
if
(
enclen
>
0
)
{
return
rdbWriteRaw
(
fp
,
buf
,
enclen
);
return
rdbWriteRaw
(
rdb
,
buf
,
enclen
);
}
else
{
/* Encode as string */
enclen
=
ll2string
((
char
*
)
buf
,
32
,
value
);
redisAssert
(
enclen
<
32
);
if
((
n
=
rdbSaveLen
(
fp
,
enclen
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
enclen
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
if
((
n
=
rdbWriteRaw
(
fp
,
buf
,
enclen
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbWriteRaw
(
rdb
,
buf
,
enclen
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
return
nwritten
;
}
/* Like rdbSaveStringObjectRaw() but handle encoded objects */
int
rdbSaveStringObject
(
FILE
*
fp
,
robj
*
obj
)
{
int
rdbSaveStringObject
(
rio
*
rdb
,
robj
*
obj
)
{
/* Avoid to decode the object, then encode it again, if the
* object is alrady integer encoded. */
if
(
obj
->
encoding
==
REDIS_ENCODING_INT
)
{
return
rdbSaveLongLongAsStringObject
(
fp
,(
long
)
obj
->
ptr
);
return
rdbSaveLongLongAsStringObject
(
rdb
,(
long
)
obj
->
ptr
);
}
else
{
redisAssert
(
obj
->
encoding
==
REDIS_ENCODING_RAW
);
return
rdbSaveRawString
(
fp
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
return
rdbSaveRawString
(
rdb
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
}
}
robj
*
rdbGenericLoadStringObject
(
rio
*
rdb
,
int
encode
)
{
int
isencoded
;
uint32_t
len
;
sds
val
;
len
=
rdbLoadLen
(
rdb
,
&
isencoded
);
if
(
isencoded
)
{
switch
(
len
)
{
case
REDIS_RDB_ENC_INT8
:
case
REDIS_RDB_ENC_INT16
:
case
REDIS_RDB_ENC_INT32
:
return
rdbLoadIntegerObject
(
rdb
,
len
,
encode
);
case
REDIS_RDB_ENC_LZF
:
return
rdbLoadLzfStringObject
(
rdb
);
default:
redisPanic
(
"Unknown RDB encoding type"
);
}
}
if
(
len
==
REDIS_RDB_LENERR
)
return
NULL
;
val
=
sdsnewlen
(
NULL
,
len
);
if
(
len
&&
rioRead
(
rdb
,
val
,
len
)
==
0
)
{
sdsfree
(
val
);
return
NULL
;
}
return
createObject
(
REDIS_STRING
,
val
);
}
robj
*
rdbLoadStringObject
(
rio
*
rdb
)
{
return
rdbGenericLoadStringObject
(
rdb
,
0
);
}
robj
*
rdbLoadEncodedStringObject
(
rio
*
rdb
)
{
return
rdbGenericLoadStringObject
(
rdb
,
1
);
}
/* Save a double value. Doubles are saved as strings prefixed by an unsigned
* 8 bit integer specifing the length of the representation.
* This 8 bit integer has special values in order to specify the following
...
...
@@ -211,7 +333,7 @@ int rdbSaveStringObject(FILE *fp, robj *obj) {
* 254: + inf
* 255: - inf
*/
int
rdbSaveDoubleValue
(
FILE
*
fp
,
double
val
)
{
int
rdbSaveDoubleValue
(
rio
*
rdb
,
double
val
)
{
unsigned
char
buf
[
128
];
int
len
;
...
...
@@ -242,36 +364,101 @@ int rdbSaveDoubleValue(FILE *fp, double val) {
buf
[
0
]
=
strlen
((
char
*
)
buf
+
1
);
len
=
buf
[
0
]
+
1
;
}
return
rdbWriteRaw
(
fp
,
buf
,
len
);
return
rdbWriteRaw
(
rdb
,
buf
,
len
);
}
/* For information about double serialization check rdbSaveDoubleValue() */
int
rdbLoadDoubleValue
(
rio
*
rdb
,
double
*
val
)
{
char
buf
[
128
];
unsigned
char
len
;
if
(
rioRead
(
rdb
,
&
len
,
1
)
==
0
)
return
-
1
;
switch
(
len
)
{
case
255
:
*
val
=
R_NegInf
;
return
0
;
case
254
:
*
val
=
R_PosInf
;
return
0
;
case
253
:
*
val
=
R_Nan
;
return
0
;
default:
if
(
rioRead
(
rdb
,
buf
,
len
)
==
0
)
return
-
1
;
buf
[
len
]
=
'\0'
;
sscanf
(
buf
,
"%lg"
,
val
);
return
0
;
}
}
/* Save the object type of object "o". */
int
rdbSaveObjectType
(
rio
*
rdb
,
robj
*
o
)
{
switch
(
o
->
type
)
{
case
REDIS_STRING
:
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_STRING
);
case
REDIS_LIST
:
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_LIST_ZIPLIST
);
else
if
(
o
->
encoding
==
REDIS_ENCODING_LINKEDLIST
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_LIST
);
else
redisPanic
(
"Unknown list encoding"
);
case
REDIS_SET
:
if
(
o
->
encoding
==
REDIS_ENCODING_INTSET
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_SET_INTSET
);
else
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_SET
);
else
redisPanic
(
"Unknown set encoding"
);
case
REDIS_ZSET
:
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_ZSET_ZIPLIST
);
else
if
(
o
->
encoding
==
REDIS_ENCODING_SKIPLIST
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_ZSET
);
else
redisPanic
(
"Unknown sorted set encoding"
);
case
REDIS_HASH
:
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_HASH_ZIPMAP
);
else
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
return
rdbSaveType
(
rdb
,
REDIS_RDB_TYPE_HASH
);
else
redisPanic
(
"Unknown hash encoding"
);
default:
redisPanic
(
"Unknown object type"
);
}
return
-
1
;
/* avoid warning */
}
/* Load object type. Return -1 when the byte doesn't contain an object type. */
int
rdbLoadObjectType
(
rio
*
rdb
)
{
int
type
;
if
((
type
=
rdbLoadType
(
rdb
))
==
-
1
)
return
-
1
;
if
(
!
rdbIsObjectType
(
type
))
return
-
1
;
return
type
;
}
/* Save a Redis object. Returns -1 on error, 0 on success. */
int
rdbSaveObject
(
FILE
*
fp
,
robj
*
o
)
{
int
rdbSaveObject
(
rio
*
rdb
,
robj
*
o
)
{
int
n
,
nwritten
=
0
;
if
(
o
->
type
==
REDIS_STRING
)
{
/* Save a string value */
if
((
n
=
rdbSaveStringObject
(
fp
,
o
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
o
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
if
(
o
->
type
==
REDIS_LIST
)
{
/* Save a list value */
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
size_t
l
=
ziplistBlobLen
((
unsigned
char
*
)
o
->
ptr
);
if
((
n
=
rdbSaveRawString
(
fp
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveRawString
(
rdb
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_LINKEDLIST
)
{
list
*
list
=
o
->
ptr
;
listIter
li
;
listNode
*
ln
;
if
((
n
=
rdbSaveLen
(
fp
,
listLength
(
list
)))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
listLength
(
list
)))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
listRewind
(
list
,
&
li
);
while
((
ln
=
listNext
(
&
li
)))
{
robj
*
eleobj
=
listNodeValue
(
ln
);
if
((
n
=
rdbSaveStringObject
(
fp
,
eleobj
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
eleobj
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
}
else
{
...
...
@@ -284,19 +471,19 @@ int rdbSaveObject(FILE *fp, robj *o) {
dictIterator
*
di
=
dictGetIterator
(
set
);
dictEntry
*
de
;
if
((
n
=
rdbSaveLen
(
fp
,
dictSize
(
set
)))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
dictSize
(
set
)))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
eleobj
=
dictGetEntryKey
(
de
);
if
((
n
=
rdbSaveStringObject
(
fp
,
eleobj
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
eleobj
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
dictReleaseIterator
(
di
);
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_INTSET
)
{
size_t
l
=
intsetBlobLen
((
intset
*
)
o
->
ptr
);
if
((
n
=
rdbSaveRawString
(
fp
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveRawString
(
rdb
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
{
redisPanic
(
"Unknown set encoding"
);
...
...
@@ -306,23 +493,23 @@ int rdbSaveObject(FILE *fp, robj *o) {
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
{
size_t
l
=
ziplistBlobLen
((
unsigned
char
*
)
o
->
ptr
);
if
((
n
=
rdbSaveRawString
(
fp
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveRawString
(
rdb
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_SKIPLIST
)
{
zset
*
zs
=
o
->
ptr
;
dictIterator
*
di
=
dictGetIterator
(
zs
->
dict
);
dictEntry
*
de
;
if
((
n
=
rdbSaveLen
(
fp
,
dictSize
(
zs
->
dict
)))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
dictSize
(
zs
->
dict
)))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
eleobj
=
dictGetEntryKey
(
de
);
double
*
score
=
dictGetEntryVal
(
de
);
if
((
n
=
rdbSaveStringObject
(
fp
,
eleobj
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
eleobj
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
if
((
n
=
rdbSaveDoubleValue
(
fp
,
*
score
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveDoubleValue
(
rdb
,
*
score
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
dictReleaseIterator
(
di
);
...
...
@@ -334,22 +521,22 @@ int rdbSaveObject(FILE *fp, robj *o) {
if
(
o
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
{
size_t
l
=
zipmapBlobLen
((
unsigned
char
*
)
o
->
ptr
);
if
((
n
=
rdbSaveRawString
(
fp
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveRawString
(
rdb
,
o
->
ptr
,
l
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
else
{
dictIterator
*
di
=
dictGetIterator
(
o
->
ptr
);
dictEntry
*
de
;
if
((
n
=
rdbSaveLen
(
fp
,
dictSize
((
dict
*
)
o
->
ptr
)))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveLen
(
rdb
,
dictSize
((
dict
*
)
o
->
ptr
)))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
key
=
dictGetEntryKey
(
de
);
robj
*
val
=
dictGetEntryVal
(
de
);
if
((
n
=
rdbSaveStringObject
(
fp
,
key
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
key
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
if
((
n
=
rdbSaveStringObject
(
fp
,
val
))
==
-
1
)
return
-
1
;
if
((
n
=
rdbSaveStringObject
(
rdb
,
val
))
==
-
1
)
return
-
1
;
nwritten
+=
n
;
}
dictReleaseIterator
(
di
);
...
...
@@ -374,33 +561,21 @@ off_t rdbSavedObjectLen(robj *o) {
* On error -1 is returned.
* On success if the key was actaully saved 1 is returned, otherwise 0
* is returned (the key was already expired). */
int
rdbSaveKeyValuePair
(
FILE
*
fp
,
robj
*
key
,
robj
*
val
,
int
rdbSaveKeyValuePair
(
rio
*
rdb
,
robj
*
key
,
robj
*
val
,
time_t
expiretime
,
time_t
now
)
{
int
vtype
;
/* Save the expire time */
if
(
expiretime
!=
-
1
)
{
/* If this key is already expired skip it */
if
(
expiretime
<
now
)
return
0
;
if
(
rdbSaveType
(
fp
,
REDIS_EXPIRETIME
)
==
-
1
)
return
-
1
;
if
(
rdbSaveTime
(
fp
,
expiretime
)
==
-
1
)
return
-
1
;
if
(
rdbSaveType
(
rdb
,
REDIS_
RDB_OPCODE_
EXPIRETIME
)
==
-
1
)
return
-
1
;
if
(
rdbSaveTime
(
rdb
,
expiretime
)
==
-
1
)
return
-
1
;
}
/* Fix the object type if needed, to support saving zipmaps, ziplists,
* and intsets, directly as blobs of bytes: they are already serialized. */
vtype
=
val
->
type
;
if
(
vtype
==
REDIS_HASH
&&
val
->
encoding
==
REDIS_ENCODING_ZIPMAP
)
vtype
=
REDIS_HASH_ZIPMAP
;
else
if
(
vtype
==
REDIS_LIST
&&
val
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
vtype
=
REDIS_LIST_ZIPLIST
;
else
if
(
vtype
==
REDIS_SET
&&
val
->
encoding
==
REDIS_ENCODING_INTSET
)
vtype
=
REDIS_SET_INTSET
;
else
if
(
vtype
==
REDIS_ZSET
&&
val
->
encoding
==
REDIS_ENCODING_ZIPLIST
)
vtype
=
REDIS_ZSET_ZIPLIST
;
/* Save type, key, value */
if
(
rdbSave
Type
(
fp
,
vtype
)
==
-
1
)
return
-
1
;
if
(
rdbSaveStringObject
(
fp
,
key
)
==
-
1
)
return
-
1
;
if
(
rdbSaveObject
(
fp
,
val
)
==
-
1
)
return
-
1
;
if
(
rdbSave
ObjectType
(
rdb
,
val
)
==
-
1
)
return
-
1
;
if
(
rdbSaveStringObject
(
rdb
,
key
)
==
-
1
)
return
-
1
;
if
(
rdbSaveObject
(
rdb
,
val
)
==
-
1
)
return
-
1
;
return
1
;
}
...
...
@@ -408,10 +583,11 @@ int rdbSaveKeyValuePair(FILE *fp, robj *key, robj *val,
int
rdbSave
(
char
*
filename
)
{
dictIterator
*
di
=
NULL
;
dictEntry
*
de
;
FILE
*
fp
;
char
tmpfile
[
256
];
int
j
;
time_t
now
=
time
(
NULL
);
FILE
*
fp
;
rio
rdb
;
snprintf
(
tmpfile
,
256
,
"temp-%d.rdb"
,
(
int
)
getpid
());
fp
=
fopen
(
tmpfile
,
"w"
);
...
...
@@ -420,7 +596,10 @@ int rdbSave(char *filename) {
strerror
(
errno
));
return
REDIS_ERR
;
}
if
(
fwrite
(
"REDIS0002"
,
9
,
1
,
fp
)
==
0
)
goto
werr
;
rdb
=
rioInitWithFile
(
fp
);
if
(
rdbWriteRaw
(
&
rdb
,
"REDIS0002"
,
9
)
==
-
1
)
goto
werr
;
for
(
j
=
0
;
j
<
server
.
dbnum
;
j
++
)
{
redisDb
*
db
=
server
.
db
+
j
;
dict
*
d
=
db
->
dict
;
...
...
@@ -432,8 +611,8 @@ int rdbSave(char *filename) {
}
/* Write the SELECT DB opcode */
if
(
rdbSaveType
(
fp
,
REDIS_SELECTDB
)
==
-
1
)
goto
werr
;
if
(
rdbSaveLen
(
fp
,
j
)
==
-
1
)
goto
werr
;
if
(
rdbSaveType
(
&
rdb
,
REDIS_
RDB_OPCODE_
SELECTDB
)
==
-
1
)
goto
werr
;
if
(
rdbSaveLen
(
&
rdb
,
j
)
==
-
1
)
goto
werr
;
/* Iterate this DB writing every entry */
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
...
...
@@ -443,12 +622,12 @@ int rdbSave(char *filename) {
initStaticStringObject
(
key
,
keystr
);
expire
=
getExpire
(
db
,
&
key
);
if
(
rdbSaveKeyValuePair
(
fp
,
&
key
,
o
,
expire
,
now
)
==
-
1
)
goto
werr
;
if
(
rdbSaveKeyValuePair
(
&
rdb
,
&
key
,
o
,
expire
,
now
)
==
-
1
)
goto
werr
;
}
dictReleaseIterator
(
di
);
}
/* EOF opcode */
if
(
rdbSaveType
(
fp
,
REDIS_EOF
)
==
-
1
)
goto
werr
;
if
(
rdbSaveType
(
&
rdb
,
REDIS_
RDB_OPCODE_
EOF
)
==
-
1
)
goto
werr
;
/* Make sure data will not remain on the OS's output buffers */
fflush
(
fp
);
...
...
@@ -515,168 +694,21 @@ void rdbRemoveTempFile(pid_t childpid) {
unlink
(
tmpfile
);
}
int
rdbLoadType
(
FILE
*
fp
)
{
unsigned
char
type
;
if
(
fread
(
&
type
,
1
,
1
,
fp
)
==
0
)
return
-
1
;
return
type
;
}
time_t
rdbLoadTime
(
FILE
*
fp
)
{
int32_t
t32
;
if
(
fread
(
&
t32
,
4
,
1
,
fp
)
==
0
)
return
-
1
;
return
(
time_t
)
t32
;
}
/* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
* of this file for a description of how this are stored on disk.
*
* isencoded is set to 1 if the readed length is not actually a length but
* an "encoding type", check the above comments for more info */
uint32_t
rdbLoadLen
(
FILE
*
fp
,
int
*
isencoded
)
{
unsigned
char
buf
[
2
];
uint32_t
len
;
int
type
;
if
(
isencoded
)
*
isencoded
=
0
;
if
(
fread
(
buf
,
1
,
1
,
fp
)
==
0
)
return
REDIS_RDB_LENERR
;
type
=
(
buf
[
0
]
&
0xC0
)
>>
6
;
if
(
type
==
REDIS_RDB_6BITLEN
)
{
/* Read a 6 bit len */
return
buf
[
0
]
&
0x3F
;
}
else
if
(
type
==
REDIS_RDB_ENCVAL
)
{
/* Read a 6 bit len encoding type */
if
(
isencoded
)
*
isencoded
=
1
;
return
buf
[
0
]
&
0x3F
;
}
else
if
(
type
==
REDIS_RDB_14BITLEN
)
{
/* Read a 14 bit len */
if
(
fread
(
buf
+
1
,
1
,
1
,
fp
)
==
0
)
return
REDIS_RDB_LENERR
;
return
((
buf
[
0
]
&
0x3F
)
<<
8
)
|
buf
[
1
];
}
else
{
/* Read a 32 bit len */
if
(
fread
(
&
len
,
4
,
1
,
fp
)
==
0
)
return
REDIS_RDB_LENERR
;
return
ntohl
(
len
);
}
}
/* Load an integer-encoded object from file 'fp', with the specified
* encoding type 'enctype'. If encode is true the function may return
* an integer-encoded object as reply, otherwise the returned object
* will always be encoded as a raw string. */
robj
*
rdbLoadIntegerObject
(
FILE
*
fp
,
int
enctype
,
int
encode
)
{
unsigned
char
enc
[
4
];
long
long
val
;
if
(
enctype
==
REDIS_RDB_ENC_INT8
)
{
if
(
fread
(
enc
,
1
,
1
,
fp
)
==
0
)
return
NULL
;
val
=
(
signed
char
)
enc
[
0
];
}
else
if
(
enctype
==
REDIS_RDB_ENC_INT16
)
{
uint16_t
v
;
if
(
fread
(
enc
,
2
,
1
,
fp
)
==
0
)
return
NULL
;
v
=
enc
[
0
]
|
(
enc
[
1
]
<<
8
);
val
=
(
int16_t
)
v
;
}
else
if
(
enctype
==
REDIS_RDB_ENC_INT32
)
{
uint32_t
v
;
if
(
fread
(
enc
,
4
,
1
,
fp
)
==
0
)
return
NULL
;
v
=
enc
[
0
]
|
(
enc
[
1
]
<<
8
)
|
(
enc
[
2
]
<<
16
)
|
(
enc
[
3
]
<<
24
);
val
=
(
int32_t
)
v
;
}
else
{
val
=
0
;
/* anti-warning */
redisPanic
(
"Unknown RDB integer encoding type"
);
}
if
(
encode
)
return
createStringObjectFromLongLong
(
val
);
else
return
createObject
(
REDIS_STRING
,
sdsfromlonglong
(
val
));
}
robj
*
rdbLoadLzfStringObject
(
FILE
*
fp
)
{
unsigned
int
len
,
clen
;
unsigned
char
*
c
=
NULL
;
sds
val
=
NULL
;
if
((
clen
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
len
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
c
=
zmalloc
(
clen
))
==
NULL
)
goto
err
;
if
((
val
=
sdsnewlen
(
NULL
,
len
))
==
NULL
)
goto
err
;
if
(
fread
(
c
,
clen
,
1
,
fp
)
==
0
)
goto
err
;
if
(
lzf_decompress
(
c
,
clen
,
val
,
len
)
==
0
)
goto
err
;
zfree
(
c
);
return
createObject
(
REDIS_STRING
,
val
);
err:
zfree
(
c
);
sdsfree
(
val
);
return
NULL
;
}
robj
*
rdbGenericLoadStringObject
(
FILE
*
fp
,
int
encode
)
{
int
isencoded
;
uint32_t
len
;
sds
val
;
len
=
rdbLoadLen
(
fp
,
&
isencoded
);
if
(
isencoded
)
{
switch
(
len
)
{
case
REDIS_RDB_ENC_INT8
:
case
REDIS_RDB_ENC_INT16
:
case
REDIS_RDB_ENC_INT32
:
return
rdbLoadIntegerObject
(
fp
,
len
,
encode
);
case
REDIS_RDB_ENC_LZF
:
return
rdbLoadLzfStringObject
(
fp
);
default:
redisPanic
(
"Unknown RDB encoding type"
);
}
}
if
(
len
==
REDIS_RDB_LENERR
)
return
NULL
;
val
=
sdsnewlen
(
NULL
,
len
);
if
(
len
&&
fread
(
val
,
len
,
1
,
fp
)
==
0
)
{
sdsfree
(
val
);
return
NULL
;
}
return
createObject
(
REDIS_STRING
,
val
);
}
robj
*
rdbLoadStringObject
(
FILE
*
fp
)
{
return
rdbGenericLoadStringObject
(
fp
,
0
);
}
robj
*
rdbLoadEncodedStringObject
(
FILE
*
fp
)
{
return
rdbGenericLoadStringObject
(
fp
,
1
);
}
/* For information about double serialization check rdbSaveDoubleValue() */
int
rdbLoadDoubleValue
(
FILE
*
fp
,
double
*
val
)
{
char
buf
[
128
];
unsigned
char
len
;
if
(
fread
(
&
len
,
1
,
1
,
fp
)
==
0
)
return
-
1
;
switch
(
len
)
{
case
255
:
*
val
=
R_NegInf
;
return
0
;
case
254
:
*
val
=
R_PosInf
;
return
0
;
case
253
:
*
val
=
R_Nan
;
return
0
;
default:
if
(
fread
(
buf
,
len
,
1
,
fp
)
==
0
)
return
-
1
;
buf
[
len
]
=
'\0'
;
sscanf
(
buf
,
"%lg"
,
val
);
return
0
;
}
}
/* Load a Redis object of the specified type from the specified file.
* On success a newly allocated object is returned, otherwise NULL. */
robj
*
rdbLoadObject
(
int
type
,
FILE
*
fp
)
{
robj
*
rdbLoadObject
(
int
rdb
type
,
rio
*
rdb
)
{
robj
*
o
,
*
ele
,
*
dec
;
size_t
len
;
unsigned
int
i
;
redisLog
(
REDIS_DEBUG
,
"LOADING OBJECT %d (at %d)
\n
"
,
type
,
f
tell
(
fp
));
if
(
type
==
REDIS_STRING
)
{
redisLog
(
REDIS_DEBUG
,
"LOADING OBJECT %d (at %d)
\n
"
,
rdb
type
,
rdb
->
tell
(
rdb
));
if
(
rdb
type
==
REDIS_
RDB_TYPE_
STRING
)
{
/* Read string value */
if
((
o
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
o
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
o
=
tryObjectEncoding
(
o
);
}
else
if
(
type
==
REDIS_LIST
)
{
}
else
if
(
rdb
type
==
REDIS_
RDB_TYPE_
LIST
)
{
/* Read list value */
if
((
len
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
len
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
/* Use a real list when there are too many entries */
if
(
len
>
server
.
list_max_ziplist_entries
)
{
...
...
@@ -687,7 +719,7 @@ robj *rdbLoadObject(int type, FILE *fp) {
/* Load every single element of the list */
while
(
len
--
)
{
if
((
ele
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
ele
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
/* If we are using a ziplist and the value is too big, convert
* the object to a real list. */
...
...
@@ -706,9 +738,9 @@ robj *rdbLoadObject(int type, FILE *fp) {
listAddNodeTail
(
o
->
ptr
,
ele
);
}
}
}
else
if
(
type
==
REDIS_SET
)
{
}
else
if
(
rdb
type
==
REDIS_
RDB_TYPE_
SET
)
{
/* Read list/set value */
if
((
len
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
len
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
/* Use a regular set when there are too many entries. */
if
(
len
>
server
.
set_max_intset_entries
)
{
...
...
@@ -724,7 +756,7 @@ robj *rdbLoadObject(int type, FILE *fp) {
/* Load every single element of the list/set */
for
(
i
=
0
;
i
<
len
;
i
++
)
{
long
long
llval
;
if
((
ele
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
ele
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
ele
=
tryObjectEncoding
(
ele
);
if
(
o
->
encoding
==
REDIS_ENCODING_INTSET
)
{
...
...
@@ -745,13 +777,13 @@ robj *rdbLoadObject(int type, FILE *fp) {
decrRefCount
(
ele
);
}
}
}
else
if
(
type
==
REDIS_ZSET
)
{
}
else
if
(
rdb
type
==
REDIS_
RDB_TYPE_
ZSET
)
{
/* Read list/set value */
size_t
zsetlen
;
size_t
maxelelen
=
0
;
zset
*
zs
;
if
((
zsetlen
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
zsetlen
=
rdbLoadLen
(
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
o
=
createZsetObject
();
zs
=
o
->
ptr
;
...
...
@@ -761,9 +793,9 @@ robj *rdbLoadObject(int type, FILE *fp) {
double
score
;
zskiplistNode
*
znode
;
if
((
ele
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
ele
=
rdbLoadEncodedStringObject
(
rdb
))
==
NULL
)
return
NULL
;
ele
=
tryObjectEncoding
(
ele
);
if
(
rdbLoadDoubleValue
(
fp
,
&
score
)
==
-
1
)
return
NULL
;
if
(
rdbLoadDoubleValue
(
rdb
,
&
score
)
==
-
1
)
return
NULL
;
/* Don't care about integer-encoded strings. */
if
(
ele
->
encoding
==
REDIS_ENCODING_RAW
&&
...
...
@@ -779,10 +811,10 @@ robj *rdbLoadObject(int type, FILE *fp) {
if
(
zsetLength
(
o
)
<=
server
.
zset_max_ziplist_entries
&&
maxelelen
<=
server
.
zset_max_ziplist_value
)
zsetConvert
(
o
,
REDIS_ENCODING_ZIPLIST
);
}
else
if
(
type
==
REDIS_HASH
)
{
}
else
if
(
rdb
type
==
REDIS_
RDB_TYPE_
HASH
)
{
size_t
hashlen
;
if
((
hashlen
=
rdbLoadLen
(
fp
,
NULL
))
==
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
)
...
...
@@ -792,8 +824,8 @@ robj *rdbLoadObject(int type, FILE *fp) {
while
(
hashlen
--
)
{
robj
*
key
,
*
val
;
if
((
key
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
val
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
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
&&
...
...
@@ -825,12 +857,12 @@ robj *rdbLoadObject(int type, FILE *fp) {
dictAdd
((
dict
*
)
o
->
ptr
,
key
,
val
);
}
}
}
else
if
(
type
==
REDIS_HASH_ZIPMAP
||
type
==
REDIS_LIST_ZIPLIST
||
type
==
REDIS_SET_INTSET
||
type
==
REDIS_ZSET_ZIPLIST
)
}
else
if
(
rdb
type
==
REDIS_
RDB_TYPE_
HASH_ZIPMAP
||
rdb
type
==
REDIS_
RDB_TYPE_
LIST_ZIPLIST
||
rdb
type
==
REDIS_
RDB_TYPE_
SET_INTSET
||
rdb
type
==
REDIS_
RDB_TYPE_
ZSET_ZIPLIST
)
{
robj
*
aux
=
rdbLoadStringObject
(
fp
);
robj
*
aux
=
rdbLoadStringObject
(
rdb
);
if
(
aux
==
NULL
)
return
NULL
;
o
=
createObject
(
REDIS_STRING
,
NULL
);
/* string is just placeholder */
...
...
@@ -844,26 +876,26 @@ robj *rdbLoadObject(int type, FILE *fp) {
* type. Note that we only check the length and not max element
* size as this is an O(N) scan. Eventually everything will get
* converted. */
switch
(
type
)
{
case
REDIS_HASH_ZIPMAP
:
switch
(
rdb
type
)
{
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
);
break
;
case
REDIS_LIST_ZIPLIST
:
case
REDIS_
RDB_TYPE_
LIST_ZIPLIST
:
o
->
type
=
REDIS_LIST
;
o
->
encoding
=
REDIS_ENCODING_ZIPLIST
;
if
(
ziplistLen
(
o
->
ptr
)
>
server
.
list_max_ziplist_entries
)
listTypeConvert
(
o
,
REDIS_ENCODING_LINKEDLIST
);
break
;
case
REDIS_SET_INTSET
:
case
REDIS_
RDB_TYPE_
SET_INTSET
:
o
->
type
=
REDIS_SET
;
o
->
encoding
=
REDIS_ENCODING_INTSET
;
if
(
intsetLen
(
o
->
ptr
)
>
server
.
set_max_intset_entries
)
setTypeConvert
(
o
,
REDIS_ENCODING_HT
);
break
;
case
REDIS_ZSET_ZIPLIST
:
case
REDIS_
RDB_TYPE_
ZSET_ZIPLIST
:
o
->
type
=
REDIS_ZSET
;
o
->
encoding
=
REDIS_ENCODING_ZIPLIST
;
if
(
zsetLength
(
o
)
>
server
.
zset_max_ziplist_entries
)
...
...
@@ -905,17 +937,19 @@ void stopLoading(void) {
}
int
rdbLoad
(
char
*
filename
)
{
FILE
*
fp
;
uint32_t
dbid
;
int
type
,
rdbver
;
redisDb
*
db
=
server
.
db
+
0
;
char
buf
[
1024
];
time_t
expiretime
,
now
=
time
(
NULL
);
long
loops
=
0
;
FILE
*
fp
;
rio
rdb
;
fp
=
fopen
(
filename
,
"r"
);
if
(
!
fp
)
return
REDIS_ERR
;
if
(
fread
(
buf
,
9
,
1
,
fp
)
==
0
)
goto
eoferr
;
rdb
=
rioInitWithFile
(
fp
);
if
(
rioRead
(
&
rdb
,
buf
,
9
)
==
0
)
goto
eoferr
;
buf
[
9
]
=
'\0'
;
if
(
memcmp
(
buf
,
"REDIS"
,
5
)
!=
0
)
{
fclose
(
fp
);
...
...
@@ -936,21 +970,24 @@ int rdbLoad(char *filename) {
/* Serve the clients from time to time */
if
(
!
(
loops
++
%
1000
))
{
loadingProgress
(
ftello
(
fp
));
loadingProgress
(
rdb
.
tell
(
&
rdb
));
aeProcessEvents
(
server
.
el
,
AE_FILE_EVENTS
|
AE_DONT_WAIT
);
}
/* Read type. */
if
((
type
=
rdbLoadType
(
fp
))
==
-
1
)
goto
eoferr
;
if
(
type
==
REDIS_EXPIRETIME
)
{
if
((
expiretime
=
rdbLoadTime
(
fp
))
==
-
1
)
goto
eoferr
;
/* We read the time so we need to read the object type again */
if
((
type
=
rdbLoadType
(
fp
))
==
-
1
)
goto
eoferr
;
if
((
type
=
rdbLoadType
(
&
rdb
))
==
-
1
)
goto
eoferr
;
if
(
type
==
REDIS_
RDB_OPCODE_
EXPIRETIME
)
{
if
((
expiretime
=
rdbLoadTime
(
&
rdb
))
==
-
1
)
goto
eoferr
;
/* We read the time so we need to read the object type again
.
*/
if
((
type
=
rdbLoadType
(
&
rdb
))
==
-
1
)
goto
eoferr
;
}
if
(
type
==
REDIS_EOF
)
break
;
if
(
type
==
REDIS_RDB_OPCODE_EOF
)
break
;
/* Handle SELECT DB opcode as a special case */
if
(
type
==
REDIS_SELECTDB
)
{
if
((
dbid
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
if
(
type
==
REDIS_
RDB_OPCODE_
SELECTDB
)
{
if
((
dbid
=
rdbLoadLen
(
&
rdb
,
NULL
))
==
REDIS_RDB_LENERR
)
goto
eoferr
;
if
(
dbid
>=
(
unsigned
)
server
.
dbnum
)
{
redisLog
(
REDIS_WARNING
,
"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting
\n
"
,
server
.
dbnum
);
...
...
@@ -960,9 +997,9 @@ int rdbLoad(char *filename) {
continue
;
}
/* Read key */
if
((
key
=
rdbLoadStringObject
(
fp
))
==
NULL
)
goto
eoferr
;
if
((
key
=
rdbLoadStringObject
(
&
rdb
))
==
NULL
)
goto
eoferr
;
/* Read value */
if
((
val
=
rdbLoadObject
(
type
,
fp
))
==
NULL
)
goto
eoferr
;
if
((
val
=
rdbLoadObject
(
type
,
&
rdb
))
==
NULL
)
goto
eoferr
;
/* Check if the key already expired */
if
(
expiretime
!=
-
1
&&
expiretime
<
now
)
{
decrRefCount
(
key
);
...
...
src/rdb.h
0 → 100644
View file @
f9c6f39b
#ifndef __REDIS_RDB_H
#define __REDIS_RDB_H
#include <stdio.h>
#include "rio.h"
/* TBD: include only necessary headers. */
#include "redis.h"
/* Defines related to the dump file format. To store 32 bits lengths for short
* keys requires a lot of space, so we check the most significant 2 bits of
* the first byte to interpreter the length:
*
* 00|000000 => if the two MSB are 00 the len is the 6 bits of this byte
* 01|000000 00000000 => 01, the len is 14 byes, 6 bits + 8 bits of next byte
* 10|000000 [32 bit integer] => if it's 01, a full 32 bit len will follow
* 11|000000 this means: specially encoded object will follow. The six bits
* number specify the kind of object that follows.
* See the REDIS_RDB_ENC_* defines.
*
* Lenghts up to 63 are stored using a single byte, most DB keys, and may
* values, will fit inside. */
#define REDIS_RDB_6BITLEN 0
#define REDIS_RDB_14BITLEN 1
#define REDIS_RDB_32BITLEN 2
#define REDIS_RDB_ENCVAL 3
#define REDIS_RDB_LENERR UINT_MAX
/* When a length of a string object stored on disk has the first two bits
* set, the remaining two bits specify a special encoding for the object
* accordingly to the following defines: */
#define REDIS_RDB_ENC_INT8 0
/* 8 bit signed integer */
#define REDIS_RDB_ENC_INT16 1
/* 16 bit signed integer */
#define REDIS_RDB_ENC_INT32 2
/* 32 bit signed integer */
#define REDIS_RDB_ENC_LZF 3
/* string compressed with FASTLZ */
/* Dup object types to RDB object types. Only reason is readability (are we
* dealing with RDB types or with in-memory object types?). */
#define REDIS_RDB_TYPE_STRING 0
#define REDIS_RDB_TYPE_LIST 1
#define REDIS_RDB_TYPE_SET 2
#define REDIS_RDB_TYPE_ZSET 3
#define REDIS_RDB_TYPE_HASH 4
/* Object types for encoded objects. */
#define REDIS_RDB_TYPE_HASH_ZIPMAP 9
#define REDIS_RDB_TYPE_LIST_ZIPLIST 10
#define REDIS_RDB_TYPE_SET_INTSET 11
#define REDIS_RDB_TYPE_ZSET_ZIPLIST 12
/* Test if a type is an object type. */
#define rdbIsObjectType(t) ((t >= 0 && t <= 4) || (t >= 9 && t <= 12))
/* Special RDB opcodes (saved/loaded with rdbSaveType/rdbLoadType). */
#define REDIS_RDB_OPCODE_EXPIRETIME 253
#define REDIS_RDB_OPCODE_SELECTDB 254
#define REDIS_RDB_OPCODE_EOF 255
/* Test if a type is an opcode. */
#define rdbIsOpcode(t) (t >= 253 && t <= 255)
int
rdbSaveType
(
rio
*
rdb
,
unsigned
char
type
);
int
rdbLoadType
(
rio
*
rdb
);
int
rdbSaveTime
(
rio
*
rdb
,
time_t
t
);
time_t
rdbLoadTime
(
rio
*
rdb
);
int
rdbSaveLen
(
rio
*
rdb
,
uint32_t
len
);
uint32_t
rdbLoadLen
(
rio
*
rdb
,
int
*
isencoded
);
int
rdbSaveObjectType
(
rio
*
rdb
,
robj
*
o
);
int
rdbLoadObjectType
(
rio
*
rdb
);
int
rdbLoad
(
char
*
filename
);
int
rdbSaveBackground
(
char
*
filename
);
void
rdbRemoveTempFile
(
pid_t
childpid
);
int
rdbSave
(
char
*
filename
);
int
rdbSaveObject
(
rio
*
rdb
,
robj
*
o
);
off_t
rdbSavedObjectLen
(
robj
*
o
);
off_t
rdbSavedObjectPages
(
robj
*
o
);
robj
*
rdbLoadObject
(
int
type
,
rio
*
rdb
);
void
backgroundSaveDoneHandler
(
int
exitcode
,
int
bysignal
);
int
rdbSaveKeyValuePair
(
rio
*
rdb
,
robj
*
key
,
robj
*
val
,
time_t
expireitme
,
time_t
now
);
robj
*
rdbLoadStringObject
(
rio
*
rdb
);
#endif
src/redis.h
View file @
f9c6f39b
...
...
@@ -77,12 +77,6 @@
#define REDIS_HASH 4
#define REDIS_VMPOINTER 8
/* Object types only used for persistence in .rdb files */
#define REDIS_HASH_ZIPMAP 9
#define REDIS_LIST_ZIPLIST 10
#define REDIS_SET_INTSET 11
#define REDIS_ZSET_ZIPLIST 12
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The 'encoding' field of the object
* is set to one of this fields for this object. */
...
...
@@ -836,11 +830,6 @@ unsigned long estimateObjectIdleTime(robj *o);
int
syncWrite
(
int
fd
,
char
*
ptr
,
ssize_t
size
,
int
timeout
);
int
syncRead
(
int
fd
,
char
*
ptr
,
ssize_t
size
,
int
timeout
);
int
syncReadLine
(
int
fd
,
char
*
ptr
,
ssize_t
size
,
int
timeout
);
int
fwriteBulkString
(
FILE
*
fp
,
char
*
s
,
unsigned
long
len
);
int
fwriteBulkDouble
(
FILE
*
fp
,
double
d
);
int
fwriteBulkLongLong
(
FILE
*
fp
,
long
long
l
);
int
fwriteBulkObject
(
FILE
*
fp
,
robj
*
obj
);
int
fwriteBulkCount
(
FILE
*
fp
,
char
prefix
,
int
count
);
/* Replication */
void
replicationFeedSlaves
(
list
*
slaves
,
int
dictid
,
robj
**
argv
,
int
argc
);
...
...
@@ -854,21 +843,7 @@ void loadingProgress(off_t pos);
void
stopLoading
(
void
);
/* RDB persistence */
int
rdbLoad
(
char
*
filename
);
int
rdbSaveBackground
(
char
*
filename
);
void
rdbRemoveTempFile
(
pid_t
childpid
);
int
rdbSave
(
char
*
filename
);
int
rdbSaveObject
(
FILE
*
fp
,
robj
*
o
);
off_t
rdbSavedObjectLen
(
robj
*
o
);
off_t
rdbSavedObjectPages
(
robj
*
o
);
robj
*
rdbLoadObject
(
int
type
,
FILE
*
fp
);
void
backgroundSaveDoneHandler
(
int
exitcode
,
int
bysignal
);
int
rdbSaveKeyValuePair
(
FILE
*
fp
,
robj
*
key
,
robj
*
val
,
time_t
expireitme
,
time_t
now
);
int
rdbLoadType
(
FILE
*
fp
);
time_t
rdbLoadTime
(
FILE
*
fp
);
robj
*
rdbLoadStringObject
(
FILE
*
fp
);
int
rdbSaveType
(
FILE
*
fp
,
unsigned
char
type
);
int
rdbSaveLen
(
FILE
*
fp
,
uint32_t
len
);
#include "rdb.h"
/* AOF persistence */
void
flushAppendOnlyFile
(
int
force
);
...
...
src/rio.c
0 → 100644
View file @
f9c6f39b
#include <string.h>
#include "rio.h"
#include "util.h"
/* Returns 1 or 0 for success/failure. */
static
size_t
rioBufferWrite
(
rio
*
r
,
const
void
*
buf
,
size_t
len
)
{
r
->
io
.
buffer
.
ptr
=
sdscatlen
(
r
->
io
.
buffer
.
ptr
,(
char
*
)
buf
,
len
);
r
->
io
.
buffer
.
pos
+=
len
;
return
len
;
}
/* Returns 1 or 0 for success/failure. */
static
size_t
rioBufferRead
(
rio
*
r
,
void
*
buf
,
size_t
len
)
{
if
(
sdslen
(
r
->
io
.
buffer
.
ptr
)
-
r
->
io
.
buffer
.
pos
<
len
)
return
0
;
memcpy
(
buf
,
r
->
io
.
buffer
.
ptr
+
r
->
io
.
buffer
.
pos
,
len
);
r
->
io
.
buffer
.
pos
+=
len
;
return
1
;
}
/* Returns read/write position in buffer. */
static
off_t
rioBufferTell
(
rio
*
r
)
{
return
r
->
io
.
buffer
.
pos
;
}
/* Returns 1 or 0 for success/failure. */
static
size_t
rioFileWrite
(
rio
*
r
,
const
void
*
buf
,
size_t
len
)
{
return
fwrite
(
buf
,
len
,
1
,
r
->
io
.
file
.
fp
);
}
/* Returns 1 or 0 for success/failure. */
static
size_t
rioFileRead
(
rio
*
r
,
void
*
buf
,
size_t
len
)
{
return
fread
(
buf
,
len
,
1
,
r
->
io
.
file
.
fp
);
}
/* Returns read/write position in file. */
static
off_t
rioFileTell
(
rio
*
r
)
{
return
ftello
(
r
->
io
.
file
.
fp
);
}
static
const
rio
rioBufferIO
=
{
rioBufferRead
,
rioBufferWrite
,
rioBufferTell
,
{
{
NULL
,
0
}
}
/* union for io-specific vars */
};
static
const
rio
rioFileIO
=
{
rioFileRead
,
rioFileWrite
,
rioFileTell
,
{
{
NULL
,
0
}
}
/* union for io-specific vars */
};
rio
rioInitWithFile
(
FILE
*
fp
)
{
rio
r
=
rioFileIO
;
r
.
io
.
file
.
fp
=
fp
;
return
r
;
}
rio
rioInitWithBuffer
(
sds
s
)
{
rio
r
=
rioBufferIO
;
r
.
io
.
buffer
.
ptr
=
s
;
r
.
io
.
buffer
.
pos
=
0
;
return
r
;
}
/* Write multi bulk count in the format: "*<count>\r\n". */
size_t
rioWriteBulkCount
(
rio
*
r
,
char
prefix
,
int
count
)
{
char
cbuf
[
128
];
int
clen
;
cbuf
[
0
]
=
prefix
;
clen
=
1
+
ll2string
(
cbuf
+
1
,
sizeof
(
cbuf
)
-
1
,
count
);
cbuf
[
clen
++
]
=
'\r'
;
cbuf
[
clen
++
]
=
'\n'
;
if
(
rioWrite
(
r
,
cbuf
,
clen
)
==
0
)
return
0
;
return
clen
;
}
/* Write binary-safe string in the format: "$<count>\r\n<payload>\r\n". */
size_t
rioWriteBulkString
(
rio
*
r
,
const
char
*
buf
,
size_t
len
)
{
size_t
nwritten
;
if
((
nwritten
=
rioWriteBulkCount
(
r
,
'$'
,
len
))
==
0
)
return
0
;
if
(
len
>
0
&&
rioWrite
(
r
,
buf
,
len
)
==
0
)
return
0
;
if
(
rioWrite
(
r
,
"
\r\n
"
,
2
)
==
0
)
return
0
;
return
nwritten
+
len
+
2
;
}
/* Write a long long value in format: "$<count>\r\n<payload>\r\n". */
size_t
rioWriteBulkLongLong
(
rio
*
r
,
long
long
l
)
{
char
lbuf
[
32
];
unsigned
int
llen
;
llen
=
ll2string
(
lbuf
,
sizeof
(
lbuf
),
l
);
return
rioWriteBulkString
(
r
,
lbuf
,
llen
);
}
/* Write a double value in the format: "$<count>\r\n<payload>\r\n" */
size_t
rioWriteBulkDouble
(
rio
*
r
,
double
d
)
{
char
dbuf
[
128
];
unsigned
int
dlen
;
dlen
=
snprintf
(
dbuf
,
sizeof
(
dbuf
),
"%.17g"
,
d
);
return
rioWriteBulkString
(
r
,
dbuf
,
dlen
);
}
src/rio.h
0 → 100644
View file @
f9c6f39b
#ifndef __REDIS_RIO_H
#define __REDIS_RIO_H
#include <stdio.h>
#include "sds.h"
struct
_rio
{
/* Backend functions. Both read and write should return 0 for short reads
* or writes, identical to the return values of fread/fwrite. */
size_t
(
*
read
)(
struct
_rio
*
,
void
*
buf
,
size_t
len
);
size_t
(
*
write
)(
struct
_rio
*
,
const
void
*
buf
,
size_t
len
);
off_t
(
*
tell
)(
struct
_rio
*
);
/* Backend-specific vars. */
union
{
struct
{
sds
ptr
;
off_t
pos
;
}
buffer
;
struct
{
FILE
*
fp
;
}
file
;
}
io
;
};
typedef
struct
_rio
rio
;
#define rioWrite(rio,buf,len) ((rio)->write((rio),(buf),(len)))
#define rioRead(rio,buf,len) ((rio)->read((rio),(buf),(len)))
rio
rioInitWithFile
(
FILE
*
fp
);
rio
rioInitWithBuffer
(
sds
s
);
size_t
rioWriteBulkCount
(
rio
*
r
,
char
prefix
,
int
count
);
size_t
rioWriteBulkString
(
rio
*
r
,
const
char
*
buf
,
size_t
len
);
size_t
rioWriteBulkLongLong
(
rio
*
r
,
long
long
l
);
size_t
rioWriteBulkDouble
(
rio
*
r
,
double
d
);
#endif
src/syncio.c
View file @
f9c6f39b
...
...
@@ -99,70 +99,3 @@ int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
}
return
nread
;
}
/* ----------------- Blocking sockets I/O with timeouts --------------------- */
/* Write binary-safe string into a file in the bulkformat
* $<count>\r\n<payload>\r\n */
int
fwriteBulkString
(
FILE
*
fp
,
char
*
s
,
unsigned
long
len
)
{
char
cbuf
[
128
];
int
clen
;
cbuf
[
0
]
=
'$'
;
clen
=
1
+
ll2string
(
cbuf
+
1
,
sizeof
(
cbuf
)
-
1
,
len
);
cbuf
[
clen
++
]
=
'\r'
;
cbuf
[
clen
++
]
=
'\n'
;
if
(
fwrite
(
cbuf
,
clen
,
1
,
fp
)
==
0
)
return
0
;
if
(
len
>
0
&&
fwrite
(
s
,
len
,
1
,
fp
)
==
0
)
return
0
;
if
(
fwrite
(
"
\r\n
"
,
2
,
1
,
fp
)
==
0
)
return
0
;
return
1
;
}
/* Write a multi bulk count in the form "*<count>\r\n" */
int
fwriteBulkCount
(
FILE
*
fp
,
char
prefix
,
int
count
)
{
char
cbuf
[
128
];
int
clen
;
cbuf
[
0
]
=
prefix
;
clen
=
1
+
ll2string
(
cbuf
+
1
,
sizeof
(
cbuf
)
-
1
,
count
);
cbuf
[
clen
++
]
=
'\r'
;
cbuf
[
clen
++
]
=
'\n'
;
if
(
fwrite
(
cbuf
,
clen
,
1
,
fp
)
==
0
)
return
0
;
return
1
;
}
/* Write a double value in bulk format $<count>\r\n<payload>\r\n */
int
fwriteBulkDouble
(
FILE
*
fp
,
double
d
)
{
char
buf
[
128
],
dbuf
[
128
];
snprintf
(
dbuf
,
sizeof
(
dbuf
),
"%.17g
\r\n
"
,
d
);
snprintf
(
buf
,
sizeof
(
buf
),
"$%lu
\r\n
"
,(
unsigned
long
)
strlen
(
dbuf
)
-
2
);
if
(
fwrite
(
buf
,
strlen
(
buf
),
1
,
fp
)
==
0
)
return
0
;
if
(
fwrite
(
dbuf
,
strlen
(
dbuf
),
1
,
fp
)
==
0
)
return
0
;
return
1
;
}
/* Write a long value in bulk format $<count>\r\n<payload>\r\n */
int
fwriteBulkLongLong
(
FILE
*
fp
,
long
long
l
)
{
char
bbuf
[
128
],
lbuf
[
128
];
unsigned
int
blen
,
llen
;
llen
=
ll2string
(
lbuf
,
32
,
l
);
blen
=
snprintf
(
bbuf
,
sizeof
(
bbuf
),
"$%u
\r\n
%s
\r\n
"
,
llen
,
lbuf
);
if
(
fwrite
(
bbuf
,
blen
,
1
,
fp
)
==
0
)
return
0
;
return
1
;
}
/* Delegate writing an object to writing a bulk string or bulk long long. */
int
fwriteBulkObject
(
FILE
*
fp
,
robj
*
obj
)
{
/* Avoid using getDecodedObject to help copy-on-write (we are often
* in a child process when this function is called). */
if
(
obj
->
encoding
==
REDIS_ENCODING_INT
)
{
return
fwriteBulkLongLong
(
fp
,(
long
)
obj
->
ptr
);
}
else
if
(
obj
->
encoding
==
REDIS_ENCODING_RAW
)
{
return
fwriteBulkString
(
fp
,
obj
->
ptr
,
sdslen
(
obj
->
ptr
));
}
else
{
redisPanic
(
"Unknown string encoding"
);
}
}
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