Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
556b2d2bee | ||
|
|
9fdcc15962 | ||
|
|
cf7600714f | ||
|
|
a57595cade | ||
|
|
8783fb9495 | ||
|
|
8cb9344b65 | ||
|
|
59080f6023 | ||
|
|
ac2a824aa9 | ||
|
|
c7197ff50f | ||
|
|
3f77777ffd | ||
|
|
7a565d7257 | ||
|
|
64bf60fb52 | ||
|
|
5bed12aa03 | ||
|
|
d71c49610b | ||
|
|
fca99e413a | ||
|
|
01407a3a42 | ||
|
|
fb5408cf68 | ||
|
|
0b8b6df472 | ||
|
|
e98627c5b5 | ||
|
|
17f5de896a | ||
|
|
266e6423bf | ||
|
|
eafaf17269 | ||
|
|
4630da375c |
+123
@@ -10,6 +10,129 @@ HIGH: There is a critical bug that may affect a subset of users. Upgrade!
|
||||
CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
================================================================================
|
||||
Redis 4.0.10 Released Wed Jun 13 12:49:13 CEST 2018
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency CRITICAL: This release fixes important security issues.
|
||||
HIGH: This release fixes a SCAN commands family bug.
|
||||
MODERATE: This release fixes a PSYNC2 edge case with expires.
|
||||
MODERATE: Sentinel related fixes.
|
||||
LOW: All the other issues
|
||||
|
||||
Redis 4.0.10 fixes a number of important issues:
|
||||
|
||||
* Important security issues related to the Lua scripting engine.
|
||||
Please check https://github.com/antirez/redis/issues/5017
|
||||
for more information.
|
||||
|
||||
* A bug with SCAN, SSCAN, HSCAN and ZSCAN, that may not return all the elements.
|
||||
We also add a regression test that can trigger the issue often when present, and
|
||||
may in theory be able to find unrelated regressions.
|
||||
|
||||
* A PSYNC2 bug is fixed: Redis should not expire keys when saving RDB files
|
||||
because otherwise it is no longer possible to use such RDB file as a base
|
||||
for partial resynchronization. It no longer represents the right state.
|
||||
|
||||
* Compatibility of AOF with RDB preamble when the RDB checksum is disabled.
|
||||
|
||||
* Sentinel bug that in some cases prevented Sentinel to detect that the master
|
||||
was down immediately. A delay was added to the detection.
|
||||
|
||||
* Other minor issues.
|
||||
|
||||
The following is the list of commits composing the release, please check
|
||||
the commit messages and authors for credits.
|
||||
|
||||
antirez in commit 9fdcc159:
|
||||
Security: fix redis-cli buffer overflow.
|
||||
1 file changed, 16 insertions(+), 11 deletions(-)
|
||||
|
||||
antirez in commit cf760071:
|
||||
Security: fix Lua struct package offset handling.
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
antirez in commit a57595ca:
|
||||
Security: more cmsgpack fixes by @soloestoy.
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
antirez in commit 8783fb94:
|
||||
Security: update Lua struct package for security.
|
||||
1 file changed, 23 insertions(+), 23 deletions(-)
|
||||
|
||||
antirez in commit 8cb9344b:
|
||||
Security: fix Lua cmsgpack library stack overflow.
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
赵磊 in commit 59080f60:
|
||||
Fix dictScan(): It can't scan all buckets when dict is shrinking.
|
||||
1 file changed, 14 insertions(+), 11 deletions(-)
|
||||
|
||||
dejun.xdj in commit ac2a824a:
|
||||
Fix redis-cli memory leak when sending set preference command.
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
dejun.xdj in commit c7197ff5:
|
||||
Check if the repeat value is positive in while loop of cliSendCommand().
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
dejun.xdj in commit 3f77777f:
|
||||
Change the type of repeat argument to long for function cliSendCommand.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
dejun.xdj in commit 7a565d72:
|
||||
Fix negtive repeat command value issue.
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
dejun.xdj in commit 64bf60fb:
|
||||
Detect and stop saving history for auth command with repeat option.
|
||||
1 file changed, 17 insertions(+), 10 deletions(-)
|
||||
|
||||
dejun.xdj in commit 5bed12aa:
|
||||
Change the warning message a little bit to avoid trademark issuses.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
dejun.xdj in commit d71c4961:
|
||||
Stop saving auth command in redis-cli history.
|
||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||
|
||||
dejun.xdj in commit fca99e41:
|
||||
Add warning message when using password on command line
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
antirez in commit 01407a3a:
|
||||
Don't expire keys while loading RDB from AOF preamble.
|
||||
3 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
WuYunlong in commit fb5408cf:
|
||||
Fix rdb save by allowing dumping of expire keys, so that when we add a new slave, and do a failover, eighter by manual or not, other local slaves will delete the expired keys properly.
|
||||
2 files changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
antirez in commit 0b8b6df4:
|
||||
Backport hiredis issue 525 fix to compile on FreeBSD.
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
antirez in commit e98627c5:
|
||||
Add INIT INFO to the provided init script.
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
antirez in commit 17f5de89:
|
||||
Fix ae.c when a timer finalizerProc adds an event.
|
||||
2 files changed, 10 insertions(+), 6 deletions(-)
|
||||
|
||||
antirez in commit 266e6423:
|
||||
Sentinel: fix delay in detecting ODOWN.
|
||||
1 file changed, 9 insertions(+), 5 deletions(-)
|
||||
|
||||
zhaozhao.zz in commit eafaf172:
|
||||
AOF & RDB: be compatible with rdbchecksum no
|
||||
1 file changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
huijing.whj in commit 4630da37:
|
||||
fix int overflow problem in freeMemoryIfNeeded
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
|
||||
================================================================================
|
||||
Redis 4.0.9 Released Mon Mar 26 17:52:32 CEST 2018
|
||||
================================================================================
|
||||
|
||||
Vendored
+1
-1
@@ -13,7 +13,7 @@
|
||||
#if defined(__sun__)
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#else
|
||||
#if !(defined(__APPLE__) && defined(__MACH__))
|
||||
#if !(defined(__APPLE__) && defined(__MACH__)) && !(defined(__FreeBSD__))
|
||||
#define _XOPEN_SOURCE 600
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Vendored
+10
@@ -385,6 +385,7 @@ void mp_encode_lua_table_as_array(lua_State *L, mp_buf *buf, int level) {
|
||||
#endif
|
||||
|
||||
mp_encode_array(L,buf,len);
|
||||
luaL_checkstack(L, 1, "in function mp_encode_lua_table_as_array");
|
||||
for (j = 1; j <= len; j++) {
|
||||
lua_pushnumber(L,j);
|
||||
lua_gettable(L,-2);
|
||||
@@ -400,6 +401,7 @@ void mp_encode_lua_table_as_map(lua_State *L, mp_buf *buf, int level) {
|
||||
* Lua API, we need to iterate a first time. Note that an alternative
|
||||
* would be to do a single run, and then hack the buffer to insert the
|
||||
* map opcodes for message pack. Too hackish for this lib. */
|
||||
luaL_checkstack(L, 3, "in function mp_encode_lua_table_as_map");
|
||||
lua_pushnil(L);
|
||||
while(lua_next(L,-2)) {
|
||||
lua_pop(L,1); /* remove value, keep key for next iteration. */
|
||||
@@ -515,10 +517,14 @@ int mp_pack(lua_State *L) {
|
||||
if (nargs == 0)
|
||||
return luaL_argerror(L, 0, "MessagePack pack needs input.");
|
||||
|
||||
if (!lua_checkstack(L, nargs))
|
||||
return luaL_argerror(L, 0, "Too many arguments for MessagePack pack.");
|
||||
|
||||
buf = mp_buf_new(L);
|
||||
for(i = 1; i <= nargs; i++) {
|
||||
/* Copy argument i to top of stack for _encode processing;
|
||||
* the encode function pops it from the stack when complete. */
|
||||
luaL_checkstack(L, 1, "in function mp_check");
|
||||
lua_pushvalue(L, i);
|
||||
|
||||
mp_encode_lua_type(L,buf,0);
|
||||
@@ -547,6 +553,7 @@ void mp_decode_to_lua_array(lua_State *L, mp_cur *c, size_t len) {
|
||||
int index = 1;
|
||||
|
||||
lua_newtable(L);
|
||||
luaL_checkstack(L, 1, "in function mp_decode_to_lua_array");
|
||||
while(len--) {
|
||||
lua_pushnumber(L,index++);
|
||||
mp_decode_to_lua_type(L,c);
|
||||
@@ -821,6 +828,9 @@ int mp_unpack_full(lua_State *L, int limit, int offset) {
|
||||
* subtract the entire buffer size from the unprocessed size
|
||||
* to get our next start offset */
|
||||
int offset = len - c.left;
|
||||
|
||||
luaL_checkstack(L, 1, "in function mp_unpack_full");
|
||||
|
||||
/* Return offset -1 when we have have processed the entire buffer. */
|
||||
lua_pushinteger(L, c.left == 0 ? -1 : offset);
|
||||
/* Results are returned with the arg elements still
|
||||
|
||||
Vendored
+29
-25
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
** {======================================================
|
||||
** Library for packing/unpacking structures.
|
||||
** $Id: struct.c,v 1.4 2012/07/04 18:54:29 roberto Exp $
|
||||
** $Id: struct.c,v 1.7 2018/05/11 22:04:31 roberto Exp $
|
||||
** See Copyright Notice at the end of this file
|
||||
** =======================================================
|
||||
*/
|
||||
@@ -15,8 +15,8 @@
|
||||
** h/H - signed/unsigned short
|
||||
** l/L - signed/unsigned long
|
||||
** T - size_t
|
||||
** i/In - signed/unsigned integer with size `n' (default is size of int)
|
||||
** cn - sequence of `n' chars (from/to a string); when packing, n==0 means
|
||||
** i/In - signed/unsigned integer with size 'n' (default is size of int)
|
||||
** cn - sequence of 'n' chars (from/to a string); when packing, n==0 means
|
||||
the whole string; when unpacking, n==0 means use the previous
|
||||
read number as the string length
|
||||
** s - zero-terminated string
|
||||
@@ -89,14 +89,12 @@ typedef struct Header {
|
||||
} Header;
|
||||
|
||||
|
||||
static int getnum (lua_State *L, const char **fmt, int df) {
|
||||
static int getnum (const char **fmt, int df) {
|
||||
if (!isdigit(**fmt)) /* no number? */
|
||||
return df; /* return default value */
|
||||
else {
|
||||
int a = 0;
|
||||
do {
|
||||
if (a > (INT_MAX / 10) || a * 10 > (INT_MAX - (**fmt - '0')))
|
||||
luaL_error(L, "integral size overflow");
|
||||
a = a*10 + *((*fmt)++) - '0';
|
||||
} while (isdigit(**fmt));
|
||||
return a;
|
||||
@@ -117,9 +115,9 @@ static size_t optsize (lua_State *L, char opt, const char **fmt) {
|
||||
case 'f': return sizeof(float);
|
||||
case 'd': return sizeof(double);
|
||||
case 'x': return 1;
|
||||
case 'c': return getnum(L, fmt, 1);
|
||||
case 'c': return getnum(fmt, 1);
|
||||
case 'i': case 'I': {
|
||||
int sz = getnum(L, fmt, sizeof(int));
|
||||
int sz = getnum(fmt, sizeof(int));
|
||||
if (sz > MAXINTSIZE)
|
||||
luaL_error(L, "integral size %d is larger than limit of %d",
|
||||
sz, MAXINTSIZE);
|
||||
@@ -152,7 +150,7 @@ static void controloptions (lua_State *L, int opt, const char **fmt,
|
||||
case '>': h->endian = BIG; return;
|
||||
case '<': h->endian = LITTLE; return;
|
||||
case '!': {
|
||||
int a = getnum(L, fmt, MAXALIGN);
|
||||
int a = getnum(fmt, MAXALIGN);
|
||||
if (!isp2(a))
|
||||
luaL_error(L, "alignment %d is not a power of 2", a);
|
||||
h->align = a;
|
||||
@@ -295,21 +293,26 @@ static int b_unpack (lua_State *L) {
|
||||
const char *fmt = luaL_checkstring(L, 1);
|
||||
size_t ld;
|
||||
const char *data = luaL_checklstring(L, 2, &ld);
|
||||
size_t pos = luaL_optinteger(L, 3, 1) - 1;
|
||||
size_t pos = luaL_optinteger(L, 3, 1);
|
||||
luaL_argcheck(L, pos > 0, 3, "offset must be 1 or greater");
|
||||
pos--; /* Lua indexes are 1-based, but here we want 0-based for C
|
||||
* pointer math. */
|
||||
int n = 0; /* number of results */
|
||||
defaultoptions(&h);
|
||||
lua_settop(L, 2);
|
||||
while (*fmt) {
|
||||
int opt = *fmt++;
|
||||
size_t size = optsize(L, opt, &fmt);
|
||||
pos += gettoalign(pos, &h, opt, size);
|
||||
luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
|
||||
luaL_checkstack(L, 1, "too many results");
|
||||
luaL_argcheck(L, size <= ld && pos <= ld - size,
|
||||
2, "data string too short");
|
||||
/* stack space for item + next position */
|
||||
luaL_checkstack(L, 2, "too many results");
|
||||
switch (opt) {
|
||||
case 'b': case 'B': case 'h': case 'H':
|
||||
case 'l': case 'L': case 'T': case 'i': case 'I': { /* integer types */
|
||||
int issigned = islower(opt);
|
||||
lua_Number res = getinteger(data+pos, h.endian, issigned, size);
|
||||
lua_pushnumber(L, res);
|
||||
lua_pushnumber(L, res); n++;
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
@@ -319,25 +322,26 @@ static int b_unpack (lua_State *L) {
|
||||
float f;
|
||||
memcpy(&f, data+pos, size);
|
||||
correctbytes((char *)&f, sizeof(f), h.endian);
|
||||
lua_pushnumber(L, f);
|
||||
lua_pushnumber(L, f); n++;
|
||||
break;
|
||||
}
|
||||
case 'd': {
|
||||
double d;
|
||||
memcpy(&d, data+pos, size);
|
||||
correctbytes((char *)&d, sizeof(d), h.endian);
|
||||
lua_pushnumber(L, d);
|
||||
lua_pushnumber(L, d); n++;
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
if (size == 0) {
|
||||
if (!lua_isnumber(L, -1))
|
||||
luaL_error(L, "format `c0' needs a previous size");
|
||||
if (n == 0 || !lua_isnumber(L, -1))
|
||||
luaL_error(L, "format 'c0' needs a previous size");
|
||||
size = lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
luaL_argcheck(L, pos+size <= ld, 2, "data string too short");
|
||||
lua_pop(L, 1); n--;
|
||||
luaL_argcheck(L, size <= ld && pos <= ld - size,
|
||||
2, "data string too short");
|
||||
}
|
||||
lua_pushlstring(L, data+pos, size);
|
||||
lua_pushlstring(L, data+pos, size); n++;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
@@ -345,15 +349,15 @@ static int b_unpack (lua_State *L) {
|
||||
if (e == NULL)
|
||||
luaL_error(L, "unfinished string in data");
|
||||
size = (e - (data+pos)) + 1;
|
||||
lua_pushlstring(L, data+pos, size - 1);
|
||||
lua_pushlstring(L, data+pos, size - 1); n++;
|
||||
break;
|
||||
}
|
||||
default: controloptions(L, opt, &fmt, &h);
|
||||
}
|
||||
pos += size;
|
||||
}
|
||||
lua_pushinteger(L, pos + 1);
|
||||
return lua_gettop(L) - 2;
|
||||
lua_pushinteger(L, pos + 1); /* next position */
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -399,7 +403,7 @@ LUALIB_API int luaopen_struct (lua_State *L) {
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (C) 2010-2012 Lua.org, PUC-Rio. All rights reserved.
|
||||
* Copyright (C) 2010-2018 Lua.org, PUC-Rio. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
|
||||
@@ -219,7 +219,10 @@ long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
|
||||
te->timeProc = proc;
|
||||
te->finalizerProc = finalizerProc;
|
||||
te->clientData = clientData;
|
||||
te->prev = NULL;
|
||||
te->next = eventLoop->timeEventHead;
|
||||
if (te->next)
|
||||
te->next->prev = te;
|
||||
eventLoop->timeEventHead = te;
|
||||
return id;
|
||||
}
|
||||
@@ -266,7 +269,7 @@ static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
|
||||
/* Process time events */
|
||||
static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
int processed = 0;
|
||||
aeTimeEvent *te, *prev;
|
||||
aeTimeEvent *te;
|
||||
long long maxId;
|
||||
time_t now = time(NULL);
|
||||
|
||||
@@ -287,7 +290,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
}
|
||||
eventLoop->lastTime = now;
|
||||
|
||||
prev = NULL;
|
||||
te = eventLoop->timeEventHead;
|
||||
maxId = eventLoop->timeEventNextId-1;
|
||||
while(te) {
|
||||
@@ -297,10 +299,12 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
/* Remove events scheduled for deletion. */
|
||||
if (te->id == AE_DELETED_EVENT_ID) {
|
||||
aeTimeEvent *next = te->next;
|
||||
if (prev == NULL)
|
||||
eventLoop->timeEventHead = te->next;
|
||||
if (te->prev)
|
||||
te->prev->next = te->next;
|
||||
else
|
||||
prev->next = te->next;
|
||||
eventLoop->timeEventHead = te->next;
|
||||
if (te->next)
|
||||
te->next->prev = te->prev;
|
||||
if (te->finalizerProc)
|
||||
te->finalizerProc(eventLoop, te->clientData);
|
||||
zfree(te);
|
||||
@@ -332,7 +336,6 @@ static int processTimeEvents(aeEventLoop *eventLoop) {
|
||||
te->id = AE_DELETED_EVENT_ID;
|
||||
}
|
||||
}
|
||||
prev = te;
|
||||
te = te->next;
|
||||
}
|
||||
return processed;
|
||||
|
||||
@@ -83,6 +83,7 @@ typedef struct aeTimeEvent {
|
||||
aeTimeProc *timeProc;
|
||||
aeEventFinalizerProc *finalizerProc;
|
||||
void *clientData;
|
||||
struct aeTimeEvent *prev;
|
||||
struct aeTimeEvent *next;
|
||||
} aeTimeEvent;
|
||||
|
||||
|
||||
@@ -713,7 +713,7 @@ int loadAppendOnlyFile(char *filename) {
|
||||
serverLog(LL_NOTICE,"Reading RDB preamble from AOF file...");
|
||||
if (fseek(fp,0,SEEK_SET) == -1) goto readerr;
|
||||
rioInitWithFile(&rdb,fp);
|
||||
if (rdbLoadRio(&rdb,NULL) != C_OK) {
|
||||
if (rdbLoadRio(&rdb,NULL,1) != C_OK) {
|
||||
serverLog(LL_WARNING,"Error reading the RDB preamble of the AOF file, AOF loading aborted");
|
||||
goto readerr;
|
||||
} else {
|
||||
|
||||
+14
-11
@@ -858,6 +858,15 @@ unsigned long dictScan(dict *d,
|
||||
de = next;
|
||||
}
|
||||
|
||||
/* Set unmasked bits so incrementing the reversed cursor
|
||||
* operates on the masked bits */
|
||||
v |= ~m0;
|
||||
|
||||
/* Increment the reverse cursor */
|
||||
v = rev(v);
|
||||
v++;
|
||||
v = rev(v);
|
||||
|
||||
} else {
|
||||
t0 = &d->ht[0];
|
||||
t1 = &d->ht[1];
|
||||
@@ -892,22 +901,16 @@ unsigned long dictScan(dict *d,
|
||||
de = next;
|
||||
}
|
||||
|
||||
/* Increment bits not covered by the smaller mask */
|
||||
v = (((v | m0) + 1) & ~m0) | (v & m0);
|
||||
/* Increment the reverse cursor not covered by the smaller mask.*/
|
||||
v |= ~m1;
|
||||
v = rev(v);
|
||||
v++;
|
||||
v = rev(v);
|
||||
|
||||
/* Continue while bits covered by mask difference is non-zero */
|
||||
} while (v & (m0 ^ m1));
|
||||
}
|
||||
|
||||
/* Set unmasked bits so incrementing the reversed cursor
|
||||
* operates on the masked bits of the smaller table */
|
||||
v |= ~m0;
|
||||
|
||||
/* Increment the reverse cursor */
|
||||
v = rev(v);
|
||||
v++;
|
||||
v = rev(v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -404,7 +404,7 @@ int freeMemoryIfNeeded(void) {
|
||||
latencyStartMonitor(latency);
|
||||
while (mem_freed < mem_tofree) {
|
||||
int j, k, i, keys_freed = 0;
|
||||
static int next_db = 0;
|
||||
static unsigned int next_db = 0;
|
||||
sds bestkey = NULL;
|
||||
int bestdbid;
|
||||
redisDb *db;
|
||||
|
||||
@@ -807,13 +807,10 @@ size_t rdbSavedObjectLen(robj *o) {
|
||||
* On error -1 is returned.
|
||||
* On success if the key was actually saved 1 is returned, otherwise 0
|
||||
* is returned (the key was already expired). */
|
||||
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val,
|
||||
long long expiretime, long long now)
|
||||
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime)
|
||||
{
|
||||
/* Save the expire time */
|
||||
if (expiretime != -1) {
|
||||
/* If this key is already expired skip it */
|
||||
if (expiretime < now) return 0;
|
||||
if (rdbSaveType(rdb,RDB_OPCODE_EXPIRETIME_MS) == -1) return -1;
|
||||
if (rdbSaveMillisecondTime(rdb,expiretime) == -1) return -1;
|
||||
}
|
||||
@@ -887,7 +884,6 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) {
|
||||
dictEntry *de;
|
||||
char magic[10];
|
||||
int j;
|
||||
long long now = mstime();
|
||||
uint64_t cksum;
|
||||
size_t processed = 0;
|
||||
|
||||
@@ -931,7 +927,7 @@ int rdbSaveRio(rio *rdb, int *error, int flags, rdbSaveInfo *rsi) {
|
||||
|
||||
initStaticStringObject(key,keystr);
|
||||
expire = getExpire(db,&key);
|
||||
if (rdbSaveKeyValuePair(rdb,&key,o,expire,now) == -1) goto werr;
|
||||
if (rdbSaveKeyValuePair(rdb,&key,o,expire) == -1) goto werr;
|
||||
|
||||
/* When this RDB is produced as part of an AOF rewrite, move
|
||||
* accumulated diff from parent to child while rewriting in
|
||||
@@ -1507,7 +1503,7 @@ void rdbLoadProgressCallback(rio *r, const void *buf, size_t len) {
|
||||
|
||||
/* Load an RDB file from the rio stream 'rdb'. On success C_OK is returned,
|
||||
* otherwise C_ERR is returned and 'errno' is set accordingly. */
|
||||
int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi) {
|
||||
int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof) {
|
||||
uint64_t dbid;
|
||||
int type, rdbver;
|
||||
redisDb *db = server.db+0;
|
||||
@@ -1635,7 +1631,7 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi) {
|
||||
* received from the master. In the latter case, the master is
|
||||
* responsible for key expiry. If we would expire keys here, the
|
||||
* snapshot taken by the master may not be reflected on the slave. */
|
||||
if (server.masterhost == NULL && expiretime != -1 && expiretime < now) {
|
||||
if (server.masterhost == NULL && !loading_aof && expiretime != -1 && expiretime < now) {
|
||||
decrRefCount(key);
|
||||
decrRefCount(val);
|
||||
continue;
|
||||
@@ -1649,16 +1645,18 @@ int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi) {
|
||||
decrRefCount(key);
|
||||
}
|
||||
/* Verify the checksum if RDB version is >= 5 */
|
||||
if (rdbver >= 5 && server.rdb_checksum) {
|
||||
if (rdbver >= 5) {
|
||||
uint64_t cksum, expected = rdb->cksum;
|
||||
|
||||
if (rioRead(rdb,&cksum,8) == 0) goto eoferr;
|
||||
memrev64ifbe(&cksum);
|
||||
if (cksum == 0) {
|
||||
serverLog(LL_WARNING,"RDB file was saved with checksum disabled: no check performed.");
|
||||
} else if (cksum != expected) {
|
||||
serverLog(LL_WARNING,"Wrong RDB checksum. Aborting now.");
|
||||
rdbExitReportCorruptRDB("RDB CRC error");
|
||||
if (server.rdb_checksum) {
|
||||
memrev64ifbe(&cksum);
|
||||
if (cksum == 0) {
|
||||
serverLog(LL_WARNING,"RDB file was saved with checksum disabled: no check performed.");
|
||||
} else if (cksum != expected) {
|
||||
serverLog(LL_WARNING,"Wrong RDB checksum. Aborting now.");
|
||||
rdbExitReportCorruptRDB("RDB CRC error");
|
||||
}
|
||||
}
|
||||
}
|
||||
return C_OK;
|
||||
@@ -1684,7 +1682,7 @@ int rdbLoad(char *filename, rdbSaveInfo *rsi) {
|
||||
if ((fp = fopen(filename,"r")) == NULL) return C_ERR;
|
||||
startLoading(fp);
|
||||
rioInitWithFile(&rdb,fp);
|
||||
retval = rdbLoadRio(&rdb,rsi);
|
||||
retval = rdbLoadRio(&rdb,rsi,0);
|
||||
fclose(fp);
|
||||
stopLoading();
|
||||
return retval;
|
||||
|
||||
@@ -137,7 +137,7 @@ ssize_t rdbSaveObject(rio *rdb, robj *o);
|
||||
size_t rdbSavedObjectLen(robj *o);
|
||||
robj *rdbLoadObject(int type, rio *rdb);
|
||||
void backgroundSaveDoneHandler(int exitcode, int bysignal);
|
||||
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime, long long now);
|
||||
int rdbSaveKeyValuePair(rio *rdb, robj *key, robj *val, long long expiretime);
|
||||
robj *rdbLoadStringObject(rio *rdb);
|
||||
ssize_t rdbSaveStringObject(rio *rdb, robj *obj);
|
||||
ssize_t rdbSaveRawString(rio *rdb, unsigned char *s, size_t len);
|
||||
@@ -146,7 +146,7 @@ int rdbSaveBinaryDoubleValue(rio *rdb, double val);
|
||||
int rdbLoadBinaryDoubleValue(rio *rdb, double *val);
|
||||
int rdbSaveBinaryFloatValue(rio *rdb, float val);
|
||||
int rdbLoadBinaryFloatValue(rio *rdb, float *val);
|
||||
int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi);
|
||||
int rdbLoadRio(rio *rdb, rdbSaveInfo *rsi, int loading_aof);
|
||||
rdbSaveInfo *rdbPopulateSaveInfo(rdbSaveInfo *rsi);
|
||||
|
||||
#endif
|
||||
|
||||
+49
-24
@@ -152,20 +152,25 @@ static long long mstime(void) {
|
||||
}
|
||||
|
||||
static void cliRefreshPrompt(void) {
|
||||
int len;
|
||||
|
||||
if (config.eval_ldb) return;
|
||||
if (config.hostsocket != NULL)
|
||||
len = snprintf(config.prompt,sizeof(config.prompt),"redis %s",
|
||||
config.hostsocket);
|
||||
else
|
||||
len = anetFormatAddr(config.prompt, sizeof(config.prompt),
|
||||
config.hostip, config.hostport);
|
||||
|
||||
sds prompt = sdsempty();
|
||||
if (config.hostsocket != NULL) {
|
||||
prompt = sdscatfmt(prompt,"redis %s",config.hostsocket);
|
||||
} else {
|
||||
char addr[256];
|
||||
anetFormatAddr(addr, sizeof(addr), config.hostip, config.hostport);
|
||||
prompt = sdscatlen(prompt,addr,strlen(addr));
|
||||
}
|
||||
|
||||
/* Add [dbnum] if needed */
|
||||
if (config.dbnum != 0)
|
||||
len += snprintf(config.prompt+len,sizeof(config.prompt)-len,"[%d]",
|
||||
config.dbnum);
|
||||
snprintf(config.prompt+len,sizeof(config.prompt)-len,"> ");
|
||||
prompt = sdscatfmt(prompt,"[%i]",config.dbnum);
|
||||
|
||||
/* Copy the prompt in the static buffer. */
|
||||
prompt = sdscatlen(prompt,"> ",2);
|
||||
snprintf(config.prompt,sizeof(config.prompt),"%s",prompt);
|
||||
sdsfree(prompt);
|
||||
}
|
||||
|
||||
/* Return the name of the dotfile for the specified 'dotfilename'.
|
||||
@@ -917,7 +922,7 @@ static int cliReadReply(int output_raw_strings) {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static int cliSendCommand(int argc, char **argv, int repeat) {
|
||||
static int cliSendCommand(int argc, char **argv, long repeat) {
|
||||
char *command = argv[0];
|
||||
size_t *argvlen;
|
||||
int j, output_raw;
|
||||
@@ -980,7 +985,7 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
|
||||
for (j = 0; j < argc; j++)
|
||||
argvlen[j] = sdslen(argv[j]);
|
||||
|
||||
while(repeat--) {
|
||||
while(repeat-- > 0) {
|
||||
redisAppendCommandArgv(context,argc,(const char**)argv,argvlen);
|
||||
while (config.monitor_mode) {
|
||||
if (cliReadReply(output_raw) != REDIS_OK) exit(1);
|
||||
@@ -1088,6 +1093,7 @@ static int parseOptions(int argc, char **argv) {
|
||||
} else if (!strcmp(argv[i],"-n") && !lastarg) {
|
||||
config.dbnum = atoi(argv[++i]);
|
||||
} else if (!strcmp(argv[i],"-a") && !lastarg) {
|
||||
fputs("Warning: Using a password with '-a' option on the command line interface may not be safe.\n", stderr);
|
||||
config.auth = argv[++i];
|
||||
} else if (!strcmp(argv[i],"-u") && !lastarg) {
|
||||
parseRedisUri(argv[++i]);
|
||||
@@ -1397,9 +1403,35 @@ static void repl(void) {
|
||||
cliRefreshPrompt();
|
||||
while((line = linenoise(context ? config.prompt : "not connected> ")) != NULL) {
|
||||
if (line[0] != '\0') {
|
||||
long repeat = 1;
|
||||
int skipargs = 0;
|
||||
char *endptr = NULL;
|
||||
|
||||
argv = cliSplitArgs(line,&argc);
|
||||
if (history) linenoiseHistoryAdd(line);
|
||||
if (historyfile) linenoiseHistorySave(historyfile);
|
||||
|
||||
/* check if we have a repeat command option and
|
||||
* need to skip the first arg */
|
||||
if (argv && argc > 0) {
|
||||
errno = 0;
|
||||
repeat = strtol(argv[0], &endptr, 10);
|
||||
if (argc > 1 && *endptr == '\0') {
|
||||
if (errno == ERANGE || errno == EINVAL || repeat <= 0) {
|
||||
fputs("Invalid redis-cli repeat command option value.\n", stdout);
|
||||
sdsfreesplitres(argv, argc);
|
||||
linenoiseFree(line);
|
||||
continue;
|
||||
}
|
||||
skipargs = 1;
|
||||
} else {
|
||||
repeat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Won't save auth command in history file */
|
||||
if (!(argv && argc > 0 && !strcasecmp(argv[0+skipargs], "auth"))) {
|
||||
if (history) linenoiseHistoryAdd(line);
|
||||
if (historyfile) linenoiseHistorySave(historyfile);
|
||||
}
|
||||
|
||||
if (argv == NULL) {
|
||||
printf("Invalid argument(s)\n");
|
||||
@@ -1412,6 +1444,8 @@ static void repl(void) {
|
||||
exit(0);
|
||||
} else if (argv[0][0] == ':') {
|
||||
cliSetPreferences(argv,argc,1);
|
||||
sdsfreesplitres(argv,argc);
|
||||
linenoiseFree(line);
|
||||
continue;
|
||||
} else if (strcasecmp(argv[0],"restart") == 0) {
|
||||
if (config.eval) {
|
||||
@@ -1431,15 +1465,6 @@ static void repl(void) {
|
||||
linenoiseClearScreen();
|
||||
} else {
|
||||
long long start_time = mstime(), elapsed;
|
||||
int repeat, skipargs = 0;
|
||||
char *endptr;
|
||||
|
||||
repeat = strtol(argv[0], &endptr, 10);
|
||||
if (argc > 1 && *endptr == '\0' && repeat) {
|
||||
skipargs = 1;
|
||||
} else {
|
||||
repeat = 1;
|
||||
}
|
||||
|
||||
issueCommandRepeat(argc-skipargs, argv+skipargs, repeat);
|
||||
|
||||
|
||||
+9
-5
@@ -2599,20 +2599,24 @@ void sentinelSendPeriodicCommands(sentinelRedisInstance *ri) {
|
||||
ping_period = ri->down_after_period;
|
||||
if (ping_period > SENTINEL_PING_PERIOD) ping_period = SENTINEL_PING_PERIOD;
|
||||
|
||||
/* Send INFO to masters and slaves, not sentinels. */
|
||||
if ((ri->flags & SRI_SENTINEL) == 0 &&
|
||||
(ri->info_refresh == 0 ||
|
||||
(now - ri->info_refresh) > info_period))
|
||||
{
|
||||
/* Send INFO to masters and slaves, not sentinels. */
|
||||
retval = redisAsyncCommand(ri->link->cc,
|
||||
sentinelInfoReplyCallback, ri, "INFO");
|
||||
if (retval == C_OK) ri->link->pending_commands++;
|
||||
} else if ((now - ri->link->last_pong_time) > ping_period &&
|
||||
}
|
||||
|
||||
/* Send PING to all the three kinds of instances. */
|
||||
if ((now - ri->link->last_pong_time) > ping_period &&
|
||||
(now - ri->link->last_ping_time) > ping_period/2) {
|
||||
/* Send PING to all the three kinds of instances. */
|
||||
sentinelSendPing(ri);
|
||||
} else if ((now - ri->last_pub_time) > SENTINEL_PUBLISH_PERIOD) {
|
||||
/* PUBLISH hello messages to all the three kinds of instances. */
|
||||
}
|
||||
|
||||
/* PUBLISH hello messages to all the three kinds of instances. */
|
||||
if ((now - ri->last_pub_time) > SENTINEL_PUBLISH_PERIOD) {
|
||||
sentinelSendHello(ri);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
#define REDIS_VERSION "4.0.9"
|
||||
#define REDIS_VERSION "4.0.10"
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
# Simple Redis init.d script conceived to work on Linux systems
|
||||
# as it does use of the /proc filesystem.
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: redis_6379
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Redis data structure server
|
||||
# Description: Redis data structure server. See https://redis.io
|
||||
### END INIT INFO
|
||||
|
||||
REDISPORT=6379
|
||||
EXEC=/usr/local/bin/redis-server
|
||||
CLIEXEC=/usr/local/bin/redis-cli
|
||||
|
||||
Reference in New Issue
Block a user