Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1c14507366 | ||
|
|
19c8d5bf22 | ||
|
|
fac62d47e7 | ||
|
|
f5936fa1c2 | ||
|
|
ff29ca1c46 | ||
|
|
b766149d5f | ||
|
|
4ac0c844ed | ||
|
|
87c96a6ed8 | ||
|
|
a58426fb15 | ||
|
|
2385ef4dfe | ||
|
|
d7554adade | ||
|
|
70a08f00d7 | ||
|
|
6ebd11cfa8 | ||
|
|
42daeb4b48 | ||
|
|
3306aefc87 | ||
|
|
c8baa20507 |
@@ -1,3 +1,58 @@
|
||||
Welcome to Redis 2.0.4
|
||||
|
||||
This release fixes two non critical bugs:
|
||||
|
||||
- HMGET used to crash when called against a key that was not holding
|
||||
an hash. Fixed by Pieter Noordhuis.
|
||||
|
||||
- Redis will now not try to save the DB if no save points for RDB are
|
||||
configured, when used as a non persistent cache. Thanks to Robey
|
||||
Pointer from Twitter for providing this patch.
|
||||
|
||||
Waiting 2.2 ...
|
||||
Salvatore
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Welcome to Redis 2.0.3
|
||||
|
||||
This release fixes two important bugs:
|
||||
|
||||
- The maxmemory directive was broken in Redis <= 2.0.2, since from time to
|
||||
time it replayed with an error about memory limit reached even when
|
||||
it was possible to expire some volatile key to make room for new data.
|
||||
|
||||
The new behaviour is the correct one of always allowing write operations
|
||||
to succeed as long as there are other volatile keys to remove.
|
||||
|
||||
- An AOF bug related to blocking POP could crash Redis on AOF reload.
|
||||
This is now fixed thanks to Pieter Noordhuis and a kind user that
|
||||
helped us on IRC.
|
||||
|
||||
Enjoy!
|
||||
Salvatore
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Welcome to Redis 2.0.2
|
||||
|
||||
This is a bugfix release, with the followign changes:
|
||||
|
||||
- Fixed a bug that may slow down significantly (from a few milliseconds
|
||||
to many seconds) server side intersections when a background write is
|
||||
in progress. This was due to the hash table resize policy, prevented when
|
||||
there was a saving child. Now it's prevented only up to 5 times
|
||||
overbooking, so we try hard to prevent a lot of copy on write, but
|
||||
avoiding to trigger pathological hash table performances of O(N) instead
|
||||
of O(1).
|
||||
- Fixed expired keys counter in INFO output. It was not counting keys
|
||||
force-expired due to max-memory limit reached.
|
||||
|
||||
Ciao,
|
||||
Salvatore
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Welcome to Redis 2.0.1
|
||||
|
||||
This is a bugfix release, with the following changes:
|
||||
|
||||
@@ -49,8 +49,13 @@
|
||||
/* Using dictEnableResize() / dictDisableResize() we make possible to
|
||||
* enable/disable resizing of the hash table as needed. This is very important
|
||||
* for Redis, as we use copy-on-write and don't want to move too much memory
|
||||
* around when there is a child performing saving operations. */
|
||||
* around when there is a child performing saving operations.
|
||||
*
|
||||
* Note that even when dict_can_resize is set to 0, not all resizes are
|
||||
* prevented: an hash table is still allowed to grow if the ratio between
|
||||
* the number of elements and the buckets > dict_force_resize_ratio. */
|
||||
static int dict_can_resize = 1;
|
||||
static unsigned int dict_force_resize_ratio = 5;
|
||||
|
||||
/* ---------------------------- Utility funcitons --------------------------- */
|
||||
|
||||
@@ -522,14 +527,23 @@ dictEntry *dictGetRandomKey(dict *d)
|
||||
/* Expand the hash table if needed */
|
||||
static int _dictExpandIfNeeded(dict *d)
|
||||
{
|
||||
/* If the hash table is empty expand it to the intial size,
|
||||
* if the table is "full" dobule its size. */
|
||||
/* Incremental rehashing already in progress. Return. */
|
||||
if (dictIsRehashing(d)) return DICT_OK;
|
||||
if (d->ht[0].size == 0)
|
||||
return dictExpand(d, DICT_HT_INITIAL_SIZE);
|
||||
if (d->ht[0].used >= d->ht[0].size && dict_can_resize)
|
||||
|
||||
/* If the hash table is empty expand it to the intial size. */
|
||||
if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);
|
||||
|
||||
/* If we reached the 1:1 ratio, and we are allowed to resize the hash
|
||||
* table (global setting) or we should avoid it but the ratio between
|
||||
* elements/buckets is over the "safe" threshold, we resize doubling
|
||||
* the number of buckets. */
|
||||
if (d->ht[0].used >= d->ht[0].size &&
|
||||
(dict_can_resize ||
|
||||
d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
|
||||
{
|
||||
return dictExpand(d, ((d->ht[0].size > d->ht[0].used) ?
|
||||
d->ht[0].size : d->ht[0].used)*2);
|
||||
}
|
||||
return DICT_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define REDIS_VERSION "2.0.1"
|
||||
#define REDIS_VERSION "2.0.4"
|
||||
|
||||
#include "fmacros.h"
|
||||
#include "config.h"
|
||||
@@ -2296,9 +2296,6 @@ static void call(redisClient *c, struct redisCommand *cmd) {
|
||||
static int processCommand(redisClient *c) {
|
||||
struct redisCommand *cmd;
|
||||
|
||||
/* Free some memory if needed (maxmemory setting) */
|
||||
if (server.maxmemory) freeMemoryIfNeeded();
|
||||
|
||||
/* Handle the multi bulk command type. This is an alternative protocol
|
||||
* supported by Redis in order to receive commands that are composed of
|
||||
* multiple binary-safe "bulk" arguments. The latency of processing is
|
||||
@@ -2430,7 +2427,12 @@ static int processCommand(redisClient *c) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Handle the maxmemory directive */
|
||||
/* Handle the maxmemory directive.
|
||||
*
|
||||
* First we try to free some memory if possible (if there are volatile
|
||||
* keys in the dataset). If there are not the only thing we can do
|
||||
* is returning an error. */
|
||||
if (server.maxmemory) freeMemoryIfNeeded();
|
||||
if (server.maxmemory && (cmd->flags & REDIS_CMD_DENYOOM) &&
|
||||
zmalloc_used_memory() > server.maxmemory)
|
||||
{
|
||||
@@ -4219,7 +4221,7 @@ static int prepareForShutdown() {
|
||||
/* Append only file: fsync() the AOF and exit */
|
||||
fsync(server.appendfd);
|
||||
if (server.vm_enabled) unlink(server.vm_swap_file);
|
||||
} else {
|
||||
} else if (server.saveparamslen > 0) {
|
||||
/* Snapshotting. Perform a SYNC SAVE and exit */
|
||||
if (rdbSave(server.dbfilename) == REDIS_OK) {
|
||||
if (server.daemonize)
|
||||
@@ -4234,6 +4236,8 @@ static int prepareForShutdown() {
|
||||
redisLog(REDIS_WARNING,"Error trying to save the DB, can't exit");
|
||||
return REDIS_ERR;
|
||||
}
|
||||
} else {
|
||||
redisLog(REDIS_WARNING,"Not saving DB.");
|
||||
}
|
||||
redisLog(REDIS_WARNING,"Server exit now, bye bye...");
|
||||
return REDIS_OK;
|
||||
@@ -6705,6 +6709,7 @@ static void hmgetCommand(redisClient *c) {
|
||||
o = lookupKeyRead(c->db,c->argv[1]);
|
||||
if (o != NULL && o->type != REDIS_HASH) {
|
||||
addReply(c,shared.wrongtypeerr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Note the check for o != NULL happens inside the loop. This is
|
||||
@@ -7634,6 +7639,22 @@ static void blockForKeys(redisClient *c, robj **keys, int numkeys, time_t timeou
|
||||
list *l;
|
||||
int j;
|
||||
|
||||
/* Never block for keys when the AOF is being replayed.
|
||||
*
|
||||
* When a BPOP is issued against an expiring list, the list is expired
|
||||
* by means of the delete-on-write semantic, which causes the BPOP
|
||||
* command to be written to the AOF. Then, the BPOP ends up in a blocking
|
||||
* state and waits for a PUSH on any given key from another client.
|
||||
*
|
||||
* On replay, the expiring list will also be expired (if it isn't already),
|
||||
* and the fake AOF client will block for a push. When multiple BPOPs
|
||||
* (issued by multiple clients) are written to the AOF, this can cause the
|
||||
* same blocking code to be executed against the single fake AOF client,
|
||||
* which in turn can place the client in the list(s) of blocking clients
|
||||
* *multiple times*. This state should be prevented, so simply skip
|
||||
* blocking for the fake AOF client. */
|
||||
if (c->fd < 0) return;
|
||||
|
||||
c->blockingkeys = zmalloc(sizeof(robj*)*numkeys);
|
||||
c->blockingkeysnum = numkeys;
|
||||
c->blockingto = timeout;
|
||||
@@ -8227,6 +8248,7 @@ static void freeMemoryIfNeeded(void) {
|
||||
}
|
||||
}
|
||||
deleteKey(server.db+j,minkey);
|
||||
server.stat_expiredkeys++;
|
||||
}
|
||||
}
|
||||
if (!freed) return; /* nothing to free... */
|
||||
|
||||
@@ -140,6 +140,11 @@ start_server {tags {"hash"}} {
|
||||
set _ $rv
|
||||
} {{{} {}} {{} {}} {{} {}}}
|
||||
|
||||
test {HMGET against wrong type} {
|
||||
r set wrongtype somevalue
|
||||
assert_error "*wrong*" {r hmget wrongtype field1 field2}
|
||||
}
|
||||
|
||||
test {HMGET - small hash} {
|
||||
set keys {}
|
||||
set vals {}
|
||||
|
||||
Reference in New Issue
Block a user