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
aaada3f9
Commit
aaada3f9
authored
Aug 20, 2010
by
Pieter Noordhuis
Browse files
Merge branch 'master' into intset-split
Conflicts: src/Makefile src/t_set.c
parents
2767f1c0
cbce5171
Changes
37
Hide whitespace changes
Inline
Side-by-side
src/t_set.c
View file @
aaada3f9
...
...
@@ -188,6 +188,7 @@ void saddCommand(redisClient *c) {
}
}
if
(
setTypeAdd
(
set
,
c
->
argv
[
2
]))
{
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
cone
);
}
else
{
...
...
@@ -203,6 +204,7 @@ void sremCommand(redisClient *c) {
if
(
setTypeRemove
(
set
,
c
->
argv
[
2
]))
{
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
cone
);
}
else
{
...
...
@@ -241,6 +243,8 @@ void smoveCommand(redisClient *c) {
/* Remove the src set from the database when empty */
if
(
setTypeSize
(
srcset
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
2
]);
server
.
dirty
++
;
/* Create the destination set when it doesn't exist */
...
...
@@ -289,6 +293,7 @@ void spopCommand(redisClient *c) {
addReplyBulk
(
c
,
ele
);
decrRefCount
(
ele
);
if
(
setTypeSize
(
set
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
}
}
...
...
@@ -325,8 +330,10 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
if
(
!
setobj
)
{
zfree
(
sets
);
if
(
dstkey
)
{
if
(
dbDelete
(
c
->
db
,
dstkey
))
if
(
dbDelete
(
c
->
db
,
dstkey
))
{
touchWatchedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
addReply
(
c
,
shared
.
czero
);
}
else
{
addReply
(
c
,
shared
.
emptymultibulk
);
...
...
@@ -390,6 +397,7 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
decrRefCount
(
dstset
);
addReply
(
c
,
shared
.
czero
);
}
touchWatchedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
else
{
lenobj
->
ptr
=
sdscatprintf
(
sdsempty
(),
"*%lu
\r\n
"
,
cardinality
);
...
...
@@ -481,6 +489,7 @@ void sunionDiffGenericCommand(redisClient *c, robj **setkeys, int setnum, robj *
decrRefCount
(
dstset
);
addReply
(
c
,
shared
.
czero
);
}
touchWatchedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
zfree
(
sets
);
...
...
src/t_string.c
View file @
aaada3f9
...
...
@@ -17,8 +17,6 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
}
touchWatchedKey
(
c
->
db
,
key
);
if
(
nx
)
deleteIfVolatile
(
c
->
db
,
key
);
retval
=
dbAdd
(
c
->
db
,
key
,
val
);
if
(
retval
==
REDIS_ERR
)
{
if
(
!
nx
)
{
...
...
@@ -31,6 +29,7 @@ void setGenericCommand(redisClient *c, int nx, robj *key, robj *val, robj *expir
}
else
{
incrRefCount
(
val
);
}
touchWatchedKey
(
c
->
db
,
key
);
server
.
dirty
++
;
removeExpire
(
c
->
db
,
key
);
if
(
expire
)
setExpire
(
c
->
db
,
key
,
time
(
NULL
)
+
seconds
);
...
...
@@ -72,6 +71,7 @@ void getsetCommand(redisClient *c) {
if
(
getGenericCommand
(
c
)
==
REDIS_ERR
)
return
;
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
c
->
argv
[
2
]);
incrRefCount
(
c
->
argv
[
2
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
removeExpire
(
c
->
db
,
c
->
argv
[
1
]);
}
...
...
@@ -120,6 +120,7 @@ void msetGenericCommand(redisClient *c, int nx) {
dbReplace
(
c
->
db
,
c
->
argv
[
j
],
c
->
argv
[
j
+
1
]);
incrRefCount
(
c
->
argv
[
j
+
1
]);
removeExpire
(
c
->
db
,
c
->
argv
[
j
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
j
]);
}
server
.
dirty
+=
(
c
->
argc
-
1
)
/
2
;
addReply
(
c
,
nx
?
shared
.
cone
:
shared
.
ok
);
...
...
@@ -144,6 +145,7 @@ void incrDecrCommand(redisClient *c, long long incr) {
value
+=
incr
;
o
=
createStringObjectFromLongLong
(
value
);
dbReplace
(
c
->
db
,
c
->
argv
[
1
],
o
);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
colon
);
addReply
(
c
,
o
);
...
...
@@ -207,6 +209,7 @@ void appendCommand(redisClient *c) {
}
totlen
=
sdslen
(
o
->
ptr
);
}
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReplySds
(
c
,
sdscatprintf
(
sdsempty
(),
":%lu
\r\n
"
,(
unsigned
long
)
totlen
));
}
...
...
@@ -248,4 +251,13 @@ void substrCommand(redisClient *c) {
decrRefCount
(
o
);
}
void
strlenCommand
(
redisClient
*
c
)
{
robj
*
o
;
if
((
o
=
lookupKeyReadOrReply
(
c
,
c
->
argv
[
1
],
shared
.
czero
))
==
NULL
||
checkType
(
c
,
o
,
REDIS_STRING
))
return
;
o
=
getDecodedObject
(
o
);
addReplyLongLong
(
c
,
sdslen
(
o
->
ptr
));
decrRefCount
(
o
);
}
src/t_zset.c
View file @
aaada3f9
...
...
@@ -327,11 +327,6 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
zset
*
zs
;
double
*
score
;
if
(
isnan
(
scoreval
))
{
addReplySds
(
c
,
sdsnew
(
"-ERR provide score is Not A Number (nan)
\r\n
"
));
return
;
}
zsetobj
=
lookupKeyWrite
(
c
->
db
,
key
);
if
(
zsetobj
==
NULL
)
{
zsetobj
=
createZsetObject
();
...
...
@@ -361,7 +356,7 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
}
if
(
isnan
(
*
score
))
{
addReplySds
(
c
,
sdsnew
(
"-ERR resulting score is
N
ot
A N
umber (
nan
)
\r\n
"
));
sdsnew
(
"-ERR resulting score is
n
ot
a n
umber (
NaN
)
\r\n
"
));
zfree
(
score
);
/* Note that we don't need to check if the zset may be empty and
* should be removed here, as we can only obtain Nan as score if
...
...
@@ -379,6 +374,7 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
incrRefCount
(
ele
);
/* added to hash */
zslInsert
(
zs
->
zsl
,
*
score
,
ele
);
incrRefCount
(
ele
);
/* added to skiplist */
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
if
(
doincrement
)
addReplyDouble
(
c
,
*
score
);
...
...
@@ -402,6 +398,7 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
incrRefCount
(
ele
);
/* Update the score in the hash table */
dictReplace
(
zs
->
dict
,
ele
,
score
);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
}
else
{
zfree
(
score
);
...
...
@@ -415,15 +412,13 @@ void zaddGenericCommand(redisClient *c, robj *key, robj *ele, double scoreval, i
void
zaddCommand
(
redisClient
*
c
)
{
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
0
);
}
void
zincrbyCommand
(
redisClient
*
c
)
{
double
scoreval
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
2
],
&
scoreval
,
NULL
)
!=
REDIS_OK
)
return
;
zaddGenericCommand
(
c
,
c
->
argv
[
1
],
c
->
argv
[
3
],
scoreval
,
1
);
}
...
...
@@ -452,6 +447,7 @@ void zremCommand(redisClient *c) {
dictDelete
(
zs
->
dict
,
c
->
argv
[
2
]);
if
(
htNeedsResize
(
zs
->
dict
))
dictResize
(
zs
->
dict
);
if
(
dictSize
(
zs
->
dict
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
++
;
addReply
(
c
,
shared
.
cone
);
}
...
...
@@ -473,6 +469,7 @@ void zremrangebyscoreCommand(redisClient *c) {
deleted
=
zslDeleteRangeByScore
(
zs
->
zsl
,
min
,
max
,
zs
->
dict
);
if
(
htNeedsResize
(
zs
->
dict
))
dictResize
(
zs
->
dict
);
if
(
dictSize
(
zs
->
dict
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
if
(
deleted
)
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
+=
deleted
;
addReplyLongLong
(
c
,
deleted
);
}
...
...
@@ -497,9 +494,9 @@ void zremrangebyrankCommand(redisClient *c) {
if
(
start
<
0
)
start
=
llen
+
start
;
if
(
end
<
0
)
end
=
llen
+
end
;
if
(
start
<
0
)
start
=
0
;
if
(
end
<
0
)
end
=
0
;
/* indexes sanity checks */
/* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if
(
start
>
end
||
start
>=
llen
)
{
addReply
(
c
,
shared
.
czero
);
return
;
...
...
@@ -511,6 +508,7 @@ void zremrangebyrankCommand(redisClient *c) {
deleted
=
zslDeleteRangeByRank
(
zs
->
zsl
,
start
+
1
,
end
+
1
,
zs
->
dict
);
if
(
htNeedsResize
(
zs
->
dict
))
dictResize
(
zs
->
dict
);
if
(
dictSize
(
zs
->
dict
)
==
0
)
dbDelete
(
c
->
db
,
c
->
argv
[
1
]);
if
(
deleted
)
touchWatchedKey
(
c
->
db
,
c
->
argv
[
1
]);
server
.
dirty
+=
deleted
;
addReplyLongLong
(
c
,
deleted
);
}
...
...
@@ -536,6 +534,10 @@ int qsortCompareZsetopsrcByCardinality(const void *s1, const void *s2) {
inline
static
void
zunionInterAggregate
(
double
*
target
,
double
val
,
int
aggregate
)
{
if
(
aggregate
==
REDIS_AGGR_SUM
)
{
*
target
=
*
target
+
val
;
/* The result of adding two doubles is NaN when one variable
* is +inf and the other is -inf. When these numbers are added,
* we maintain the convention of the result being 0.0. */
if
(
isnan
(
*
target
))
*
target
=
0
.
0
;
}
else
if
(
aggregate
==
REDIS_AGGR_MIN
)
{
*
target
=
val
<
*
target
?
val
:
*
target
;
}
else
if
(
aggregate
==
REDIS_AGGR_MAX
)
{
...
...
@@ -554,6 +556,7 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
zset
*
dstzset
;
dictIterator
*
di
;
dictEntry
*
de
;
int
touched
=
0
;
/* expect setnum input keys to be given */
setnum
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
...
...
@@ -598,8 +601,12 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
if
(
remaining
>=
(
setnum
+
1
)
&&
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"weights"
))
{
j
++
;
remaining
--
;
for
(
i
=
0
;
i
<
setnum
;
i
++
,
j
++
,
remaining
--
)
{
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
j
],
&
src
[
i
].
weight
,
NULL
)
!=
REDIS_OK
)
if
(
getDoubleFromObjectOrReply
(
c
,
c
->
argv
[
j
],
&
src
[
i
].
weight
,
"weight value is not a double"
)
!=
REDIS_OK
)
{
zfree
(
src
);
return
;
}
}
}
else
if
(
remaining
>=
2
&&
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"aggregate"
))
{
j
++
;
remaining
--
;
...
...
@@ -698,10 +705,15 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
redisAssert
(
op
==
REDIS_OP_INTER
||
op
==
REDIS_OP_UNION
);
}
dbDelete
(
c
->
db
,
dstkey
);
if
(
dbDelete
(
c
->
db
,
dstkey
))
{
touchWatchedKey
(
c
->
db
,
dstkey
);
touched
=
1
;
server
.
dirty
++
;
}
if
(
dstzset
->
zsl
->
length
)
{
dbAdd
(
c
->
db
,
dstkey
,
dstobj
);
addReplyLongLong
(
c
,
dstzset
->
zsl
->
length
);
if
(
!
touched
)
touchWatchedKey
(
c
->
db
,
dstkey
);
server
.
dirty
++
;
}
else
{
decrRefCount
(
dstobj
);
...
...
@@ -750,11 +762,10 @@ void zrangeGenericCommand(redisClient *c, int reverse) {
if
(
start
<
0
)
start
=
llen
+
start
;
if
(
end
<
0
)
end
=
llen
+
end
;
if
(
start
<
0
)
start
=
0
;
if
(
end
<
0
)
end
=
0
;
/* indexes sanity checks */
/* Invariant: start >= 0, so this test will be true when end < 0.
* The range is empty when start > end or start >= length. */
if
(
start
>
end
||
start
>=
llen
)
{
/* Out of range start or start > end result in empty list */
addReply
(
c
,
shared
.
emptymultibulk
);
return
;
}
...
...
src/vm.c
View file @
aaada3f9
...
...
@@ -86,10 +86,9 @@ void vmInit(void) {
}
else
{
redisLog
(
REDIS_NOTICE
,
"Swap file allocated with success"
);
}
server
.
vm_bitmap
=
z
m
alloc
((
server
.
vm_pages
+
7
)
/
8
);
server
.
vm_bitmap
=
z
c
alloc
((
server
.
vm_pages
+
7
)
/
8
);
redisLog
(
REDIS_VERBOSE
,
"Allocated %lld bytes page table for %lld pages"
,
(
long
long
)
(
server
.
vm_pages
+
7
)
/
8
,
server
.
vm_pages
);
memset
(
server
.
vm_bitmap
,
0
,(
server
.
vm_pages
+
7
)
/
8
);
/* Initialize threaded I/O (used by Virtual Memory) */
server
.
io_newjobs
=
listCreate
();
...
...
@@ -1075,6 +1074,11 @@ int dontWaitForSwappedKey(redisClient *c, robj *key) {
listIter
li
;
struct
dictEntry
*
de
;
/* The key object might be destroyed when deleted from the c->io_keys
* list (and the "key" argument is physically the same object as the
* object inside the list), so we need to protect it. */
incrRefCount
(
key
);
/* Remove the key from the list of keys this client is waiting for. */
listRewind
(
c
->
io_keys
,
&
li
);
while
((
ln
=
listNext
(
&
li
))
!=
NULL
)
{
...
...
@@ -1095,6 +1099,7 @@ int dontWaitForSwappedKey(redisClient *c, robj *key) {
if
(
listLength
(
l
)
==
0
)
dictDelete
(
c
->
db
->
io_keys
,
key
);
decrRefCount
(
key
);
return
listLength
(
c
->
io_keys
)
==
0
;
}
...
...
src/ziplist.c
View file @
aaada3f9
...
...
@@ -23,6 +23,8 @@
#include "zmalloc.h"
#include "ziplist.h"
int
ll2string
(
char
*
s
,
size_t
len
,
long
long
value
);
/* Important note: the ZIP_END value is used to depict the end of the
* ziplist structure. When a pointer contains an entry, the first couple
* of bytes contain the encoded length of the previous entry. This length
...
...
@@ -174,15 +176,27 @@ static int zipPrevLenByteDiff(unsigned char *p, unsigned int len) {
}
/* Check if string pointed to by 'entry' can be encoded as an integer.
* Stores the integer value in 'v' and its encoding in 'encoding'.
* Warning: this function requires a NULL-terminated string! */
static
int
zipTryEncoding
(
unsigned
char
*
entry
,
long
long
*
v
,
unsigned
char
*
encoding
)
{
* Stores the integer value in 'v' and its encoding in 'encoding'. */
static
int
zipTryEncoding
(
unsigned
char
*
entry
,
unsigned
int
entrylen
,
long
long
*
v
,
unsigned
char
*
encoding
)
{
long
long
value
;
char
*
eptr
;
char
buf
[
32
];
if
(
entrylen
>=
32
||
entrylen
==
0
)
return
0
;
if
(
entry
[
0
]
==
'-'
||
(
entry
[
0
]
>=
'0'
&&
entry
[
0
]
<=
'9'
))
{
value
=
strtoll
((
char
*
)
entry
,
&
eptr
,
10
);
int
slen
;
/* Perform a back-and-forth conversion to make sure that
* the string turned into an integer is not losing any info. */
memcpy
(
buf
,
entry
,
entrylen
);
buf
[
entrylen
]
=
'\0'
;
value
=
strtoll
(
buf
,
&
eptr
,
10
);
if
(
eptr
[
0
]
!=
'\0'
)
return
0
;
slen
=
ll2string
(
buf
,
32
,
value
);
if
(
entrylen
!=
(
unsigned
)
slen
||
memcmp
(
buf
,
entry
,
slen
))
return
0
;
/* Great, the string can be encoded. Check what's the smallest
* of our encoding types that can hold this value. */
if
(
value
>=
INT16_MIN
&&
value
<=
INT16_MAX
)
{
*
encoding
=
ZIP_ENC_INT16
;
}
else
if
(
value
>=
INT32_MIN
&&
value
<=
INT32_MAX
)
{
...
...
@@ -329,7 +343,7 @@ static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsig
}
/* See if the entry can be encoded */
if
(
zipTryEncoding
(
s
,
&
value
,
&
encoding
))
{
if
(
zipTryEncoding
(
s
,
slen
,
&
value
,
&
encoding
))
{
reqlen
=
zipEncodingSize
(
encoding
);
}
else
{
reqlen
=
slen
;
...
...
@@ -505,7 +519,7 @@ unsigned int ziplistCompare(unsigned char *p, unsigned char *sstr, unsigned int
}
}
else
{
/* Try to compare encoded values */
if
(
zipTryEncoding
(
sstr
,
&
sval
,
&
sencoding
))
{
if
(
zipTryEncoding
(
sstr
,
slen
,
&
sval
,
&
sencoding
))
{
if
(
entry
.
encoding
==
sencoding
)
{
zval
=
zipLoadInteger
(
p
+
entry
.
headersize
,
entry
.
encoding
);
return
zval
==
sval
;
...
...
src/zmalloc.c
View file @
aaada3f9
...
...
@@ -89,6 +89,20 @@ void *zmalloc(size_t size) {
#endif
}
void
*
zcalloc
(
size_t
size
)
{
void
*
ptr
=
calloc
(
1
,
size
+
PREFIX_SIZE
);
if
(
!
ptr
)
zmalloc_oom
(
size
);
#ifdef HAVE_MALLOC_SIZE
increment_used_memory
(
redis_malloc_size
(
ptr
));
return
ptr
;
#else
*
((
size_t
*
)
ptr
)
=
size
;
increment_used_memory
(
size
+
PREFIX_SIZE
);
return
(
char
*
)
ptr
+
PREFIX_SIZE
;
#endif
}
void
*
zrealloc
(
void
*
ptr
,
size_t
size
)
{
#ifndef HAVE_MALLOC_SIZE
void
*
realptr
;
...
...
src/zmalloc.h
View file @
aaada3f9
...
...
@@ -32,6 +32,7 @@
#define _ZMALLOC_H
void
*
zmalloc
(
size_t
size
);
void
*
zcalloc
(
size_t
size
);
void
*
zrealloc
(
void
*
ptr
,
size_t
size
);
void
zfree
(
void
*
ptr
);
char
*
zstrdup
(
const
char
*
s
);
...
...
tests/integration/replication.tcl
View file @
aaada3f9
start_server
{
tags
{
"repl"
}}
{
start_server
{}
{
test
{
First server should have role slave after SLAVEOF
}
{
r -1 slaveof
[
srv 0 host
]
[
srv 0 port
]
after 1000
s -1 role
}
{
slave
}
test
{
MASTER and SLAVE dataset should be identical after complex ops
}
{
createComplexDataset r 10000
after 500
if
{[
r debug digest
]
ne
[
r -1 debug digest
]}
{
set csv1
[
csvdump r
]
set csv2
[
csvdump
{
r -1
}]
set fd
[
open /tmp/repldump1.txt w
]
puts -nonewline $fd $csv1
close $fd
set fd
[
open /tmp/repldump2.txt w
]
puts -nonewline $fd $csv2
close $fd
puts
"Master - Slave inconsistency"
puts
"Run diff -u against /tmp/repldump*.txt for more info"
}
assert_equal
[
r debug digest
]
[
r -1 debug digest
]
}
test
{
MASTER and SLAVE consistency with expire
}
{
createComplexDataset r 50000 useexpire
after 4000
;
# Make sure everything expired before taking the digest
if
{[
r debug digest
]
ne
[
r -1 debug digest
]}
{
set csv1
[
csvdump r
]
set csv2
[
csvdump
{
r -1
}]
set fd
[
open /tmp/repldump1.txt w
]
puts -nonewline $fd $csv1
close $fd
set fd
[
open /tmp/repldump2.txt w
]
puts -nonewline $fd $csv2
close $fd
puts
"Master - Slave inconsistency"
puts
"Run diff -u against /tmp/repldump*.txt for more info"
}
assert_equal
[
r debug digest
]
[
r -1 debug digest
]
}
}
}
start_server
{
tags
{
"repl"
}}
{
r set mykey foo
...
...
tests/support/test.tcl
View file @
aaada3f9
...
...
@@ -33,9 +33,14 @@ proc assert_error {pattern code} {
}
proc assert_encoding
{
enc key
}
{
# swapped out value doesn't have encoding, so swap in first
r debug swapin $key
assert_match
"* encoding:
$enc
*"
[
r debug object $key
]
# Swapped out values don't have an encoding, so make sure that
# the value is swapped in before checking the encoding.
set dbg
[
r debug object $key
]
while
{[
string match
"* swapped at:*"
$dbg
]}
{
r debug swapin $key
set dbg
[
r debug object $key
]
}
assert_match
"* encoding:
$enc
*"
$dbg
}
proc assert_type
{
type key
}
{
...
...
tests/support/util.tcl
View file @
aaada3f9
...
...
@@ -44,7 +44,7 @@ proc warnings_from_file {filename} {
# Return value for INFO property
proc status
{
r property
}
{
if
{[
regexp
"
\r\n
$property:
(.*?)
\r\n
"
[
$r
info
]
_ value
]}
{
if
{[
regexp
"
\r\n
$property:
(.*?)
\r\n
"
[
{*}
$r
info
]
_ value
]}
{
set _ $value
}
}
...
...
@@ -127,11 +127,32 @@ proc randomKey {} {
}
}
proc createComplexDataset
{
r ops
}
{
proc findKeyWithType
{
r type
}
{
for
{
set j 0
}
{
$j
< 20
}
{
incr j
}
{
set k
[
{*}
$r
randomkey
]
if
{
$k
eq
{}}
{
return
{}
}
if
{[
{*}
$r
type $k
]
eq $type
}
{
return $k
}
}
return
{}
}
proc createComplexDataset
{
r ops
{
opt
{}}}
{
for
{
set j 0
}
{
$j
< $ops
}
{
incr j
}
{
set k
[
randomKey
]
set k2
[
randomKey
]
set f
[
randomValue
]
set v
[
randomValue
]
if
{[
lsearch -exact $opt useexpire
]
!= -1
}
{
if
{
rand
()
< 0.1
}
{
{*}
$r
expire
[
randomKey
]
[
randomInt 2
]
}
}
randpath
{
set d
[
expr
{
rand
()}]
}
{
...
...
@@ -145,21 +166,23 @@ proc createComplexDataset {r ops} {
}
{
randpath
{
set d +inf
}
{
set d -inf
}
}
set t
[
$r
type $k
]
set t
[
{*}
$r
type $k
]
if
{
$t
eq
{
none
}}
{
randpath
{
$r set $k $v
{*}
$r
set $k $v
}
{
$r lpush $k $v
{*}
$r
lpush $k $v
}
{
$r sadd $k $v
{*}
$r
sadd $k $v
}
{
$r zadd $k $d $v
{*}
$r
zadd $k $d $v
}
{
$r hset $k $f $v
{*}
$r
hset $k $f $v
}
{
{*}
$r
del $k
}
set t
[
$r
type $k
]
set t
[
{*}
$r
type $k
]
}
switch $t
{
...
...
@@ -167,23 +190,45 @@ proc createComplexDataset {r ops} {
# Nothing to do
}
{
list
}
{
randpath
{
$r
lpush $k $v
}
\
{
$r
rpush $k $v
}
\
{
$r
lrem $k 0 $v
}
\
{
$r
rpop $k
}
\
{
$r
lpop $k
}
randpath
{
{*}
$r
lpush $k $v
}
\
{
{*}
$r
rpush $k $v
}
\
{
{*}
$r
lrem $k 0 $v
}
\
{
{*}
$r
rpop $k
}
\
{
{*}
$r
lpop $k
}
}
{
set
}
{
randpath
{
$r
sadd $k $v
}
\
{
$r
srem $k $v
}
randpath
{
{*}
$r
sadd $k $v
}
\
{
{*}
$r
srem $k $v
}
\
{
set otherset
[
findKeyWithType r set
]
if
{
$otherset
ne
{}}
{
randpath
{
{*}
$r
sunionstore $k2 $k $otherset
}
{
{*}
$r
sinterstore $k2 $k $otherset
}
{
{*}
$r
sdiffstore $k2 $k $otherset
}
}
}
}
{
zset
}
{
randpath
{
$r
zadd $k $d $v
}
\
{
$r
zrem $k $v
}
randpath
{
{*}
$r
zadd $k $d $v
}
\
{
{*}
$r
zrem $k $v
}
\
{
set otherzset
[
findKeyWithType r zset
]
if
{
$otherzset
ne
{}}
{
randpath
{
{*}
$r
zunionstore $k2 2 $k $otherzset
}
{
{*}
$r
zinterstore $k2 2 $k $otherzset
}
}
}
}
{
hash
}
{
randpath
{
$r
hset $k $f $v
}
\
{
$r
hdel $k $f
}
randpath
{
{*}
$r
hset $k $f $v
}
\
{
{*}
$r
hdel $k $f
}
}
}
}
...
...
@@ -196,3 +241,52 @@ proc formatCommand {args} {
}
set _ $cmd
}
proc csvdump r
{
set o
{}
foreach k
[
lsort
[
{*}
$r
keys *
]]
{
set type
[
{*}
$r
type $k
]
append o
[
csvstring $k
]
,
[
csvstring $type
]
,
switch $type
{
string
{
append o
[
csvstring
[
{*}
$r
get $k
]]
"
\n
"
}
list
{
foreach e
[
{*}
$r
lrange $k 0 -1
]
{
append o
[
csvstring $e
]
,
}
append o
"
\n
"
}
set
{
foreach e
[
lsort
[
{*}
$r
smembers $k
]]
{
append o
[
csvstring $e
]
,
}
append o
"
\n
"
}
zset
{
foreach e
[
{*}
$r
zrange $k 0 -1 withscores
]
{
append o
[
csvstring $e
]
,
}
append o
"
\n
"
}
hash
{
set fields
[
{*}
$r
hgetall $k
]
set newfields
{}
foreach
{
k v
}
$fields
{
lappend newfields
[
list $k $v
]
}
set fields
[
lsort -index 0 $newfields
]
foreach kv $fields
{
append o
[
csvstring
[
lindex $kv 0
]]
,
append o
[
csvstring
[
lindex $kv 1
]]
,
}
append o
"
\n
"
}
}
}
return $o
}
proc csvstring s
{
return
"
\"
$s
\"
"
}
tests/test_helper.tcl
View file @
aaada3f9
...
...
@@ -102,13 +102,13 @@ proc main {} {
execute_tests
"unit/expire"
execute_tests
"unit/other"
execute_tests
"unit/cas"
cleanup
puts
"
\n
[
expr $::passed+$::failed
]
tests,
$::passed
passed,
$::failed
failed"
if
{
$::failed
> 0
}
{
puts
"
\n
*** WARNING!!!
$::failed
FAILED TESTS ***
\n
"
exit 1
}
cleanup
}
# parse arguments
...
...
tests/unit/basic.tcl
View file @
aaada3f9
...
...
@@ -148,12 +148,11 @@ start_server {tags {"basic"}} {
r get novar2
}
{
foobared
}
test
{
SETNX
will overwrite EXPIREing
key
}
{
test
{
SETNX
against volatile
key
}
{
r set x 10
r expire x 10000
r setnx x 20
r get x
}
{
20
}
list
[
r setnx x 20
]
[
r get x
]
}
{
0 10
}
test
{
EXISTS
}
{
set res
{}
...
...
@@ -362,10 +361,17 @@ start_server {tags {"basic"}} {
list
[
r msetnx x1 xxx y2 yyy
]
[
r get x1
]
[
r get y2
]
}
{
1 xxx yyy
}
test
{
MSETNX should remove all the volatile keys even on failure
}
{
r mset x 1 y 2 z 3
r expire y 10000
r expire z 10000
list
[
r msetnx x A y B z C
]
[
r mget x y z
]
}
{
0
{
1
{}
{}}}
test
{
STRLEN against non existing key
}
{
r strlen notakey
}
{
0
}
test
{
STRLEN against integer
}
{
r set myinteger -555
r strlen myinteger
}
{
4
}
test
{
STRLEN against plain string
}
{
r set mystring
"foozzz0123456789 baz"
r strlen mystring
}
}
tests/unit/cas.tcl
View file @
aaada3f9
...
...
@@ -111,4 +111,25 @@ start_server {tags {"cas"}} {
r ping
r exec
}
{
PONG
}
test
{
WATCH will consider touched keys target of EXPIRE
}
{
r del x
r set x foo
r watch x
r expire x 10
r multi
r ping
r exec
}
{}
test
{
WATCH will not consider touched expired keys
}
{
r del x
r set x foo
r expire x 2
r watch x
after 3000
r multi
r ping
r exec
}
{
PONG
}
}
tests/unit/expire.tcl
View file @
aaada3f9
start_server
{
tags
{
"expire"
}}
{
test
{
EXPIRE -
don't
set timeouts multiple times
}
{
test
{
EXPIRE - set timeouts multiple times
}
{
r set x foobar
set v1
[
r expire x 5
]
set v2
[
r ttl x
]
set v3
[
r expire x 10
]
set v4
[
r ttl x
]
r expire x 4
list $v1 $v2 $v3 $v4
}
{
1 5
0 5
}
}
{
1 5
1 10
}
test
{
EXPIRE - It should be still possible to read 'x'
}
{
r get x
...
...
@@ -19,13 +20,13 @@ start_server {tags {"expire"}} {
}
{{}
0
}
}
test
{
EXPIRE -
Dele
te on
write policy
}
{
test
{
EXPIRE -
wri
te on
expire should work
}
{
r del x
r lpush x foo
r expire x 1000
r lpush x bar
r lrange x 0 -1
}
{
bar
}
}
{
bar
foo
}
test
{
EXPIREAT - Check for EXPIRE alike behavior
}
{
r del x
...
...
@@ -59,4 +60,15 @@ start_server {tags {"expire"}} {
catch
{
r setex z -10 foo
}
e
set _ $e
}
{
*invalid expire*
}
test
{
PERSIST can undo an EXPIRE
}
{
r set x foo
r expire x 50
list
[
r ttl x
]
[
r persist x
]
[
r ttl x
]
[
r get x
]
}
{
50 1 -1 foo
}
test
{
PERSIST returns 0 against non existing or non volatile keys
}
{
r set x foo
list
[
r persist foo
]
[
r persist nokeyatall
]
}
{
0 0
}
}
tests/unit/other.tcl
View file @
aaada3f9
...
...
@@ -46,23 +46,56 @@ start_server {} {
set _ $err
}
{
*invalid*
}
if
{
!
[
catch
{
package require sha1
}]}
{
test
{
Check consistency of different data types after a reload
}
{
r flushdb
createComplexDataset r 10000
set sha1
[
r debug digest
]
r debug reload
set sha1_after
[
r debug digest
]
expr
{
$sha1
eq $sha1_after
}
}
{
1
}
test
{
Same dataset digest if saving/reloading as AOF?
}
{
r bgrewriteaof
waitForBgrewriteaof r
r debug loadaof
set sha1_after
[
r debug digest
]
expr
{
$sha1
eq $sha1_after
}
}
{
1
}
tags
{
consistency
}
{
if
{
!
[
catch
{
package require sha1
}]}
{
test
{
Check consistency of different data types after a reload
}
{
r flushdb
createComplexDataset r 10000
set dump
[
csvdump r
]
set sha1
[
r debug digest
]
r debug reload
set sha1_after
[
r debug digest
]
if
{
$sha1
eq $sha1_after
}
{
set _ 1
}
else
{
set newdump
[
csvdump r
]
puts
"Consistency test failed!"
puts
"You can inspect the two dumps in /tmp/repldump*.txt"
set fd
[
open /tmp/repldump1.txt w
]
puts $fd $dump
close $fd
set fd
[
open /tmp/repldump2.txt w
]
puts $fd $newdump
close $fd
set _ 0
}
}
{
1
}
test
{
Same dataset digest if saving/reloading as AOF?
}
{
r bgrewriteaof
waitForBgrewriteaof r
r debug loadaof
set sha1_after
[
r debug digest
]
if
{
$sha1
eq $sha1_after
}
{
set _ 1
}
else
{
set newdump
[
csvdump r
]
puts
"Consistency test failed!"
puts
"You can inspect the two dumps in /tmp/aofdump*.txt"
set fd
[
open /tmp/aofdump1.txt w
]
puts $fd $dump
close $fd
set fd
[
open /tmp/aofdump2.txt w
]
puts $fd $newdump
close $fd
set _ 0
}
}
{
1
}
}
}
test
{
EXPIRES after a reload
(
snapshot + append only file
)}
{
...
...
tests/unit/type/list.tcl
View file @
aaada3f9
...
...
@@ -5,6 +5,12 @@ start_server {
"list-max-ziplist-entries"
256
}
}
{
# We need a value larger than list-max-ziplist-value to make sure
# the list has the right encoding when it is swapped in again.
array set largevalue
{}
set largevalue
(
ziplist
)
"hello"
set largevalue
(
linkedlist
)
[
string repeat
"hello"
4
]
test
{
LPUSH, RPUSH, LLENGTH, LINDEX - ziplist
}
{
# first lpush then rpush
assert_equal 1
[
r lpush myziplist1 a
]
...
...
@@ -28,28 +34,25 @@ start_server {
}
test
{
LPUSH, RPUSH, LLENGTH, LINDEX - regular list
}
{
# use a string of length 17 to ensure a regular list is used
set large_value
"aaaaaaaaaaaaaaaaa"
# first lpush then rpush
assert_equal 1
[
r lpush mylist1 $large
_
value
]
assert_equal 1
[
r lpush mylist1 $largevalue
(
linkedlist
)
]
assert_encoding linkedlist mylist1
assert_equal 2
[
r rpush mylist1 b
]
assert_equal 3
[
r rpush mylist1 c
]
assert_equal 3
[
r llen mylist1
]
assert_equal $large
_
value
[
r lindex mylist1 0
]
assert_equal $largevalue
(
linkedlist
)
[
r lindex mylist1 0
]
assert_equal b
[
r lindex mylist1 1
]
assert_equal c
[
r lindex mylist1 2
]
# first rpush then lpush
assert_equal 1
[
r rpush mylist2 $large
_
value
]
assert_equal 1
[
r rpush mylist2 $largevalue
(
linkedlist
)
]
assert_encoding linkedlist mylist2
assert_equal 2
[
r lpush mylist2 b
]
assert_equal 3
[
r lpush mylist2 c
]
assert_equal 3
[
r llen mylist2
]
assert_equal c
[
r lindex mylist2 0
]
assert_equal b
[
r lindex mylist2 1
]
assert_equal $large
_
value
[
r lindex mylist2 2
]
assert_equal $largevalue
(
linkedlist
)
[
r lindex mylist2 2
]
}
test
{
DEL a list - ziplist
}
{
...
...
@@ -72,16 +75,14 @@ start_server {
proc create_linkedlist
{
key entries
}
{
r del $key
r rpush $key
"aaaaaaaaaaaaaaaaa"
foreach entry $entries
{
r rpush $key $entry
}
assert_equal
"aaaaaaaaaaaaaaaaa"
[
r lpop $key
]
assert_encoding linkedlist $key
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"BLPOP, BRPOP: single existing list -
$type
"
{
set rd
[
redis_deferring_client
]
create_$type blist
{
a b c d
}
create_$type blist
"
a b
$large
c d
"
$rd blpop blist 1
assert_equal
{
blist a
}
[
$rd
read
]
...
...
@@ -96,8 +97,8 @@ start_server {
test
"BLPOP, BRPOP: multiple existing lists -
$type
"
{
set rd
[
redis_deferring_client
]
create_$type blist1
{
a
b
c
}
create_$type blist2
{
d e f
}
create_$type blist1
"
a
$large
c
"
create_$type blist2
"
d
$larg
e
f
"
$rd blpop blist1 blist2 1
assert_equal
{
blist1 a
}
[
$rd
read
]
...
...
@@ -117,7 +118,7 @@ start_server {
test
"BLPOP, BRPOP: second list has an entry -
$type
"
{
set rd
[
redis_deferring_client
]
r del blist1
create_$type blist2
{
d e f
}
create_$type blist2
"
d
$larg
e
f
"
$rd blpop blist1 blist2 1
assert_equal
{
blist2 d
}
[
$rd
read
]
...
...
@@ -179,26 +180,26 @@ start_server {
assert_equal 0
[
r llen xlist
]
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"LPUSHX, RPUSHX -
$type
"
{
create_$type xlist
{
b
c
}
create_$type xlist
"
$large
c
"
assert_equal 3
[
r rpushx xlist d
]
assert_equal 4
[
r lpushx xlist a
]
assert_equal
{
a
b
c d
}
[
r lrange xlist 0 -1
]
assert_equal
"
a
$large
c d
"
[
r lrange xlist 0 -1
]
}
test
"LINSERT -
$type
"
{
create_$type xlist
{
a
b
c d
}
create_$type xlist
"
a
$large
c d
"
assert_equal 5
[
r linsert xlist before c zz
]
assert_equal
{
a
b
zz c d
}
[
r lrange xlist 0 10
]
assert_equal
"
a
$large
zz c d
"
[
r lrange xlist 0 10
]
assert_equal 6
[
r linsert xlist after c yy
]
assert_equal
{
a
b
zz c yy d
}
[
r lrange xlist 0 10
]
assert_equal
"
a
$large
zz c yy d
"
[
r lrange xlist 0 10
]
assert_equal 7
[
r linsert xlist after d dd
]
assert_equal -1
[
r linsert xlist after bad ddd
]
assert_equal
{
a
b
zz c yy d dd
}
[
r lrange xlist 0 10
]
assert_equal
"
a
$large
zz c yy d dd
"
[
r lrange xlist 0 10
]
assert_equal 8
[
r linsert xlist before a aa
]
assert_equal -1
[
r linsert xlist before bad aaa
]
assert_equal
{
aa a
b
zz c yy d dd
}
[
r lrange xlist 0 10
]
assert_equal
"
aa a
$large
zz c yy d dd
"
[
r lrange xlist 0 10
]
# check inserting integer encoded value
assert_equal 9
[
r linsert xlist before aa 42
]
...
...
@@ -207,14 +208,14 @@ start_server {
}
test
{
LPUSHX, RPUSHX convert from ziplist to list
}
{
set large
_value
"aaaaaaaaaaaaaaaaa"
set large
$largevalue
(
linkedlist
)
# convert when a large value is pushed
create_ziplist xlist a
assert_equal 2
[
r rpushx xlist $large
_value
]
assert_equal 2
[
r rpushx xlist $large
]
assert_encoding linkedlist xlist
create_ziplist xlist a
assert_equal 2
[
r lpushx xlist $large
_value
]
assert_equal 2
[
r lpushx xlist $large
]
assert_encoding linkedlist xlist
# convert when the length threshold is exceeded
...
...
@@ -227,14 +228,14 @@ start_server {
}
test
{
LINSERT convert from ziplist to list
}
{
set large
_value
"aaaaaaaaaaaaaaaaa"
set large
$largevalue
(
linkedlist
)
# convert when a large value is inserted
create_ziplist xlist a
assert_equal 2
[
r linsert xlist before a $large
_value
]
assert_equal 2
[
r linsert xlist before a $large
]
assert_encoding linkedlist xlist
create_ziplist xlist a
assert_equal 2
[
r linsert xlist after a $large
_value
]
assert_equal 2
[
r linsert xlist after a $large
]
assert_encoding linkedlist xlist
# convert when the length threshold is exceeded
...
...
@@ -320,32 +321,38 @@ start_server {
assert_error ERR*
{
r rpush mylist 0
}
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"RPOPLPUSH base case -
$type
"
{
r del mylist1 mylist2
create_$type mylist1
{
a
b
c d
}
create_$type mylist1
"
a
$large
c d
"
assert_equal d
[
r rpoplpush mylist1 mylist2
]
assert_equal c
[
r rpoplpush mylist1 mylist2
]
assert_equal
{
a
b
}
[
r lrange mylist1 0 -1
]
assert_equal
{
c d
}
[
r lrange mylist2 0 -1
]
assert_equal
"
a
$large
"
[
r lrange mylist1 0 -1
]
assert_equal
"
c d
"
[
r lrange mylist2 0 -1
]
assert_encoding ziplist mylist2
}
test
"RPOPLPUSH with the same list as src and dst -
$type
"
{
create_$type mylist
{
a
b
c
}
assert_equal
{
a
b
c
}
[
r lrange mylist 0 -1
]
create_$type mylist
"
a
$large
c
"
assert_equal
"
a
$large
c
"
[
r lrange mylist 0 -1
]
assert_equal c
[
r rpoplpush mylist mylist
]
assert_equal
{
c a
b
}
[
r lrange mylist 0 -1
]
assert_equal
"
c a
$large
"
[
r lrange mylist 0 -1
]
}
foreach othertype
{
ziplist linkedlist
}
{
foreach
{
othertype
otherlarge
}
[
array get largevalue
]
{
test
"RPOPLPUSH with
$type
source and existing target
$othertype
"
{
create_$type srclist
{
a b c
d
}
create_$othertype dstlist
{
x
}
assert_equal
d
[
r rpoplpush srclist dstlist
]
create_$type srclist
"
a b c
$large
"
create_$othertype dstlist
"
$otherlarge
"
assert_equal
$large
[
r rpoplpush srclist dstlist
]
assert_equal c
[
r rpoplpush srclist dstlist
]
assert_equal
{
a b
}
[
r lrange srclist 0 -1
]
assert_equal
{
c d x
}
[
r lrange dstlist 0 -1
]
assert_equal
"a b"
[
r lrange srclist 0 -1
]
assert_equal
"c
$large
$otherlarge
"
[
r lrange dstlist 0 -1
]
# When we rpoplpush'ed a large value, dstlist should be
# converted to the same encoding as srclist.
if
{
$type
eq
"linkedlist"
}
{
assert_encoding linkedlist dstlist
}
}
}
}
...
...
@@ -378,10 +385,10 @@ start_server {
assert_equal
{}
[
r rpoplpush srclist dstlist
]
}
{}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"Basic LPOP/RPOP -
$type
"
{
create_$type mylist
{
0
1 2
}
assert_equal
0
[
r lpop mylist
]
create_$type mylist
"
$large
1 2
"
assert_equal
$large
[
r lpop mylist
]
assert_equal 2
[
r rpop mylist
]
assert_equal 1
[
r lpop mylist
]
assert_equal 0
[
r llen mylist
]
...
...
@@ -416,28 +423,28 @@ start_server {
}
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"LRANGE basics -
$type
"
{
create_$type mylist
{
0
1 2 3 4 5 6 7 8 9
}
create_$type mylist
"
$large
1 2 3 4 5 6 7 8 9
"
assert_equal
{
1 2 3 4 5 6 7 8
}
[
r lrange mylist 1 -2
]
assert_equal
{
7 8 9
}
[
r lrange mylist -3 -1
]
assert_equal
{
4
}
[
r lrange mylist 4 4
]
}
test
"LRANGE inverted indexes -
$type
"
{
create_$type mylist
{
0
1 2 3 4 5 6 7 8 9
}
create_$type mylist
"
$large
1 2 3 4 5 6 7 8 9
"
assert_equal
{}
[
r lrange mylist 6 2
]
}
test
"LRANGE out of range indexes including the full list -
$type
"
{
create_$type mylist
{
1 2 3
}
assert_equal
{
1 2 3
}
[
r lrange mylist -1000 1000
]
create_$type mylist
"
$large
1 2 3
"
assert_equal
"
$large
1 2 3
"
[
r lrange mylist -1000 1000
]
}
test
"LRANGE out of range negative end index -
$type
"
{
create_$type mylist
{
1 2 3
}
assert_equal
{
1
}
[
r lrange mylist 0 -
3
]
assert_equal
{}
[
r lrange mylist 0 -
4
]
create_$type mylist
"
$large
1 2 3
"
assert_equal
$large
[
r lrange mylist 0 -
4
]
assert_equal
{}
[
r lrange mylist 0 -
5
]
}
}
...
...
@@ -445,27 +452,28 @@ start_server {
assert_equal
{}
[
r lrange nosuchkey 0 1
]
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
proc trim_list
{
type min max
}
{
upvar 1 large large
r del mylist
create_$type mylist
{
1 2 3 4
5
}
create_$type mylist
"
1 2 3 4
$large
"
r ltrim mylist $min $max
r lrange mylist 0 -1
}
test
"LTRIM basics -
$type
"
{
assert_equal
{
1
}
[
trim_list $type 0 0
]
assert_equal
{
1 2
}
[
trim_list $type 0 1
]
assert_equal
{
1 2 3
}
[
trim_list $type 0 2
]
assert_equal
{
2 3
}
[
trim_list $type 1 2
]
assert_equal
{
2 3 4
5
}
[
trim_list $type 1 -1
]
assert_equal
{
2 3 4
}
[
trim_list $type 1 -2
]
assert_equal
{
4
5
}
[
trim_list $type -2 -1
]
assert_equal
{
5
}
[
trim_list $type -1 -1
]
assert_equal
{
1 2 3 4
5
}
[
trim_list $type -5 -1
]
assert_equal
{
1 2 3 4
5
}
[
trim_list $type -10 10
]
assert_equal
{
1 2 3 4
5
}
[
trim_list $type 0 5
]
assert_equal
{
1 2 3 4
5
}
[
trim_list $type 0 10
]
assert_equal
"1"
[
trim_list $type 0 0
]
assert_equal
"
1 2
"
[
trim_list $type 0 1
]
assert_equal
"
1 2 3
"
[
trim_list $type 0 2
]
assert_equal
"
2 3
"
[
trim_list $type 1 2
]
assert_equal
"
2 3 4
$large
"
[
trim_list $type 1 -1
]
assert_equal
"
2 3 4
"
[
trim_list $type 1 -2
]
assert_equal
"
4
$large
"
[
trim_list $type -2 -1
]
assert_equal
"
$large
"
[
trim_list $type -1 -1
]
assert_equal
"
1 2 3 4
$large
"
[
trim_list $type -5 -1
]
assert_equal
"
1 2 3 4
$large
"
[
trim_list $type -10 10
]
assert_equal
"
1 2 3 4
$large
"
[
trim_list $type 0 5
]
assert_equal
"
1 2 3 4
$large
"
[
trim_list $type 0 10
]
}
test
"LTRIM out of range negative end index -
$type
"
{
...
...
@@ -478,20 +486,19 @@ start_server {
set mylist
{}
set startlen 32
r del mylist
# Start with the large value to ensure the
# right encoding is used.
r rpush mylist $large
lappend mylist $large
for
{
set i 0
}
{
$i
< $startlen
}
{
incr i
}
{
set str
[
randomInt 9223372036854775807
]
r rpush mylist $str
lappend mylist $str
}
# do a push/pop of a large value to convert to a real list
if
{
$type
eq
"list"
}
{
r rpush mylist
"aaaaaaaaaaaaaaaaa"
r rpop mylist
assert_encoding linkedlist mylist
}
for
{
set i 0
}
{
$i
< 10000
}
{
incr i
}
{
for
{
set i 0
}
{
$i
< 1000
}
{
incr i
}
{
set min
[
expr
{
int
(
rand
()
*$startlen
)}]
set max
[
expr
{
$min
+int
(
rand
()
*$startlen
)}]
set mylist
[
lrange $mylist $min $max
]
...
...
@@ -508,12 +515,12 @@ start_server {
}
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
large
}
[
array get largevalue
]
{
test
"LSET -
$type
"
{
create_$type mylist
{
99 98
97
96 95
}
create_$type mylist
"
99 98
$large
96 95
"
r lset mylist 1 foo
r lset mylist -1 bar
assert_equal
{
99 foo
97
96 bar
}
[
r lrange mylist 0 -1
]
assert_equal
"
99 foo
$large
96 bar
"
[
r lrange mylist 0 -1
]
}
test
"LSET out of range index -
$type
"
{
...
...
@@ -530,38 +537,38 @@ start_server {
assert_error ERR*value*
{
r lset nolist 0 foo
}
}
foreach type
{
ziplist linkedlist
}
{
foreach
{
type
e
}
[
array get largevalue
]
{
test
"LREM remove all the occurrences -
$type
"
{
create_$type mylist
{
foo bar foobar foobared zap bar test foo
}
create_$type mylist
"
$e
foo bar foobar foobared zap bar test foo
"
assert_equal 2
[
r lrem mylist 0 bar
]
assert_equal
{
foo foobar foobared zap test foo
}
[
r lrange mylist 0 -1
]
assert_equal
"
$e
foo foobar foobared zap test foo
"
[
r lrange mylist 0 -1
]
}
test
"LREM remove the first occurrence -
$type
"
{
assert_equal 1
[
r lrem mylist 1 foo
]
assert_equal
{
foobar foobared zap test foo
}
[
r lrange mylist 0 -1
]
assert_equal
"
$e
foobar foobared zap test foo
"
[
r lrange mylist 0 -1
]
}
test
"LREM remove non existing element -
$type
"
{
assert_equal 0
[
r lrem mylist 1 nosuchelement
]
assert_equal
{
foobar foobared zap test foo
}
[
r lrange mylist 0 -1
]
assert_equal
"
$e
foobar foobared zap test foo
"
[
r lrange mylist 0 -1
]
}
test
"LREM starting from tail with negative count -
$type
"
{
create_$type mylist
{
foo bar foobar foobared zap bar test foo foo
}
create_$type mylist
"
$e
foo bar foobar foobared zap bar test foo foo
"
assert_equal 1
[
r lrem mylist -1 bar
]
assert_equal
{
foo bar foobar foobared zap test foo foo
}
[
r lrange mylist 0 -1
]
assert_equal
"
$e
foo bar foobar foobared zap test foo foo
"
[
r lrange mylist 0 -1
]
}
test
"LREM starting from tail with negative count (2) -
$type
"
{
assert_equal 2
[
r lrem mylist -2 foo
]
assert_equal
{
foo bar foobar foobared zap test
}
[
r lrange mylist 0 -1
]
assert_equal
"
$e
foo bar foobar foobared zap test
"
[
r lrange mylist 0 -1
]
}
test
"LREM deleting objects that may be int encoded -
$type
"
{
create_$type myotherlist
{
1 2 3
}
create_$type myotherlist
"
$e
1 2 3
"
assert_equal 1
[
r lrem myotherlist 1 2
]
assert_equal
2
[
r llen myotherlist
]
assert_equal
3
[
r llen myotherlist
]
}
}
}
tests/unit/type/zset.tcl
View file @
aaada3f9
...
...
@@ -433,6 +433,42 @@ start_server {tags {"zset"}} {
list
[
r zinterstore zsetc 2 zseta zsetb aggregate max
]
[
r zrange zsetc 0 -1 withscores
]
}
{
2
{
b 2 c 3
}}
foreach cmd
{
ZUNIONSTORE ZINTERSTORE
}
{
test
"
$cmd
with +inf/-inf scores"
{
r del zsetinf1 zsetinf2
r zadd zsetinf1 +inf key
r zadd zsetinf2 +inf key
r $cmd zsetinf3 2 zsetinf1 zsetinf2
assert_equal inf
[
r zscore zsetinf3 key
]
r zadd zsetinf1 -inf key
r zadd zsetinf2 +inf key
r $cmd zsetinf3 2 zsetinf1 zsetinf2
assert_equal 0
[
r zscore zsetinf3 key
]
r zadd zsetinf1 +inf key
r zadd zsetinf2 -inf key
r $cmd zsetinf3 2 zsetinf1 zsetinf2
assert_equal 0
[
r zscore zsetinf3 key
]
r zadd zsetinf1 -inf key
r zadd zsetinf2 -inf key
r $cmd zsetinf3 2 zsetinf1 zsetinf2
assert_equal -inf
[
r zscore zsetinf3 key
]
}
test
"
$cmd
with NaN weights"
{
r del zsetinf1 zsetinf2
r zadd zsetinf1 1.0 key
r zadd zsetinf2 1.0 key
assert_error
"*weight value is not a double*"
{
r $cmd zsetinf3 2 zsetinf1 zsetinf2 weights nan nan
}
}
}
tags
{
"slow"
}
{
test
{
ZSETs skiplist implementation backlink consistency test
}
{
set diff 0
...
...
@@ -477,22 +513,16 @@ start_server {tags {"zset"}} {
}
{}
}
test
{
ZSET element can't be set to nan with ZADD
}
{
set e
{}
catch
{
r zadd myzset nan abc
}
e
set _ $e
}
{
*Not A Number*
}
test
{
ZSET element can't be set to NaN with ZADD
}
{
assert_error
"*not a double*"
{
r zadd myzset nan abc
}
}
test
{
ZSET element can't be set to nan with ZINCRBY
}
{
set e
{}
catch
{
r zincrby myzset nan abc
}
e
set _ $e
}
{
*Not A Number*
}
test
{
ZSET element can't be set to NaN with ZINCRBY
}
{
assert_error
"*not a double*"
{
r zadd myzset nan abc
}
}
test
{
ZINCRBY calls leading to Nan are refused
}
{
set e
{}
test
{
ZINCRBY calls leading to NaN result in error
}
{
r zincrby myzset +inf abc
catch
{
r zincrby myzset -inf abc
}
e
set _ $e
}
{
*Not A Number*
}
assert_error
"*NaN*"
{
r zincrby myzset -inf abc
}
}
}
Prev
1
2
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