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
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