Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d5c461bea | ||
|
|
68c308f8b6 | ||
|
|
1da104e01d |
@@ -12,13 +12,6 @@ for 2.0.
|
||||
CHANGELOG
|
||||
---------
|
||||
|
||||
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
|
||||
=========================
|
||||
|
||||
|
||||
@@ -364,13 +364,6 @@ vm-pages 134217728
|
||||
# Virtual Memory implementation.
|
||||
vm-max-threads 4
|
||||
|
||||
################################ LUA SCRIPTING ###############################
|
||||
|
||||
# Max execution time of a Lua script in milliseconds.
|
||||
# This prevents that a programming error generating an infinite loop will block
|
||||
# your server forever. Set it to 0 or a negative value for unlimited execution.
|
||||
lua-time-limit 60000
|
||||
|
||||
############################### ADVANCED CONFIG ###############################
|
||||
|
||||
# Hashes are encoded in a special way (much more memory efficient) when they
|
||||
|
||||
@@ -288,8 +288,6 @@ void loadServerConfig(char *filename) {
|
||||
err = "Target command name already exists"; goto loaderr;
|
||||
}
|
||||
}
|
||||
} else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
|
||||
server.lua_time_limit = strtoll(argv[1],NULL,10);
|
||||
} else {
|
||||
err = "Bad directive or wrong number of arguments"; goto loaderr;
|
||||
}
|
||||
@@ -448,9 +446,6 @@ void configSetCommand(redisClient *c) {
|
||||
} else if (!strcasecmp(c->argv[2]->ptr,"set-max-intset-entries")) {
|
||||
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
|
||||
server.set_max_intset_entries = ll;
|
||||
} else if (!strcasecmp(c->argv[2]->ptr,"lua-time-limit")) {
|
||||
if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
|
||||
server.lua_time_limit = ll;
|
||||
} else {
|
||||
addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
|
||||
(char*)c->argv[2]->ptr);
|
||||
@@ -602,11 +597,6 @@ void configGetCommand(redisClient *c) {
|
||||
addReplyBulkLongLong(c,server.set_max_intset_entries);
|
||||
matches++;
|
||||
}
|
||||
if (stringmatch(pattern,"lua-time-limit",0)) {
|
||||
addReplyBulkCString(c,"lua-time-limit");
|
||||
addReplyBulkLongLong(c,server.lua_time_limit);
|
||||
matches++;
|
||||
}
|
||||
setDeferredMultiBulkLength(c,replylen,matches*2);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -80,7 +80,7 @@ void computeDatasetDigest(unsigned char *final) {
|
||||
redisDb *db = server.db+j;
|
||||
|
||||
if (dictSize(db->dict) == 0) continue;
|
||||
di = dictGetSafeIterator(db->dict);
|
||||
di = dictGetIterator(db->dict);
|
||||
|
||||
/* hash the DB id, so the same dataset moved in a different
|
||||
* DB will lead to a different digest */
|
||||
|
||||
+5
-15
@@ -244,9 +244,9 @@ int dictRehashMilliseconds(dict *d, int ms) {
|
||||
}
|
||||
|
||||
/* This function performs just a step of rehashing, and only if there are
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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,26 +423,17 @@ 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->safe && iter->index == -1 && iter->table == 0)
|
||||
iter->d->iterators++;
|
||||
if (iter->index == -1 && iter->table == 0) iter->d->iterators++;
|
||||
iter->index++;
|
||||
if (iter->index >= (signed) ht->size) {
|
||||
if (dictIsRehashing(iter->d) && iter->table == 0) {
|
||||
@@ -469,8 +460,7 @@ dictEntry *dictNext(dictIterator *iter)
|
||||
|
||||
void dictReleaseIterator(dictIterator *iter)
|
||||
{
|
||||
if (iter->safe && !(iter->index == -1 && iter->table == 0))
|
||||
iter->d->iterators--;
|
||||
if (!(iter->index == -1 && iter->table == 0)) iter->d->iterators--;
|
||||
zfree(iter);
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -74,13 +74,10 @@ 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, index, safe;
|
||||
int table;
|
||||
int index;
|
||||
dictEntry *entry, *nextEntry;
|
||||
} dictIterator;
|
||||
|
||||
@@ -135,7 +132,6 @@ 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
@@ -423,7 +423,7 @@ void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
cfd = anetTcpAccept(server.neterr, fd, cip, &cport);
|
||||
if (cfd == AE_ERR) {
|
||||
redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr);
|
||||
redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
|
||||
return;
|
||||
}
|
||||
redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
|
||||
@@ -438,7 +438,7 @@ void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
|
||||
|
||||
cfd = anetUnixAccept(server.neterr, fd);
|
||||
if (cfd == AE_ERR) {
|
||||
redisLog(REDIS_WARNING,"Accepting client connection: %s", server.neterr);
|
||||
redisLog(REDIS_VERBOSE,"Accepting client connection: %s", server.neterr);
|
||||
return;
|
||||
}
|
||||
redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket);
|
||||
|
||||
@@ -803,7 +803,6 @@ void initServerConfig() {
|
||||
server.list_max_ziplist_value = REDIS_LIST_MAX_ZIPLIST_VALUE;
|
||||
server.set_max_intset_entries = REDIS_SET_MAX_INTSET_ENTRIES;
|
||||
server.shutdown_asap = 0;
|
||||
server.lua_time_limit = REDIS_LUA_TIME_LIMIT;
|
||||
|
||||
updateLRUClock();
|
||||
resetServerSaveParams();
|
||||
|
||||
@@ -213,9 +213,6 @@
|
||||
#define REDIS_MAXMEMORY_ALLKEYS_RANDOM 4
|
||||
#define REDIS_MAXMEMORY_NO_EVICTION 5
|
||||
|
||||
/* Scripting */
|
||||
#define REDIS_LUA_TIME_LIMIT 60000 /* milliseconds */
|
||||
|
||||
/* We can print the stacktrace, so our assert is defined this way: */
|
||||
#define redisAssert(_e) ((_e)?(void)0 : (_redisAssert(#_e,__FILE__,__LINE__),_exit(1)))
|
||||
#define redisPanic(_e) _redisPanic(#_e,__FILE__,__LINE__),_exit(1)
|
||||
@@ -501,8 +498,6 @@ struct redisServer {
|
||||
/* Scripting */
|
||||
lua_State *lua;
|
||||
redisClient *lua_client;
|
||||
long long lua_time_limit;
|
||||
long long lua_time_start;
|
||||
};
|
||||
|
||||
typedef struct pubsubPattern {
|
||||
@@ -873,7 +868,6 @@ int isStringRepresentableAsLong(sds s, long *longval);
|
||||
int isStringRepresentableAsLongLong(sds s, long long *longval);
|
||||
int isObjectRepresentableAsLongLong(robj *o, long long *llongval);
|
||||
int string2ll(char *s, size_t slen, long long *value);
|
||||
long long ustime(void);
|
||||
|
||||
/* Configuration */
|
||||
void loadServerConfig(char *filename);
|
||||
|
||||
@@ -199,18 +199,6 @@ int luaRedisCommand(lua_State *lua) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void luaMaskCountHook(lua_State *lua, lua_Debug *ar) {
|
||||
long long elapsed;
|
||||
REDIS_NOTUSED(ar);
|
||||
|
||||
elapsed = (ustime()/1000) - server.lua_time_start;
|
||||
if (elapsed >= server.lua_time_limit) {
|
||||
redisLog(REDIS_NOTICE,"Lua script aborted for max execution time after %lld milliseconds of running time.",elapsed);
|
||||
lua_pushstring(lua,"Script aborted for max execution time.");
|
||||
lua_error(lua);
|
||||
}
|
||||
}
|
||||
|
||||
void scriptingInit(void) {
|
||||
lua_State *lua = lua_open();
|
||||
luaL_openlibs(lua);
|
||||
@@ -384,17 +372,6 @@ void evalCommand(redisClient *c) {
|
||||
/* Select the right DB in the context of the Lua client */
|
||||
selectDb(server.lua_client,c->db->id);
|
||||
|
||||
/* Set an hook in order to be able to stop the script execution if it
|
||||
* is running for too much time.
|
||||
* We set the hook only if the time limit is enabled as the hook will
|
||||
* make the Lua script execution slower. */
|
||||
if (server.lua_time_limit > 0) {
|
||||
lua_sethook(lua,luaMaskCountHook,LUA_MASKCOUNT,100000);
|
||||
server.lua_time_start = ustime()/1000;
|
||||
} else {
|
||||
lua_sethook(lua,luaMaskCountHook,0,0);
|
||||
}
|
||||
|
||||
/* At this point whatever this script was never seen before or if it was
|
||||
* already defined, we can call it. We have zero arguments and expect
|
||||
* a single return value. */
|
||||
|
||||
@@ -817,6 +817,7 @@ 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 */
|
||||
|
||||
-12
@@ -1,7 +1,6 @@
|
||||
#include "redis.h"
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Glob-style pattern matching. */
|
||||
int stringmatchlen(const char *pattern, int patternLen,
|
||||
@@ -302,14 +301,3 @@ int string2ll(char *s, size_t slen, long long *value) {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return the UNIX time in microseconds */
|
||||
long long ustime(void) {
|
||||
struct timeval tv;
|
||||
long long ust;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ust = ((long long)tv.tv_sec)*1000000;
|
||||
ust += tv.tv_usec;
|
||||
return ust;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define REDIS_VERSION "2.2.107"
|
||||
#define REDIS_VERSION "2.2.106"
|
||||
|
||||
Reference in New Issue
Block a user