Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
cb9b35c8
Commit
cb9b35c8
authored
Jan 07, 2011
by
antirez
Browse files
Merge branch 'unstable' of github.com:antirez/redis-private into unstable
parents
44898603
249ad25f
Changes
10
Hide whitespace changes
Inline
Side-by-side
redis.conf
View file @
cb9b35c8
...
...
@@ -319,11 +319,6 @@ cache-flush-delay 0
############################### ADVANCED CONFIG ###############################
# Glue small output buffers together in order to send small replies in a
# single TCP packet. Uses a bit more CPU but most of the times it is a win
# in terms of number of queries per second. Use 'yes' if unsure.
glueoutputbuf
yes
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given numer of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
...
...
src/anet.c
View file @
cb9b35c8
...
...
@@ -64,11 +64,11 @@ int anetNonBlock(char *err, int fd)
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
* interrupted by a signal. */
if
((
flags
=
fcntl
(
fd
,
F_GETFL
))
==
-
1
)
{
anetSetError
(
err
,
"fcntl(F_GETFL): %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"fcntl(F_GETFL): %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
if
(
fcntl
(
fd
,
F_SETFL
,
flags
|
O_NONBLOCK
)
==
-
1
)
{
anetSetError
(
err
,
"fcntl(F_SETFL,O_NONBLOCK): %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"fcntl(F_SETFL,O_NONBLOCK): %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
return
ANET_OK
;
...
...
@@ -79,7 +79,7 @@ int anetTcpNoDelay(char *err, int fd)
int
yes
=
1
;
if
(
setsockopt
(
fd
,
IPPROTO_TCP
,
TCP_NODELAY
,
&
yes
,
sizeof
(
yes
))
==
-
1
)
{
anetSetError
(
err
,
"setsockopt TCP_NODELAY: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"setsockopt TCP_NODELAY: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
return
ANET_OK
;
...
...
@@ -89,7 +89,7 @@ int anetSetSendBuffer(char *err, int fd, int buffsize)
{
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_SNDBUF
,
&
buffsize
,
sizeof
(
buffsize
))
==
-
1
)
{
anetSetError
(
err
,
"setsockopt SO_SNDBUF: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"setsockopt SO_SNDBUF: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
return
ANET_OK
;
...
...
@@ -99,7 +99,7 @@ int anetTcpKeepAlive(char *err, int fd)
{
int
yes
=
1
;
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_KEEPALIVE
,
&
yes
,
sizeof
(
yes
))
==
-
1
)
{
anetSetError
(
err
,
"setsockopt SO_KEEPALIVE: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"setsockopt SO_KEEPALIVE: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
return
ANET_OK
;
...
...
@@ -115,7 +115,7 @@ int anetResolve(char *err, char *host, char *ipbuf)
he
=
gethostbyname
(
host
);
if
(
he
==
NULL
)
{
anetSetError
(
err
,
"can't resolve: %s
\n
"
,
host
);
anetSetError
(
err
,
"can't resolve: %s"
,
host
);
return
ANET_ERR
;
}
memcpy
(
&
sa
.
sin_addr
,
he
->
h_addr
,
sizeof
(
struct
in_addr
));
...
...
@@ -127,14 +127,14 @@ int anetResolve(char *err, char *host, char *ipbuf)
static
int
anetCreateSocket
(
char
*
err
,
int
domain
)
{
int
s
,
on
=
1
;
if
((
s
=
socket
(
domain
,
SOCK_STREAM
,
0
))
==
-
1
)
{
anetSetError
(
err
,
"creating socket: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"creating socket: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
/* Make sure connection-intensive things like the redis benckmark
* will be able to close/open sockets a zillion of times */
if
(
setsockopt
(
s
,
SOL_SOCKET
,
SO_REUSEADDR
,
&
on
,
sizeof
(
on
))
==
-
1
)
{
anetSetError
(
err
,
"setsockopt SO_REUSEADDR: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"setsockopt SO_REUSEADDR: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
return
s
;
...
...
@@ -157,7 +157,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
he
=
gethostbyname
(
addr
);
if
(
he
==
NULL
)
{
anetSetError
(
err
,
"can't resolve: %s
\n
"
,
addr
);
anetSetError
(
err
,
"can't resolve: %s"
,
addr
);
close
(
s
);
return
ANET_ERR
;
}
...
...
@@ -172,7 +172,7 @@ static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
flags
&
ANET_CONNECT_NONBLOCK
)
return
s
;
anetSetError
(
err
,
"connect: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"connect: %s"
,
strerror
(
errno
));
close
(
s
);
return
ANET_ERR
;
}
...
...
@@ -208,7 +208,7 @@ int anetUnixGenericConnect(char *err, char *path, int flags)
flags
&
ANET_CONNECT_NONBLOCK
)
return
s
;
anetSetError
(
err
,
"connect: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"connect: %s"
,
strerror
(
errno
));
close
(
s
);
return
ANET_ERR
;
}
...
...
@@ -257,12 +257,12 @@ int anetWrite(int fd, char *buf, int count)
static
int
anetListen
(
char
*
err
,
int
s
,
struct
sockaddr
*
sa
,
socklen_t
len
)
{
if
(
bind
(
s
,
sa
,
len
)
==
-
1
)
{
anetSetError
(
err
,
"bind: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"bind: %s"
,
strerror
(
errno
));
close
(
s
);
return
ANET_ERR
;
}
if
(
listen
(
s
,
511
)
==
-
1
)
{
/* the magic 511 constant is from nginx */
anetSetError
(
err
,
"listen: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"listen: %s"
,
strerror
(
errno
));
close
(
s
);
return
ANET_ERR
;
}
...
...
@@ -282,7 +282,7 @@ int anetTcpServer(char *err, int port, char *bindaddr)
sa
.
sin_port
=
htons
(
port
);
sa
.
sin_addr
.
s_addr
=
htonl
(
INADDR_ANY
);
if
(
bindaddr
&&
inet_aton
(
bindaddr
,
&
sa
.
sin_addr
)
==
0
)
{
anetSetError
(
err
,
"
I
nvalid bind address
\n
"
);
anetSetError
(
err
,
"
i
nvalid bind address"
);
close
(
s
);
return
ANET_ERR
;
}
...
...
@@ -315,7 +315,7 @@ static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *l
if
(
errno
==
EINTR
)
continue
;
else
{
anetSetError
(
err
,
"accept: %s
\n
"
,
strerror
(
errno
));
anetSetError
(
err
,
"accept: %s"
,
strerror
(
errno
));
return
ANET_ERR
;
}
}
...
...
src/config.c
View file @
cb9b35c8
...
...
@@ -194,10 +194,8 @@ void loadServerConfig(char *filename) {
if
((
server
.
repl_serve_stale_data
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"glueoutputbuf"
)
&&
argc
==
2
)
{
if
((
server
.
glueoutputbuf
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
}
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"glueoutputbuf"
))
{
redisLog
(
REDIS_WARNING
,
"Deprecated configuration directive:
\"
%s
\"
"
,
argv
[
0
]);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"rdbcompression"
)
&&
argc
==
2
)
{
if
((
server
.
rdbcompression
=
yesnotoi
(
argv
[
1
]))
==
-
1
)
{
err
=
"argument must be 'yes' or 'no'"
;
goto
loaderr
;
...
...
src/diskstore.c
View file @
cb9b35c8
...
...
@@ -348,3 +348,50 @@ void dsFlushDb(int dbid) {
}
}
}
int
dsRdbSave
(
char
*
filename
)
{
char
tmpfile
[
256
];
int
j
,
i
;
time_t
now
=
time
(
NULL
);
snprintf
(
tmpfile
,
256
,
"temp-%d.rdb"
,
(
int
)
getpid
());
fp
=
fopen
(
tmpfile
,
"w"
);
if
(
!
fp
)
{
redisLog
(
REDIS_WARNING
,
"Failed saving the DB: %s"
,
strerror
(
errno
));
return
REDIS_ERR
;
}
if
(
fwrite
(
"REDIS0001"
,
9
,
1
,
fp
)
==
0
)
goto
werr
;
/* Scan all diskstore dirs looking for keys */
for
(
j
=
0
;
j
<
256
;
j
++
)
{
for
(
i
=
0
;
i
<
256
;
i
++
)
{
snprintf
(
buf
,
1024
,
"%s/%02x/%02x"
,
server
.
ds_path
,
j
,
i
);
/* Write the SELECT DB opcode */
if
(
rdbSaveType
(
fp
,
REDIS_SELECTDB
)
==
-
1
)
goto
werr
;
if
(
rdbSaveLen
(
fp
,
j
)
==
-
1
)
goto
werr
;
}
}
/* Make sure data will not remain on the OS's output buffers */
fflush
(
fp
);
fsync
(
fileno
(
fp
));
fclose
(
fp
);
/* Use RENAME to make sure the DB file is changed atomically only
* if the generate DB file is ok. */
if
(
rename
(
tmpfile
,
filename
)
==
-
1
)
{
redisLog
(
REDIS_WARNING
,
"Error moving temp DB file on the final destination: %s"
,
strerror
(
errno
));
unlink
(
tmpfile
);
return
REDIS_ERR
;
}
redisLog
(
REDIS_NOTICE
,
"DB saved on disk"
);
server
.
dirty
=
0
;
server
.
lastsave
=
time
(
NULL
);
return
REDIS_OK
;
werr:
fclose
(
fp
);
unlink
(
tmpfile
);
redisLog
(
REDIS_WARNING
,
"Write error saving DB on disk: %s"
,
strerror
(
errno
));
}
src/dscache.c
View file @
cb9b35c8
...
...
@@ -512,7 +512,7 @@ int processActiveIOJobs(int max) {
#if 0
/* If there are new jobs we need to signal the thread to
* process the next one. */
* process the next one.
FIXME: drop this if useless.
*/
redisLog(REDIS_DEBUG,"waitEmptyIOJobsQueue: new %d, processing %d",
listLength(server.io_newjobs),
listLength(server.io_processing));
...
...
@@ -576,7 +576,21 @@ void queueIOJob(iojob *j) {
spawnIOThread
();
}
void
dsCreateIOJob
(
int
type
,
redisDb
*
db
,
robj
*
key
,
robj
*
val
)
{
/* Consume all the IO scheduled operations, and all the thread IO jobs
* so that eventually the state of diskstore is a point-in-time snapshot.
*
* This is useful when we need to BGSAVE with diskstore enabled. */
void
cacheForcePointInTime
(
void
)
{
redisLog
(
REDIS_NOTICE
,
"Diskstore: synching on disk to reach point-in-time state."
);
while
(
listLength
(
server
.
cache_io_queue
)
!=
0
)
{
cacheScheduleIOPushJobs
(
REDIS_IO_ASAP
);
processActiveIOJobs
(
1
);
}
waitEmptyIOJobsQueue
();
processAllPendingIOJobs
();
}
void
cacheCreateIOJob
(
int
type
,
redisDb
*
db
,
robj
*
key
,
robj
*
val
)
{
iojob
*
j
;
j
=
zmalloc
(
sizeof
(
*
j
));
...
...
@@ -762,7 +776,7 @@ int cacheScheduleIOPushJobs(int flags) {
op
->
type
==
REDIS_IO_LOAD
?
"load"
:
"save"
,
op
->
key
->
ptr
);
if
(
op
->
type
==
REDIS_IO_LOAD
)
{
ds
CreateIOJob
(
REDIS_IOJOB_LOAD
,
op
->
db
,
op
->
key
,
NULL
);
cache
CreateIOJob
(
REDIS_IOJOB_LOAD
,
op
->
db
,
op
->
key
,
NULL
);
}
else
{
/* Lookup the key, in order to put the current value in the IO
* Job. Otherwise if the key does not exists we schedule a disk
...
...
@@ -775,7 +789,7 @@ int cacheScheduleIOPushJobs(int flags) {
* the key on disk. */
val
=
NULL
;
}
ds
CreateIOJob
(
REDIS_IOJOB_SAVE
,
op
->
db
,
op
->
key
,
val
);
cache
CreateIOJob
(
REDIS_IOJOB_SAVE
,
op
->
db
,
op
->
key
,
val
);
}
/* Mark the operation as in progress. */
cacheScheduleIODelFlag
(
op
->
db
,
op
->
key
,
op
->
type
);
...
...
src/networking.c
View file @
cb9b35c8
...
...
@@ -515,15 +515,6 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
REDIS_NOTUSED
(
el
);
REDIS_NOTUSED
(
mask
);
/* Use writev() if we have enough buffers to send */
if
(
!
server
.
glueoutputbuf
&&
listLength
(
c
->
reply
)
>
REDIS_WRITEV_THRESHOLD
&&
!
(
c
->
flags
&
REDIS_MASTER
))
{
sendReplyToClientWritev
(
el
,
fd
,
privdata
,
mask
);
return
;
}
while
(
c
->
bufpos
>
0
||
listLength
(
c
->
reply
))
{
if
(
c
->
bufpos
>
0
)
{
if
(
c
->
flags
&
REDIS_MASTER
)
{
...
...
@@ -594,84 +585,6 @@ void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {
}
}
void
sendReplyToClientWritev
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
)
{
redisClient
*
c
=
privdata
;
int
nwritten
=
0
,
totwritten
=
0
,
objlen
,
willwrite
;
robj
*
o
;
struct
iovec
iov
[
REDIS_WRITEV_IOVEC_COUNT
];
int
offset
,
ion
=
0
;
REDIS_NOTUSED
(
el
);
REDIS_NOTUSED
(
mask
);
listNode
*
node
;
while
(
listLength
(
c
->
reply
))
{
offset
=
c
->
sentlen
;
ion
=
0
;
willwrite
=
0
;
/* fill-in the iov[] array */
for
(
node
=
listFirst
(
c
->
reply
);
node
;
node
=
listNextNode
(
node
))
{
o
=
listNodeValue
(
node
);
objlen
=
sdslen
(
o
->
ptr
);
if
(
totwritten
+
objlen
-
offset
>
REDIS_MAX_WRITE_PER_EVENT
)
break
;
if
(
ion
==
REDIS_WRITEV_IOVEC_COUNT
)
break
;
/* no more iovecs */
iov
[
ion
].
iov_base
=
((
char
*
)
o
->
ptr
)
+
offset
;
iov
[
ion
].
iov_len
=
objlen
-
offset
;
willwrite
+=
objlen
-
offset
;
offset
=
0
;
/* just for the first item */
ion
++
;
}
if
(
willwrite
==
0
)
break
;
/* write all collected blocks at once */
if
((
nwritten
=
writev
(
fd
,
iov
,
ion
))
<
0
)
{
if
(
errno
!=
EAGAIN
)
{
redisLog
(
REDIS_VERBOSE
,
"Error writing to client: %s"
,
strerror
(
errno
));
freeClient
(
c
);
return
;
}
break
;
}
totwritten
+=
nwritten
;
offset
=
c
->
sentlen
;
/* remove written robjs from c->reply */
while
(
nwritten
&&
listLength
(
c
->
reply
))
{
o
=
listNodeValue
(
listFirst
(
c
->
reply
));
objlen
=
sdslen
(
o
->
ptr
);
if
(
nwritten
>=
objlen
-
offset
)
{
listDelNode
(
c
->
reply
,
listFirst
(
c
->
reply
));
nwritten
-=
objlen
-
offset
;
c
->
sentlen
=
0
;
}
else
{
/* partial write */
c
->
sentlen
+=
nwritten
;
break
;
}
offset
=
0
;
}
}
if
(
totwritten
>
0
)
c
->
lastinteraction
=
time
(
NULL
);
if
(
listLength
(
c
->
reply
)
==
0
)
{
c
->
sentlen
=
0
;
aeDeleteFileEvent
(
server
.
el
,
c
->
fd
,
AE_WRITABLE
);
}
}
/* resetClient prepare the client to process the next command */
void
resetClient
(
redisClient
*
c
)
{
freeClientArgv
(
c
);
...
...
src/rdb.c
View file @
cb9b35c8
...
...
@@ -429,8 +429,10 @@ int rdbSave(char *filename) {
int
j
;
time_t
now
=
time
(
NULL
);
/* FIXME: implement .rdb save for disk store properly */
redisAssert
(
server
.
ds_enabled
==
0
);
if
(
server
.
ds_enabled
)
{
cacheForcePointInTime
();
return
dsRdbSave
(
filename
);
}
snprintf
(
tmpfile
,
256
,
"temp-%d.rdb"
,
(
int
)
getpid
());
fp
=
fopen
(
tmpfile
,
"w"
);
...
...
@@ -495,17 +497,22 @@ int rdbSaveBackground(char *filename) {
pid_t
childpid
;
if
(
server
.
bgsavechildpid
!=
-
1
)
return
REDIS_ERR
;
redisAssert
(
server
.
ds_enabled
==
0
);
server
.
dirty_before_bgsave
=
server
.
dirty
;
if
((
childpid
=
fork
())
==
0
)
{
int
retval
;
/* Child */
if
(
server
.
ipfd
>
0
)
close
(
server
.
ipfd
);
if
(
server
.
sofd
>
0
)
close
(
server
.
sofd
);
if
(
rdbSave
(
filename
)
==
REDIS_OK
)
{
_exit
(
0
);
if
(
server
.
ds_enabled
)
{
cacheForcePointInTime
();
dsRdbSave
(
filename
);
}
else
{
_exit
(
1
);
rdbSave
(
filename
);
}
_exit
((
retval
==
REDIS_OK
)
?
0
:
1
);
}
else
{
/* Parent */
if
(
childpid
==
-
1
)
{
...
...
src/redis.c
View file @
cb9b35c8
...
...
@@ -749,7 +749,6 @@ void initServerConfig() {
server
.
syslog_enabled
=
0
;
server
.
syslog_ident
=
zstrdup
(
"redis"
);
server
.
syslog_facility
=
LOG_LOCAL0
;
server
.
glueoutputbuf
=
1
;
server
.
daemonize
=
0
;
server
.
appendonly
=
0
;
server
.
appendfsync
=
APPENDFSYNC_EVERYSEC
;
...
...
src/redis.h
View file @
cb9b35c8
...
...
@@ -50,11 +50,6 @@
#define REDIS_REPLY_CHUNK_BYTES (5*1500)
/* 5 TCP packets with default MTU */
#define REDIS_MAX_LOGMSG_LEN 1024
/* Default maximum length of syslog messages */
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
#define REDIS_WRITEV_THRESHOLD 3
/* Max number of iovecs used for each writev call */
#define REDIS_WRITEV_IOVEC_COUNT 256
/* Hash table parameters */
#define REDIS_HT_MINFILL 10
/* Minimal hash table fill 10% */
...
...
@@ -388,7 +383,6 @@ struct redisServer {
long
long
stat_keyspace_misses
;
/* number of failed lookups of keys */
/* Configuration */
int
verbosity
;
int
glueoutputbuf
;
int
maxidletime
;
int
dbnum
;
int
daemonize
;
...
...
@@ -633,7 +627,6 @@ void closeTimedoutClients(void);
void
freeClient
(
redisClient
*
c
);
void
resetClient
(
redisClient
*
c
);
void
sendReplyToClient
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
sendReplyToClientWritev
(
aeEventLoop
*
el
,
int
fd
,
void
*
privdata
,
int
mask
);
void
addReply
(
redisClient
*
c
,
robj
*
obj
);
void
*
addDeferredMultiBulkLength
(
redisClient
*
c
);
void
setDeferredMultiBulkLength
(
redisClient
*
c
,
void
*
node
,
long
length
);
...
...
@@ -820,6 +813,7 @@ void cacheCron(void);
int
cacheKeyMayExist
(
redisDb
*
db
,
robj
*
key
);
void
cacheSetKeyMayExist
(
redisDb
*
db
,
robj
*
key
);
void
cacheSetKeyDoesNotExist
(
redisDb
*
db
,
robj
*
key
);
void
cacheForcePointInTime
(
void
);
/* Set data type */
robj
*
setTypeCreate
(
robj
*
value
);
...
...
utils/whatisdoing.sh
0 → 100755
View file @
cb9b35c8
# This script is from http://poormansprofiler.org/
#!/bin/bash
nsamples
=
1
sleeptime
=
0
pid
=
$(
pidof redis-server
)
for
x
in
$(
seq
1
$nsamples
)
do
gdb
-ex
"set pagination 0"
-ex
"thread apply all bt"
-batch
-p
$pid
sleep
$sleeptime
done
|
\
awk
'
BEGIN { s = ""; }
/Thread/ { print s; s = ""; }
/^\#/ { if (s != "" ) { s = s "," $4} else { s = $4 } }
END { print s }'
|
\
sort
|
uniq
-c
|
sort
-r
-n
-k
1,1
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