Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec279203df | ||
|
|
480a2e73cf | ||
|
|
f447a7ebb4 | ||
|
|
748a2da3e8 | ||
|
|
b02e81be07 | ||
|
|
430719ca53 | ||
|
|
cc8a0f898b | ||
|
|
cd128d2882 | ||
|
|
c717adbc2e | ||
|
|
1ffa5d73ed |
@@ -12,6 +12,19 @@ for 2.0.
|
||||
CHANGELOG
|
||||
---------
|
||||
|
||||
What's new in Redis 2.2.8
|
||||
=========================
|
||||
|
||||
* A new form of dict.c (hash table implementation) iterator that performs less
|
||||
copy-on-write of pages, introduced in Redis 2.2.7, caused ZINTERSTORE,
|
||||
ZUNIONSTORE, SINTER, SINTERSTORE commands to behave in the wrong way.
|
||||
This bug is now fixed.
|
||||
* Print version info before running the test with 'make test'. This is mainly
|
||||
useful for the Continuous Integration system we run.
|
||||
* Fix for DEBUG DIGEST, key may expire on lookup, producing the wrong result.
|
||||
* Replication with expire test modified to produce no or less false failures.
|
||||
* Fixed Z*STORE when dealing with intsets, regression test added.
|
||||
|
||||
What's new in Redis 2.2.7
|
||||
=========================
|
||||
|
||||
|
||||
@@ -101,6 +101,11 @@ void computeDatasetDigest(unsigned char *final) {
|
||||
|
||||
/* Make sure the key is loaded if VM is active */
|
||||
o = lookupKeyRead(db,keyobj);
|
||||
if (o == NULL) {
|
||||
/* Key expired on lookup? Try the next one. */
|
||||
decrRefCount(keyobj);
|
||||
continue;
|
||||
}
|
||||
|
||||
aux = htonl(o->type);
|
||||
mixDigest(digest,&aux,sizeof(aux));
|
||||
|
||||
@@ -433,6 +433,7 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
|
||||
si = setTypeInitIterator(sets[0]);
|
||||
while((encoding = setTypeNext(si,&eleobj,&intobj)) != -1) {
|
||||
for (j = 1; j < setnum; j++) {
|
||||
if (sets[j] == sets[0]) continue;
|
||||
if (encoding == REDIS_ENCODING_INTSET) {
|
||||
/* intset with intset is simple... and fast */
|
||||
if (sets[j]->encoding == REDIS_ENCODING_INTSET &&
|
||||
|
||||
+28
-4
@@ -615,6 +615,10 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
|
||||
if (obj->type == REDIS_ZSET) {
|
||||
src[i].dict = ((zset*)obj->ptr)->dict;
|
||||
} else if (obj->type == REDIS_SET) {
|
||||
if (obj->encoding == REDIS_ENCODING_INTSET)
|
||||
setTypeConvert(obj, REDIS_ENCODING_HT);
|
||||
|
||||
redisAssert(obj->encoding == REDIS_ENCODING_HT);
|
||||
src[i].dict = (obj->ptr);
|
||||
} else {
|
||||
zfree(src);
|
||||
@@ -682,7 +686,18 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
|
||||
|
||||
score = src[0].weight * zunionInterDictValue(de);
|
||||
for (j = 1; j < setnum; j++) {
|
||||
dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
|
||||
dictEntry *other;
|
||||
|
||||
/* If it's the same dictionary don't lookup as we are not
|
||||
* in the context of a safe iterator. It's the same
|
||||
* dictionary so we are sure the element is inside.
|
||||
* This happens on SINTERSTORE dest 2 mykey mykey. */
|
||||
if (src[j].dict == src[0].dict) {
|
||||
other = de;
|
||||
} else {
|
||||
other = dictFind(src[j].dict,dictGetEntryKey(de));
|
||||
}
|
||||
|
||||
if (other) {
|
||||
value = src[j].weight * zunionInterDictValue(other);
|
||||
zunionInterAggregate(&score,value,aggregate);
|
||||
@@ -720,10 +735,19 @@ void zunionInterGenericCommand(redisClient *c, robj *dstkey, int op) {
|
||||
/* because the zsets are sorted by size, its only possible
|
||||
* for sets at larger indices to hold this entry */
|
||||
for (j = (i+1); j < setnum; j++) {
|
||||
dictEntry *other = dictFind(src[j].dict,dictGetEntryKey(de));
|
||||
if (other) {
|
||||
value = src[j].weight * zunionInterDictValue(other);
|
||||
/* It is not safe to access the zset we are
|
||||
* iterating, so explicitly check for equal object. */
|
||||
if (src[j].dict == src[i].dict) {
|
||||
value = src[i].weight * zunionInterDictValue(de);
|
||||
zunionInterAggregate(&score,value,aggregate);
|
||||
} else {
|
||||
dictEntry *other;
|
||||
|
||||
other = dictFind(src[j].dict,dictGetEntryKey(de));
|
||||
if (other) {
|
||||
value = src[j].weight * zunionInterDictValue(other);
|
||||
zunionInterAggregate(&score,value,aggregate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define REDIS_VERSION "2.2.7"
|
||||
#define REDIS_VERSION "2.2.8"
|
||||
|
||||
@@ -27,6 +27,8 @@ start_server {tags {"repl"}} {
|
||||
test {MASTER and SLAVE consistency with expire} {
|
||||
createComplexDataset r 50000 useexpire
|
||||
after 4000 ;# Make sure everything expired before taking the digest
|
||||
r keys * ;# Force DEL syntesizing to slave
|
||||
after 1000 ;# Wait another second. Now everything should be fine.
|
||||
if {[r debug digest] ne [r -1 debug digest]} {
|
||||
set csv1 [csvdump r]
|
||||
set csv2 [csvdump {r -1}]
|
||||
|
||||
@@ -108,6 +108,7 @@ proc cleanup {} {
|
||||
}
|
||||
|
||||
proc execute_everything {} {
|
||||
execute_tests "unit/printver"
|
||||
execute_tests "unit/auth"
|
||||
execute_tests "unit/protocol"
|
||||
execute_tests "unit/basic"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
start_server {} {
|
||||
set i [r info]
|
||||
regexp {redis_version:(.*?)\r\n} $i - version
|
||||
regexp {redis_git_sha1:(.*?)\r\n} $i - sha1
|
||||
puts "Testing Redis version $version ($sha1)"
|
||||
}
|
||||
@@ -484,6 +484,13 @@ start_server {tags {"zset"}} {
|
||||
test {ZINTERSTORE with AGGREGATE MAX} {
|
||||
list [r zinterstore zsetc 2 zseta zsetb aggregate max] [r zrange zsetc 0 -1 withscores]
|
||||
} {2 {b 2 c 3}}
|
||||
|
||||
test {ZINTERSTORE regression with two sets, intset+hashtable} {
|
||||
r del seta setb setc
|
||||
r sadd set1 a
|
||||
r sadd set2 10
|
||||
r zinterstore set3 2 set1 set2
|
||||
} {0}
|
||||
|
||||
foreach cmd {ZUNIONSTORE ZINTERSTORE} {
|
||||
test "$cmd with +inf/-inf scores" {
|
||||
|
||||
Reference in New Issue
Block a user