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
994ed2bc
Commit
994ed2bc
authored
Jun 25, 2011
by
antirez
Browse files
unstable merge conflicts resolved
parents
45ec3243
d5b36c51
Changes
110
Show whitespace changes
Inline
Side-by-side
src/sort.c
View file @
994ed2bc
...
...
@@ -366,12 +366,12 @@ void sortCommand(redisClient *c) {
}
}
}
dbReplace
(
c
->
db
,
storekey
,
sobj
);
setKey
(
c
->
db
,
storekey
,
sobj
);
decrRefCount
(
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
* replaced. */
server
.
dirty
+=
1
+
outputlen
;
signalModifiedKey
(
c
->
db
,
storekey
);
addReplyLongLong
(
c
,
outputlen
);
}
...
...
src/t_list.c
View file @
994ed2bc
...
...
@@ -640,7 +640,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
)
{
...
...
@@ -648,9 +650,25 @@ void rpoplpushHandlePush(redisClient *c, robj *dstkey, robj *dstobj, robj *value
dbAdd
(
c
->
db
,
dstkey
,
dstobj
);
}
else
{
signalModifiedKey
(
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. */
...
...
@@ -666,16 +684,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
]);
signalModifiedKey
(
c
->
db
,
c
->
argv
[
1
]);
if
(
listTypeLength
(
sobj
)
==
0
)
dbDelete
(
c
->
db
,
touchedkey
);
signalModifiedKey
(
c
->
db
,
touchedkey
);
decrRefCount
(
touchedkey
);
server
.
dirty
++
;
}
}
...
...
@@ -777,6 +801,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
;
...
...
@@ -820,6 +845,10 @@ 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
);
...
...
@@ -828,17 +857,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
View file @
994ed2bc
...
...
@@ -332,7 +332,7 @@ void scardCommand(redisClient *c) {
}
void
spopCommand
(
redisClient
*
c
)
{
robj
*
set
,
*
ele
;
robj
*
set
,
*
ele
,
*
aux
;
int64_t
llele
;
int
encoding
;
...
...
@@ -348,16 +348,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
View file @
994ed2bc
...
...
@@ -13,7 +13,6 @@ static int checkStringLength(redisClient *c, long long size) {
}
void
setGenericCommand
(
redisClient
*
c
,
int
nx
,
robj
*
key
,
robj
*
val
,
robj
*
expire
)
{
int
retval
;
long
seconds
=
0
;
/* initialized to avoid an harmness warning */
if
(
expire
)
{
...
...
@@ -25,21 +24,12 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
}
retval
=
dbAdd
(
c
->
db
,
key
,
val
);
if
(
retval
==
REDIS_ERR
)
{
if
(
!
nx
)
{
dbReplace
(
c
->
db
,
key
,
val
);
incrRefCount
(
val
);
}
else
{
if
(
lookupKeyWrite
(
c
->
db
,
key
)
!=
NULL
&&
nx
)
{
addReply
(
c
,
shared
.
czero
);
return
;
}
}
else
{
incrRefCount
(
val
);
}
signalModifiedKey
(
c
->
db
,
key
);
setKey
(
c
->
db
,
key
,
val
);
server
.
dirty
++
;
removeExpire
(
c
->
db
,
key
);
if
(
expire
)
setExpire
(
c
->
db
,
key
,
time
(
NULL
)
+
seconds
);
addReply
(
c
,
nx
?
shared
.
cone
:
shared
.
ok
);
}
...
...
@@ -81,11 +71,8 @@ void getCommand(redisClient *c) {
void
getsetCommand
(
redisClient
*
c
)
{
if
(
getGenericCommand
(
c
)
==
REDIS_ERR
)
return
;
c
->
argv
[
2
]
=
tryObjectEncoding
(
c
->
argv
[
2
]);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
signalModifiedKey
(
c
->
db
,
c
->
argv
[
1
]);
setKey
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
server
.
dirty
++
;
removeExpire
(
c
->
db
,
c
->
argv
[
1
]);
}
static
int
getBitOffsetFromArgument
(
redisClient
*
c
,
robj
*
o
,
size_t
*
offset
)
{
...
...
@@ -138,7 +125,7 @@ void setbitCommand(redisClient *c) {
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
db
Replac
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
db
Overwrit
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
...
...
@@ -236,7 +223,7 @@ void setrangeCommand(redisClient *c) {
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
db
Replac
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
db
Overwrit
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
}
...
...
@@ -319,18 +306,15 @@ void msetGenericCommand(redisClient *c, int nx) {
busykeys
++
;
}
}
}
if
(
busykeys
)
{
addReply
(
c
,
shared
.
czero
);
return
;
}
}
for
(
j
=
1
;
j
<
c
->
argc
;
j
+=
2
)
{
c
->
argv
[
j
+
1
]
=
tryObjectEncoding
(
c
->
argv
[
j
+
1
]);
dbReplace
(
c
->
db
,
c
->
argv
[
j
],
c
->
argv
[
j
+
1
]);
incrRefCount
(
c
->
argv
[
j
+
1
]);
removeExpire
(
c
->
db
,
c
->
argv
[
j
]);
signalModifiedKey
(
c
->
db
,
c
->
argv
[
j
]);
setKey
(
c
->
db
,
c
->
argv
[
j
],
c
->
argv
[
j
+
1
]);
}
server
.
dirty
+=
(
c
->
argc
-
1
)
/
2
;
addReply
(
c
,
nx
?
shared
.
cone
:
shared
.
ok
);
...
...
@@ -346,7 +330,7 @@ void msetnxCommand(redisClient *c) {
void
incrDecrCommand
(
redisClient
*
c
,
long
long
incr
)
{
long
long
value
,
oldvalue
;
robj
*
o
;
robj
*
o
,
*
new
;
o
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
1
]);
if
(
o
!=
NULL
&&
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
...
...
@@ -358,12 +342,15 @@ void incrDecrCommand(redisClient *c, long long incr) {
addReplyError
(
c
,
"increment or decrement would overflow"
);
return
;
}
o
=
createStringObjectFromLongLong
(
value
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
new
=
createStringObjectFromLongLong
(
value
);
if
(
o
)
dbOverwrite
(
c
->
db
,
c
->
argv
[
1
],
new
);
else
dbAdd
(
c
->
db
,
c
->
argv
[
1
],
new
);
signalModifiedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
colon
);
addReply
(
c
,
o
);
addReply
(
c
,
new
);
addReply
(
c
,
shared
.
crlf
);
}
...
...
@@ -416,7 +403,7 @@ void appendCommand(redisClient *c) {
robj
*
decoded
=
getDecodedObject
(
o
);
o
=
createStringObject
(
decoded
->
ptr
,
sdslen
(
decoded
->
ptr
));
decrRefCount
(
decoded
);
db
Replac
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
db
Overwrit
e
(
c
->
db
,
c
->
argv
[
1
],
o
);
}
/* Append the value */
...
...
src/zmalloc.c
View file @
994ed2bc
...
...
@@ -51,6 +51,11 @@
#define calloc(count,size) tc_calloc(count,size)
#define realloc(ptr,size) tc_realloc(ptr,size)
#define free(ptr) tc_free(ptr)
#elif defined(USE_JEMALLOC)
#define malloc(size) je_malloc(size)
#define calloc(count,size) je_calloc(count,size)
#define realloc(ptr,size) je_realloc(ptr,size)
#define free(ptr) je_free(ptr)
#endif
#define update_zmalloc_stat_alloc(__n,__size) do { \
...
...
@@ -98,7 +103,7 @@ void *zmalloc(size_t size) {
if
(
!
ptr
)
zmalloc_oom
(
size
);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc
(
redis_
malloc_size
(
ptr
),
size
);
update_zmalloc_stat_alloc
(
z
malloc_size
(
ptr
),
size
);
return
ptr
;
#else
*
((
size_t
*
)
ptr
)
=
size
;
...
...
@@ -112,7 +117,7 @@ void *zcalloc(size_t size) {
if
(
!
ptr
)
zmalloc_oom
(
size
);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc
(
redis_
malloc_size
(
ptr
),
size
);
update_zmalloc_stat_alloc
(
z
malloc_size
(
ptr
),
size
);
return
ptr
;
#else
*
((
size_t
*
)
ptr
)
=
size
;
...
...
@@ -130,12 +135,12 @@ void *zrealloc(void *ptr, size_t size) {
if
(
ptr
==
NULL
)
return
zmalloc
(
size
);
#ifdef HAVE_MALLOC_SIZE
oldsize
=
redis_
malloc_size
(
ptr
);
oldsize
=
z
malloc_size
(
ptr
);
newptr
=
realloc
(
ptr
,
size
);
if
(
!
newptr
)
zmalloc_oom
(
size
);
update_zmalloc_stat_free
(
oldsize
);
update_zmalloc_stat_alloc
(
redis_
malloc_size
(
newptr
),
size
);
update_zmalloc_stat_alloc
(
z
malloc_size
(
newptr
),
size
);
return
newptr
;
#else
realptr
=
(
char
*
)
ptr
-
PREFIX_SIZE
;
...
...
@@ -158,7 +163,7 @@ void zfree(void *ptr) {
if
(
ptr
==
NULL
)
return
;
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_free
(
redis_
malloc_size
(
ptr
));
update_zmalloc_stat_free
(
z
malloc_size
(
ptr
));
free
(
ptr
);
#else
realptr
=
(
char
*
)
ptr
-
PREFIX_SIZE
;
...
...
src/zmalloc.h
View file @
994ed2bc
...
...
@@ -28,8 +28,43 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _ZMALLOC_H
#define _ZMALLOC_H
#ifndef __ZMALLOC_H
#define __ZMALLOC_H
/* Double expansion needed for stringification of macro values. */
#define __xstr(s) __str(s)
#define __str(s) #s
#if defined(USE_TCMALLOC)
#define ZMALLOC_LIB ("tcmalloc-" __xstr(TC_VERSION_MAJOR) "." __xstr(TC_VERSION_MINOR))
#include <google/tcmalloc.h>
#if TC_VERSION_MAJOR >= 1 && TC_VERSION_MINOR >= 6
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) tc_malloc_size(p)
#else
#error "Newer version of tcmalloc required"
#endif
#elif defined(USE_JEMALLOC)
#define ZMALLOC_LIB ("jemalloc-" __xstr(JEMALLOC_VERSION_MAJOR) "." __xstr(JEMALLOC_VERSION_MINOR) "." __xstr(JEMALLOC_VERSION_BUGFIX))
#define JEMALLOC_MANGLE
#include <jemalloc/jemalloc.h>
#if JEMALLOC_VERSION_MAJOR >= 2 && JEMALLOC_VERSION_MINOR >= 1
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) JEMALLOC_P(malloc_usable_size)(p)
#else
#error "Newer version of jemalloc required"
#endif
#elif defined(__APPLE__)
#include <malloc/malloc.h>
#define HAVE_MALLOC_SIZE 1
#define zmalloc_size(p) malloc_size(p)
#endif
#ifndef ZMALLOC_LIB
#define ZMALLOC_LIB "libc"
#endif
void
*
zmalloc
(
size_t
size
);
void
*
zcalloc
(
size_t
size
);
...
...
@@ -44,4 +79,4 @@ size_t zmalloc_allocations_for_size(size_t size);
#define ZMALLOC_MAX_ALLOC_STAT 256
#endif
/* _ZMALLOC_H */
#endif
/*
_
_ZMALLOC_H */
tests/assets/default.conf
View file @
994ed2bc
...
...
@@ -291,32 +291,6 @@ appendfsync everysec
# "no" that is the safest pick from the point of view of durability.
no
-
appendfsync
-
on
-
rewrite
no
#################################### DISK STORE ###############################
# When disk store is active Redis works as an on-disk database, where memory
# is only used as a object cache.
#
# This mode is good for datasets that are bigger than memory, and in general
# when you want to trade speed for:
#
# - less memory used
# - immediate server restart
# - per key durability, without need for backgrond savig
#
# On the other hand, with disk store enabled MULTI/EXEC are no longer
# transactional from the point of view of the persistence on disk, that is,
# Redis transactions will still guarantee that commands are either processed
# all or nothing, but there is no guarantee that all the keys are flushed
# on disk in an atomic way.
#
# Of course with disk store enabled Redis is not as fast as it is when
# working with just the memory back end.
diskstore
-
enabled
no
diskstore
-
path
redis
.
ds
cache
-
max
-
memory
0
cache
-
flush
-
delay
0
############################### ADVANCED CONFIG ###############################
# Hashes are encoded in a special way (much more memory efficient) when they
...
...
tests/integration/replication.tcl
View file @
994ed2bc
...
...
@@ -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
View file @
994ed2bc
...
...
@@ -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
View file @
994ed2bc
...
...
@@ -278,6 +278,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
]
...
...
Prev
1
2
3
4
5
6
Next
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