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
8f92e768
Commit
8f92e768
authored
Mar 09, 2010
by
Pieter Noordhuis
Browse files
use a struct to store both a dict and its weight for ZUNION and ZINTER, so qsort can be applied
parent
2830ca53
Changes
1
Hide whitespace changes
Inline
Side-by-side
redis.c
View file @
8f92e768
...
...
@@ -5330,10 +5330,22 @@ static void zremrangebyscoreCommand(redisClient *c) {
}
}
typedef
struct
{
dict
*
dict
;
double
weight
;
}
zsetopsrc
;
static
int
qsortCompareZsetopsrcByCardinality
(
const
void
*
s1
,
const
void
*
s2
)
{
zsetopsrc
*
d1
=
(
void
*
)
s1
,
*
d2
=
(
void
*
)
s2
;
unsigned
long
size1
,
size2
;
size1
=
d1
->
dict
?
dictSize
(
d1
->
dict
)
:
0
;
size2
=
d2
->
dict
?
dictSize
(
d2
->
dict
)
:
0
;
return
size1
-
size2
;
}
static
void
zunionInterGenericCommand
(
redisClient
*
c
,
robj
*
dstkey
,
int
op
)
{
int
i
,
j
,
k
,
zsetnum
;
dict
**
srcdicts
;
double
*
weights
;
int
i
,
j
,
zsetnum
;
zsetopsrc
*
src
;
robj
*
dstobj
;
zset
*
dstzset
;
dictIterator
*
di
;
...
...
@@ -5353,24 +5365,22 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
}
/* read keys to be used for input */
srcdicts
=
zmalloc
(
sizeof
(
dict
*
)
*
zsetnum
);
weights
=
zmalloc
(
sizeof
(
double
)
*
zsetnum
);
src
=
malloc
(
sizeof
(
zsetopsrc
)
*
zsetnum
);
for
(
i
=
0
,
j
=
3
;
i
<
zsetnum
;
i
++
,
j
++
)
{
robj
*
zsetobj
=
lookupKeyWrite
(
c
->
db
,
c
->
argv
[
j
]);
if
(
!
zsetobj
)
{
srcdict
s
[
i
]
=
NULL
;
src
[
i
].
dict
=
NULL
;
}
else
{
if
(
zsetobj
->
type
!=
REDIS_ZSET
)
{
zfree
(
srcdicts
);
zfree
(
weights
);
zfree
(
src
);
addReply
(
c
,
shared
.
wrongtypeerr
);
return
;
}
srcdict
s
[
i
]
=
((
zset
*
)
zsetobj
->
ptr
)
->
dict
;
src
[
i
].
dict
=
((
zset
*
)
zsetobj
->
ptr
)
->
dict
;
}
/* default all weights to 1 */
weight
s
[
i
]
=
1
.
0
;
src
[
i
].
weight
=
1
.
0
;
}
/* parse optional extra arguments */
...
...
@@ -5381,17 +5391,15 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
if
(
!
strcasecmp
(
c
->
argv
[
j
]
->
ptr
,
"weights"
))
{
j
++
;
remaining
--
;
if
(
remaining
<
zsetnum
)
{
zfree
(
srcdicts
);
zfree
(
weights
);
zfree
(
src
);
addReplySds
(
c
,
sdsnew
(
"-ERR not enough weights for ZUNION/ZINTER
\r\n
"
));
return
;
}
for
(
i
=
0
;
i
<
zsetnum
;
i
++
,
j
++
,
remaining
--
)
{
weight
s
[
i
]
=
strtod
(
c
->
argv
[
j
]
->
ptr
,
NULL
);
src
[
i
].
weight
=
strtod
(
c
->
argv
[
j
]
->
ptr
,
NULL
);
}
}
else
{
zfree
(
srcdicts
);
zfree
(
weights
);
zfree
(
src
);
addReply
(
c
,
shared
.
syntaxerr
);
return
;
}
...
...
@@ -5402,34 +5410,30 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
dstzset
=
dstobj
->
ptr
;
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
]);
/* sort sets from the smallest to largest, this will improve our
* algorithm's performance */
qsort
(
src
,
zsetnum
,
sizeof
(
zsetopsrc
),
qsortCompareZsetopsrcByCardinality
);
/* skip going over all entries if the smallest zset is NULL or empty */
if
(
src
[
0
].
dict
&&
dictSize
(
src
[
0
].
dict
)
>
0
)
{
/* precondition: as src[0].dict is non-empty and the zsets are ordered
* from small to large, all src[i > 0].dict are non-empty too */
di
=
dictGetIterator
(
src
[
0
].
dict
);
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
(
srcdict
s
[
k
]
,
dictGetEntryKey
(
de
));
for
(
j
=
0
;
j
<
zsetnum
;
j
++
)
{
dictEntry
*
other
=
(
j
==
0
)
?
de
:
dictFind
(
src
[
j
].
dict
,
dictGetEntryKey
(
de
));
if
(
other
)
{
*
score
=
*
score
+
weight
s
[
k
]
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
*
score
=
*
score
+
src
[
j
].
weight
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
}
else
{
break
;
}
}
/* skip entry when not present in every source dict */
if
(
k
!=
zsetnum
)
{
if
(
j
!=
zsetnum
)
{
zfree
(
score
);
}
else
{
robj
*
o
=
dictGetEntryKey
(
de
);
...
...
@@ -5443,9 +5447,9 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
}
}
else
if
(
op
==
REDIS_OP_UNION
)
{
for
(
i
=
0
;
i
<
zsetnum
;
i
++
)
{
if
(
!
srcdict
s
[
i
]
)
continue
;
if
(
!
src
[
i
].
dict
)
continue
;
di
=
dictGetIterator
(
srcdict
s
[
i
]
);
di
=
dictGetIterator
(
src
[
i
].
dict
);
while
((
de
=
dictNext
(
di
))
!=
NULL
)
{
/* skip key when already processed */
if
(
dictFind
(
dstzset
->
dict
,
dictGetEntryKey
(
de
))
!=
NULL
)
continue
;
...
...
@@ -5453,11 +5457,11 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
double
*
score
=
zmalloc
(
sizeof
(
double
));
*
score
=
0
.
0
;
for
(
j
=
0
;
j
<
zsetnum
;
j
++
)
{
if
(
!
srcdict
s
[
j
]
)
continue
;
if
(
!
src
[
j
].
dict
)
continue
;
dictEntry
*
other
=
(
i
==
j
)
?
de
:
dictFind
(
srcdict
s
[
j
]
,
dictGetEntryKey
(
de
));
dictEntry
*
other
=
(
i
==
j
)
?
de
:
dictFind
(
src
[
j
].
dict
,
dictGetEntryKey
(
de
));
if
(
other
)
{
*
score
=
*
score
+
weight
s
[
j
]
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
*
score
=
*
score
+
src
[
j
].
weight
*
(
*
(
double
*
)
dictGetEntryVal
(
other
));
}
}
...
...
@@ -5480,8 +5484,7 @@ static void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
addReplyLong
(
c
,
dstzset
->
zsl
->
length
);
server
.
dirty
++
;
zfree
(
srcdicts
);
zfree
(
weights
);
zfree
(
src
);
}
static
void
zunionCommand
(
redisClient
*
c
)
{
...
...
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