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
96ffb2fe
Commit
96ffb2fe
authored
Jul 02, 2010
by
Pieter Noordhuis
Browse files
merged intset code into the split files
parents
3688d7f3
400aea2b
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
src/Makefile
View file @
96ffb2fe
...
@@ -15,7 +15,7 @@ endif
...
@@ -15,7 +15,7 @@ endif
CCOPT
=
$(CFLAGS)
$(CCLINK)
$(ARCH)
$(PROF)
CCOPT
=
$(CFLAGS)
$(CCLINK)
$(ARCH)
$(PROF)
DEBUG
?=
-g
-rdynamic
-ggdb
DEBUG
?=
-g
-rdynamic
-ggdb
OBJ
=
adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o vm.o pubsub.o multi.o debug.o sort.o
OBJ
=
adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o vm.o pubsub.o multi.o debug.o sort.o
intset.o
BENCHOBJ
=
ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
BENCHOBJ
=
ae.o anet.o redis-benchmark.o sds.o adlist.o zmalloc.o
CLIOBJ
=
anet.o sds.o adlist.o redis-cli.o zmalloc.o linenoise.o
CLIOBJ
=
anet.o sds.o adlist.o redis-cli.o zmalloc.o linenoise.o
CHECKDUMPOBJ
=
redis-check-dump.o lzf_c.o lzf_d.o
CHECKDUMPOBJ
=
redis-check-dump.o lzf_c.o lzf_d.o
...
@@ -54,6 +54,7 @@ sds.o: sds.c sds.h zmalloc.h
...
@@ -54,6 +54,7 @@ sds.o: sds.c sds.h zmalloc.h
sha1.o
:
sha1.c sha1.h
sha1.o
:
sha1.c sha1.h
ziplist.o
:
ziplist.c zmalloc.h ziplist.h
ziplist.o
:
ziplist.c zmalloc.h ziplist.h
zipmap.o
:
zipmap.c zmalloc.h
zipmap.o
:
zipmap.c zmalloc.h
intset.o
:
intset.c zmalloc.h
zmalloc.o
:
zmalloc.c config.h
zmalloc.o
:
zmalloc.c config.h
redis-server
:
$(OBJ)
redis-server
:
$(OBJ)
...
...
src/config.c
View file @
96ffb2fe
...
@@ -199,6 +199,8 @@ void loadServerConfig(char *filename) {
...
@@ -199,6 +199,8 @@ void loadServerConfig(char *filename) {
server
.
list_max_ziplist_entries
=
memtoll
(
argv
[
1
],
NULL
);
server
.
list_max_ziplist_entries
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"list-max-ziplist-value"
)
&&
argc
==
2
){
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"list-max-ziplist-value"
)
&&
argc
==
2
){
server
.
list_max_ziplist_value
=
memtoll
(
argv
[
1
],
NULL
);
server
.
list_max_ziplist_value
=
memtoll
(
argv
[
1
],
NULL
);
}
else
if
(
!
strcasecmp
(
argv
[
0
],
"set-max-intset-entries"
)
&&
argc
==
2
){
server
.
set_max_intset_entries
=
memtoll
(
argv
[
1
],
NULL
);
}
else
{
}
else
{
err
=
"Bad directive or wrong number of arguments"
;
goto
loaderr
;
err
=
"Bad directive or wrong number of arguments"
;
goto
loaderr
;
}
}
...
...
src/intset.c
0 → 100644
View file @
96ffb2fe
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "intset.h"
#include "zmalloc.h"
/* Note that these encodings are ordered, so:
* INTSET_ENC_INT16 < INTSET_ENC_INT32 < INTSET_ENC_INT64. */
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))
/* Accessors for each type of encoding */
#define INTSET_VALUE_ENCODING(__val) (((__val) < INT32_MIN || (__val) > INT32_MAX) ? \
INTSET_ENC_INT64 : (((__val) < INT16_MIN || (__val) > INT16_MAX) ? \
INTSET_ENC_INT32 : INTSET_ENC_INT16))
#define INTSET_GET_ENCODED(__is,__pos,__enc) ((__enc == INTSET_ENC_INT64) ? \
((int64_t*)(__is)->contents)[__pos] : ((__enc == INTSET_ENC_INT32) ? \
((int32_t*)(__is)->contents)[__pos] : ((int16_t*)(__is)->contents)[__pos]))
#define INTSET_GET(__is,__pos) (INTSET_GET_ENCODED(__is,__pos,(__is)->encoding))
#define INTSET_SET(__is,__pos,__val) { \
if ((__is)->encoding == INTSET_ENC_INT64) \
((int64_t*)(__is)->contents)[__pos] = (__val); \
else if ((__is)->encoding == INTSET_ENC_INT32) \
((int32_t*)(__is)->contents)[__pos] = (__val); \
else \
((int16_t*)(__is)->contents)[__pos] = (__val); }
/* Create an empty intset. */
intset
*
intsetNew
(
void
)
{
intset
*
is
=
zmalloc
(
sizeof
(
intset
));
is
->
encoding
=
INTSET_ENC_INT16
;
is
->
length
=
0
;
return
is
;
}
/* Resize the intset */
static
intset
*
intsetResize
(
intset
*
is
,
uint32_t
len
)
{
uint32_t
size
=
len
*
is
->
encoding
;
is
=
zrealloc
(
is
,
sizeof
(
intset
)
+
size
);
return
is
;
}
static
intset
*
intsetUpgrade
(
intset
*
is
,
uint8_t
newenc
,
uint8_t
extra
,
uint8_t
offset
)
{
uint8_t
curenc
=
is
->
encoding
;
int
length
=
is
->
length
;
/* First set new encoding and resize */
is
->
encoding
=
newenc
;
is
=
intsetResize
(
is
,
is
->
length
+
extra
);
/* Upgrade back-to-front so we don't overwrite values */
while
(
length
--
)
INTSET_SET
(
is
,
length
+
offset
,
INTSET_GET_ENCODED
(
is
,
length
,
curenc
));
return
is
;
}
/* Search for the position of "value". Return 1 when the value was found and
* sets "pos" to the position of the value within the intset. Return 0 when
* the value is not present in the intset and sets "pos" to the position
* where "value" can be inserted. */
static
uint8_t
intsetSearch
(
intset
*
is
,
int64_t
value
,
uint32_t
*
pos
)
{
int
min
=
0
,
max
=
is
->
length
-
1
,
mid
=
-
1
;
int64_t
cur
=
-
1
;
/* The value can never be found when the set is empty */
if
(
is
->
length
==
0
)
{
if
(
pos
)
*
pos
=
0
;
return
0
;
}
else
{
/* Check for the case where we know we cannot find the value,
* but do know the insert position. */
if
(
value
>
INTSET_GET
(
is
,
is
->
length
-
1
))
{
if
(
pos
)
*
pos
=
is
->
length
;
return
0
;
}
else
if
(
value
<
INTSET_GET
(
is
,
0
))
{
if
(
pos
)
*
pos
=
0
;
return
0
;
}
}
while
(
max
>=
min
)
{
mid
=
(
min
+
max
)
/
2
;
cur
=
INTSET_GET
(
is
,
mid
);
if
(
value
>
cur
)
{
min
=
mid
+
1
;
}
else
if
(
value
<
cur
)
{
max
=
mid
-
1
;
}
else
{
break
;
}
}
if
(
value
==
cur
)
{
if
(
pos
)
*
pos
=
mid
;
return
1
;
}
else
{
if
(
pos
)
*
pos
=
min
;
return
0
;
}
}
static
void
intsetMoveTail
(
intset
*
is
,
uint32_t
from
,
uint32_t
to
)
{
void
*
src
,
*
dst
;
uint32_t
bytes
=
is
->
length
-
from
;
if
(
is
->
encoding
==
INTSET_ENC_INT64
)
{
src
=
(
int64_t
*
)
is
->
contents
+
from
;
dst
=
(
int64_t
*
)
is
->
contents
+
to
;
bytes
*=
sizeof
(
int64_t
);
}
else
if
(
is
->
encoding
==
INTSET_ENC_INT32
)
{
src
=
(
int32_t
*
)
is
->
contents
+
from
;
dst
=
(
int32_t
*
)
is
->
contents
+
to
;
bytes
*=
sizeof
(
int32_t
);
}
else
{
src
=
(
int16_t
*
)
is
->
contents
+
from
;
dst
=
(
int16_t
*
)
is
->
contents
+
to
;
bytes
*=
sizeof
(
int16_t
);
}
memmove
(
dst
,
src
,
bytes
);
}
/* Insert an integer in the intset */
intset
*
intsetAdd
(
intset
*
is
,
int64_t
value
,
uint8_t
*
success
)
{
uint8_t
valenc
=
INTSET_VALUE_ENCODING
(
value
);
uint32_t
pos
,
offset
;
if
(
success
)
*
success
=
1
;
/* Upgrade encoding if necessary. If we need to upgrade, we know that
* this value should be either appended (if > 0) or prepended (if < 0),
* because it lies outside the range of existing values. */
if
(
valenc
>
is
->
encoding
)
{
offset
=
value
<
0
?
1
:
0
;
is
=
intsetUpgrade
(
is
,
valenc
,
1
,
offset
);
pos
=
(
value
<
0
)
?
0
:
is
->
length
;
}
else
{
/* Abort if the value is already present in the set.
* This call will populate "pos" with the right position to insert
* the value when it cannot be found. */
if
(
intsetSearch
(
is
,
value
,
&
pos
))
{
if
(
success
)
*
success
=
0
;
return
is
;
}
is
=
intsetResize
(
is
,
is
->
length
+
1
);
if
(
pos
<
is
->
length
)
intsetMoveTail
(
is
,
pos
,
pos
+
1
);
}
INTSET_SET
(
is
,
pos
,
value
);
is
->
length
++
;
return
is
;
}
/* Delete integer from intset */
intset
*
intsetRemove
(
intset
*
is
,
int64_t
value
,
uint8_t
*
success
)
{
uint8_t
valenc
=
INTSET_VALUE_ENCODING
(
value
);
uint32_t
pos
;
if
(
success
)
*
success
=
0
;
if
(
valenc
<=
is
->
encoding
&&
intsetSearch
(
is
,
value
,
&
pos
))
{
/* We know we can delete */
if
(
success
)
*
success
=
1
;
/* Overwrite value with tail and update length */
if
(
pos
<
(
is
->
length
-
1
))
intsetMoveTail
(
is
,
pos
+
1
,
pos
);
is
=
intsetResize
(
is
,
is
->
length
-
1
);
is
->
length
--
;
}
return
is
;
}
/* Determine whether a value belongs to this set */
uint8_t
intsetFind
(
intset
*
is
,
int64_t
value
)
{
uint8_t
valenc
=
INTSET_VALUE_ENCODING
(
value
);
return
valenc
<=
is
->
encoding
&&
intsetSearch
(
is
,
value
,
NULL
);
}
/* Return random member */
int64_t
intsetRandom
(
intset
*
is
)
{
return
INTSET_GET
(
is
,
rand
()
%
is
->
length
);
}
/* Sets the value to the value at the given position. When this position is
* out of range the function returns 0, when in range it returns 1. */
uint8_t
intsetGet
(
intset
*
is
,
uint32_t
pos
,
int64_t
*
value
)
{
if
(
pos
<
is
->
length
)
{
*
value
=
INTSET_GET
(
is
,
pos
);
return
1
;
}
return
0
;
}
/* Return intset length */
uint32_t
intsetLen
(
intset
*
is
)
{
return
is
->
length
;
}
#ifdef INTSET_TEST_MAIN
#include <sys/time.h>
void
intsetRepr
(
intset
*
is
)
{
int
i
;
for
(
i
=
0
;
i
<
is
->
length
;
i
++
)
{
printf
(
"%lld
\n
"
,
(
uint64_t
)
INTSET_GET
(
is
,
i
));
}
printf
(
"
\n
"
);
}
void
error
(
char
*
err
)
{
printf
(
"%s
\n
"
,
err
);
exit
(
1
);
}
void
ok
(
void
)
{
printf
(
"OK
\n
"
);
}
long
long
usec
(
void
)
{
struct
timeval
tv
;
gettimeofday
(
&
tv
,
NULL
);
return
(((
long
long
)
tv
.
tv_sec
)
*
1000000
)
+
tv
.
tv_usec
;
}
#define assert(_e) ((_e)?(void)0:(_assert(#_e,__FILE__,__LINE__),exit(1)))
void
_assert
(
char
*
estr
,
char
*
file
,
int
line
)
{
printf
(
"
\n\n
=== ASSERTION FAILED ===
\n
"
);
printf
(
"==> %s:%d '%s' is not true
\n
"
,
file
,
line
,
estr
);
}
intset
*
createSet
(
int
bits
,
int
size
)
{
uint64_t
mask
=
(
1
<<
bits
)
-
1
;
uint64_t
i
,
value
;
intset
*
is
=
intsetNew
();
for
(
i
=
0
;
i
<
size
;
i
++
)
{
if
(
bits
>
32
)
{
value
=
(
rand
()
*
rand
())
&
mask
;
}
else
{
value
=
rand
()
&
mask
;
}
is
=
intsetAdd
(
is
,
value
,
NULL
);
}
return
is
;
}
void
checkConsistency
(
intset
*
is
)
{
int
i
;
for
(
i
=
0
;
i
<
(
is
->
length
-
1
);
i
++
)
{
if
(
is
->
encoding
==
INTSET_ENC_INT16
)
{
int16_t
*
i16
=
(
int16_t
*
)
is
->
contents
;
assert
(
i16
[
i
]
<
i16
[
i
+
1
]);
}
else
if
(
is
->
encoding
==
INTSET_ENC_INT32
)
{
int32_t
*
i32
=
(
int32_t
*
)
is
->
contents
;
assert
(
i32
[
i
]
<
i32
[
i
+
1
]);
}
else
{
int64_t
*
i64
=
(
int64_t
*
)
is
->
contents
;
assert
(
i64
[
i
]
<
i64
[
i
+
1
]);
}
}
}
int
main
(
int
argc
,
char
**
argv
)
{
uint8_t
success
;
int
i
;
intset
*
is
;
sranddev
();
printf
(
"Value encodings: "
);
{
assert
(
INTSET_VALUE_ENCODING
(
-
32768
)
==
INTSET_ENC_INT16
);
assert
(
INTSET_VALUE_ENCODING
(
+
32767
)
==
INTSET_ENC_INT16
);
assert
(
INTSET_VALUE_ENCODING
(
-
32769
)
==
INTSET_ENC_INT32
);
assert
(
INTSET_VALUE_ENCODING
(
+
32768
)
==
INTSET_ENC_INT32
);
assert
(
INTSET_VALUE_ENCODING
(
-
2147483648
)
==
INTSET_ENC_INT32
);
assert
(
INTSET_VALUE_ENCODING
(
+
2147483647
)
==
INTSET_ENC_INT32
);
assert
(
INTSET_VALUE_ENCODING
(
-
2147483649
)
==
INTSET_ENC_INT64
);
assert
(
INTSET_VALUE_ENCODING
(
+
2147483648
)
==
INTSET_ENC_INT64
);
assert
(
INTSET_VALUE_ENCODING
(
-
9223372036854775808ull
)
==
INTSET_ENC_INT64
);
assert
(
INTSET_VALUE_ENCODING
(
+
9223372036854775807ull
)
==
INTSET_ENC_INT64
);
ok
();
}
printf
(
"Basic adding: "
);
{
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
5
,
&
success
);
assert
(
success
);
is
=
intsetAdd
(
is
,
6
,
&
success
);
assert
(
success
);
is
=
intsetAdd
(
is
,
4
,
&
success
);
assert
(
success
);
is
=
intsetAdd
(
is
,
4
,
&
success
);
assert
(
!
success
);
ok
();
}
printf
(
"Large number of random adds: "
);
{
int
inserts
=
0
;
is
=
intsetNew
();
for
(
i
=
0
;
i
<
1024
;
i
++
)
{
is
=
intsetAdd
(
is
,
rand
()
%
0x800
,
&
success
);
if
(
success
)
inserts
++
;
}
assert
(
is
->
length
==
inserts
);
checkConsistency
(
is
);
ok
();
}
printf
(
"Upgrade from int16 to int32: "
);
{
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
32
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT16
);
is
=
intsetAdd
(
is
,
65535
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT32
);
assert
(
intsetFind
(
is
,
32
));
assert
(
intsetFind
(
is
,
65535
));
checkConsistency
(
is
);
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
32
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT16
);
is
=
intsetAdd
(
is
,
-
65535
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT32
);
assert
(
intsetFind
(
is
,
32
));
assert
(
intsetFind
(
is
,
-
65535
));
checkConsistency
(
is
);
ok
();
}
printf
(
"Upgrade from int16 to int64: "
);
{
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
32
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT16
);
is
=
intsetAdd
(
is
,
4294967295
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT64
);
assert
(
intsetFind
(
is
,
32
));
assert
(
intsetFind
(
is
,
4294967295
));
checkConsistency
(
is
);
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
32
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT16
);
is
=
intsetAdd
(
is
,
-
4294967295
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT64
);
assert
(
intsetFind
(
is
,
32
));
assert
(
intsetFind
(
is
,
-
4294967295
));
checkConsistency
(
is
);
ok
();
}
printf
(
"Upgrade from int32 to int64: "
);
{
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
65535
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT32
);
is
=
intsetAdd
(
is
,
4294967295
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT64
);
assert
(
intsetFind
(
is
,
65535
));
assert
(
intsetFind
(
is
,
4294967295
));
checkConsistency
(
is
);
is
=
intsetNew
();
is
=
intsetAdd
(
is
,
65535
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT32
);
is
=
intsetAdd
(
is
,
-
4294967295
,
NULL
);
assert
(
is
->
encoding
==
INTSET_ENC_INT64
);
assert
(
intsetFind
(
is
,
65535
));
assert
(
intsetFind
(
is
,
-
4294967295
));
checkConsistency
(
is
);
ok
();
}
printf
(
"Stress lookups: "
);
{
long
num
=
100000
,
size
=
10000
;
int
i
,
bits
=
20
;
long
long
start
;
is
=
createSet
(
bits
,
size
);
checkConsistency
(
is
);
start
=
usec
();
for
(
i
=
0
;
i
<
num
;
i
++
)
intsetSearch
(
is
,
rand
()
%
((
1
<<
bits
)
-
1
),
NULL
);
printf
(
"%ld lookups, %ld element set, %lldusec
\n
"
,
num
,
size
,
usec
()
-
start
);
}
printf
(
"Stress add+delete: "
);
{
int
i
,
v1
,
v2
;
is
=
intsetNew
();
for
(
i
=
0
;
i
<
0xffff
;
i
++
)
{
v1
=
rand
()
%
0xfff
;
is
=
intsetAdd
(
is
,
v1
,
NULL
);
assert
(
intsetFind
(
is
,
v1
));
v2
=
rand
()
%
0xfff
;
is
=
intsetRemove
(
is
,
v2
,
NULL
);
assert
(
!
intsetFind
(
is
,
v2
));
}
checkConsistency
(
is
);
ok
();
}
}
#endif
src/intset.h
0 → 100644
View file @
96ffb2fe
#ifndef __INTSET_H
#define __INTSET_H
#include <stdint.h>
typedef
struct
intset
{
uint32_t
encoding
;
uint32_t
length
;
int8_t
contents
[];
}
intset
;
intset
*
intsetNew
(
void
);
intset
*
intsetAdd
(
intset
*
is
,
int64_t
value
,
uint8_t
*
success
);
intset
*
intsetRemove
(
intset
*
is
,
int64_t
value
,
uint8_t
*
success
);
uint8_t
intsetFind
(
intset
*
is
,
int64_t
value
);
int64_t
intsetRandom
(
intset
*
is
);
uint8_t
intsetGet
(
intset
*
is
,
uint32_t
pos
,
int64_t
*
value
);
uint32_t
intsetLen
(
intset
*
is
);
#endif // __INTSET_H
src/object.c
View file @
96ffb2fe
...
@@ -73,7 +73,16 @@ robj *createZiplistObject(void) {
...
@@ -73,7 +73,16 @@ robj *createZiplistObject(void) {
robj
*
createSetObject
(
void
)
{
robj
*
createSetObject
(
void
)
{
dict
*
d
=
dictCreate
(
&
setDictType
,
NULL
);
dict
*
d
=
dictCreate
(
&
setDictType
,
NULL
);
return
createObject
(
REDIS_SET
,
d
);
robj
*
o
=
createObject
(
REDIS_SET
,
d
);
o
->
encoding
=
REDIS_ENCODING_HT
;
return
o
;
}
robj
*
createIntsetObject
(
void
)
{
intset
*
is
=
intsetNew
();
robj
*
o
=
createObject
(
REDIS_SET
,
is
);
o
->
encoding
=
REDIS_ENCODING_INTSET
;
return
o
;
}
}
robj
*
createHashObject
(
void
)
{
robj
*
createHashObject
(
void
)
{
...
@@ -114,7 +123,16 @@ void freeListObject(robj *o) {
...
@@ -114,7 +123,16 @@ void freeListObject(robj *o) {
}
}
void
freeSetObject
(
robj
*
o
)
{
void
freeSetObject
(
robj
*
o
)
{
dictRelease
((
dict
*
)
o
->
ptr
);
switch
(
o
->
encoding
)
{
case
REDIS_ENCODING_HT
:
dictRelease
((
dict
*
)
o
->
ptr
);
break
;
case
REDIS_ENCODING_INTSET
:
zfree
(
o
->
ptr
);
break
;
default:
redisPanic
(
"Unknown set encoding type"
);
}
}
}
void
freeZsetObject
(
robj
*
o
)
{
void
freeZsetObject
(
robj
*
o
)
{
...
@@ -356,7 +374,7 @@ int getLongLongFromObject(robj *o, long long *target) {
...
@@ -356,7 +374,7 @@ int getLongLongFromObject(robj *o, long long *target) {
}
}
}
}
*
target
=
value
;
if
(
target
)
*
target
=
value
;
return
REDIS_OK
;
return
REDIS_OK
;
}
}
...
@@ -400,6 +418,7 @@ char *strEncoding(int encoding) {
...
@@ -400,6 +418,7 @@ char *strEncoding(int encoding) {
case
REDIS_ENCODING_ZIPMAP
:
return
"zipmap"
;
case
REDIS_ENCODING_ZIPMAP
:
return
"zipmap"
;
case
REDIS_ENCODING_LINKEDLIST
:
return
"linkedlist"
;
case
REDIS_ENCODING_LINKEDLIST
:
return
"linkedlist"
;
case
REDIS_ENCODING_ZIPLIST
:
return
"ziplist"
;
case
REDIS_ENCODING_ZIPLIST
:
return
"ziplist"
;
case
REDIS_ENCODING_INTSET
:
return
"intset"
;
default:
return
"unknown"
;
default:
return
"unknown"
;
}
}
}
}
src/rdb.c
View file @
96ffb2fe
...
@@ -260,17 +260,29 @@ int rdbSaveObject(FILE *fp, robj *o) {
...
@@ -260,17 +260,29 @@ int rdbSaveObject(FILE *fp, robj *o) {
}
}
}
else
if
(
o
->
type
==
REDIS_SET
)
{
}
else
if
(
o
->
type
==
REDIS_SET
)
{
/* Save a set value */
/* Save a set value */
dict
*
set
=
o
->
ptr
;
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
{
dictIterator
*
di
=
dictGetIterator
(
set
);
dict
*
set
=
o
->
ptr
;
dictEntry
*
de
;
dictIterator
*
di
=
dictGetIterator
(
set
);
dictEntry
*
de
;
if
(
rdbSaveLen
(
fp
,
dictSize
(
set
))
==
-
1
)
return
-
1
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
eleobj
=
dictGetEntryKey
(
de
);
if
(
rdbSaveStringObject
(
fp
,
eleobj
)
==
-
1
)
return
-
1
;
if
(
rdbSaveLen
(
fp
,
dictSize
(
set
))
==
-
1
)
return
-
1
;
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
robj
*
eleobj
=
dictGetEntryKey
(
de
);
if
(
rdbSaveStringObject
(
fp
,
eleobj
)
==
-
1
)
return
-
1
;
}
dictReleaseIterator
(
di
);
}
else
if
(
o
->
encoding
==
REDIS_ENCODING_INTSET
)
{
intset
*
is
=
o
->
ptr
;
long
long
llval
;
int
i
=
0
;
if
(
rdbSaveLen
(
fp
,
intsetLen
(
is
))
==
-
1
)
return
-
1
;
while
(
intsetGet
(
is
,
i
++
,
&
llval
))
{
if
(
rdbSaveLongLongAsStringObject
(
fp
,
llval
)
==
-
1
)
return
-
1
;
}
}
else
{
redisPanic
(
"Unknown set encoding"
);
}
}
dictReleaseIterator
(
di
);
}
else
if
(
o
->
type
==
REDIS_ZSET
)
{
}
else
if
(
o
->
type
==
REDIS_ZSET
)
{
/* Save a set value */
/* Save a set value */
zset
*
zs
=
o
->
ptr
;
zset
*
zs
=
o
->
ptr
;
...
@@ -628,6 +640,7 @@ int rdbLoadDoubleValue(FILE *fp, double *val) {
...
@@ -628,6 +640,7 @@ int rdbLoadDoubleValue(FILE *fp, double *val) {
robj
*
rdbLoadObject
(
int
type
,
FILE
*
fp
)
{
robj
*
rdbLoadObject
(
int
type
,
FILE
*
fp
)
{
robj
*
o
,
*
ele
,
*
dec
;
robj
*
o
,
*
ele
,
*
dec
;
size_t
len
;
size_t
len
;
unsigned
int
i
;
redisLog
(
REDIS_DEBUG
,
"LOADING OBJECT %d (at %d)
\n
"
,
type
,
ftell
(
fp
));
redisLog
(
REDIS_DEBUG
,
"LOADING OBJECT %d (at %d)
\n
"
,
type
,
ftell
(
fp
));
if
(
type
==
REDIS_STRING
)
{
if
(
type
==
REDIS_STRING
)
{
...
@@ -669,16 +682,39 @@ robj *rdbLoadObject(int type, FILE *fp) {
...
@@ -669,16 +682,39 @@ robj *rdbLoadObject(int type, FILE *fp) {
}
else
if
(
type
==
REDIS_SET
)
{
}
else
if
(
type
==
REDIS_SET
)
{
/* Read list/set value */
/* Read list/set value */
if
((
len
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
if
((
len
=
rdbLoadLen
(
fp
,
NULL
))
==
REDIS_RDB_LENERR
)
return
NULL
;
o
=
createSetObject
();
/* It's faster to expand the dict to the right size asap in order
/* Use a regular set when there are too many entries. */
* to avoid rehashing */
if
(
len
>
server
.
set_max_intset_entries
)
{
if
(
len
>
DICT_HT_INITIAL_SIZE
)
o
=
createSetObject
();
dictExpand
(
o
->
ptr
,
len
);
/* It's faster to expand the dict to the right size asap in order
* to avoid rehashing */
if
(
len
>
DICT_HT_INITIAL_SIZE
)
dictExpand
(
o
->
ptr
,
len
);
}
else
{
o
=
createIntsetObject
();
}
/* Load every single element of the list/set */
/* Load every single element of the list/set */
while
(
len
--
)
{
for
(
i
=
0
;
i
<
len
;
i
++
)
{
long
long
llval
;
if
((
ele
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
if
((
ele
=
rdbLoadEncodedStringObject
(
fp
))
==
NULL
)
return
NULL
;
ele
=
tryObjectEncoding
(
ele
);
ele
=
tryObjectEncoding
(
ele
);
dictAdd
((
dict
*
)
o
->
ptr
,
ele
,
NULL
);
if
(
o
->
encoding
==
REDIS_ENCODING_INTSET
)
{
/* Fetch integer value from element */
if
(
getLongLongFromObject
(
ele
,
&
llval
)
==
REDIS_OK
)
{
o
->
ptr
=
intsetAdd
(
o
->
ptr
,
llval
,
NULL
);
}
else
{
setTypeConvert
(
o
,
REDIS_ENCODING_HT
);
dictExpand
(
o
->
ptr
,
len
);
}
}
/* This will also be called when the set was just converted
* to regular hashtable encoded set */
if
(
o
->
encoding
==
REDIS_ENCODING_HT
)
{
dictAdd
((
dict
*
)
o
->
ptr
,
ele
,
NULL
);
}
}
}
}
else
if
(
type
==
REDIS_ZSET
)
{
}
else
if
(
type
==
REDIS_ZSET
)
{
/* Read list/set value */
/* Read list/set value */
...
...
src/redis.c
View file @
96ffb2fe
...
@@ -731,6 +731,7 @@ void initServerConfig() {
...
@@ -731,6 +731,7 @@ void initServerConfig() {
server
.
hash_max_zipmap_value
=
REDIS_HASH_MAX_ZIPMAP_VALUE
;
server
.
hash_max_zipmap_value
=
REDIS_HASH_MAX_ZIPMAP_VALUE
;
server
.
list_max_ziplist_entries
=
REDIS_LIST_MAX_ZIPLIST_ENTRIES
;
server
.
list_max_ziplist_entries
=
REDIS_LIST_MAX_ZIPLIST_ENTRIES
;
server
.
list_max_ziplist_value
=
REDIS_LIST_MAX_ZIPLIST_VALUE
;
server
.
list_max_ziplist_value
=
REDIS_LIST_MAX_ZIPLIST_VALUE
;
server
.
set_max_intset_entries
=
REDIS_SET_MAX_INTSET_ENTRIES
;
server
.
shutdown_asap
=
0
;
server
.
shutdown_asap
=
0
;
resetServerSaveParams
();
resetServerSaveParams
();
...
...
src/redis.h
View file @
96ffb2fe
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
#include "anet.h"
/* Networking the easy way */
#include "anet.h"
/* Networking the easy way */
#include "zipmap.h"
/* Compact string -> string data structure */
#include "zipmap.h"
/* Compact string -> string data structure */
#include "ziplist.h"
/* Compact list data structure */
#include "ziplist.h"
/* Compact list data structure */
#include "intset.h"
/* Compact integer set structure */
#include "version.h"
#include "version.h"
/* Error codes */
/* Error codes */
...
@@ -81,6 +82,7 @@
...
@@ -81,6 +82,7 @@
#define REDIS_ENCODING_ZIPMAP 3
/* Encoded as zipmap */
#define REDIS_ENCODING_ZIPMAP 3
/* Encoded as zipmap */
#define REDIS_ENCODING_LINKEDLIST 4
/* Encoded as regular linked list */
#define REDIS_ENCODING_LINKEDLIST 4
/* Encoded as regular linked list */
#define REDIS_ENCODING_ZIPLIST 5
/* Encoded as ziplist */
#define REDIS_ENCODING_ZIPLIST 5
/* Encoded as ziplist */
#define REDIS_ENCODING_INTSET 6
/* Encoded as intset */
/* Object types only used for dumping to disk */
/* Object types only used for dumping to disk */
#define REDIS_EXPIRETIME 253
#define REDIS_EXPIRETIME 253
...
@@ -187,6 +189,7 @@
...
@@ -187,6 +189,7 @@
#define REDIS_HASH_MAX_ZIPMAP_VALUE 512
#define REDIS_HASH_MAX_ZIPMAP_VALUE 512
#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 1024
#define REDIS_LIST_MAX_ZIPLIST_ENTRIES 1024
#define REDIS_LIST_MAX_ZIPLIST_VALUE 32
#define REDIS_LIST_MAX_ZIPLIST_VALUE 32
#define REDIS_SET_MAX_INTSET_ENTRIES 4096
/* Sets operations codes */
/* Sets operations codes */
#define REDIS_OP_UNION 0
#define REDIS_OP_UNION 0
...
@@ -396,6 +399,7 @@ struct redisServer {
...
@@ -396,6 +399,7 @@ struct redisServer {
size_t
hash_max_zipmap_value
;
size_t
hash_max_zipmap_value
;
size_t
list_max_ziplist_entries
;
size_t
list_max_ziplist_entries
;
size_t
list_max_ziplist_value
;
size_t
list_max_ziplist_value
;
size_t
set_max_intset_entries
;
/* Virtual memory state */
/* Virtual memory state */
FILE
*
vm_fp
;
FILE
*
vm_fp
;
int
vm_fd
;
int
vm_fd
;
...
@@ -533,6 +537,14 @@ typedef struct {
...
@@ -533,6 +537,14 @@ typedef struct {
listNode
*
ln
;
/* Entry in linked list */
listNode
*
ln
;
/* Entry in linked list */
}
listTypeEntry
;
}
listTypeEntry
;
/* Structure to hold set iteration abstraction. */
typedef
struct
{
robj
*
subject
;
int
encoding
;
int
ii
;
/* intset iterator */
dictIterator
*
di
;
}
setIterator
;
/* Structure to hold hash iteration abstration. Note that iteration over
/* Structure to hold hash iteration abstration. Note that iteration over
* hashes involves both fields and values. Because it is possible that
* hashes involves both fields and values. Because it is possible that
* not both are required, store pointers in the iterator to avoid
* not both are required, store pointers in the iterator to avoid
...
@@ -631,6 +643,7 @@ robj *createStringObjectFromLongLong(long long value);
...
@@ -631,6 +643,7 @@ robj *createStringObjectFromLongLong(long long value);
robj
*
createListObject
(
void
);
robj
*
createListObject
(
void
);
robj
*
createZiplistObject
(
void
);
robj
*
createZiplistObject
(
void
);
robj
*
createSetObject
(
void
);
robj
*
createSetObject
(
void
);
robj
*
createIntsetObject
(
void
);
robj
*
createHashObject
(
void
);
robj
*
createHashObject
(
void
);
robj
*
createZsetObject
(
void
);
robj
*
createZsetObject
(
void
);
int
getLongFromObjectOrReply
(
redisClient
*
c
,
robj
*
o
,
long
*
target
,
const
char
*
msg
);
int
getLongFromObjectOrReply
(
redisClient
*
c
,
robj
*
o
,
long
*
target
,
const
char
*
msg
);
...
@@ -714,6 +727,18 @@ int dontWaitForSwappedKey(redisClient *c, robj *key);
...
@@ -714,6 +727,18 @@ int dontWaitForSwappedKey(redisClient *c, robj *key);
void
handleClientsBlockedOnSwappedKey
(
redisDb
*
db
,
robj
*
key
);
void
handleClientsBlockedOnSwappedKey
(
redisDb
*
db
,
robj
*
key
);
vmpointer
*
vmSwapObjectBlocking
(
robj
*
val
);
vmpointer
*
vmSwapObjectBlocking
(
robj
*
val
);
/* Set data type */
robj
*
setTypeCreate
(
robj
*
value
);
int
setTypeAdd
(
robj
*
subject
,
robj
*
value
);
int
setTypeRemove
(
robj
*
subject
,
robj
*
value
);
int
setTypeIsMember
(
robj
*
subject
,
robj
*
value
);
setIterator
*
setTypeInitIterator
(
robj
*
subject
);
void
setTypeReleaseIterator
(
setIterator
*
si
);
robj
*
setTypeNext
(
setIterator
*
si
);
robj
*
setTypeRandomElement
(
robj
*
subject
);
unsigned
long
setTypeSize
(
robj
*
subject
);
void
setTypeConvert
(
robj
*
subject
,
int
enc
);
/* Hash data type */
/* Hash data type */
void
convertToRealHash
(
robj
*
o
);
void
convertToRealHash
(
robj
*
o
);
void
hashTypeTryConversion
(
robj
*
subject
,
robj
**
argv
,
int
start
,
int
end
);
void
hashTypeTryConversion
(
robj
*
subject
,
robj
**
argv
,
int
start
,
int
end
);
...
...
src/t_set.c
View file @
96ffb2fe
This diff is collapsed.
Click to expand it.
tests/unit/type/set.tcl
View file @
96ffb2fe
start_server
{
tags
{
"set"
}}
{
start_server
{
test
{
SADD, SCARD, SISMEMBER, SMEMBERS basics
}
{
tags
{
"set"
}
r sadd myset foo
overrides
{
r sadd myset bar
"set-max-intset-entries"
512
list
[
r scard myset
]
[
r sismember myset foo
]
\
}
[
r sismember myset bar
]
[
r sismember myset bla
]
\
}
{
[
lsort
[
r smembers myset
]]
proc create_set
{
key entries
}
{
}
{
2 1 1 0
{
bar foo
}}
r del $key
foreach entry $entries
{
r sadd $key $entry
}
test
{
SADD adding the same element multiple times
}
{
}
r sadd myset foo
r sadd myset foo
test
{
SADD, SCARD, SISMEMBER, SMEMBERS basics - regular set
}
{
r sadd myset foo
create_set myset
{
foo
}
r scard myset
assert_encoding hashtable myset
}
{
2
}
assert_equal 1
[
r sadd myset bar
]
assert_equal 0
[
r sadd myset bar
]
assert_equal 2
[
r scard myset
]
assert_equal 1
[
r sismember myset foo
]
assert_equal 1
[
r sismember myset bar
]
assert_equal 0
[
r sismember myset bla
]
assert_equal
{
bar foo
}
[
lsort
[
r smembers myset
]]
}
test
{
SADD, SCARD, SISMEMBER, SMEMBERS basics - intset
}
{
create_set myset
{
17
}
assert_encoding intset myset
assert_equal 1
[
r sadd myset 16
]
assert_equal 0
[
r sadd myset 16
]
assert_equal 2
[
r scard myset
]
assert_equal 1
[
r sismember myset 16
]
assert_equal 1
[
r sismember myset 17
]
assert_equal 0
[
r sismember myset 18
]
assert_equal
{
16 17
}
[
lsort
[
r smembers myset
]]
}
test
{
SADD against non set
}
{
test
{
SADD against non set
}
{
r lpush mylist foo
r lpush mylist foo
catch
{
r sadd mylist bar
}
err
assert_error ERR*kind*
{
r sadd mylist bar
}
format $err
}
}
{
ERR*kind*
}
test
"SADD a non-integer against an intset"
{
test
{
SREM basics
}
{
create_set myset
{
1 2 3
}
r sadd myset ciao
assert_encoding intset myset
r srem myset foo
assert_equal 1
[
r sadd myset a
]
lsort
[
r smembers myset
]
assert_encoding hashtable myset
}
{
bar ciao
}
}
test
{
Mass SADD and SINTER with two sets
}
{
test
"SADD overflows the maximum allowed integers in an intset"
{
for
{
set i 0
}
{
$i
< 1000
}
{
incr i
}
{
r del myset
for
{
set i 0
}
{
$i
< 512
}
{
incr i
}
{
r sadd myset $i
}
assert_encoding intset myset
assert_equal 1
[
r sadd myset 512
]
assert_encoding hashtable myset
}
test
"Set encoding after DEBUG RELOAD"
{
r del myintset myhashset mylargeintset
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
r sadd myintset $i
}
for
{
set i 0
}
{
$i
< 1280
}
{
incr i
}
{
r sadd mylargeintset $i
}
for
{
set i 0
}
{
$i
< 256
}
{
incr i
}
{
r sadd myhashset
[
format
"i%03d"
$i
]
}
assert_encoding intset myintset
assert_encoding hashtable mylargeintset
assert_encoding hashtable myhashset
r debug reload
assert_encoding intset myintset
assert_encoding hashtable mylargeintset
assert_encoding hashtable myhashset
}
test
{
SREM basics - regular set
}
{
create_set myset
{
foo bar ciao
}
assert_encoding hashtable myset
assert_equal 0
[
r srem myset qux
]
assert_equal 1
[
r srem myset foo
]
assert_equal
{
bar ciao
}
[
lsort
[
r smembers myset
]]
}
test
{
SREM basics - intset
}
{
create_set myset
{
3 4 5
}
assert_encoding intset myset
assert_equal 0
[
r srem myset 6
]
assert_equal 1
[
r srem myset 4
]
assert_equal
{
3 5
}
[
lsort
[
r smembers myset
]]
}
foreach
{
type
}
{
hashtable intset
}
{
for
{
set i 1
}
{
$i
<= 5
}
{
incr i
}
{
r del
[
format
"set%d"
$i
]
}
for
{
set i 0
}
{
$i
< 200
}
{
incr i
}
{
r sadd set1 $i
r sadd set1 $i
r sadd set2
[
expr $i+995
]
r sadd set2
[
expr $i+195
]
}
foreach i
{
199 195 1000 2000
}
{
r sadd set3 $i
}
for
{
set i 5
}
{
$i
< 200
}
{
incr i
}
{
r sadd set4 $i
}
}
lsort
[
r sinter set1 set2
]
r sadd set5 0
}
{
995 996 997 998 999
}
test
{
SUNION with two sets
}
{
# it is possible that a hashtable encoded only contains integers,
lsort
[
r sunion set1 set2
]
# because it is converted from an intset to a hashtable when a
}
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
# non-integer element is added and then removed.
if
{
$type
eq
"hashtable"
}
{
for
{
set i 1
}
{
$i
<= 5
}
{
incr i
}
{
r sadd
[
format
"set%d"
$i
]
foo
r srem
[
format
"set%d"
$i
]
foo
}
}
test
{
SINTERSTORE with two sets
}
{
test
"Generated sets must be encoded as
$type
"
{
r sinterstore setres set1 set2
for
{
set i 1
}
{
$i
<= 5
}
{
incr i
}
{
lsort
[
r smembers setres
]
assert_encoding $type
[
format
"set%d"
$i
]
}
{
995 996 997 998 999
}
}
}
test
{
SINTERSTORE with two sets, after a DEBUG RELOAD
}
{
test
"SINTER with two sets -
$type
"
{
r debug reload
assert_equal
{
195 196 197 198 199
}
[
lsort
[
r sinter set1 set2
]]
r sinterstore setres set1 set2
}
lsort
[
r smembers setres
]
}
{
995 996 997 998 999
}
test
"SINTERSTORE with two sets -
$type
"
{
r sinterstore setres set1 set2
assert_encoding intset setres
assert_equal
{
195 196 197 198 199
}
[
lsort
[
r smembers setres
]]
}
test
"SINTERSTORE with two sets, after a DEBUG RELOAD -
$type
"
{
r debug reload
r sinterstore setres set1 set2
assert_encoding intset setres
assert_equal
{
195 196 197 198 199
}
[
lsort
[
r smembers setres
]]
}
test
"SUNION with two sets -
$type
"
{
set expected
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
assert_equal $expected
[
lsort
[
r sunion set1 set2
]]
}
test
"SUNIONSTORE with two sets -
$type
"
{
r sunionstore setres set1 set2
assert_encoding intset setres
set expected
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
assert_equal $expected
[
lsort
[
r smembers setres
]]
}
test
{
SUNIONSTORE with two sets
}
{
test
"SINTER against three sets -
$type
"
{
r sunionstore setres set1 set2
assert_equal
{
195 199
}
[
lsort
[
r sinter set1 set2 set3
]]
lsort
[
r smembers setres
]
}
}
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
test
"SINTERSTORE with three sets -
$type
"
{
r sinterstore setres set1 set2 set3
assert_equal
{
195 199
}
[
r smembers setres
]
}
test
"SUNION with non existing keys -
$type
"
{
set expected
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
assert_equal $expected
[
lsort
[
r sunion nokey1 set1 set2 nokey2
]]
}
test
"SDIFF with two sets -
$type
"
{
assert_equal
{
0 1 2 3 4
}
[
lsort
[
r sdiff set1 set4
]]
}
test
{
SUNIONSTORE against non existing keys
}
{
test
"SDIFF with three sets -
$type
"
{
assert_equal
{
1 2 3 4
}
[
lsort
[
r sdiff set1 set4 set5
]]
}
test
"SDIFFSTORE with three sets -
$type
"
{
r sdiffstore setres set1 set4 set5
assert_encoding intset setres
assert_equal
{
1 2 3 4
}
[
lsort
[
r smembers setres
]]
}
}
test
"SINTER against non-set should throw error"
{
r set key1 x
assert_error
"ERR*wrong kind*"
{
r sinter key1 noset
}
}
test
"SUNION against non-set should throw error"
{
r set key1 x
assert_error
"ERR*wrong kind*"
{
r sunion key1 noset
}
}
test
"SINTERSTORE against non existing keys should delete dstkey"
{
r set setres xxx
r set setres xxx
list
[
r sunionstore setres foo111 bar222
]
[
r exists xxx
]
assert_equal 0
[
r sinterstore setres foo111 bar222
]
}
{
0 0
}
assert_equal 0
[
r exists setres
]
}
test
{
SINTER against three sets
}
{
r sadd set3 999
test
"SUNIONSTORE against non existing keys should delete dstkey"
{
r sadd set3 995
r set setres xxx
r sadd set3 1000
assert_equal 0
[
r sunionstore setres foo111 bar222
]
r sadd set3 2000
assert_equal 0
[
r exists setres
]
lsort
[
r sinter set1 set2 set3
]
}
}
{
995 999
}
foreach
{
type contents
}
{
hashtable
{
a b c
}
intset
{
1 2 3
}}
{
test
{
SINTERSTORE with three sets
}
{
test
"SPOP basics -
$type
"
{
r sinterstore setres set1 set2 set3
create_set myset $contents
lsort
[
r smembers setres
]
assert_encoding $type myset
}
{
995 999
}
assert_equal $contents
[
lsort
[
list
[
r spop myset
]
[
r spop myset
]
[
r spop myset
]]]
assert_equal 0
[
r scard myset
]
test
{
SUNION with non existing keys
}
{
lsort
[
r sunion nokey1 set1 set2 nokey2
]
}
[
lsort -uniq
"
[
r smembers set1
]
[
r smembers set2
]
"
]
test
{
SDIFF with two sets
}
{
for
{
set i 5
}
{
$i
< 1000
}
{
incr i
}
{
r sadd set4 $i
}
}
lsort
[
r sdiff set1 set4
]
}
{
0 1 2 3 4
}
test
{
SDIFF with three sets
}
{
test
"SRANDMEMBER -
$type
"
{
r sadd set5 0
create_set myset $contents
lsort
[
r sdiff set1 set4 set5
]
unset -nocomplain myset
}
{
1 2 3 4
}
array set myset
{}
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set myset
([
r srandmember myset
])
1
}
assert_equal $contents
[
lsort
[
array names myset
]]
}
}
test
{
SDIFFSTORE with three sets
}
{
proc setup_move
{}
{
r sdiffstore sres set1 set4 set5
r del myset3 myset4
lsort
[
r smembers sres
]
create_set myset1
{
1 a b
}
}
{
1 2 3 4
}
create_set myset2
{
2 3 4
}
assert_encoding hashtable myset1
assert_encoding intset myset2
}
test
{
SPOP basics
}
{
test
"SMOVE basics - from regular set to intset"
{
r del myset
# move a non-integer element to an intset should convert encoding
r sadd myset 1
setup_move
r sadd myset 2
assert_equal 1
[
r smove myset1 myset2 a
]
r sadd myset 3
assert_equal
{
1 b
}
[
lsort
[
r smembers myset1
]]
list
[
lsort
[
list
[
r spop myset
]
[
r spop myset
]
[
r spop myset
]]]
[
r scard myset
]
assert_equal
{
2 3 4 a
}
[
lsort
[
r smembers myset2
]]
}
{{
1 2 3
}
0
}
assert_encoding hashtable myset2
test
{
SRANDMEMBER
}
{
# move an integer element should not convert the encoding
r del myset
setup_move
r sadd myset a
assert_equal 1
[
r smove myset1 myset2 1
]
r sadd myset b
assert_equal
{
a b
}
[
lsort
[
r smembers myset1
]]
r sadd myset c
assert_equal
{
1 2 3 4
}
[
lsort
[
r smembers myset2
]]
unset -nocomplain myset
assert_encoding intset myset2
array set myset
{}
}
for
{
set i 0
}
{
$i
< 100
}
{
incr i
}
{
set myset
([
r srandmember myset
])
1
test
"SMOVE basics - from intset to regular set"
{
}
setup_move
lsort
[
array names myset
]
assert_equal 1
[
r smove myset2 myset1 2
]
}
{
a b c
}
assert_equal
{
1 2 a b
}
[
lsort
[
r smembers myset1
]]
assert_equal
{
3 4
}
[
lsort
[
r smembers myset2
]]
test
{
SMOVE basics
}
{
}
r sadd myset1 a
r sadd myset1 b
test
"SMOVE non existing key"
{
r sadd myset1 c
setup_move
r sadd myset2 x
assert_equal 0
[
r smove myset1 myset2 foo
]
r sadd myset2 y
assert_equal
{
1 a b
}
[
lsort
[
r smembers myset1
]]
r sadd myset2 z
assert_equal
{
2 3 4
}
[
lsort
[
r smembers myset2
]]
r smove myset1 myset2 a
}
list
[
lsort
[
r smembers myset2
]]
[
lsort
[
r smembers myset1
]]
}
{{
a x y z
}
{
b c
}}
test
"SMOVE non existing src set"
{
setup_move
test
{
SMOVE non existing key
}
{
assert_equal 0
[
r smove noset myset2 foo
]
list
[
r smove myset1 myset2 foo
]
[
lsort
[
r smembers myset2
]]
[
lsort
[
r smembers myset1
]]
assert_equal
{
2 3 4
}
[
lsort
[
r smembers myset2
]]
}
{
0
{
a x y z
}
{
b c
}}
}
test
{
SMOVE non existing src set
}
{
test
"SMOVE from regular set to non existing destination set"
{
list
[
r smove noset myset2 foo
]
[
lsort
[
r smembers myset2
]]
setup_move
}
{
0
{
a x y z
}}
assert_equal 1
[
r smove myset1 myset3 a
]
assert_equal
{
1 b
}
[
lsort
[
r smembers myset1
]]
test
{
SMOVE non existing dst set
}
{
assert_equal
{
a
}
[
lsort
[
r smembers myset3
]]
list
[
r smove myset2 myset3 y
]
[
lsort
[
r smembers myset2
]]
[
lsort
[
r smembers myset3
]]
assert_encoding hashtable myset3
}
{
1
{
a x z
}
y
}
}
test
{
SMOVE wrong src key type
}
{
test
"SMOVE from intset to non existing destination set"
{
setup_move
assert_equal 1
[
r smove myset2 myset3 2
]
assert_equal
{
3 4
}
[
lsort
[
r smembers myset2
]]
assert_equal
{
2
}
[
lsort
[
r smembers myset3
]]
assert_encoding intset myset3
}
test
"SMOVE wrong src key type"
{
r set x 10
r set x 10
catch
{
r smove x myset2 foo
}
err
assert_error
"ERR*wrong kind*"
{
r smove x myset2 foo
}
format $err
}
}
{
ERR*
}
test
{
SMOVE wrong dst key type
}
{
test
"
SMOVE wrong dst key type
"
{
r set x 10
r set x 10
catch
{
r smove myset2 x foo
}
err
assert_error
"ERR*wrong kind*"
{
r smove myset2 x foo
}
format $err
}
}
{
ERR*
}
}
}
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