Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xindoo
redis
提交
a59e797a
R
redis
项目概览
xindoo
/
redis
通知
2
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
a59e797a
编写于
6月 14, 2011
作者:
A
antirez
浏览文件
操作
浏览文件
下载
差异文件
Redis 2.2.110-scripting
上级
d5f262a7
4ec8b732
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
254 addition
and
77 deletion
+254
-77
00-RELEASENOTES
00-RELEASENOTES
+23
-0
deps/hiredis/Makefile
deps/hiredis/Makefile
+4
-1
src/networking.c
src/networking.c
+25
-0
src/redis-cli.c
src/redis-cli.c
+75
-35
src/redis.h
src/redis.h
+1
-0
src/replication.c
src/replication.c
+2
-1
src/sort.c
src/sort.c
+1
-0
src/t_list.c
src/t_list.c
+37
-10
src/t_set.c
src/t_set.c
+6
-11
src/t_string.c
src/t_string.c
+1
-0
src/version.h
src/version.h
+1
-1
tests/integration/replication.tcl
tests/integration/replication.tcl
+18
-0
tests/unit/basic.tcl
tests/unit/basic.tcl
+38
-11
tests/unit/type/list.tcl
tests/unit/type/list.tcl
+8
-0
utils/redis_init_script
utils/redis_init_script
+14
-7
未找到文件。
00-RELEASENOTES
浏览文件 @
a59e797a
...
...
@@ -12,6 +12,29 @@ for 2.0.
CHANGELOG
---------
What's new in Redis 2.2.10
==========================
* Fix for issue 566. It was possible for SETNX to behave in abnormal ways.
* Work with make v3.80
* redis-cli updated to the same version as the 2.4 branch. Now the
reconnection handling is better. You can prefix commands with a number
to execute the command the specified number of times. When using -r
in non interactive mode it is possible to set a delay between commands.
* Better init script.
What's new in Redis 2.2.9
=========================
Redis 2.2.9 is an important bugfix release:
* A Slave used to rewrite the AOF log after a sync with the master, but the
rewrite was performed at the wrong time, causing inconsistencies in the
AOF file generated.
* [LR]LPUSH replication in presence of BRPOPLPUSH was broken. Fixed.
* Memory leak in BRPOPLPUSH fixed.
* Pub/Sub bug resulting in random crashes fixed.
What's new in Redis 2.2.8
=========================
...
...
deps/hiredis/Makefile
浏览文件 @
a59e797a
...
...
@@ -15,7 +15,8 @@ ifeq ($(uname_S),SunOS)
DYLIB_MAKE_CMD
?=
$(CC)
-G
-o
${DYLIBNAME}
${OBJ}
STLIBNAME
?=
libhiredis.a
STLIB_MAKE_CMD
?=
ar rcs
${STLIBNAME}
${OBJ}
else
ifeq
($(uname_S),Darwin)
else
ifeq
($(uname_S),Darwin)
CFLAGS
?=
-std
=
c99
-pedantic
$(OPTIMIZATION)
-fPIC
-Wall
-W
-Wwrite-strings
$(ARCH)
$(PROF)
CCLINK
?=
-lm
-pthread
LDFLAGS
?=
-L
.
-Wl
,-rpath,.
...
...
@@ -33,6 +34,8 @@ else
STLIBNAME
?=
libhiredis.a
STLIB_MAKE_CMD
?=
ar rcs
${STLIBNAME}
${OBJ}
endif
endif
CCOPT
=
$(CFLAGS)
$(CCLINK)
DEBUG
?=
-g
-ggdb
...
...
src/networking.c
浏览文件 @
a59e797a
...
...
@@ -879,3 +879,28 @@ void getClientsMaxBuffers(unsigned long *longest_output_list,
*
biggest_input_buffer
=
bib
;
}
void
rewriteClientCommandVector
(
redisClient
*
c
,
int
argc
,
...)
{
va_list
ap
;
int
j
;
robj
**
argv
;
/* The new argument vector */
argv
=
zmalloc
(
sizeof
(
robj
*
)
*
argc
);
va_start
(
ap
,
argc
);
for
(
j
=
0
;
j
<
argc
;
j
++
)
{
robj
*
a
;
a
=
va_arg
(
ap
,
robj
*
);
argv
[
j
]
=
a
;
incrRefCount
(
a
);
}
/* We free the objects in the original vector at the end, so we are
* sure that if the same objects are reused in the new vector the
* refcount gets incremented before it gets decremented. */
for
(
j
=
0
;
j
<
c
->
argc
;
j
++
)
decrRefCount
(
c
->
argv
[
j
]);
zfree
(
c
->
argv
);
/* Replace argv and argc with our new versions. */
c
->
argv
=
argv
;
c
->
argc
=
argc
;
va_end
(
ap
);
}
src/redis-cli.c
浏览文件 @
a59e797a
...
...
@@ -55,6 +55,7 @@ static struct config {
int
hostport
;
char
*
hostsocket
;
long
repeat
;
long
interval
;
int
dbnum
;
int
interactive
;
int
shutdown
;
...
...
@@ -62,7 +63,6 @@ static struct config {
int
pubsub_mode
;
int
stdinarg
;
/* get last arg from stdin. (-x option) */
char
*
auth
;
char
*
historyfile
;
int
raw_output
;
/* output mode per command */
sds
mb_delim
;
char
prompt
[
32
];
...
...
@@ -88,9 +88,11 @@ static long long mstime(void) {
static
void
cliRefreshPrompt
(
void
)
{
if
(
config
.
dbnum
==
0
)
snprintf
(
config
.
prompt
,
sizeof
(
config
.
prompt
),
"redis> "
);
snprintf
(
config
.
prompt
,
sizeof
(
config
.
prompt
),
"redis %s:%d> "
,
config
.
hostip
,
config
.
hostport
);
else
snprintf
(
config
.
prompt
,
sizeof
(
config
.
prompt
),
"redis:%d> "
,
config
.
dbnum
);
snprintf
(
config
.
prompt
,
sizeof
(
config
.
prompt
),
"redis %s:%d[%d]> "
,
config
.
hostip
,
config
.
hostport
,
config
.
dbnum
);
}
/*------------------------------------------------------------------------------
...
...
@@ -315,10 +317,9 @@ static int cliConnect(int force) {
return
REDIS_OK
;
}
static
void
cliPrintContextError
AndExit
()
{
static
void
cliPrintContextError
()
{
if
(
context
==
NULL
)
return
;
fprintf
(
stderr
,
"Error: %s
\n
"
,
context
->
errstr
);
exit
(
1
);
}
static
sds
cliFormatReplyTTY
(
redisReply
*
r
,
char
*
prefix
)
{
...
...
@@ -395,15 +396,18 @@ static sds cliFormatReplyRaw(redisReply *r) {
switch
(
r
->
type
)
{
case
REDIS_REPLY_NIL
:
/* Nothing... */
break
;
break
;
case
REDIS_REPLY_ERROR
:
out
=
sdscatlen
(
out
,
r
->
str
,
r
->
len
);
out
=
sdscatlen
(
out
,
"
\n
"
,
1
);
break
;
case
REDIS_REPLY_STATUS
:
case
REDIS_REPLY_STRING
:
out
=
sdscatlen
(
out
,
r
->
str
,
r
->
len
);
break
;
break
;
case
REDIS_REPLY_INTEGER
:
out
=
sdscatprintf
(
out
,
"%lld"
,
r
->
integer
);
break
;
break
;
case
REDIS_REPLY_ARRAY
:
for
(
i
=
0
;
i
<
r
->
elements
;
i
++
)
{
if
(
i
>
0
)
out
=
sdscat
(
out
,
config
.
mb_delim
);
...
...
@@ -411,7 +415,7 @@ static sds cliFormatReplyRaw(redisReply *r) {
out
=
sdscatlen
(
out
,
tmp
,
sdslen
(
tmp
));
sdsfree
(
tmp
);
}
break
;
break
;
default:
fprintf
(
stderr
,
"Unknown reply type: %d
\n
"
,
r
->
type
);
exit
(
1
);
...
...
@@ -434,7 +438,8 @@ static int cliReadReply(int output_raw_strings) {
if
(
context
->
err
==
REDIS_ERR_EOF
)
return
REDIS_ERR
;
}
cliPrintContextErrorAndExit
();
cliPrintContextError
();
exit
(
1
);
return
REDIS_ERR
;
/* avoid compiler warning */
}
...
...
@@ -460,12 +465,17 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
size_t
*
argvlen
;
int
j
,
output_raw
;
if
(
context
==
NULL
)
{
printf
(
"Not connected, please use: connect <host> <port>
\n
"
);
return
REDIS_OK
;
if
(
context
==
NULL
)
return
REDIS_ERR
;
output_raw
=
0
;
if
(
!
strcasecmp
(
command
,
"info"
)
||
(
argc
==
2
&&
!
strcasecmp
(
command
,
"client"
)
&&
!
strcasecmp
(
argv
[
1
],
"list"
)))
{
output_raw
=
1
;
}
output_raw
=
!
strcasecmp
(
command
,
"info"
);
if
(
!
strcasecmp
(
command
,
"help"
)
||
!
strcasecmp
(
command
,
"?"
))
{
cliOutputHelp
(
--
argc
,
++
argv
);
return
REDIS_OK
;
...
...
@@ -505,6 +515,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
cliRefreshPrompt
();
}
}
if
(
config
.
interval
)
usleep
(
config
.
interval
);
fflush
(
stdout
);
/* Make it grep friendly */
}
free
(
argvlen
);
...
...
@@ -540,6 +552,10 @@ static int parseOptions(int argc, char **argv) {
}
else
if
(
!
strcmp
(
argv
[
i
],
"-r"
)
&&
!
lastarg
)
{
config
.
repeat
=
strtoll
(
argv
[
i
+
1
],
NULL
,
10
);
i
++
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-i"
)
&&
!
lastarg
)
{
double
seconds
=
atof
(
argv
[
i
+
1
]);
config
.
interval
=
seconds
*
1000000
;
i
++
;
}
else
if
(
!
strcmp
(
argv
[
i
],
"-n"
)
&&
!
lastarg
)
{
config
.
dbnum
=
atoi
(
argv
[
i
+
1
]);
i
++
;
...
...
@@ -592,6 +608,8 @@ static void usage() {
" -s <socket> Server socket (overrides hostname and port)
\n
"
" -a <password> Password to use when connecting to the server
\n
"
" -r <repeat> Execute specified command N times
\n
"
" -i <interval> When -r is used, waits <interval> seconds per command.
\n
"
" It is possible to specify sub-second times like -i 0.1.
\n
"
" -n <db> Database number
\n
"
" -x Read last argument from STDIN
\n
"
" -d <delimiter> Multi-bulk delimiter in for raw formatting (default:
\\
n)
\n
"
...
...
@@ -603,6 +621,7 @@ static void usage() {
" cat /etc/passwd | redis-cli -x set mypasswd
\n
"
" redis-cli get mypasswd
\n
"
" redis-cli -r 100 lpush mylist x
\n
"
" redis-cli -r 100 -i 1 info | grep used_memory_human:
\n
"
"
\n
"
"When no command is given, redis-cli starts in interactive mode.
\n
"
"Type
\"
help
\"
in interactive mode for information on available commands.
\n
"
...
...
@@ -625,19 +644,32 @@ static char **convertToSds(int count, char** args) {
#define LINE_BUFLEN 4096
static
void
repl
()
{
int
argc
,
j
;
sds
historyfile
=
NULL
;
int
history
=
0
;
char
*
line
;
int
argc
;
sds
*
argv
;
config
.
interactive
=
1
;
linenoiseSetCompletionCallback
(
completionCallback
);
/* Only use history when stdin is a tty. */
if
(
isatty
(
fileno
(
stdin
)))
{
history
=
1
;
if
(
getenv
(
"HOME"
)
!=
NULL
)
{
historyfile
=
sdscatprintf
(
sdsempty
(),
"%s/.rediscli_history"
,
getenv
(
"HOME"
));
linenoiseHistoryLoad
(
historyfile
);
}
}
cliRefreshPrompt
();
while
((
line
=
linenoise
(
context
?
config
.
prompt
:
"not connected> "
))
!=
NULL
)
{
if
(
line
[
0
]
!=
'\0'
)
{
argv
=
sdssplitargs
(
line
,
&
argc
);
linenoiseHistoryAdd
(
line
);
if
(
config
.
historyfile
)
linenoiseHistorySave
(
config
.
historyfile
);
if
(
history
)
linenoiseHistoryAdd
(
line
);
if
(
historyfile
)
linenoiseHistorySave
(
historyfile
);
if
(
argv
==
NULL
)
{
printf
(
"Invalid argument(s)
\n
"
);
continue
;
...
...
@@ -655,14 +687,25 @@ static void repl() {
linenoiseClearScreen
();
}
else
{
long
long
start_time
=
mstime
(),
elapsed
;
int
repeat
,
skipargs
=
0
;
if
(
cliSendCommand
(
argc
,
argv
,
1
)
!=
REDIS_OK
)
{
repeat
=
atoi
(
argv
[
0
]);
if
(
repeat
)
{
skipargs
=
1
;
}
else
{
repeat
=
1
;
}
if
(
cliSendCommand
(
argc
-
skipargs
,
argv
+
skipargs
,
repeat
)
!=
REDIS_OK
)
{
cliConnect
(
1
);
/* If we still cannot send the command,
* print error and abort. */
if
(
cliSendCommand
(
argc
,
argv
,
1
)
!=
REDIS_OK
)
cliPrintContextErrorAndExit
();
/* If we still cannot send the command print error.
* We'll try to reconnect the next time. */
if
(
cliSendCommand
(
argc
-
skipargs
,
argv
+
skipargs
,
repeat
)
!=
REDIS_OK
)
cliPrintContextError
();
}
elapsed
=
mstime
()
-
start_time
;
if
(
elapsed
>=
500
)
{
...
...
@@ -671,8 +714,7 @@ static void repl() {
}
}
/* Free the argument vector */
for
(
j
=
0
;
j
<
argc
;
j
++
)
sdsfree
(
argv
[
j
]);
while
(
argc
--
)
sdsfree
(
argv
[
argc
]);
zfree
(
argv
);
}
/* linenoise() returns malloc-ed lines like readline() */
...
...
@@ -701,6 +743,7 @@ int main(int argc, char **argv) {
config
.
hostport
=
6379
;
config
.
hostsocket
=
NULL
;
config
.
repeat
=
1
;
config
.
interval
=
0
;
config
.
dbnum
=
0
;
config
.
interactive
=
0
;
config
.
shutdown
=
0
;
...
...
@@ -708,26 +751,23 @@ int main(int argc, char **argv) {
config
.
pubsub_mode
=
0
;
config
.
stdinarg
=
0
;
config
.
auth
=
NULL
;
config
.
historyfile
=
NULL
;
config
.
raw_output
=
!
isatty
(
fileno
(
stdout
))
&&
(
getenv
(
"FAKETTY"
)
==
NULL
);
config
.
mb_delim
=
sdsnew
(
"
\n
"
);
cliInitHelp
();
if
(
getenv
(
"HOME"
)
!=
NULL
)
{
config
.
historyfile
=
malloc
(
256
);
snprintf
(
config
.
historyfile
,
256
,
"%s/.rediscli_history"
,
getenv
(
"HOME"
));
linenoiseHistoryLoad
(
config
.
historyfile
);
}
firstarg
=
parseOptions
(
argc
,
argv
);
argc
-=
firstarg
;
argv
+=
firstarg
;
/* Try to connect */
if
(
cliConnect
(
0
)
!=
REDIS_OK
)
exit
(
1
);
/* Start interactive mode when no command is provided */
if
(
argc
==
0
)
repl
();
if
(
argc
==
0
)
{
/* Note that in repl mode we don't abort on connection error.
* A new attempt will be performed for every command send. */
cliConnect
(
0
);
repl
();
}
/* Otherwise, we have some arguments to execute */
if
(
cliConnect
(
0
)
!=
REDIS_OK
)
exit
(
1
);
return
noninteractive
(
argc
,
convertToSds
(
argc
,
argv
));
}
src/redis.h
浏览文件 @
a59e797a
...
...
@@ -671,6 +671,7 @@ void addReplyMultiBulkLen(redisClient *c, long length);
void
*
dupClientReplyValue
(
void
*
o
);
void
getClientsMaxBuffers
(
unsigned
long
*
longest_output_list
,
unsigned
long
*
biggest_input_buffer
);
void
rewriteClientCommandVector
(
redisClient
*
c
,
int
argc
,
...);
#ifdef __GNUC__
void
addReplyErrorFormat
(
redisClient
*
c
,
const
char
*
fmt
,
...)
...
...
src/replication.c
浏览文件 @
a59e797a
...
...
@@ -390,6 +390,8 @@ void readSyncBulkPayload(aeEventLoop *el, int fd, void *privdata, int mask) {
server
.
master
->
authenticated
=
1
;
server
.
replstate
=
REDIS_REPL_CONNECTED
;
redisLog
(
REDIS_NOTICE
,
"MASTER <-> SLAVE sync: Finished with success"
);
/* Rewrite the AOF file now that the dataset changed. */
if
(
server
.
appendonly
)
rewriteAppendOnlyFileBackground
();
}
}
...
...
@@ -519,7 +521,6 @@ void replicationCron(void) {
redisLog
(
REDIS_NOTICE
,
"Connecting to MASTER..."
);
if
(
syncWithMaster
()
==
REDIS_OK
)
{
redisLog
(
REDIS_NOTICE
,
"MASTER <-> SLAVE sync started: SYNC sent"
);
if
(
server
.
appendonly
)
rewriteAppendOnlyFileBackground
();
}
}
...
...
src/sort.c
浏览文件 @
a59e797a
...
...
@@ -363,6 +363,7 @@ void sortCommand(redisClient *c) {
}
}
}
lookupKeyWrite
(
c
->
db
,
storekey
);
/* Force expire of old key if needed. */
dbReplace
(
c
->
db
,
storekey
,
sobj
);
/* Note: we add 1 because the DB is dirty anyway since even if the
* SORT result is empty a new key is set and maybe the old content
...
...
src/t_list.c
浏览文件 @
a59e797a
...
...
@@ -635,7 +635,9 @@ void lremCommand(redisClient *c) {
* as well. This command was originally proposed by Ezra Zygmuntowicz.
*/
void
rpoplpushHandlePush
(
redisClient
*
c
,
robj
*
dstkey
,
robj
*
dstobj
,
robj
*
value
)
{
void
rpoplpushHandlePush
(
redisClient
*
origclient
,
redisClient
*
c
,
robj
*
dstkey
,
robj
*
dstobj
,
robj
*
value
)
{
robj
*
aux
;
if
(
!
handleClientsWaitingListPush
(
c
,
dstkey
,
value
))
{
/* Create the list if the key does not exist */
if
(
!
dstobj
)
{
...
...
@@ -643,9 +645,25 @@ void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value
dbAdd
(
c
->
db
,
dstkey
,
dstobj
);
}
else
{
touchWatchedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
listTypePush
(
dstobj
,
value
,
REDIS_HEAD
);
/* If we are pushing as a result of LPUSH against a key
* watched by BLPOPLPUSH, we need to rewrite the command vector.
* But if this is called directly by RPOPLPUSH (either directly
* or via a BRPOPLPUSH where the popped list exists)
* we should replicate the BRPOPLPUSH command itself. */
if
(
c
!=
origclient
)
{
aux
=
createStringObject
(
"LPUSH"
,
5
);
rewriteClientCommandVector
(
origclient
,
3
,
aux
,
dstkey
,
value
);
decrRefCount
(
aux
);
}
else
{
/* Make sure to always use RPOPLPUSH in the replication / AOF,
* even if the original command was BRPOPLPUSH. */
aux
=
createStringObject
(
"RPOPLPUSH"
,
9
);
rewriteClientCommandVector
(
origclient
,
3
,
aux
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
decrRefCount
(
aux
);
}
server
.
dirty
++
;
}
/* Always send the pushed value to the client. */
...
...
@@ -661,16 +679,22 @@ void rpoplpushCommand(redisClient *c) {
addReply
(
c
,
shared
.
nullbulk
);
}
else
{
robj
*
dobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
2
]);
robj
*
touchedkey
=
c
->
argv
[
1
];
if
(
dobj
&&
checkType
(
c
,
dobj
,
REDIS_LIST
))
return
;
value
=
listTypePop
(
sobj
,
REDIS_TAIL
);
rpoplpushHandlePush
(
c
,
c
->
argv
[
2
],
dobj
,
value
);
/* We saved touched key, and protect it, since rpoplpushHandlePush
* may change the client command argument vector. */
incrRefCount
(
touchedkey
);
rpoplpushHandlePush
(
c
,
c
,
c
->
argv
[
2
],
dobj
,
value
);
/* listTypePop returns an object with its refcount incremented */
decrRefCount
(
value
);
/* Delete the source list when it is empty */
if
(
listTypeLength
(
sobj
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
if
(
listTypeLength
(
sobj
)
==
0
)
dbDelete
(
c
->
db
,
touchedkey
);
touchWatchedKey
(
c
->
db
,
touchedkey
);
decrRefCount
(
touchedkey
);
server
.
dirty
++
;
}
}
...
...
@@ -772,6 +796,7 @@ void unblockClientWaitingData(redisClient *c) {
/* Cleanup the client structure */
zfree
(
c
->
bpop
.
keys
);
c
->
bpop
.
keys
=
NULL
;
if
(
c
->
bpop
.
target
)
decrRefCount
(
c
->
bpop
.
target
);
c
->
bpop
.
target
=
NULL
;
c
->
flags
&=
~
REDIS_BLOCKED
;
c
->
flags
|=
REDIS_UNBLOCKED
;
...
...
@@ -815,6 +840,9 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
receiver
=
ln
->
value
;
dstkey
=
receiver
->
bpop
.
target
;
/* Protect receiver->bpop.target, that will be freed by
* the next unblockClientWaitingData() call. */
if
(
dstkey
)
incrRefCount
(
dstkey
);
/* This should remove the first element of the "clients" list. */
unblockClientWaitingData
(
receiver
);
...
...
@@ -823,17 +851,16 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
addReplyMultiBulkLen
(
receiver
,
2
);
addReplyBulk
(
receiver
,
key
);
addReplyBulk
(
receiver
,
ele
);
return
1
;
return
1
;
/* Serve just the first client as in B[RL]POP semantics */
}
else
{
/* BRPOPLPUSH, note that receiver->db is always equal to c->db. */
dstobj
=
lookupKeyWrite
(
receiver
->
db
,
dstkey
);
if
(
dstobj
&&
checkType
(
receiver
,
dstobj
,
REDIS_LIST
))
{
decrRefCount
(
dstkey
);
}
else
{
rpoplpushHandlePush
(
receiver
,
dstkey
,
dstobj
,
ele
);
if
(
!
(
dstobj
&&
checkType
(
receiver
,
dstobj
,
REDIS_LIST
)))
{
rpoplpushHandlePush
(
c
,
receiver
,
dstkey
,
dstobj
,
ele
);
decrRefCount
(
dstkey
);
return
1
;
}
decrRefCount
(
dstkey
);
}
}
...
...
src/t_set.c
浏览文件 @
a59e797a
...
...
@@ -325,7 +325,7 @@ void scardCommand(redisClient *c) {
}
void
spopCommand
(
redisClient
*
c
)
{
robj
*
set
,
*
ele
;
robj
*
set
,
*
ele
,
*
aux
;
int64_t
llele
;
int
encoding
;
...
...
@@ -341,16 +341,11 @@ void spopCommand(redisClient *c) {
setTypeRemove
(
set
,
ele
);
}
/* Change argv to replicate as SREM */
c
->
argc
=
3
;
c
->
argv
=
zrealloc
(
c
->
argv
,
sizeof
(
robj
*
)
*
(
c
->
argc
));
/* Overwrite SREM with SPOP (same length) */
redisAssert
(
sdslen
(
c
->
argv
[
0
]
->
ptr
)
==
4
);
memcpy
(
c
->
argv
[
0
]
->
ptr
,
"SREM"
,
4
);
/* Popped element already has incremented refcount */
c
->
argv
[
2
]
=
ele
;
/* Replicate/AOF this command as an SREM operation */
aux
=
createStringObject
(
"SREM"
,
4
);
rewriteClientCommandVector
(
c
,
3
,
aux
,
c
->
argv
[
1
],
ele
);
decrRefCount
(
ele
);
decrRefCount
(
aux
);
addReplyBulk
(
c
,
ele
);
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
...
...
src/t_string.c
浏览文件 @
a59e797a
...
...
@@ -25,6 +25,7 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
}
lookupKeyWrite
(
c
->
db
,
key
);
/* Force expire of old key if needed */
retval
=
dbAdd
(
c
->
db
,
key
,
val
);
if
(
retval
==
REDIS_ERR
)
{
if
(
!
nx
)
{
...
...
src/version.h
浏览文件 @
a59e797a
#define REDIS_VERSION "2.2.1
08
"
#define REDIS_VERSION "2.2.1
10
"
tests/integration/replication.tcl
浏览文件 @
a59e797a
...
...
@@ -6,6 +6,24 @@ start_server {tags {"repl"}} {
s -1 role
}
{
slave
}
test
{
BRPOPLPUSH replication, when blocking against empty list
}
{
set rd
[
redis_deferring_client
]
$rd brpoplpush a b 5
r lpush a foo
after 1000
assert_equal
[
r debug digest
]
[
r -1 debug digest
]
}
test
{
BRPOPLPUSH replication, list exists
}
{
set rd
[
redis_deferring_client
]
r lpush c 1
r lpush c 2
r lpush c 3
$rd brpoplpush c d 5
after 1000
assert_equal
[
r debug digest
]
[
r -1 debug digest
]
}
test
{
MASTER and SLAVE dataset should be identical after complex ops
}
{
createComplexDataset r 10000
after 500
...
...
tests/unit/basic.tcl
浏览文件 @
a59e797a
...
...
@@ -138,21 +138,48 @@ start_server {tags {"basic"}} {
r decrby novar 17179869185
}
{
-1
}
test
{
SETNX target key missing
}
{
r setnx novar2 foobared
r get novar2
}
{
foobared
}
test
"SETNX target key missing"
{
r del novar
assert_equal 1
[
r setnx novar foobared
]
assert_equal
"foobared"
[
r get novar
]
}
test
{
SETNX target key exists
}
{
r setnx novar2 blabla
r get novar2
}
{
foobared
}
test
"SETNX target key exists"
{
r set novar foobared
assert_equal 0
[
r setnx novar blabla
]
assert_equal
"foobared"
[
r get novar
]
}
test
{
SETNX against volatile key
}
{
test
"SETNX against not-expired volatile key"
{
r set x 10
r expire x 10000
list
[
r setnx x 20
]
[
r get x
]
}
{
0 10
}
assert_equal 0
[
r setnx x 20
]
assert_equal 10
[
r get x
]
}
test
"SETNX against expired volatile key"
{
# Make it very unlikely for the key this test uses to be expired by the
# active expiry cycle. This is tightly coupled to the implementation of
# active expiry and dbAdd
()
but currently the only way to test that
# SETNX expires a key when it should have been.
for
{
set x 0
}
{
$x
< 9999
}
{
incr x
}
{
r setex key-$x 3600 value
}
# This will be one of 10000 expiring keys. A cycle is executed every
# 100ms, sampling 10 keys for being expired or not. This key will be
# expired for at most 1s when we wait 2s, resulting in a total sample
# of 100 keys. The probability of the success of this test being a
# false positive is therefore approx. 1%.
r set x 10
r expire x 1
# Wait for the key to expire
after 2000
assert_equal 1
[
r setnx x 20
]
assert_equal 20
[
r get x
]
}
test
{
EXISTS
}
{
set res
{}
...
...
tests/unit/type/list.tcl
浏览文件 @
a59e797a
...
...
@@ -262,6 +262,14 @@ start_server {
r exec
}
{
foo bar
{}
{}
{
bar foo
}}
test
{
BRPOPLPUSH timeout
}
{
set rd
[
redis_deferring_client
]
$rd brpoplpush foo_list bar_list 1
after 2000
$rd read
}
{}
foreach
{
pop
}
{
BLPOP BRPOP
}
{
test
"
$pop:
with single empty list argument"
{
set rd
[
redis_deferring_client
]
...
...
utils/redis_init_script
浏览文件 @
a59e797a
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
REDISPORT
=
6379
EXEC
=
/usr/local/bin/redis-server
CLIEXEC
=
/usr/local/bin/redis-cli
PIDFILE
=
/var/run/redis_
${
REDISPORT
}
.pid
CONF
=
"/etc/redis/
${
REDISPORT
}
.conf"
...
...
@@ -10,21 +14,21 @@ case "$1" in
start
)
if
[
-f
$PIDFILE
]
then
echo
-n
"
$PIDFILE
exists, process is already running or crashed
\n
"
echo
"
$PIDFILE
exists, process is already running or crashed
"
else
echo
-n
"Starting Redis server...
\n
"
echo
"Starting Redis server...
"
$EXEC
$CONF
fi
;;
stop
)
if
[
!
-f
$PIDFILE
]
then
echo
-n
"
$PIDFILE
does not exist, process is not running
\n
"
echo
"
$PIDFILE
does not exist, process is not running
"
else
PID
=
$(
cat
$PIDFILE
)
echo
-n
"Stopping ...
\n
"
echo
-n
"SHUTDOWN
\r\n
"
| nc localhost
$REDISPORT
&
while
[
-x
/proc/
${
PID
FILE
}
]
PID
=
$(
cat
$PIDFILE
)
echo
"Stopping ...
"
$CLIEXEC
-p
$REDISPORT
shutdown
while
[
-x
/proc/
${
PID
}
]
do
echo
"Waiting for Redis to shutdown ..."
sleep
1
...
...
@@ -32,4 +36,7 @@ case "$1" in
echo
"Redis stopped"
fi
;;
*
)
echo
"Please use start or stop as first argument"
;;
esac
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录