Compare commits

...
16 Commits
Author SHA1 Message Date
antirez ec279203df Redis 2.2.8 2011-05-24 16:34:53 +02:00
antirez 480a2e73cf Comment typo fixed 2011-05-24 10:43:31 +02:00
antirez f447a7ebb4 ZUNIONSTORE new iterator API fix backported into 2.2 2011-05-21 20:34:59 +02:00
antirez 748a2da3e8 Print version info before running the test 2011-05-20 11:44:09 +02:00
antirez b02e81be07 Fixed SINTER[STORE] problem related to the new copy on write safe iterator 2011-05-15 12:15:54 +02:00
antirez 430719ca53 Fixed bug introduced with the copy-on-write friendly iteartor 2011-05-13 12:53:07 +02:00
antirez cc8a0f898b Fix for DEBUG DIGEST, key may expire on lookup 2011-05-13 11:42:02 +02:00
antirez cd128d2882 replication with expire test modified to produce no or less false failures 2011-05-12 20:15:13 +02:00
antirez c717adbc2e regression for zinterstore bug 2011-05-12 20:14:15 +02:00
Pieter Noordhuis 1ffa5d73ed Convert intset encoded set before Z*STORE 2011-05-12 16:18:43 +02:00
antirez a7fa2baf06 Redis 2.2.7 2011-05-11 10:40:24 +02:00
antirez f7aef5241b removed assert causing an illegal memory access. This was responsible of crashes during BLPOP and other list blocking operations. 2011-05-11 09:49:23 +02:00
antirez c86a4f9102 use safe Dict iteration in DEBUG DIGEST 2011-05-10 11:04:30 +02:00
antirez 2e638590ad Introduced a safe iterator interface that can be used to iterate while accessing the dictionary at the same time. Now the default interface is consireded unsafe and should be used only with dictNext() 2011-05-10 11:04:03 +02:00
antirez 3554f09ddc Merge branch '2.2' of github.com:antirez/redis into 2.2 2011-05-07 12:10:47 +02:00
antirez ccab83e729 when Redis fails accepting a new connection reports the error at WARNING and not VERBOSE error level. Thanks to offby1 for proposing this in the Redis mailing list. #backport-candidate 2011-05-07 12:10:39 +02:00
13 changed files with 95 additions and 16 deletions
+20
View File
@@ -12,6 +12,26 @@ 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
=========================
* Fixed bug #543-2 (the issue was reopened with a completely different report)
that caused Redis to randomly crash on list push performed against lists
with other clients blocked with BLPOP (or variants).
What's new in Redis 2.2.6
=========================
+6 -1
View File
@@ -80,7 +80,7 @@ void computeDatasetDigest(unsigned char *final) {
redisDb *db = server.db+j;
if (dictSize(db->dict) == 0) continue;
di = dictGetIterator(db->dict);
di = dictGetSafeIterator(db->dict);
/* hash the DB id, so the same dataset moved in a different
* DB will lead to a different digest */
@@ -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));
+15 -5
View File
@@ -244,9 +244,9 @@ int dictRehashMilliseconds(dict *d, int ms) {
}
/* This function performs just a step of rehashing, and only if there are
* not iterators bound to our hash table. When we have iterators in the middle
* of a rehashing we can't mess with the two hash tables otherwise some element
* can be missed or duplicated.
* no safe iterators bound to our hash table. When we have iterators in the
* middle of a rehashing we can't mess with the two hash tables otherwise
* some element can be missed or duplicated.
*
* This function is called by common lookup or update operations in the
* dictionary so that the hash table automatically migrates from H1 to H2
@@ -423,17 +423,26 @@ dictIterator *dictGetIterator(dict *d)
iter->d = d;
iter->table = 0;
iter->index = -1;
iter->safe = 0;
iter->entry = NULL;
iter->nextEntry = NULL;
return iter;
}
dictIterator *dictGetSafeIterator(dict *d) {
dictIterator *i = dictGetIterator(d);
i->safe = 1;
return i;
}
dictEntry *dictNext(dictIterator *iter)
{
while (1) {
if (iter->entry == NULL) {
dictht *ht = &iter->d->ht[iter->table];
if (iter->index == -1 && iter->table == 0) iter->d->iterators++;
if (iter->safe && iter->index == -1 && iter->table == 0)
iter->d->iterators++;
iter->index++;
if (iter->index >= (signed) ht->size) {
if (dictIsRehashing(iter->d) && iter->table == 0) {
@@ -460,7 +469,8 @@ dictEntry *dictNext(dictIterator *iter)
void dictReleaseIterator(dictIterator *iter)
{
if (!(iter->index == -1 && iter->table == 0)) iter->d->iterators--;
if (iter->safe && !(iter->index == -1 && iter->table == 0))
iter->d->iterators--;
zfree(iter);
}
+6 -2
View File
@@ -74,10 +74,13 @@ typedef struct dict {
int iterators; /* number of iterators currently running */
} dict;
/* If safe is set to 1 this is a safe iteartor, that means, you can call
* dictAdd, dictFind, and other functions against the dictionary even while
* iterating. Otherwise it is a non safe iterator, and only dictNext()
* should be called while iterating. */
typedef struct dictIterator {
dict *d;
int table;
int index;
int table, index, safe;
dictEntry *entry, *nextEntry;
} dictIterator;
@@ -132,6 +135,7 @@ dictEntry * dictFind(dict *d, const void *key);
void *dictFetchValue(dict *d, const void *key);
int dictResize(dict *d);
dictIterator *dictGetIterator(dict *d);
dictIterator *dictGetSafeIterator(dict *d);
dictEntry *dictNext(dictIterator *iter);
void dictReleaseIterator(dictIterator *iter);
dictEntry *dictGetRandomKey(dict *d);
+2 -2
View File
@@ -416,7 +416,7 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
cfd = anetTcpAccept(server.neterr, fd, cip, &cport);
if (cfd == AE_ERR) {
redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr);
return;
}
redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
@@ -431,7 +431,7 @@ void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
cfd = anetUnixAccept(server.neterr, fd);
if (cfd == AE_ERR) {
redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr);
return;
}
redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket);
-1
View File
@@ -817,7 +817,6 @@ int handleClientsWaitingListPush(redisClient *c, robj *key, robj *ele) {
/* This should remove the first element of the "clients" list. */
unblockClientWaitingData(receiver);
redisAssert(ln != listFirst(clients));
if (dstkey == NULL) {
/* BRPOP/BLPOP */
+1
View File
@@ -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
View File
@@ -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
View File
@@ -1 +1 @@
#define REDIS_VERSION "2.2.6"
#define REDIS_VERSION "2.2.8"
+2
View File
@@ -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}]
+1
View File
@@ -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"
+6
View File
@@ -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)"
}
+7
View File
@@ -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" {