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
2830ca53
Commit
2830ca53
authored
Mar 09, 2010
by
Pieter Noordhuis
Browse files
replaced ZMERGE by ZUNION and ZINTER. note: key preloading by the VM does not yet work
parent
b287c9bb
Changes
2
Hide whitespace changes
Inline
Side-by-side
redis.c
View file @
2830ca53
...
@@ -675,8 +675,8 @@ static void substrCommand(redisClient *c);
...
@@ -675,8 +675,8 @@ static void substrCommand(redisClient *c);
static
void
zrankCommand
(
redisClient
*
c
);
static
void
zrankCommand
(
redisClient
*
c
);
static
void
hsetCommand
(
redisClient
*
c
);
static
void
hsetCommand
(
redisClient
*
c
);
static
void
hgetCommand
(
redisClient
*
c
);
static
void
hgetCommand
(
redisClient
*
c
);
static
void
z
merge
Command
(
redisClient
*
c
);
static
void
z
union
Command
(
redisClient
*
c
);
static
void
z
mergeweighed
Command
(
redisClient
*
c
);
static
void
z
inter
Command
(
redisClient
*
c
);
/*================================= Globals ================================= */
/*================================= Globals ================================= */
...
@@ -724,8 +724,8 @@ static struct redisCommand cmdTable[] = {
...
@@ -724,8 +724,8 @@ static struct redisCommand cmdTable[] = {
{
"zincrby"
,
zincrbyCommand
,
4
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
1
,
1
,
1
},
{
"zincrby"
,
zincrbyCommand
,
4
,
REDIS_CMD_BULK
|
REDIS_CMD_DENYOOM
,
1
,
1
,
1
},
{
"zrem"
,
zremCommand
,
3
,
REDIS_CMD_BULK
,
1
,
1
,
1
},
{
"zrem"
,
zremCommand
,
3
,
REDIS_CMD_BULK
,
1
,
1
,
1
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zremrangebyscore"
,
zremrangebyscoreCommand
,
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"z
merge"
,
zmerge
Command
,
-
3
,
REDIS_CMD_INLINE
|
REDIS_CMD_DENYOOM
,
2
,
-
1
,
1
},
{
"z
union"
,
zunion
Command
,
-
4
,
REDIS_CMD_INLINE
|
REDIS_CMD_DENYOOM
,
0
,
0
,
0
},
{
"z
mergeweighed"
,
zmergeweighed
Command
,
-
4
,
REDIS_CMD_INLINE
|
REDIS_CMD_DENYOOM
,
2
,
-
2
,
2
},
{
"z
inter"
,
zinter
Command
,
-
4
,
REDIS_CMD_INLINE
|
REDIS_CMD_DENYOOM
,
0
,
0
,
0
},
{
"zrange"
,
zrangeCommand
,
-
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zrange"
,
zrangeCommand
,
-
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zrangebyscore"
,
zrangebyscoreCommand
,
-
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zcount"
,
zcountCommand
,
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
{
"zcount"
,
zcountCommand
,
4
,
REDIS_CMD_INLINE
,
1
,
1
,
1
},
...
@@ -4771,6 +4771,7 @@ static void sinterstoreCommand(redisClient *c) {
...
@@ -4771,6 +4771,7 @@ static void sinterstoreCommand(redisClient *c) {
#define REDIS_OP_UNION 0
#define REDIS_OP_UNION 0
#define REDIS_OP_DIFF 1
#define REDIS_OP_DIFF 1
#define REDIS_OP_INTER 2
static
void
sunionDiffGenericCommand
(
redisClient
*
c
,
robj
**
setskeys
,
int
setsnum
,
robj
*
dstkey
,
int
op
)
{
static
void
sunionDiffGenericCommand
(
redisClient
*
c
,
robj
**
setskeys
,
int
setsnum
,
robj
*
dstkey
,
int
op
)
{
dict
**
dv
=
zmalloc
(
sizeof
(
dict
*
)
*
setsnum
);
dict
**
dv
=
zmalloc
(
sizeof
(
dict
*
)
*
setsnum
);
...
@@ -5329,103 +5330,166 @@ static void zremrangebyscoreCommand(redisClient *c) {
...
@@ -5329,103 +5330,166 @@ static void zremrangebyscoreCommand(redisClient *c) {
}
}
}
}
/* This command merges 2 or more zsets to a destination. When an element
static
void
zunionInterGenericCommand
(
redisClient
*
c
,
robj
*
dstkey
,
int
op
)
{
* does not exist in a certain set, score 0 is assumed. The score for an
int
i
,
j
,
k
,
zsetnum
;
* element across sets is summed. */
dict
**
srcdicts
;
static
void
zmergeGenericCommand
(
redisClient
*
c
,
int
readweights
)
{
int
i
,
j
,
zsetnum
;
dict
**
srcdict
;
double
*
weights
;
double
*
weights
;
robj
*
dstkey
=
c
->
argv
[
1
],
*
dstobj
;
robj
*
dstobj
;
zset
*
dst
;
zset
*
dst
zset
;
dictIterator
*
di
;
dictIterator
*
di
;
dictEntry
*
de
;
dictEntry
*
de
;
zsetnum
=
c
->
argc
-
2
;
/* expect zsetnum input keys to be given */
if
(
readweights
)
{
zsetnum
=
atoi
(
c
->
argv
[
2
]
->
ptr
);
/* force number of arguments to be even */
if
(
zsetnum
<
1
)
{
if
(
zsetnum
%
2
>
0
)
{
addReplySds
(
c
,
sdsnew
(
"-ERR at least 1 input key is needed for ZUNION/ZINTER
\r\n
"
));
addReplySds
(
c
,
sdsnew
(
"-ERR wrong number of arguments for ZMERGEWEIGHED
\r\n
"
));
return
;
return
;
}
zsetnum
/=
2
;
}
}
if
(
!
zsetnum
)
{
/* test if the expected number of keys would overflow */
if
(
3
+
zsetnum
>
c
->
argc
)
{
addReply
(
c
,
shared
.
syntaxerr
);
addReply
(
c
,
shared
.
syntaxerr
);
return
;
return
;
}
}
srcdict
=
zmalloc
(
sizeof
(
dict
*
)
*
zsetnum
);
/* read keys to be used for input */
srcdicts
=
zmalloc
(
sizeof
(
dict
*
)
*
zsetnum
);
weights
=
zmalloc
(
sizeof
(
double
)
*
zsetnum
);
weights
=
zmalloc
(
sizeof
(
double
)
*
zsetnum
);
for
(
i
=
0
;
i
<
zsetnum
;
i
++
)
{
for
(
i
=
0
,
j
=
3
;
i
<
zsetnum
;
i
++
,
j
++
)
{
if
(
readweights
)
{
j
=
2
+
2
*
i
;
weights
[
i
]
=
strtod
(
c
->
argv
[
j
+
1
]
->
ptr
,
NULL
);
}
else
{
j
=
2
+
i
;
weights
[
i
]
=
1
.
0
;
}
robj
*
zsetobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
j
]);
robj
*
zsetobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
j
]);
if
(
!
zsetobj
)
{
if
(
!
zsetobj
)
{
srcdict
[
i
]
=
NULL
;
srcdict
s
[
i
]
=
NULL
;
}
else
{
}
else
{
if
(
zsetobj
->
type
!=
REDIS_ZSET
)
{
if
(
zsetobj
->
type
!=
REDIS_ZSET
)
{
zfree
(
srcdict
);
zfree
(
srcdict
s
);
zfree
(
weights
);
zfree
(
weights
);
addReply
(
c
,
shared
.
wrongtypeerr
);
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
return
;
}
}
srcdict
[
i
]
=
((
zset
*
)
zsetobj
->
ptr
)
->
dict
;
srcdict
s
[
i
]
=
((
zset
*
)
zsetobj
->
ptr
)
->
dict
;
}
}
/* default all weights to 1 */
weights
[
i
]
=
1
.
0
;
}
}
dstobj
=
createZsetObject
();
/* parse optional extra arguments */
dst
=
dstobj
->
ptr
;
if
(
j
<
c
->
argc
)
{
for
(
i
=
0
;
i
<
zsetnum
;
i
++
)
{
int
remaining
=
c
->
argc
-
j
;
if
(
!
srcdict
[
i
])
continue
;
di
=
dictGetIterator
(
srcdict
[
i
]);
while
(
remaining
)
{
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
if
(
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"weights"
))
{
/* skip key when already processed */
j
++
;
remaining
--
;
if
(
dictFind
(
dst
->
dict
,
dictGetEntryKey
(
de
))
!=
NULL
)
continue
;
if
(
remaining
<
zsetnum
)
{
zfree
(
srcdicts
);
zfree
(
weights
);
addReplySds
(
c
,
sdsnew
(
"-ERR not enough weights for ZUNION/ZINTER
\r\n
"
));
return
;
}
for
(
i
=
0
;
i
<
zsetnum
;
i
++
,
j
++
,
remaining
--
)
{
weights
[
i
]
=
strtod
(
c
->
argv
[
j
]
->
ptr
,
NULL
);
}
}
else
{
zfree
(
srcdicts
);
zfree
(
weights
);
addReply
(
c
,
shared
.
syntaxerr
);
return
;
}
}
}
double
*
score
=
zmalloc
(
sizeof
(
double
));
dstobj
=
createZsetObject
();
*
score
=
0
.
0
;
dstzset
=
dstobj
->
ptr
;
for
(
j
=
0
;
j
<
zsetnum
;
j
++
)
{
if
(
!
srcdict
[
j
])
continue
;
if
(
op
==
REDIS_OP_INTER
)
{
/* store index of smallest zset in variable j */
for
(
i
=
0
,
j
=
0
;
i
<
zsetnum
;
i
++
)
{
if
(
!
srcdicts
[
i
]
||
dictSize
(
srcdicts
[
i
])
==
0
)
{
break
;
}
if
(
dictSize
(
srcdicts
[
i
])
<
dictSize
(
srcdicts
[
j
]))
{
j
=
i
;
}
}
/* skip going over all entries if at least one dict was NULL or empty */
if
(
i
==
zsetnum
)
{
/* precondition: all srcdicts are non-NULL and non-empty */
di
=
dictGetIterator
(
srcdicts
[
j
]);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
double
*
score
=
zmalloc
(
sizeof
(
double
));
*
score
=
0
.
0
;
for
(
k
=
0
;
k
<
zsetnum
;
k
++
)
{
dictEntry
*
other
=
(
k
==
j
)
?
de
:
dictFind
(
srcdicts
[
k
],
dictGetEntryKey
(
de
));
if
(
other
)
{
*
score
=
*
score
+
weights
[
k
]
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
}
else
{
break
;
}
}
dictEntry
*
other
=
dictFind
(
srcdict
[
j
],
dictGetEntryKey
(
de
));
/* skip entry when not present in every source dict */
if
(
other
)
{
if
(
k
!=
zsetnum
)
{
*
score
=
*
score
+
weights
[
j
]
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
zfree
(
score
);
}
else
{
robj
*
o
=
dictGetEntryKey
(
de
);
dictAdd
(
dstzset
->
dict
,
o
,
score
);
incrRefCount
(
o
);
/* added to dictionary */
zslInsert
(
dstzset
->
zsl
,
*
score
,
o
);
incrRefCount
(
o
);
/* added to skiplist */
}
}
}
}
dictReleaseIterator
(
di
);
}
}
else
if
(
op
==
REDIS_OP_UNION
)
{
for
(
i
=
0
;
i
<
zsetnum
;
i
++
)
{
if
(
!
srcdicts
[
i
])
continue
;
di
=
dictGetIterator
(
srcdicts
[
i
]);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
/* skip key when already processed */
if
(
dictFind
(
dstzset
->
dict
,
dictGetEntryKey
(
de
))
!=
NULL
)
continue
;
double
*
score
=
zmalloc
(
sizeof
(
double
));
*
score
=
0
.
0
;
for
(
j
=
0
;
j
<
zsetnum
;
j
++
)
{
if
(
!
srcdicts
[
j
])
continue
;
dictEntry
*
other
=
(
i
==
j
)
?
de
:
dictFind
(
srcdicts
[
j
],
dictGetEntryKey
(
de
));
if
(
other
)
{
*
score
=
*
score
+
weights
[
j
]
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
}
}
robj
*
o
=
dictGetEntryKey
(
de
);
robj
*
o
=
dictGetEntryKey
(
de
);
dictAdd
(
dst
->
dict
,
o
,
score
);
dictAdd
(
dstzset
->
dict
,
o
,
score
);
incrRefCount
(
o
);
/* added to dictionary */
incrRefCount
(
o
);
/* added to dictionary */
zslInsert
(
dst
->
zsl
,
*
score
,
o
);
zslInsert
(
dstzset
->
zsl
,
*
score
,
o
);
incrRefCount
(
o
);
/* added to skiplist */
incrRefCount
(
o
);
/* added to skiplist */
}
dictReleaseIterator
(
di
);
}
}
dictReleaseIterator
(
di
);
}
else
{
/* unknown operator */
redisAssert
(
op
==
REDIS_OP_INTER
||
op
==
REDIS_OP_UNION
);
}
}
deleteKey
(
c
->
db
,
dstkey
);
deleteKey
(
c
->
db
,
dstkey
);
dictAdd
(
c
->
db
->
dict
,
dstkey
,
dstobj
);
dictAdd
(
c
->
db
->
dict
,
dstkey
,
dstobj
);
incrRefCount
(
dstkey
);
incrRefCount
(
dstkey
);
addReplyLong
(
c
,
dst
->
zsl
->
length
);
addReplyLong
(
c
,
dst
zset
->
zsl
->
length
);
server
.
dirty
++
;
server
.
dirty
++
;
zfree
(
srcdict
);
zfree
(
srcdict
s
);
zfree
(
weights
);
zfree
(
weights
);
}
}
static
void
z
merge
Command
(
redisClient
*
c
)
{
static
void
z
union
Command
(
redisClient
*
c
)
{
z
merge
GenericCommand
(
c
,
0
);
z
unionInter
GenericCommand
(
c
,
c
->
argv
[
1
],
REDIS_OP_UNION
);
}
}
static
void
z
mergeweighed
Command
(
redisClient
*
c
)
{
static
void
z
inter
Command
(
redisClient
*
c
)
{
z
merge
GenericCommand
(
c
,
1
);
z
unionInter
GenericCommand
(
c
,
c
->
argv
[
1
],
REDIS_OP_INTER
);
}
}
static
void
zrangeGenericCommand
(
redisClient
*
c
,
int
reverse
)
{
static
void
zrangeGenericCommand
(
redisClient
*
c
,
int
reverse
)
{
...
...
test-redis.tcl
View file @
2830ca53
...
@@ -1462,7 +1462,7 @@ proc main {server port} {
...
@@ -1462,7 +1462,7 @@ proc main {server port} {
list
[
$r
zremrangebyscore zset -inf +inf
]
[
$r
zrange zset 0 -1
]
list
[
$r
zremrangebyscore zset -inf +inf
]
[
$r
zrange zset 0 -1
]
}
{
5
{}}
}
{
5
{}}
test
{
Z
MERGE
basics
}
{
test
{
Z
UNION
basics
}
{
$r del zseta zsetb zsetc
$r del zseta zsetb zsetc
$r zadd zseta 1 a
$r zadd zseta 1 a
$r zadd zseta 2 b
$r zadd zseta 2 b
...
@@ -1470,13 +1470,21 @@ proc main {server port} {
...
@@ -1470,13 +1470,21 @@ proc main {server port} {
$r zadd zsetb 1 b
$r zadd zsetb 1 b
$r zadd zsetb 2 c
$r zadd zsetb 2 c
$r zadd zsetb 3 d
$r zadd zsetb 3 d
list
[
$r
z
merge
zsetc zseta zsetb
]
[
$r
zrange zsetc 0 -1 withscores
]
list
[
$r
z
union
zsetc
2
zseta zsetb
]
[
$r
zrange zsetc 0 -1 withscores
]
}
{
4
{
a 1 b 3 d 3 c 5
}}
}
{
4
{
a 1 b 3 d 3 c 5
}}
test
{
Z
MERGEWEIGHED basic
s
}
{
test
{
Z
UNION with weight
s
}
{
list
[
$r
z
mergeweighed
zsetc zseta
2
zsetb 3
]
[
$r
zrange zsetc 0 -1 withscores
]
list
[
$r
z
union
zsetc
2
zseta zsetb
weights 2
3
]
[
$r
zrange zsetc 0 -1 withscores
]
}
{
4
{
a 2 b 7 d 9 c 12
}}
}
{
4
{
a 2 b 7 d 9 c 12
}}
test
{
ZINTER basics
}
{
list
[
$r
zinter zsetc 2 zseta zsetb
]
[
$r
zrange zsetc 0 -1 withscores
]
}
{
2
{
b 3 c 5
}}
test
{
ZINTER with weights
}
{
list
[
$r
zinter zsetc 2 zseta zsetb weights 2 3
]
[
$r
zrange zsetc 0 -1 withscores
]
}
{
2
{
b 7 c 12
}}
test
{
SORT against sorted sets
}
{
test
{
SORT against sorted sets
}
{
$r del zset
$r del zset
$r zadd zset 1 a
$r zadd zset 1 a
...
...
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