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
Expand all
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
This diff is collapsed.
Click to expand it.
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