Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee4d13ab88 | ||
|
|
ffa361256a | ||
|
|
5e93f9cb9d | ||
|
|
98f91fea4e | ||
|
|
0d6a6dca38 | ||
|
|
773f141504 | ||
|
|
699b6db0fc | ||
|
|
cd2f92d5ca | ||
|
|
ff4ce3ce01 | ||
|
|
c652d95ea1 | ||
|
|
441001a4e5 | ||
|
|
ca0a9ab822 | ||
|
|
ad950e4c32 | ||
|
|
0e9710d4dd | ||
|
|
9317bf6465 | ||
|
|
1f7c148be2 | ||
|
|
91863dd854 | ||
|
|
2f27ebb414 | ||
|
|
89391e42c8 | ||
|
|
8f30d2a604 | ||
|
|
24c0bf5c5b | ||
|
|
b313fa4166 | ||
|
|
f613873de0 | ||
|
|
405d14fd44 |
@@ -52,12 +52,20 @@ jobs:
|
||||
- name: make
|
||||
run: make REDIS_CFLAGS='-Werror' MALLOC=libc
|
||||
|
||||
build-centos7-jemalloc:
|
||||
build-old-chain-jemalloc:
|
||||
runs-on: ubuntu-latest
|
||||
container: centos:7
|
||||
container: ubuntu:20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
yum -y install gcc make
|
||||
make REDIS_CFLAGS='-Werror'
|
||||
apt-get update
|
||||
apt-get install -y gnupg2
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial main" >> /etc/apt/sources.list
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe" >> /etc/apt/sources.list
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
make CC=gcc REDIS_CFLAGS='-Werror'
|
||||
|
||||
+41
-26
@@ -175,21 +175,29 @@ jobs:
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --valgrind --no-latency --verbose --clients 1
|
||||
|
||||
test-centos7-jemalloc:
|
||||
test-old-chain-jemalloc:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'redis/redis'
|
||||
container: centos:7
|
||||
container: ubuntu:20.04
|
||||
timeout-minutes: 14400
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
yum -y install gcc make
|
||||
make
|
||||
apt-get update
|
||||
apt-get install -y gnupg2
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial main" >> /etc/apt/sources.list
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe" >> /etc/apt/sources.list
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
make CC=gcc REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: apt-get install -y tcl tcltls tclx
|
||||
- name: test
|
||||
run: |
|
||||
yum -y install which tcl
|
||||
./runtest --accurate --verbose --dump-logs
|
||||
run: ./runtest --accurate --verbose --dump-logs
|
||||
- name: module api test
|
||||
run: ./runtest-moduleapi --verbose
|
||||
- name: sentinel tests
|
||||
@@ -197,22 +205,31 @@ jobs:
|
||||
- name: cluster tests
|
||||
run: ./runtest-cluster
|
||||
|
||||
test-centos7-tls:
|
||||
test-old-chain-tls:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'redis/redis'
|
||||
container: centos:7
|
||||
container: ubuntu:20.04
|
||||
timeout-minutes: 14400
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: make
|
||||
run: |
|
||||
yum -y install centos-release-scl epel-release
|
||||
yum -y install devtoolset-7 openssl-devel openssl
|
||||
scl enable devtoolset-7 "make BUILD_TLS=yes"
|
||||
apt-get update
|
||||
apt-get install -y gnupg2
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial main" >> /etc/apt/sources.list
|
||||
echo "deb http://dk.archive.ubuntu.com/ubuntu/ xenial universe" >> /etc/apt/sources.list
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
|
||||
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
|
||||
apt-get update
|
||||
apt-get install -y make gcc-4.8 openssl libssl-dev
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 100
|
||||
make CC=gcc BUILD_TLS=yes REDIS_CFLAGS='-Werror'
|
||||
- name: testprep
|
||||
run: |
|
||||
apt-get install -y tcl tcltls tclx
|
||||
./utils/gen-test-certs.sh
|
||||
- name: test
|
||||
run: |
|
||||
yum -y install tcl tcltls
|
||||
./utils/gen-test-certs.sh
|
||||
./runtest --accurate --verbose --tls --dump-logs
|
||||
./runtest --accurate --verbose --dump-logs
|
||||
- name: module api test
|
||||
@@ -247,24 +264,22 @@ jobs:
|
||||
run: ./runtest-cluster
|
||||
|
||||
test-freebsd:
|
||||
runs-on: macos-12
|
||||
runs-on: macos-13
|
||||
if: github.repository == 'redis/redis'
|
||||
timeout-minutes: 14400
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: test
|
||||
uses: vmactions/freebsd-vm@v0.3.0
|
||||
uses: cross-platform-actions/action@v0.22.0
|
||||
with:
|
||||
usesh: true
|
||||
sync: rsync
|
||||
copyback: false
|
||||
prepare: pkg install -y bash gmake lang/tcl86
|
||||
run: >
|
||||
gmake &&
|
||||
./runtest --accurate --verbose --no-latency --tags -large-memory --dump-logs &&
|
||||
MAKE=gmake ./runtest-moduleapi --verbose &&
|
||||
./runtest-sentinel &&
|
||||
./runtest-cluster
|
||||
operating_system: freebsd
|
||||
environment_variables: MAKE
|
||||
version: 13.2
|
||||
shell: bash
|
||||
run: |
|
||||
sudo pkg install -y bash gmake lang/tcl86 lang/tclx gcc
|
||||
gmake
|
||||
./runtest --single unit/keyspace --single unit/auth --single unit/networking --single unit/protocol
|
||||
|
||||
test-alpine-jemalloc:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -11,6 +11,75 @@ CRITICAL: There is a critical bug affecting MOST USERS. Upgrade ASAP.
|
||||
SECURITY: There are security fixes in the release.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.18 Released Wed 23 Apr 2025 12:00:00 IST
|
||||
================================================================================
|
||||
|
||||
Update urgency: `SECURITY`: There are security fixes in the release.
|
||||
|
||||
|
||||
### Security fixes
|
||||
|
||||
* (CVE-2025-21605) An unauthenticated client can cause an unlimited growth of output buffers
|
||||
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.17 Released Mon 6 Jan 2025 12:30:00 IDT
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: See security fixes below.
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
* (CVE-2024-46981) Lua script commands may lead to remote code execution
|
||||
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.16 Released Wed 02 Oct 2024 20:17:04 IDT
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: See security fixes below.
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
|
||||
* (CVE-2024-31449) Lua library commands may lead to stack overflow and potential RCE.
|
||||
* (CVE-2024-31228) Potential Denial-of-service due to unbounded pattern matching.
|
||||
|
||||
6.2.15 was an erroneous release,
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.14 Released Wed 18 Oct 2023 10:33:40 IDT
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: See security fixes below.
|
||||
|
||||
Security fixes
|
||||
==============
|
||||
|
||||
* (CVE-2023-45145) The wrong order of listen(2) and chmod(2) calls creates a
|
||||
race condition that can be used by another process to bypass desired Unix
|
||||
socket permissions on startup.
|
||||
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.13 Released Mon July 10 12:00:00 IDT 2023
|
||||
================================================================================
|
||||
|
||||
Upgrade urgency SECURITY: See security fixes below.
|
||||
|
||||
Security Fixes:
|
||||
* (CVE-2022-24834) A specially crafted Lua script executing in Redis can trigger
|
||||
a heap overflow in the cjson and cmsgpack libraries, and result in heap
|
||||
corruption and potentially remote code execution. The problem exists in all
|
||||
versions of Redis with Lua scripting support, starting from 2.6, and affects
|
||||
only authenticated and authorized users.
|
||||
|
||||
Bug Fixes
|
||||
=========
|
||||
|
||||
* Re-enable downscale rehashing while there is a fork child (#12276)
|
||||
|
||||
|
||||
================================================================================
|
||||
Redis 6.2.12 Released Mon Apr 17 16:00:00 IST 2023
|
||||
|
||||
Vendored
+7
@@ -2,6 +2,8 @@
|
||||
|
||||
uname_S:= $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
||||
|
||||
LUA_COVERAGE?=no
|
||||
|
||||
CCCOLOR="\033[34m"
|
||||
LINKCOLOR="\033[34;1m"
|
||||
SRCCOLOR="\033[33m"
|
||||
@@ -71,6 +73,11 @@ endif
|
||||
|
||||
LUA_CFLAGS+= -O2 -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -DLUA_USE_MKSTEMP $(CFLAGS)
|
||||
LUA_LDFLAGS+= $(LDFLAGS)
|
||||
ifeq ($(LUA_COVERAGE),yes)
|
||||
LUA_CFLAGS += -fprofile-arcs -ftest-coverage
|
||||
LUA_LDFLAGS += -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
|
||||
# lua's Makefile defines AR="ar rcu", which is unusual, and makes it more
|
||||
# challenging to cross-compile lua (and redis). These defines make it easier
|
||||
# to fit redis into cross-compilation environments, which typically set AR.
|
||||
|
||||
Vendored
+1
@@ -131,6 +131,7 @@ static int bit_tohex(lua_State *L)
|
||||
const char *hexdigits = "0123456789abcdef";
|
||||
char buf[8];
|
||||
int i;
|
||||
if (n == INT32_MIN) n = INT32_MIN+1;
|
||||
if (n < 0) { n = -n; hexdigits = "0123456789ABCDEF"; }
|
||||
if (n > 8) n = 8;
|
||||
for (i = (int)n; --i >= 0; ) { buf[i] = hexdigits[b & 15]; b >>= 4; }
|
||||
|
||||
Vendored
+6
-3
@@ -39,6 +39,7 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
@@ -141,13 +142,13 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
json_token_type_t type;
|
||||
int index;
|
||||
size_t index;
|
||||
union {
|
||||
const char *string;
|
||||
double number;
|
||||
int boolean;
|
||||
} value;
|
||||
int string_len;
|
||||
size_t string_len;
|
||||
} json_token_t;
|
||||
|
||||
static const char *char2escape[256] = {
|
||||
@@ -473,6 +474,8 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex)
|
||||
* This buffer is reused constantly for small strings
|
||||
* If there are any excess pages, they won't be hit anyway.
|
||||
* This gains ~5% speedup. */
|
||||
if (len > SIZE_MAX / 6 - 3)
|
||||
abort(); /* Overflow check */
|
||||
strbuf_ensure_empty_length(json, len * 6 + 2);
|
||||
|
||||
strbuf_append_char_unsafe(json, '\"');
|
||||
@@ -706,7 +709,7 @@ static int json_encode(lua_State *l)
|
||||
strbuf_t local_encode_buf;
|
||||
strbuf_t *encode_buf;
|
||||
char *json;
|
||||
int len;
|
||||
size_t len;
|
||||
|
||||
luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument");
|
||||
|
||||
|
||||
Vendored
+17
-14
@@ -117,7 +117,9 @@ mp_buf *mp_buf_new(lua_State *L) {
|
||||
|
||||
void mp_buf_append(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) {
|
||||
if (buf->free < len) {
|
||||
size_t newsize = (buf->len+len)*2;
|
||||
size_t newsize = buf->len+len;
|
||||
if (newsize < buf->len || newsize >= SIZE_MAX/2) abort();
|
||||
newsize *= 2;
|
||||
|
||||
buf->b = (unsigned char*)mp_realloc(L, buf->b, buf->len + buf->free, newsize);
|
||||
buf->free = newsize - buf->len;
|
||||
@@ -173,7 +175,7 @@ void mp_cur_init(mp_cur *cursor, const unsigned char *s, size_t len) {
|
||||
|
||||
void mp_encode_bytes(lua_State *L, mp_buf *buf, const unsigned char *s, size_t len) {
|
||||
unsigned char hdr[5];
|
||||
int hdrlen;
|
||||
size_t hdrlen;
|
||||
|
||||
if (len < 32) {
|
||||
hdr[0] = 0xa0 | (len&0xff); /* fix raw */
|
||||
@@ -220,7 +222,7 @@ void mp_encode_double(lua_State *L, mp_buf *buf, double d) {
|
||||
|
||||
void mp_encode_int(lua_State *L, mp_buf *buf, int64_t n) {
|
||||
unsigned char b[9];
|
||||
int enclen;
|
||||
size_t enclen;
|
||||
|
||||
if (n >= 0) {
|
||||
if (n <= 127) {
|
||||
@@ -290,9 +292,9 @@ void mp_encode_int(lua_State *L, mp_buf *buf, int64_t n) {
|
||||
mp_buf_append(L,buf,b,enclen);
|
||||
}
|
||||
|
||||
void mp_encode_array(lua_State *L, mp_buf *buf, int64_t n) {
|
||||
void mp_encode_array(lua_State *L, mp_buf *buf, uint64_t n) {
|
||||
unsigned char b[5];
|
||||
int enclen;
|
||||
size_t enclen;
|
||||
|
||||
if (n <= 15) {
|
||||
b[0] = 0x90 | (n & 0xf); /* fix array */
|
||||
@@ -313,7 +315,7 @@ void mp_encode_array(lua_State *L, mp_buf *buf, int64_t n) {
|
||||
mp_buf_append(L,buf,b,enclen);
|
||||
}
|
||||
|
||||
void mp_encode_map(lua_State *L, mp_buf *buf, int64_t n) {
|
||||
void mp_encode_map(lua_State *L, mp_buf *buf, uint64_t n) {
|
||||
unsigned char b[5];
|
||||
int enclen;
|
||||
|
||||
@@ -790,7 +792,7 @@ void mp_decode_to_lua_type(lua_State *L, mp_cur *c) {
|
||||
}
|
||||
}
|
||||
|
||||
int mp_unpack_full(lua_State *L, int limit, int offset) {
|
||||
int mp_unpack_full(lua_State *L, lua_Integer limit, lua_Integer offset) {
|
||||
size_t len;
|
||||
const char *s;
|
||||
mp_cur c;
|
||||
@@ -802,10 +804,10 @@ int mp_unpack_full(lua_State *L, int limit, int offset) {
|
||||
if (offset < 0 || limit < 0) /* requesting negative off or lim is invalid */
|
||||
return luaL_error(L,
|
||||
"Invalid request to unpack with offset of %d and limit of %d.",
|
||||
offset, len);
|
||||
(int) offset, (int) len);
|
||||
else if (offset > len)
|
||||
return luaL_error(L,
|
||||
"Start offset %d greater than input length %d.", offset, len);
|
||||
"Start offset %d greater than input length %d.", (int) offset, (int) len);
|
||||
|
||||
if (decode_all) limit = INT_MAX;
|
||||
|
||||
@@ -827,12 +829,13 @@ int mp_unpack_full(lua_State *L, int limit, int offset) {
|
||||
/* c->left is the remaining size of the input buffer.
|
||||
* subtract the entire buffer size from the unprocessed size
|
||||
* to get our next start offset */
|
||||
int offset = len - c.left;
|
||||
size_t new_offset = len - c.left;
|
||||
if (new_offset > LONG_MAX) abort();
|
||||
|
||||
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);
|
||||
lua_pushinteger(L, c.left == 0 ? -1 : (lua_Integer) new_offset);
|
||||
/* Results are returned with the arg elements still
|
||||
* in place. Lua takes care of only returning
|
||||
* elements above the args for us.
|
||||
@@ -851,15 +854,15 @@ int mp_unpack(lua_State *L) {
|
||||
}
|
||||
|
||||
int mp_unpack_one(lua_State *L) {
|
||||
int offset = luaL_optinteger(L, 2, 0);
|
||||
lua_Integer offset = luaL_optinteger(L, 2, 0);
|
||||
/* Variable pop because offset may not exist */
|
||||
lua_pop(L, lua_gettop(L)-1);
|
||||
return mp_unpack_full(L, 1, offset);
|
||||
}
|
||||
|
||||
int mp_unpack_limit(lua_State *L) {
|
||||
int limit = luaL_checkinteger(L, 2);
|
||||
int offset = luaL_optinteger(L, 3, 0);
|
||||
lua_Integer limit = luaL_checkinteger(L, 2);
|
||||
lua_Integer offset = luaL_optinteger(L, 3, 0);
|
||||
/* Variable pop because offset may not exist */
|
||||
lua_pop(L, lua_gettop(L)-1);
|
||||
|
||||
|
||||
Vendored
+28
-81
@@ -26,6 +26,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "strbuf.h"
|
||||
|
||||
@@ -38,22 +39,22 @@ static void die(const char *fmt, ...)
|
||||
va_end(arg);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(-1);
|
||||
abort();
|
||||
}
|
||||
|
||||
void strbuf_init(strbuf_t *s, int len)
|
||||
void strbuf_init(strbuf_t *s, size_t len)
|
||||
{
|
||||
int size;
|
||||
size_t size;
|
||||
|
||||
if (len <= 0)
|
||||
if (!len)
|
||||
size = STRBUF_DEFAULT_SIZE;
|
||||
else
|
||||
size = len + 1; /* \0 terminator */
|
||||
|
||||
size = len + 1;
|
||||
if (size < len)
|
||||
die("Overflow, len: %zu", len);
|
||||
s->buf = NULL;
|
||||
s->size = size;
|
||||
s->length = 0;
|
||||
s->increment = STRBUF_DEFAULT_INCREMENT;
|
||||
s->dynamic = 0;
|
||||
s->reallocs = 0;
|
||||
s->debug = 0;
|
||||
@@ -65,7 +66,7 @@ void strbuf_init(strbuf_t *s, int len)
|
||||
strbuf_ensure_null(s);
|
||||
}
|
||||
|
||||
strbuf_t *strbuf_new(int len)
|
||||
strbuf_t *strbuf_new(size_t len)
|
||||
{
|
||||
strbuf_t *s;
|
||||
|
||||
@@ -81,20 +82,10 @@ strbuf_t *strbuf_new(int len)
|
||||
return s;
|
||||
}
|
||||
|
||||
void strbuf_set_increment(strbuf_t *s, int increment)
|
||||
{
|
||||
/* Increment > 0: Linear buffer growth rate
|
||||
* Increment < -1: Exponential buffer growth rate */
|
||||
if (increment == 0 || increment == -1)
|
||||
die("BUG: Invalid string increment");
|
||||
|
||||
s->increment = increment;
|
||||
}
|
||||
|
||||
static inline void debug_stats(strbuf_t *s)
|
||||
{
|
||||
if (s->debug) {
|
||||
fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %d, size: %d\n",
|
||||
fprintf(stderr, "strbuf(%lx) reallocs: %d, length: %zd, size: %zd\n",
|
||||
(long)s, s->reallocs, s->length, s->size);
|
||||
}
|
||||
}
|
||||
@@ -113,7 +104,7 @@ void strbuf_free(strbuf_t *s)
|
||||
free(s);
|
||||
}
|
||||
|
||||
char *strbuf_free_to_string(strbuf_t *s, int *len)
|
||||
char *strbuf_free_to_string(strbuf_t *s, size_t *len)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
@@ -131,57 +122,62 @@ char *strbuf_free_to_string(strbuf_t *s, int *len)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int calculate_new_size(strbuf_t *s, int len)
|
||||
static size_t calculate_new_size(strbuf_t *s, size_t len)
|
||||
{
|
||||
int reqsize, newsize;
|
||||
size_t reqsize, newsize;
|
||||
|
||||
if (len <= 0)
|
||||
die("BUG: Invalid strbuf length requested");
|
||||
|
||||
/* Ensure there is room for optional NULL termination */
|
||||
reqsize = len + 1;
|
||||
if (reqsize < len)
|
||||
die("Overflow, len: %zu", len);
|
||||
|
||||
/* If the user has requested to shrink the buffer, do it exactly */
|
||||
if (s->size > reqsize)
|
||||
return reqsize;
|
||||
|
||||
newsize = s->size;
|
||||
if (s->increment < 0) {
|
||||
if (reqsize >= SIZE_MAX / 2) {
|
||||
newsize = reqsize;
|
||||
} else {
|
||||
/* Exponential sizing */
|
||||
while (newsize < reqsize)
|
||||
newsize *= -s->increment;
|
||||
} else {
|
||||
/* Linear sizing */
|
||||
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
|
||||
newsize *= 2;
|
||||
}
|
||||
|
||||
if (newsize < reqsize)
|
||||
die("BUG: strbuf length would overflow, len: %zu", len);
|
||||
|
||||
return newsize;
|
||||
}
|
||||
|
||||
|
||||
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
|
||||
* optional termination). */
|
||||
void strbuf_resize(strbuf_t *s, int len)
|
||||
void strbuf_resize(strbuf_t *s, size_t len)
|
||||
{
|
||||
int newsize;
|
||||
size_t newsize;
|
||||
|
||||
newsize = calculate_new_size(s, len);
|
||||
|
||||
if (s->debug > 1) {
|
||||
fprintf(stderr, "strbuf(%lx) resize: %d => %d\n",
|
||||
fprintf(stderr, "strbuf(%lx) resize: %zd => %zd\n",
|
||||
(long)s, s->size, newsize);
|
||||
}
|
||||
|
||||
s->size = newsize;
|
||||
s->buf = realloc(s->buf, s->size);
|
||||
if (!s->buf)
|
||||
die("Out of memory");
|
||||
die("Out of memory, len: %zu", len);
|
||||
s->reallocs++;
|
||||
}
|
||||
|
||||
void strbuf_append_string(strbuf_t *s, const char *str)
|
||||
{
|
||||
int space, i;
|
||||
int i;
|
||||
size_t space;
|
||||
|
||||
space = strbuf_empty_length(s);
|
||||
|
||||
@@ -197,55 +193,6 @@ void strbuf_append_string(strbuf_t *s, const char *str)
|
||||
}
|
||||
}
|
||||
|
||||
/* strbuf_append_fmt() should only be used when an upper bound
|
||||
* is known for the output string. */
|
||||
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len;
|
||||
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
|
||||
va_start(arg, fmt);
|
||||
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len < 0)
|
||||
die("BUG: Unable to convert number"); /* This should never happen.. */
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
|
||||
/* strbuf_append_fmt_retry() can be used when the there is no known
|
||||
* upper bound for the output string. */
|
||||
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
|
||||
{
|
||||
va_list arg;
|
||||
int fmt_len, try;
|
||||
int empty_len;
|
||||
|
||||
/* If the first attempt to append fails, resize the buffer appropriately
|
||||
* and try again */
|
||||
for (try = 0; ; try++) {
|
||||
va_start(arg, fmt);
|
||||
/* Append the new formatted string */
|
||||
/* fmt_len is the length of the string required, excluding the
|
||||
* trailing NULL */
|
||||
empty_len = strbuf_empty_length(s);
|
||||
/* Add 1 since there is also space to store the terminating NULL. */
|
||||
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
|
||||
va_end(arg);
|
||||
|
||||
if (fmt_len <= empty_len)
|
||||
break; /* SUCCESS */
|
||||
if (try > 0)
|
||||
die("BUG: length of formatted string changed");
|
||||
|
||||
strbuf_resize(s, s->length + fmt_len);
|
||||
}
|
||||
|
||||
s->length += fmt_len;
|
||||
}
|
||||
|
||||
/* vi:ai et sw=4 ts=4:
|
||||
*/
|
||||
|
||||
Vendored
+19
-27
@@ -27,15 +27,13 @@
|
||||
|
||||
/* Size: Total bytes allocated to *buf
|
||||
* Length: String length, excluding optional NULL terminator.
|
||||
* Increment: Allocation increments when resizing the string buffer.
|
||||
* Dynamic: True if created via strbuf_new()
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int size;
|
||||
int length;
|
||||
int increment;
|
||||
size_t size;
|
||||
size_t length;
|
||||
int dynamic;
|
||||
int reallocs;
|
||||
int debug;
|
||||
@@ -44,32 +42,26 @@ typedef struct {
|
||||
#ifndef STRBUF_DEFAULT_SIZE
|
||||
#define STRBUF_DEFAULT_SIZE 1023
|
||||
#endif
|
||||
#ifndef STRBUF_DEFAULT_INCREMENT
|
||||
#define STRBUF_DEFAULT_INCREMENT -2
|
||||
#endif
|
||||
|
||||
/* Initialise */
|
||||
extern strbuf_t *strbuf_new(int len);
|
||||
extern void strbuf_init(strbuf_t *s, int len);
|
||||
extern void strbuf_set_increment(strbuf_t *s, int increment);
|
||||
extern strbuf_t *strbuf_new(size_t len);
|
||||
extern void strbuf_init(strbuf_t *s, size_t len);
|
||||
|
||||
/* Release */
|
||||
extern void strbuf_free(strbuf_t *s);
|
||||
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
|
||||
extern char *strbuf_free_to_string(strbuf_t *s, size_t *len);
|
||||
|
||||
/* Management */
|
||||
extern void strbuf_resize(strbuf_t *s, int len);
|
||||
static int strbuf_empty_length(strbuf_t *s);
|
||||
static int strbuf_length(strbuf_t *s);
|
||||
static char *strbuf_string(strbuf_t *s, int *len);
|
||||
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
|
||||
extern void strbuf_resize(strbuf_t *s, size_t len);
|
||||
static size_t strbuf_empty_length(strbuf_t *s);
|
||||
static size_t strbuf_length(strbuf_t *s);
|
||||
static char *strbuf_string(strbuf_t *s, size_t *len);
|
||||
static void strbuf_ensure_empty_length(strbuf_t *s, size_t len);
|
||||
static char *strbuf_empty_ptr(strbuf_t *s);
|
||||
static void strbuf_extend_length(strbuf_t *s, int len);
|
||||
static void strbuf_extend_length(strbuf_t *s, size_t len);
|
||||
|
||||
/* Update */
|
||||
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
|
||||
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
|
||||
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
|
||||
static void strbuf_append_mem(strbuf_t *s, const char *c, size_t len);
|
||||
extern void strbuf_append_string(strbuf_t *s, const char *str);
|
||||
static void strbuf_append_char(strbuf_t *s, const char c);
|
||||
static void strbuf_ensure_null(strbuf_t *s);
|
||||
@@ -87,12 +79,12 @@ static inline int strbuf_allocated(strbuf_t *s)
|
||||
|
||||
/* Return bytes remaining in the string buffer
|
||||
* Ensure there is space for a NULL terminator. */
|
||||
static inline int strbuf_empty_length(strbuf_t *s)
|
||||
static inline size_t strbuf_empty_length(strbuf_t *s)
|
||||
{
|
||||
return s->size - s->length - 1;
|
||||
}
|
||||
|
||||
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
|
||||
static inline void strbuf_ensure_empty_length(strbuf_t *s, size_t len)
|
||||
{
|
||||
if (len > strbuf_empty_length(s))
|
||||
strbuf_resize(s, s->length + len);
|
||||
@@ -103,12 +95,12 @@ static inline char *strbuf_empty_ptr(strbuf_t *s)
|
||||
return s->buf + s->length;
|
||||
}
|
||||
|
||||
static inline void strbuf_extend_length(strbuf_t *s, int len)
|
||||
static inline void strbuf_extend_length(strbuf_t *s, size_t len)
|
||||
{
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline int strbuf_length(strbuf_t *s)
|
||||
static inline size_t strbuf_length(strbuf_t *s)
|
||||
{
|
||||
return s->length;
|
||||
}
|
||||
@@ -124,14 +116,14 @@ static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
|
||||
s->buf[s->length++] = c;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
|
||||
static inline void strbuf_append_mem(strbuf_t *s, const char *c, size_t len)
|
||||
{
|
||||
strbuf_ensure_empty_length(s, len);
|
||||
memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
}
|
||||
|
||||
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
|
||||
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, size_t len)
|
||||
{
|
||||
memcpy(s->buf + s->length, c, len);
|
||||
s->length += len;
|
||||
@@ -142,7 +134,7 @@ static inline void strbuf_ensure_null(strbuf_t *s)
|
||||
s->buf[s->length] = 0;
|
||||
}
|
||||
|
||||
static inline char *strbuf_string(strbuf_t *s, int *len)
|
||||
static inline char *strbuf_string(strbuf_t *s, size_t *len)
|
||||
{
|
||||
if (len)
|
||||
*len = s->length;
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ ifneq (,$(findstring FreeBSD,$(uname_S)))
|
||||
STD+=-Wno-c11-extensions
|
||||
endif
|
||||
endif
|
||||
WARN=-Wall -W -Wno-missing-field-initializers
|
||||
WARN=-Wall -W -Wno-missing-field-initializers -Wno-strict-prototypes
|
||||
OPT=$(OPTIMIZATION)
|
||||
|
||||
# Detect if the compiler supports C11 _Atomic.
|
||||
|
||||
+6
-5
@@ -397,13 +397,16 @@ int anetUnixGenericConnect(char *err, const char *path, int flags)
|
||||
return s;
|
||||
}
|
||||
|
||||
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog) {
|
||||
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog, mode_t perm) {
|
||||
if (bind(s,sa,len) == -1) {
|
||||
anetSetError(err, "bind: %s", strerror(errno));
|
||||
close(s);
|
||||
return ANET_ERR;
|
||||
}
|
||||
|
||||
if (sa->sa_family == AF_LOCAL && perm)
|
||||
chmod(((struct sockaddr_un *) sa)->sun_path, perm);
|
||||
|
||||
if (listen(s, backlog) == -1) {
|
||||
anetSetError(err, "listen: %s", strerror(errno));
|
||||
close(s);
|
||||
@@ -447,7 +450,7 @@ static int _anetTcpServer(char *err, int port, char *bindaddr, int af, int backl
|
||||
|
||||
if (af == AF_INET6 && anetV6Only(err,s) == ANET_ERR) goto error;
|
||||
if (anetSetReuseAddr(err,s) == ANET_ERR) goto error;
|
||||
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog) == ANET_ERR) s = ANET_ERR;
|
||||
if (anetListen(err,s,p->ai_addr,p->ai_addrlen,backlog,0) == ANET_ERR) s = ANET_ERR;
|
||||
goto end;
|
||||
}
|
||||
if (p == NULL) {
|
||||
@@ -484,10 +487,8 @@ int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
|
||||
memset(&sa,0,sizeof(sa));
|
||||
sa.sun_family = AF_LOCAL;
|
||||
strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
|
||||
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog) == ANET_ERR)
|
||||
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog,perm) == ANET_ERR)
|
||||
return ANET_ERR;
|
||||
if (perm)
|
||||
chmod(sa.sun_path, perm);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
+7
-3
@@ -39,8 +39,12 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
|
||||
#define MAC_OS_10_6_DETECTED
|
||||
#endif
|
||||
|
||||
/* Define redis_fstat to fstat or fstat64() */
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_10_6_DETECTED)
|
||||
#define redis_fstat fstat64
|
||||
#define redis_stat stat64
|
||||
#else
|
||||
@@ -79,7 +83,7 @@
|
||||
#define HAVE_EPOLL 1
|
||||
#endif
|
||||
|
||||
#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
|
||||
#if (defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__)
|
||||
#define HAVE_KQUEUE 1
|
||||
#endif
|
||||
|
||||
@@ -248,7 +252,7 @@ void setproctitle(const char *fmt, ...);
|
||||
#include <kernel/OS.h>
|
||||
#define redis_set_thread_title(name) rename_thread(find_thread(0), name)
|
||||
#else
|
||||
#if (defined __APPLE__ && defined(MAC_OS_X_VERSION_10_7))
|
||||
#if (defined __APPLE__ && defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1070)
|
||||
int pthread_setname_np(const char *name);
|
||||
#include <pthread.h>
|
||||
#define redis_set_thread_title(name) pthread_setname_np(name)
|
||||
|
||||
+3
-3
@@ -1042,7 +1042,7 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) {
|
||||
} \
|
||||
return old_val; \
|
||||
} while(0)
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_6)
|
||||
#if defined(__APPLE__) && !defined(MAC_OS_10_6_DETECTED)
|
||||
/* OSX < 10.6 */
|
||||
#if defined(__x86_64__)
|
||||
GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip);
|
||||
@@ -1051,7 +1051,7 @@ static void* getAndSetMcontextEip(ucontext_t *uc, void *eip) {
|
||||
#else
|
||||
GET_SET_RETURN(uc->uc_mcontext->__ss.__srr0, eip);
|
||||
#endif
|
||||
#elif defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||
#elif defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)
|
||||
/* OSX >= 10.6 */
|
||||
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||
GET_SET_RETURN(uc->uc_mcontext->__ss.__rip, eip);
|
||||
@@ -1123,7 +1123,7 @@ void logRegisters(ucontext_t *uc) {
|
||||
serverLog(LL_WARNING|LL_RAW, "\n------ REGISTERS ------\n");
|
||||
|
||||
/* OSX */
|
||||
#if defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)
|
||||
#if defined(__APPLE__) && defined(MAC_OS_10_6_DETECTED)
|
||||
/* OSX AMD64 */
|
||||
#if defined(_STRUCT_X86_THREAD_STATE64) && !defined(__i386__)
|
||||
serverLog(LL_WARNING,
|
||||
|
||||
+7
-2
@@ -210,9 +210,12 @@ int dictTryExpand(dict *d, unsigned long size) {
|
||||
* work it does would be unbound and the function may block for a long time. */
|
||||
int dictRehash(dict *d, int n) {
|
||||
int empty_visits = n*10; /* Max number of empty buckets to visit. */
|
||||
unsigned long s0 = d->ht[0].size;
|
||||
unsigned long s1 = d->ht[1].size;
|
||||
if (dict_can_resize == DICT_RESIZE_FORBID || !dictIsRehashing(d)) return 0;
|
||||
if (dict_can_resize == DICT_RESIZE_AVOID &&
|
||||
(d->ht[1].size / d->ht[0].size < dict_force_resize_ratio))
|
||||
((s1 > s0 && s1 / s0 < dict_force_resize_ratio) ||
|
||||
(s1 < s0 && s0 / s1 < dict_force_resize_ratio)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -1108,7 +1111,9 @@ size_t _dictGetStatsHt(char *buf, size_t bufsize, dictht *ht, int tableid) {
|
||||
|
||||
if (ht->used == 0) {
|
||||
return snprintf(buf,bufsize,
|
||||
"No stats available for empty dictionaries\n");
|
||||
"Hash table %d stats (%s):\n"
|
||||
"No stats available for empty dictionaries\n",
|
||||
tableid, (tableid == 0) ? "main hash table" : "rehashing target");
|
||||
}
|
||||
|
||||
/* Compute stats. */
|
||||
|
||||
@@ -3285,6 +3285,11 @@ int checkClientOutputBufferLimits(client *c) {
|
||||
int soft = 0, hard = 0, class;
|
||||
unsigned long used_mem = getClientOutputBufferMemoryUsage(c);
|
||||
|
||||
/* For unauthenticated clients the output buffer is limited to prevent
|
||||
* them from abusing it by not reading the replies */
|
||||
if (used_mem > 1024 && authRequired(c))
|
||||
return 1;
|
||||
|
||||
class = getClientType(c);
|
||||
/* For the purpose of output buffer limiting, masters are handled
|
||||
* like normal clients. */
|
||||
|
||||
@@ -1467,6 +1467,7 @@ void scriptingRelease(int async) {
|
||||
else
|
||||
dictRelease(server.lua_scripts);
|
||||
server.lua_scripts_mem = 0;
|
||||
lua_gc(server.lua, LUA_GCCOLLECT, 0);
|
||||
lua_close(server.lua);
|
||||
}
|
||||
|
||||
|
||||
+6
-3
@@ -46,8 +46,11 @@
|
||||
|
||||
/* Glob-style pattern matching. */
|
||||
static int stringmatchlen_impl(const char *pattern, int patternLen,
|
||||
const char *string, int stringLen, int nocase, int *skipLongerMatches)
|
||||
const char *string, int stringLen, int nocase, int *skipLongerMatches, int nesting)
|
||||
{
|
||||
/* Protection against abusive patterns. */
|
||||
if (nesting > 1000) return 0;
|
||||
|
||||
while(patternLen && stringLen) {
|
||||
switch(pattern[0]) {
|
||||
case '*':
|
||||
@@ -59,7 +62,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
|
||||
return 1; /* match */
|
||||
while(stringLen) {
|
||||
if (stringmatchlen_impl(pattern+1, patternLen-1,
|
||||
string, stringLen, nocase, skipLongerMatches))
|
||||
string, stringLen, nocase, skipLongerMatches, nesting+1))
|
||||
return 1; /* match */
|
||||
if (*skipLongerMatches)
|
||||
return 0; /* no match */
|
||||
@@ -181,7 +184,7 @@ static int stringmatchlen_impl(const char *pattern, int patternLen,
|
||||
int stringmatchlen(const char *pattern, int patternLen,
|
||||
const char *string, int stringLen, int nocase) {
|
||||
int skipLongerMatches = 0;
|
||||
return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches);
|
||||
return stringmatchlen_impl(pattern,patternLen,string,stringLen,nocase,&skipLongerMatches,0);
|
||||
}
|
||||
|
||||
int stringmatch(const char *pattern, const char *string, int nocase) {
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
#define REDIS_VERSION "6.2.12"
|
||||
#define REDIS_VERSION_NUM 0x0006020c
|
||||
#define REDIS_VERSION "6.2.18"
|
||||
#define REDIS_VERSION_NUM 0x00060212
|
||||
|
||||
@@ -36,6 +36,14 @@ start_server {tags {"repl network"}} {
|
||||
}
|
||||
}
|
||||
|
||||
test {Slave enters wait_bgsave} {
|
||||
wait_for_condition 50 1000 {
|
||||
[string match *state=wait_bgsave* [$master info replication]]
|
||||
} else {
|
||||
fail "Replica does not enter wait_bgsave state"
|
||||
}
|
||||
}
|
||||
|
||||
# But make the master unable to send
|
||||
# the periodic newlines to refresh the connection. The slave
|
||||
# should detect the timeout.
|
||||
|
||||
+31
-1
@@ -569,7 +569,7 @@ proc get_child_pid {idx} {
|
||||
}
|
||||
|
||||
proc process_is_alive pid {
|
||||
if {[catch {exec ps -p $pid} err]} {
|
||||
if {[catch {exec ps -p $pid -f} err]} {
|
||||
return 0
|
||||
} else {
|
||||
if {[string match "*<defunct>*" $err]} { return 0 }
|
||||
@@ -800,3 +800,33 @@ proc wait_for_blocked_clients_count {count {maxtries 100} {delay 10}} {
|
||||
}
|
||||
}
|
||||
|
||||
proc config_set {param value {options {}}} {
|
||||
set mayfail 0
|
||||
foreach option $options {
|
||||
switch $option {
|
||||
"mayfail" {
|
||||
set mayfail 1
|
||||
}
|
||||
default {
|
||||
error "Unknown option $option"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if {[catch {r config set $param $value} err]} {
|
||||
if {!$mayfail} {
|
||||
error $err
|
||||
} else {
|
||||
if {$::verbose} {
|
||||
puts "Ignoring CONFIG SET $param $value failure: $err"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc config_get_set {param value {options {}}} {
|
||||
set config [lindex [r config get $param] 1]
|
||||
config_set $param $value $options
|
||||
return $config
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,24 @@ start_server {tags {"auth"} overrides {requirepass foobar}} {
|
||||
assert_match {*unauthenticated bulk length*} $e
|
||||
$rr close
|
||||
}
|
||||
|
||||
test {For unauthenticated clients output buffer is limited} {
|
||||
set rr [redis [srv "host"] [srv "port"] 1 $::tls]
|
||||
$rr SET x 5
|
||||
catch {[$rr read]} e
|
||||
assert_match {*NOAUTH Authentication required*} $e
|
||||
|
||||
# Fill the output buffer in a loop without reading it and make
|
||||
# sure the client disconnected.
|
||||
# Considering the socket eat some of the replies, we are testing
|
||||
# that such client can't consume more than few MB's.
|
||||
catch {
|
||||
for {set j 0} {$j < 1000000} {incr j} {
|
||||
$rr SET x 5
|
||||
}
|
||||
} e
|
||||
assert_match {I/O error reading reply} $e
|
||||
}
|
||||
}
|
||||
|
||||
start_server {tags {"auth_binary_password"}} {
|
||||
|
||||
@@ -485,4 +485,10 @@ start_server {tags {"keyspace"}} {
|
||||
r SET aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1
|
||||
r KEYS "a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*b"
|
||||
} {}
|
||||
|
||||
test {Regression for pattern matching very long nested loops} {
|
||||
r flushdb
|
||||
r SET [string repeat "a" 50000] 1
|
||||
r KEYS [string repeat "*?" 50000]
|
||||
} {}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ start_server {tags {"defrag"} overrides {appendonly yes auto-aof-rewrite-percent
|
||||
if {[r config get activedefrag] eq "activedefrag yes"} {
|
||||
# reset stats and load the AOF file
|
||||
r config resetstat
|
||||
r config set key-load-delay -50 ;# sleep on average 1/50 usec
|
||||
r config set key-load-delay -25 ;# sleep on average 1/25 usec
|
||||
r debug loadaof
|
||||
r config set activedefrag no
|
||||
# measure hits and misses right after aof loading
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
set system_name [string tolower [exec uname -s]]
|
||||
set user_id [exec id -u]
|
||||
|
||||
if {$system_name eq {linux}} {
|
||||
start_server {tags {"oom-score-adj"}} {
|
||||
@@ -47,8 +46,15 @@ if {$system_name eq {linux}} {
|
||||
}
|
||||
}
|
||||
|
||||
# Determine whether the current user is unprivileged
|
||||
set original_value [exec cat /proc/self/oom_score_adj]
|
||||
catch {
|
||||
set fd [open "/proc/self/oom_score_adj" "w"]
|
||||
puts $fd -1000
|
||||
close $fd
|
||||
} e
|
||||
# Failed oom-score-adj tests can only run unprivileged
|
||||
if {$user_id != 0} {
|
||||
if {[string match "*permission denied*" $e]} {
|
||||
test {CONFIG SET oom-score-adj handles configuration failures} {
|
||||
# Bad config
|
||||
r config set oom-score-adj no
|
||||
@@ -72,6 +78,11 @@ if {$system_name eq {linux}} {
|
||||
# Make sure previous values remain
|
||||
assert {[r config get oom-score-adj-values] == {oom-score-adj-values {0 100 100}}}
|
||||
}
|
||||
} else {
|
||||
# Restore the original oom_score_adj value
|
||||
set fd [open "/proc/self/oom_score_adj" "w"]
|
||||
puts $fd $original_value
|
||||
close $fd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +259,66 @@ start_server {tags {"scripting"}} {
|
||||
} 0
|
||||
} {a b}
|
||||
|
||||
test {EVAL - JSON smoke test} {
|
||||
r eval {
|
||||
local some_map = {
|
||||
s1="Some string",
|
||||
n1=100,
|
||||
a1={"Some","String","Array"},
|
||||
nil1=nil,
|
||||
b1=true,
|
||||
b2=false}
|
||||
local encoded = cjson.encode(some_map)
|
||||
local decoded = cjson.decode(encoded)
|
||||
assert(table.concat(some_map) == table.concat(decoded))
|
||||
|
||||
cjson.encode_keep_buffer(false)
|
||||
encoded = cjson.encode(some_map)
|
||||
decoded = cjson.decode(encoded)
|
||||
assert(table.concat(some_map) == table.concat(decoded))
|
||||
|
||||
-- Table with numeric keys
|
||||
local table1 = {one="one", [1]="one"}
|
||||
encoded = cjson.encode(table1)
|
||||
decoded = cjson.decode(encoded)
|
||||
assert(decoded["one"] == table1["one"])
|
||||
assert(decoded["1"] == table1[1])
|
||||
|
||||
-- Array
|
||||
local array1 = {[1]="one", [2]="two"}
|
||||
encoded = cjson.encode(array1)
|
||||
decoded = cjson.decode(encoded)
|
||||
assert(table.concat(array1) == table.concat(decoded))
|
||||
|
||||
-- Invalid keys
|
||||
local invalid_map = {}
|
||||
invalid_map[false] = "false"
|
||||
local ok, encoded = pcall(cjson.encode, invalid_map)
|
||||
assert(ok == false)
|
||||
|
||||
-- Max depth
|
||||
cjson.encode_max_depth(1)
|
||||
ok, encoded = pcall(cjson.encode, some_map)
|
||||
assert(ok == false)
|
||||
|
||||
cjson.decode_max_depth(1)
|
||||
ok, decoded = pcall(cjson.decode, '{"obj": {"array": [1,2,3,4]}}')
|
||||
assert(ok == false)
|
||||
|
||||
-- Invalid numbers
|
||||
ok, encoded = pcall(cjson.encode, {num1=0/0})
|
||||
assert(ok == false)
|
||||
cjson.encode_invalid_numbers(true)
|
||||
ok, encoded = pcall(cjson.encode, {num1=0/0})
|
||||
assert(ok == true)
|
||||
|
||||
-- Restore defaults
|
||||
cjson.decode_max_depth(1000)
|
||||
cjson.encode_max_depth(1000)
|
||||
cjson.encode_invalid_numbers(false)
|
||||
} 0
|
||||
}
|
||||
|
||||
test {EVAL - cmsgpack can pack double?} {
|
||||
r eval {local encoded = cmsgpack.pack(0.1)
|
||||
local h = ""
|
||||
@@ -279,6 +339,68 @@ start_server {tags {"scripting"}} {
|
||||
} 0
|
||||
} {d3ffffff0000000000}
|
||||
|
||||
test {EVAL - cmsgpack pack/unpack smoke test} {
|
||||
r eval {
|
||||
local str_lt_32 = string.rep("x", 30)
|
||||
local str_lt_255 = string.rep("x", 250)
|
||||
local str_lt_65535 = string.rep("x", 65530)
|
||||
local str_long = string.rep("x", 100000)
|
||||
local array_lt_15 = {1, 2, 3, 4, 5}
|
||||
local array_lt_65535 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}
|
||||
local array_big = {}
|
||||
for i=1, 100000 do
|
||||
array_big[i] = i
|
||||
end
|
||||
local map_lt_15 = {a=1, b=2}
|
||||
local map_big = {}
|
||||
for i=1, 100000 do
|
||||
map_big[tostring(i)] = i
|
||||
end
|
||||
local some_map = {
|
||||
s1=str_lt_32,
|
||||
s2=str_lt_255,
|
||||
s3=str_lt_65535,
|
||||
s4=str_long,
|
||||
d1=0.1,
|
||||
i1=1,
|
||||
i2=250,
|
||||
i3=65530,
|
||||
i4=100000,
|
||||
i5=2^40,
|
||||
i6=-1,
|
||||
i7=-120,
|
||||
i8=-32000,
|
||||
i9=-100000,
|
||||
i10=-3147483648,
|
||||
a1=array_lt_15,
|
||||
a2=array_lt_65535,
|
||||
a3=array_big,
|
||||
m1=map_lt_15,
|
||||
m2=map_big,
|
||||
b1=false,
|
||||
b2=true,
|
||||
n=nil
|
||||
}
|
||||
local encoded = cmsgpack.pack(some_map)
|
||||
local decoded = cmsgpack.unpack(encoded)
|
||||
assert(table.concat(some_map) == table.concat(decoded))
|
||||
local offset, decoded_one = cmsgpack.unpack_one(encoded, 0)
|
||||
assert(table.concat(some_map) == table.concat(decoded_one))
|
||||
assert(offset == -1)
|
||||
|
||||
local encoded_multiple = cmsgpack.pack(str_lt_32, str_lt_255, str_lt_65535, str_long)
|
||||
local offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, 0)
|
||||
assert(obj == str_lt_32)
|
||||
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
|
||||
assert(obj == str_lt_255)
|
||||
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
|
||||
assert(obj == str_lt_65535)
|
||||
offset, obj = cmsgpack.unpack_limit(encoded_multiple, 1, offset)
|
||||
assert(obj == str_long)
|
||||
assert(offset == -1)
|
||||
} 0
|
||||
}
|
||||
|
||||
test {EVAL - cmsgpack can pack and unpack circular references?} {
|
||||
r eval {local a = {x=nil,y=5}
|
||||
local b = {x=a}
|
||||
@@ -406,6 +528,12 @@ start_server {tags {"scripting"}} {
|
||||
set e
|
||||
} {ERR*Attempt to modify a readonly table*}
|
||||
|
||||
test {lua bit.tohex bug} {
|
||||
set res [r eval {return bit.tohex(65535, -2147483648)} 0]
|
||||
r ping
|
||||
set res
|
||||
} {0000FFFF}
|
||||
|
||||
test {Test an example script DECR_IF_GT} {
|
||||
set decr_if_gt {
|
||||
local current
|
||||
@@ -449,6 +577,7 @@ start_server {tags {"scripting"}} {
|
||||
}
|
||||
|
||||
test {EVAL does not leak in the Lua stack} {
|
||||
r script flush ;# reset Lua VM
|
||||
r set x 0
|
||||
# Use a non blocking client to speedup the loop.
|
||||
set rd [redis_deferring_client]
|
||||
|
||||
@@ -753,6 +753,85 @@ start_server {
|
||||
}
|
||||
}
|
||||
|
||||
proc is_rehashing {myset} {
|
||||
set htstats [r debug HTSTATS-KEY $myset]
|
||||
return [string match {*rehashing target*} $htstats]
|
||||
}
|
||||
|
||||
proc rem_hash_set_top_N {myset n} {
|
||||
set cursor 0
|
||||
set members {}
|
||||
set enough 0
|
||||
while 1 {
|
||||
set res [r sscan $myset $cursor]
|
||||
set cursor [lindex $res 0]
|
||||
set k [lindex $res 1]
|
||||
foreach m $k {
|
||||
lappend members $m
|
||||
if {[llength $members] >= $n} {
|
||||
set enough 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$enough || $cursor == 0} {
|
||||
break
|
||||
}
|
||||
}
|
||||
r srem $myset {*}$members
|
||||
}
|
||||
|
||||
test "SRANDMEMBER with a dict containing long chain" {
|
||||
set origin_save [config_get_set save ""]
|
||||
set origin_max_is [config_get_set set-max-intset-entries 0]
|
||||
set origin_save_delay [config_get_set rdb-key-save-delay 2147483647]
|
||||
|
||||
# 1) Create a hash set with 100000 members.
|
||||
set members {}
|
||||
for {set i 0} {$i < 100000} {incr i} {
|
||||
lappend members [format "m:%d" $i]
|
||||
}
|
||||
create_set myset $members
|
||||
|
||||
# 2) Wait for the hash set rehashing to finish.
|
||||
while {[is_rehashing myset]} {
|
||||
r srandmember myset 100
|
||||
}
|
||||
|
||||
# 3) Turn off the rehashing of this set, and remove the members to 500.
|
||||
r bgsave
|
||||
rem_hash_set_top_N myset [expr {[r scard myset] - 500}]
|
||||
assert_equal [r scard myset] 500
|
||||
|
||||
# 4) Kill RDB child process to restart rehashing.
|
||||
set pid1 [get_child_pid 0]
|
||||
catch {exec kill -9 $pid1}
|
||||
waitForBgsave r
|
||||
|
||||
# 5) Let the set hash to start rehashing
|
||||
r spop myset 1
|
||||
assert [is_rehashing myset]
|
||||
|
||||
# 6) Verify that when rdb saving is in progress, rehashing will still be performed (because
|
||||
# the ratio is extreme) by waiting for it to finish during an active bgsave.
|
||||
r bgsave
|
||||
|
||||
while {[is_rehashing myset]} {
|
||||
r srandmember myset 1
|
||||
}
|
||||
if {$::verbose} {
|
||||
puts [r debug HTSTATS-KEY myset]
|
||||
}
|
||||
|
||||
set pid1 [get_child_pid 0]
|
||||
catch {exec kill -9 $pid1}
|
||||
waitForBgsave r
|
||||
|
||||
r config set save $origin_save
|
||||
r config set set-max-intset-entries $origin_max_is
|
||||
r config set rdb-key-save-delay $origin_save_delay
|
||||
r save
|
||||
} {OK}
|
||||
|
||||
proc setup_move {} {
|
||||
r del myset3 myset4
|
||||
create_set myset1 {1 a b}
|
||||
|
||||
@@ -458,6 +458,7 @@ start_server {tags {"string"}} {
|
||||
}
|
||||
}
|
||||
|
||||
if {[string match {*jemalloc*} [s mem_allocator]]} {
|
||||
test {trim on SET with big value} {
|
||||
# set a big value to trigger increasing the query buf
|
||||
r set key [string repeat A 100000]
|
||||
@@ -466,6 +467,7 @@ start_server {tags {"string"}} {
|
||||
# asset the value was trimmed
|
||||
assert {[r memory usage key] < 42000}; # 42K to count for Jemalloc's additional memory overhead.
|
||||
}
|
||||
} ;# if jemalloc
|
||||
|
||||
test {Extended SET can detect syntax errors} {
|
||||
set e {}
|
||||
|
||||
Reference in New Issue
Block a user