Unverified Commit 2667c412 authored by Oran Agra's avatar Oran Agra Committed by GitHub
Browse files

Merge pull request #10829 from oranagra/release-7.0.1

Release 7.0.1
parents d375595d 595e725d
......@@ -1651,8 +1651,11 @@ void luaCallFunction(scriptRunCtx* run_ctx, lua_State *lua, robj** keys, size_t
* {err='<error msg>', source='<source file>', line=<line>}
* We can construct the error message from this information */
if (!lua_istable(lua, -1)) {
/* Should not happened, and we should considered assert it */
addReplyErrorFormat(c,"Error running script (call to %s)\n", run_ctx->funcname);
const char *msg = "execution failure";
if (lua_isstring(lua, -1)) {
msg = lua_tostring(lua, -1);
}
addReplyErrorFormat(c,"Error running script %s, %.100s\n", run_ctx->funcname, msg);
} else {
errorInfo err_info = {0};
sds final_msg = sdsempty();
......
......@@ -4127,7 +4127,7 @@ numargserr:
void addInfoSectionsToDict(dict *section_dict, char **sections);
/* SENTINEL INFO [section] */
/* INFO [<section> [<section> ...]] */
void sentinelInfoCommand(client *c) {
char *sentinel_sections[] = {"server", "clients", "cpu", "stats", "sentinel", NULL};
int sec_all = 0, sec_everything = 0;
......
This diff is collapsed.
......@@ -70,7 +70,6 @@ typedef long long ustime_t; /* microsecond time type. */
#include "adlist.h" /* Linked lists */
#include "zmalloc.h" /* total memory usage aware version of malloc/free */
#include "anet.h" /* Networking the easy way */
#include "ziplist.h" /* Compact list data structure */
#include "intset.h" /* Compact integer set structure */
#include "version.h" /* Version macro */
#include "util.h" /* Misc functions useful in many places */
......@@ -86,11 +85,14 @@ typedef long long ustime_t; /* microsecond time type. */
/* Following includes allow test functions to be called from Redis main() */
#include "zipmap.h"
#include "ziplist.h" /* Compact list data structure */
#include "sha1.h"
#include "endianconv.h"
#include "crc64.h"
/* min/max */
#undef min
#undef max
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
......@@ -112,7 +114,6 @@ typedef long long ustime_t; /* microsecond time type. */
#define LOG_MAX_LEN 1024 /* Default maximum length of syslog messages.*/
#define AOF_REWRITE_ITEMS_PER_CMD 64
#define AOF_ANNOTATION_LINE_MAX_LEN 1024
#define CONFIG_AUTHPASS_MAX_LEN 512
#define CONFIG_RUN_ID_SIZE 40
#define RDB_EOF_MARK_SIZE 40
#define CONFIG_REPL_BACKLOG_MIN_SIZE (1024*16) /* 16k */
......@@ -153,9 +154,11 @@ typedef long long ustime_t; /* microsecond time type. */
/* Instantaneous metrics tracking. */
#define STATS_METRIC_SAMPLES 16 /* Number of samples per metric. */
#define STATS_METRIC_COMMAND 0 /* Number of commands executed. */
#define STATS_METRIC_NET_INPUT 1 /* Bytes read to network .*/
#define STATS_METRIC_NET_INPUT 1 /* Bytes read to network. */
#define STATS_METRIC_NET_OUTPUT 2 /* Bytes written to network. */
#define STATS_METRIC_COUNT 3
#define STATS_METRIC_NET_INPUT_REPLICATION 3 /* Bytes read to network during replication. */
#define STATS_METRIC_NET_OUTPUT_REPLICATION 4 /* Bytes written to network during replication. */
#define STATS_METRIC_COUNT 5
/* Protocol and I/O related defines */
#define PROTO_IOBUF_LEN (1024*16) /* Generic I/O buffer size */
......@@ -289,7 +292,7 @@ extern int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT];
#define AOF_ON 1 /* AOF is on */
#define AOF_WAIT_REWRITE 2 /* AOF waits rewrite to start appending */
/* AOF return values for loadAppendOnlyFile() */
/* AOF return values for loadAppendOnlyFiles() and loadSingleAppendOnlyFile() */
#define AOF_OK 0
#define AOF_NOT_EXIST 1
#define AOF_EMPTY 2
......@@ -674,6 +677,7 @@ struct redisObject;
struct RedisModuleDefragCtx;
struct RedisModuleInfoCtx;
struct RedisModuleKeyOptCtx;
struct RedisModuleCommand;
/* Each module type implementation should export a set of methods in order
* to serialize and deserialize the value in the RDB file, rewrite the AOF
......@@ -825,9 +829,9 @@ typedef struct RedisModuleDigest {
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_ZIPMAP 3 /* No longer used: old hash encoding. */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_ZIPLIST 5 /* No longer used: old list/hash/zset encoding. */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
......@@ -1077,6 +1081,7 @@ typedef struct {
typedef struct client {
uint64_t id; /* Client incremental unique ID. */
uint64_t flags; /* Client flags: CLIENT_* macros. */
connection *conn;
int resp; /* RESP protocol version. Can be 2 or 3. */
redisDb *db; /* Pointer to currently SELECTed DB. */
......@@ -1110,7 +1115,6 @@ typedef struct client {
int slot; /* The slot the client is executing against. Set to -1 if no slot is being used */
time_t lastinteraction; /* Time of the last interaction, used for timeout */
time_t obuf_soft_limit_reached_time;
uint64_t flags; /* Client flags: CLIENT_* macros. */
int authenticated; /* Needed when the default user requires auth. */
int replstate; /* Replication state if this is a slave. */
int repl_start_cmd_stream_on_ack; /* Install slave write handler on first ACK. */
......@@ -1225,7 +1229,7 @@ struct sharedObjectsStruct {
*time, *pxat, *absttl, *retrycount, *force, *justid, *entriesread,
*lastid, *ping, *setid, *keepttl, *load, *createconsumer,
*getack, *special_asterick, *special_equals, *default_username, *redacted,
*ssubscribebulk,*sunsubscribebulk,
*ssubscribebulk,*sunsubscribebulk, *smessagebulk,
*select[PROTO_SHARED_SELECT_CMDS],
*integers[OBJ_SHARED_INTEGERS],
*mbulkhdr[OBJ_SHARED_BULKHDR_LEN], /* "*<value>\r\n" */
......@@ -1473,7 +1477,6 @@ struct redisServer {
int sentinel_mode; /* True if this instance is a Sentinel. */
size_t initial_memory_usage; /* Bytes used after initialization. */
int always_show_logo; /* Show logo even for non-stdout logging. */
int in_script; /* Are we inside EVAL? */
int in_exec; /* Are we inside EXEC? */
int busy_module_yield_flags; /* Are we inside a busy module? (triggered by RM_Yield). see BUSY_MODULE_YIELD_ flags. */
const char *busy_module_yield_reply; /* When non-null, we are inside RM_Yield. */
......@@ -1584,6 +1587,8 @@ struct redisServer {
struct malloc_stats cron_malloc_stats; /* sampled in serverCron(). */
redisAtomic long long stat_net_input_bytes; /* Bytes read from network. */
redisAtomic long long stat_net_output_bytes; /* Bytes written to network. */
redisAtomic long long stat_net_repl_input_bytes; /* Bytes read during replication, added to stat_net_input_bytes in 'info'. */
redisAtomic long long stat_net_repl_output_bytes; /* Bytes written during replication, added to stat_net_output_bytes in 'info'. */
size_t stat_current_cow_peak; /* Peak size of copy on write bytes. */
size_t stat_current_cow_bytes; /* Copy on write bytes while child is active. */
monotime stat_current_cow_updated; /* Last update time of stat_current_cow_bytes */
......@@ -1884,7 +1889,7 @@ struct redisServer {
/* Scripting */
client *script_caller; /* The client running script right now, or NULL */
mstime_t busy_reply_threshold; /* Script / module timeout in milliseconds */
int script_oom; /* OOM detected when script start */
int pre_command_oom_state; /* OOM before command (script?) was started */
int script_disable_deny_script; /* Allow running commands marked "no-script" inside a script. */
/* Lazy free */
int lazyfree_lazy_eviction;
......@@ -2258,6 +2263,7 @@ struct redisCommand {
dict *subcommands_dict; /* A dictionary that holds the subcommands, the key is the subcommand sds name
* (not the fullname), and the value is the redisCommand structure pointer. */
struct redisCommand *parent;
struct RedisModuleCommand *module_cmd; /* A pointer to the module command data (NULL if native command) */
};
struct redisError {
......@@ -2586,7 +2592,7 @@ void listElementsRemoved(client *c, robj *key, int where, robj *o, long count, i
void unwatchAllKeys(client *c);
void initClientMultiState(client *c);
void freeClientMultiState(client *c);
void queueMultiCommand(client *c);
void queueMultiCommand(client *c, uint64_t cmd_flags);
size_t multiStateMemOverhead(client *c);
void touchWatchedKey(redisDb *db, robj *key);
int isWatchedKeyExpired(client *c);
......@@ -2988,7 +2994,7 @@ void pubsubUnsubscribeShardChannels(robj **channels, unsigned int count);
int pubsubUnsubscribeAllPatterns(client *c, int notify);
int pubsubPublishMessage(robj *channel, robj *message, int sharded);
int pubsubPublishMessageAndPropagateToCluster(robj *channel, robj *message, int sharded);
void addReplyPubsubMessage(client *c, robj *channel, robj *msg);
void addReplyPubsubMessage(client *c, robj *channel, robj *msg, robj *message_bulk);
int serverPubsubSubscriptionCount();
int serverPubsubShardSubscriptionCount();
......@@ -3010,6 +3016,10 @@ sds keyspaceEventsFlagsToString(int flags);
#define DENY_LOADING_CONFIG (1ULL<<6) /* This config is forbidden during loading. */
#define ALIAS_CONFIG (1ULL<<7) /* For configs with multiple names, this flag is set on the alias. */
#define MODULE_CONFIG (1ULL<<8) /* This config is a module config */
#define VOLATILE_CONFIG (1ULL<<9) /* The config is a reference to the config data and not the config data itself (ex.
* a file name containing more configuration like a tls key). In this case we want
* to apply the configuration change even if the new config value is the same as
* the old. */
#define INTEGER_CONFIG 0 /* No flags means a simple integer configuration */
#define MEMORY_CONFIG (1<<0) /* Indicates if this value can be loaded as a memory value */
......@@ -3191,6 +3201,9 @@ void sha1hex(char *digest, char *script, size_t len);
unsigned long evalMemory();
dict* evalScriptsDict();
unsigned long evalScriptsMemory();
uint64_t evalGetCommandFlags(client *c, uint64_t orig_flags);
uint64_t fcallGetCommandFlags(client *c, uint64_t orig_flags);
int isInsideYieldingLongCommand();
typedef struct luaScript {
uint64_t flags;
......
/*
* Copyright (c) 2022, Redis Ltd.
* Copyright (c) 2016, Salvatore Sanfilippo <antirez at gmail dot com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "fmacros.h"
#include "config.h"
#include "syscheck.h"
#include "sds.h"
#include "anet.h"
#include <time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#ifdef __linux__
#include <sys/mman.h>
#endif
#ifdef __linux__
static sds read_sysfs_line(char *path) {
char buf[256];
FILE *f = fopen(path, "r");
if (!f) return NULL;
if (!fgets(buf, sizeof(buf), f)) {
fclose(f);
return NULL;
}
fclose(f);
sds res = sdsnew(buf);
res = sdstrim(res, " \n");
return res;
}
/* Verify our clokcsource implementation doesn't go through a system call (uses vdso).
* Going through a system call to check the time degrades Redis performance. */
static int checkClocksource(sds *error_msg) {
unsigned long test_time_us, system_hz;
struct timespec ts;
unsigned long long start_us;
struct rusage ru_start, ru_end;
system_hz = sysconf(_SC_CLK_TCK);
if (getrusage(RUSAGE_SELF, &ru_start) != 0)
return 0;
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) {
return 0;
}
start_us = (ts.tv_sec * 1000000 + ts.tv_nsec / 1000);
/* clock_gettime() busy loop of 5 times system tick (for a system_hz of 100 this is 50ms)
* Using system_hz is required to ensure accurate measurements from getrusage().
* If our clocksource is configured correctly (vdso) this will result in no system calls.
* If our clocksource is inefficient it'll waste most of the busy loop in the kernel. */
test_time_us = 5 * 1000000 / system_hz;
while (1) {
unsigned long long d;
if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
return 0;
d = (ts.tv_sec * 1000000 + ts.tv_nsec / 1000) - start_us;
if (d >= test_time_us) break;
}
if (getrusage(RUSAGE_SELF, &ru_end) != 0)
return 0;
long long stime_us = (ru_end.ru_stime.tv_sec * 1000000 + ru_end.ru_stime.tv_usec) - (ru_start.ru_stime.tv_sec * 1000000 + ru_start.ru_stime.tv_usec);
long long utime_us = (ru_end.ru_utime.tv_sec * 1000000 + ru_end.ru_utime.tv_usec) - (ru_start.ru_utime.tv_sec * 1000000 + ru_start.ru_utime.tv_usec);
/* If more than 10% of the process time was in system calls we probably have an inefficient clocksource, print a warning */
if (stime_us * 10 > stime_us + utime_us) {
sds avail = read_sysfs_line("/sys/devices/system/clocksource/clocksource0/available_clocksource");
sds curr = read_sysfs_line("/sys/devices/system/clocksource/clocksource0/current_clocksource");
*error_msg = sdscatprintf(sdsempty(),
"Slow system clocksource detected. This can result in degraded performance. "
"Consider changing the system's clocksource. "
"Current clocksource: %s. Available clocksources: %s. "
"For example: run the command 'echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource' as root. "
"To permanently change the system's clocksource you'll need to set the 'clocksource=' kernel command line parameter.",
curr ? curr : "", avail ? avail : "");
sdsfree(avail);
sdsfree(curr);
return -1;
} else {
return 1;
}
}
/* Verify we're not using the `xen` clocksource. The xen hypervisor's default clocksource is slow and affects
* Redis's performance. This has been measured on ec2 xen based instances. ec2 recommends using the non-default
* tsc clock source for these instances. */
int checkXenClocksource(sds *error_msg) {
sds curr = read_sysfs_line("/sys/devices/system/clocksource/clocksource0/current_clocksource");
int res = 1;
if (curr == NULL) {
res = 0;
} else if (strcmp(curr, "xen") == 0) {
*error_msg = sdsnew(
"Your system is configured to use the 'xen' clocksource which might lead to degraded performance. "
"Check the result of the [slow-clocksource] system check: run 'redis-server --check-system' to check if "
"the system's clocksource isn't degrading performance.");
res = -1;
}
sdsfree(curr);
return res;
}
/* Verify overcommit is enabled.
* When overcommit memory is disabled Linux will kill the forked child of a background save
* if we don't have enough free memory to satisfy double the current memory usage even though
* the forked child uses copy-on-write to reduce its actual memory usage. */
int checkOvercommit(sds *error_msg) {
FILE *fp = fopen("/proc/sys/vm/overcommit_memory","r");
char buf[64];
if (!fp) return -1;
if (fgets(buf,64,fp) == NULL) {
fclose(fp);
return 0;
}
fclose(fp);
if (atoi(buf)) {
*error_msg = sdsnew(
"WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. "
"To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the "
"command 'sysctl vm.overcommit_memory=1' for this to take effect.");
return -1;
} else {
return 1;
}
}
/* Make sure transparent huge pages aren't always enabled. When they are this can cause copy-on-write logic
* to consume much more memory and reduce performance during forks. */
int checkTHPEnabled(sds *error_msg) {
char buf[1024];
FILE *fp = fopen("/sys/kernel/mm/transparent_hugepage/enabled","r");
if (!fp) return 0;
if (fgets(buf,sizeof(buf),fp) == NULL) {
fclose(fp);
return 0;
}
fclose(fp);
if (strstr(buf,"[always]") != NULL) {
*error_msg = sdsnew(
"You have Transparent Huge Pages (THP) support enabled in your kernel. "
"This will create latency and memory usage issues with Redis. "
"To fix this issue run the command 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled' as root, "
"and add it to your /etc/rc.local in order to retain the setting after a reboot. "
"Redis must be restarted after THP is disabled (set to 'madvise' or 'never').");
return -1;
} else {
return 1;
}
}
#ifdef __arm64__
/* Get size in kilobytes of the Shared_Dirty pages of the calling process for the
* memory map corresponding to the provided address, or -1 on error. */
static int smapsGetSharedDirty(unsigned long addr) {
int ret, in_mapping = 0, val = -1;
unsigned long from, to;
char buf[64];
FILE *f;
f = fopen("/proc/self/smaps", "r");
if (!f) return -1;
while (1) {
if (!fgets(buf, sizeof(buf), f))
break;
ret = sscanf(buf, "%lx-%lx", &from, &to);
if (ret == 2)
in_mapping = from <= addr && addr < to;
if (in_mapping && !memcmp(buf, "Shared_Dirty:", 13)) {
sscanf(buf, "%*s %d", &val);
/* If parsing fails, we remain with val == -1 */
break;
}
}
fclose(f);
return val;
}
/* Older arm64 Linux kernels have a bug that could lead to data corruption
* during background save in certain scenarios. This function checks if the
* kernel is affected.
* The bug was fixed in commit ff1712f953e27f0b0718762ec17d0adb15c9fd0b
* titled: "arm64: pgtable: Ensure dirty bit is preserved across pte_wrprotect()"
*/
int checkLinuxMadvFreeForkBug(sds *error_msg) {
int ret, pipefd[2] = { -1, -1 };
pid_t pid;
char *p = NULL, *q;
int res = 1;
long page_size = sysconf(_SC_PAGESIZE);
long map_size = 3 * page_size;
/* Create a memory map that's in our full control (not one used by the allocator). */
p = mmap(NULL, map_size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (p == MAP_FAILED) {
return 0;
}
q = p + page_size;
/* Split the memory map in 3 pages by setting their protection as RO|RW|RO to prevent
* Linux from merging this memory map with adjacent VMAs. */
ret = mprotect(q, page_size, PROT_READ | PROT_WRITE);
if (ret < 0) {
res = 0;
goto exit;
}
/* Write to the page once to make it resident */
*(volatile char*)q = 0;
/* Tell the kernel that this page is free to be reclaimed. */
#ifndef MADV_FREE
#define MADV_FREE 8
#endif
ret = madvise(q, page_size, MADV_FREE);
if (ret < 0) {
/* MADV_FREE is not available on older kernels that are presumably
* not affected. */
if (errno == EINVAL) goto exit;
res = 0;
goto exit;
}
/* Write to the page after being marked for freeing, this is supposed to take
* ownership of that page again. */
*(volatile char*)q = 0;
/* Create a pipe for the child to return the info to the parent. */
ret = anetPipe(pipefd, 0, 0);
if (ret < 0) {
res = 0;
goto exit;
}
/* Fork the process. */
pid = fork();
if (pid < 0) {
res = 0;
goto exit;
} else if (!pid) {
/* Child: check if the page is marked as dirty, page_size in kb.
* A value of 0 means the kernel is affected by the bug. */
ret = smapsGetSharedDirty((unsigned long) q);
if (!ret)
res = -1;
else if (ret == -1) /* Failed to read */
res = 0;
ret = write(pipefd[1], &res, sizeof(res)); /* Assume success, ignore return value*/
exit(0);
} else {
/* Read the result from the child. */
ret = read(pipefd[0], &res, sizeof(res));
if (ret < 0) {
res = 0;
}
/* Reap the child pid. */
waitpid(pid, NULL, 0);
}
exit:
/* Cleanup */
if (pipefd[0] != -1) close(pipefd[0]);
if (pipefd[1] != -1) close(pipefd[1]);
if (p != NULL) munmap(p, map_size);
if (res == -1)
*error_msg = sdsnew(
"Your kernel has a bug that could lead to data corruption during background save. "
"Please upgrade to the latest stable kernel.");
return res;
}
#endif /* __arm64__ */
#endif /* __linux__ */
/*
* Standard system check interface:
* Each check has a name `name` and a functions pointer `check_fn`.
* `check_fn` should return:
* -1 in case the check fails.
* 1 in case the check passes.
* 0 in case the check could not be completed (usually because of some unexpected failed system call).
* When (and only when) the check fails and -1 is returned and error description is places in a new sds pointer to by
* the single `sds*` argument to `check_fn`. This message should be freed by the caller via `sdsfree()`.
*/
typedef struct {
const char *name;
int (*check_fn)(sds*);
} check;
check checks[] = {
#ifdef __linux__
{.name = "slow-clocksource", .check_fn = checkClocksource},
{.name = "xen-clocksource", .check_fn = checkXenClocksource},
{.name = "overcommit", .check_fn = checkOvercommit},
{.name = "THP", .check_fn = checkTHPEnabled},
#ifdef __arm64__
{.name = "madvise-free-fork-bug", .check_fn = checkLinuxMadvFreeForkBug},
#endif
#endif
{.name = NULL, .check_fn = NULL}
};
/* Performs various system checks, returns 0 if any check fails, 1 otherwise. */
int syscheck(void) {
check *cur_check = checks;
int ret = 1;
sds err_msg;
while (cur_check->check_fn) {
int res = cur_check->check_fn(&err_msg);
printf("[%s]...", cur_check->name);
if (res == 0) {
printf("skipped\n");
} else if (res == 1) {
printf("OK\n");
} else {
printf("WARNING:\n");
printf("%s\n", err_msg);
sdsfree(err_msg);
ret = 0;
}
cur_check++;
}
return ret;
}
/*
* Copyright (c) 2022, Redis Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SYSCHECK_H
#define __SYSCHECK_H
#include "sds.h"
#include "config.h"
int syscheck(void);
#ifdef __linux__
int checkXenClocksource(sds *error_msg);
int checkTHPEnabled(sds *error_msg);
int checkOvercommit(sds *error_msg);
#ifdef __arm64__
int checkLinuxMadvFreeForkBug(sds *error_msg);
#endif
#endif
#endif
......@@ -679,7 +679,8 @@ void lposCommand(client *c) {
return;
if (rank == 0) {
addReplyError(c,"RANK can't be zero: use 1 to start from "
"the first match, 2 from the second, ...");
"the first match, 2 from the second ... "
"or use negative to start from the end of the list");
return;
}
} else if (!strcasecmp(opt,"COUNT") && moreargs) {
......@@ -1197,12 +1198,12 @@ void lmpopGenericCommand(client *c, int numkeys_idx, int is_block) {
}
}
/* LMPOP numkeys [<key> ...] LEFT|RIGHT [COUNT count] */
/* LMPOP numkeys <key> [<key> ...] (LEFT|RIGHT) [COUNT count] */
void lmpopCommand(client *c) {
lmpopGenericCommand(c, 1, 0);
}
/* BLMPOP timeout numkeys [<key> ...] LEFT|RIGHT [COUNT count] */
/* BLMPOP timeout numkeys <key> [<key> ...] (LEFT|RIGHT) [COUNT count] */
void blmpopCommand(client *c) {
lmpopGenericCommand(c, 2, 1);
}
......@@ -203,7 +203,7 @@ sds setTypeNextObject(setTypeIterator *si) {
* The caller provides both pointers to be populated with the right
* object. The return value of the function is the object->encoding
* field of the object and is used by the caller to check if the
* int64_t pointer or the redis object pointer was populated.
* int64_t pointer or the sds pointer was populated.
*
* Note that both the sdsele and llele pointers should be passed and cannot
* be NULL since the function will try to defensively populate the non
......@@ -805,7 +805,7 @@ void srandmemberWithCountCommand(client *c) {
}
}
/* SRANDMEMBER [<count>] */
/* SRANDMEMBER <key> [<count>] */
void srandmemberCommand(client *c) {
robj *set;
sds ele;
......@@ -850,7 +850,7 @@ int qsortCompareSetsByRevCardinality(const void *s1, const void *s2) {
return 0;
}
/* SINTER / SINTERSTORE / SINTERCARD
/* SINTER / SMEMBERS / SINTERSTORE / SINTERCARD
*
* 'cardinality_only' work for SINTERCARD, only return the cardinality
* with minimum processing and memory overheads.
......@@ -1055,6 +1055,7 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
sds ele;
int j, cardinality = 0;
int diff_algo = 1;
int sameset = 0;
for (j = 0; j < setnum; j++) {
robj *setobj = lookupKeyRead(c->db, setkeys[j]);
......@@ -1067,6 +1068,9 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
return;
}
sets[j] = setobj;
if (j > 0 && sets[0] == sets[j]) {
sameset = 1;
}
}
/* Select what DIFF algorithm to use.
......@@ -1078,7 +1082,7 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
* the sets.
*
* We compute what is the best bet with the current input here. */
if (op == SET_OP_DIFF && sets[0]) {
if (op == SET_OP_DIFF && sets[0] && !sameset) {
long long algo_one_work = 0, algo_two_work = 0;
for (j = 0; j < setnum; j++) {
......@@ -1120,6 +1124,8 @@ void sunionDiffGenericCommand(client *c, robj **setkeys, int setnum,
}
setTypeReleaseIterator(si);
}
} else if (op == SET_OP_DIFF && sameset) {
/* At least one of the sets is the same one (same key) as the first one, result must be empty. */
} else if (op == SET_OP_DIFF && sets[0] && diff_algo == 1) {
/* DIFF Algorithm 1:
*
......
......@@ -401,7 +401,7 @@ void streamGetEdgeID(stream *s, int first, int skip_tombstones, streamID *edge_i
streamID min_id = {0, 0}, max_id = {UINT64_MAX, UINT64_MAX};
*edge_id = first ? max_id : min_id;
}
streamIteratorStop(&si);
}
/* Adds a new item into the stream 's' having the specified number of
......@@ -946,7 +946,7 @@ static int streamParseAddOrTrimArgsOrReply(client *c, streamAddTrimArgs *args, i
}
args->approx_trim = 0;
char *next = c->argv[i+1]->ptr;
/* Check for the form MINID ~ <id>|<age>. */
/* Check for the form MINID ~ <id> */
if (moreargs >= 2 && next[0] == '~' && next[1] == '\0') {
args->approx_trim = 1;
i++;
......
......@@ -927,7 +927,7 @@ int zzlLexValueLteMax(unsigned char *p, zlexrangespec *spec) {
}
/* Returns if there is a part of the zset is in range. Should only be used
* internally by zzlFirstInRange and zzlLastInRange. */
* internally by zzlFirstInLexRange and zzlLastInLexRange. */
int zzlIsInLexRange(unsigned char *zl, zlexrangespec *range) {
unsigned char *p;
......@@ -1186,9 +1186,10 @@ void zsetConvert(robj *zobj, int encoding) {
zs->zsl = zslCreate();
eptr = lpSeek(zl,0);
serverAssertWithInfo(NULL,zobj,eptr != NULL);
if (eptr != NULL) {
sptr = lpNext(zl,eptr);
serverAssertWithInfo(NULL,zobj,sptr != NULL);
}
while (eptr != NULL) {
score = zzlGetScore(sptr);
......@@ -4041,7 +4042,7 @@ void blockingGenericZpopCommand(client *c, robj **keys, int numkeys, int where,
/* If the keys do not exist we must block */
struct blockPos pos = {where};
blockForKeys(c,BLOCKED_ZSET,c->argv+1,c->argc-2,count,timeout,NULL,&pos,NULL);
blockForKeys(c,BLOCKED_ZSET,keys,numkeys,count,timeout,NULL,&pos,NULL);
}
// BZPOPMIN key [key ...] timeout
......@@ -4054,7 +4055,7 @@ void bzpopmaxCommand(client *c) {
blockingGenericZpopCommand(c, c->argv+1, c->argc-2, ZSET_MAX, c->argc-1, -1, 0, 0);
}
static void zarndmemberReplyWithListpack(client *c, unsigned int count, listpackEntry *keys, listpackEntry *vals) {
static void zrandmemberReplyWithListpack(client *c, unsigned int count, listpackEntry *keys, listpackEntry *vals) {
for (unsigned long i = 0; i < count; i++) {
if (vals && c->resp > 2)
addReplyArrayLen(c,2);
......@@ -4135,7 +4136,7 @@ void zrandmemberWithCountCommand(client *c, long l, int withscores) {
sample_count = count > limit ? limit : count;
count -= sample_count;
lpRandomPairs(zsetobj->ptr, sample_count, keys, vals);
zarndmemberReplyWithListpack(c, sample_count, keys, vals);
zrandmemberReplyWithListpack(c, sample_count, keys, vals);
}
zfree(keys);
zfree(vals);
......@@ -4234,7 +4235,7 @@ void zrandmemberWithCountCommand(client *c, long l, int withscores) {
if (withscores)
vals = zmalloc(sizeof(listpackEntry)*count);
serverAssert(lpRandomPairsUnique(zsetobj->ptr, count, keys, vals) == count);
zarndmemberReplyWithListpack(c, count, keys, vals);
zrandmemberReplyWithListpack(c, count, keys, vals);
zfree(keys);
zfree(vals);
zuiClearIterator(&src);
......
......@@ -295,7 +295,7 @@ void sendTrackingMessage(client *c, char *keyname, size_t keylen, int proto) {
} else if (using_redirection && c->flags & CLIENT_PUBSUB) {
/* We use a static object to speedup things, however we assume
* that addReplyPubsubMessage() will not take a reference. */
addReplyPubsubMessage(c,TrackingChannelName,NULL);
addReplyPubsubMessage(c,TrackingChannelName,NULL,shared.messagebulk);
} else {
/* If are here, the client is not using RESP3, nor is
* redirecting to another client. We can't send anything to
......
......@@ -522,7 +522,7 @@ int string2ld(const char *s, size_t slen, long double *dp) {
if (isspace(buf[0]) || eptr[0] != '\0' ||
(size_t)(eptr-buf) != slen ||
(errno == ERANGE &&
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
(value == HUGE_VAL || value == -HUGE_VAL || fpclassify(value) == FP_ZERO)) ||
errno == EINVAL ||
isnan(value))
return 0;
......@@ -546,7 +546,7 @@ int string2d(const char *s, size_t slen, double *dp) {
isspace(((const char*)s)[0]) ||
(size_t)(eptr-(char*)s) != slen ||
(errno == ERANGE &&
(*dp == HUGE_VAL || *dp == -HUGE_VAL || *dp == 0)) ||
(*dp == HUGE_VAL || *dp == -HUGE_VAL || fpclassify(*dp) == FP_ZERO)) ||
isnan(*dp))
return 0;
return 1;
......
#define REDIS_VERSION "7.0.0"
#define REDIS_VERSION_NUM 0x00070000
#define REDIS_VERSION "7.0.1"
#define REDIS_VERSION_NUM 0x00070001
......@@ -255,7 +255,7 @@
/* Return the pointer to the last byte of a ziplist, which is, the
* end of ziplist FF entry. */
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-1)
#define ZIPLIST_ENTRY_END(zl) ((zl)+intrev32ifbe(ZIPLIST_BYTES(zl))-ZIPLIST_END_SIZE)
/* Increment the number of items field in the ziplist header. Note that this
* macro should never overflow the unsigned 16 bit integer, since entries are
......
......@@ -55,6 +55,8 @@ void zlibc_free(void *ptr) {
#include "zmalloc.h"
#include "atomicvar.h"
#define UNUSED(x) ((void)(x))
#ifdef HAVE_MALLOC_SIZE
#define PREFIX_SIZE (0)
#define ASSERT_NO_SIZE_OVERFLOW(sz)
......@@ -395,35 +397,58 @@ void zmadvise_dontneed(void *ptr) {
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
size_t zmalloc_get_rss(void) {
int page = sysconf(_SC_PAGESIZE);
size_t rss;
/* Get the i'th field from "/proc/self/stats" note i is 1 based as appears in the 'proc' man page */
int get_proc_stat_ll(int i, long long *res) {
#if defined(HAVE_PROC_STAT)
char buf[4096];
char filename[256];
int fd, count;
int fd, l;
char *p, *x;
snprintf(filename,256,"/proc/%ld/stat",(long) getpid());
if ((fd = open(filename,O_RDONLY)) == -1) return 0;
if (read(fd,buf,4096) <= 0) {
if ((fd = open("/proc/self/stat",O_RDONLY)) == -1) return 0;
if ((l = read(fd,buf,sizeof(buf)-1)) <= 0) {
close(fd);
return 0;
}
close(fd);
buf[l] = '\0';
if (buf[l-1] == '\n') buf[l-1] = '\0';
p = buf;
count = 23; /* RSS is the 24th field in /proc/<pid>/stat */
while(p && count--) {
p = strchr(p,' ');
/* Skip pid and process name (surrounded with parentheses) */
p = strrchr(buf, ')');
if (!p) return 0;
p++;
while (*p == ' ') p++;
if (*p == '\0') return 0;
i -= 3;
if (i < 0) return 0;
while (p && i--) {
p = strchr(p, ' ');
if (p) p++;
else return 0;
}
if (!p) return 0;
x = strchr(p,' ');
if (!x) return 0;
*x = '\0';
if (x) *x = '\0';
rss = strtoll(p,NULL,10);
*res = strtoll(p,&x,10);
if (*x != '\0') return 0;
return 1;
#else
UNUSED(i);
UNUSED(res);
return 0;
#endif
}
#if defined(HAVE_PROC_STAT)
size_t zmalloc_get_rss(void) {
int page = sysconf(_SC_PAGESIZE);
long long rss;
/* RSS is the 24th field in /proc/<pid>/stat */
if (!get_proc_stat_ll(24, &rss)) return 0;
rss *= page;
return rss;
}
......@@ -492,6 +517,23 @@ size_t zmalloc_get_rss(void) {
return 0L;
}
#elif defined(__HAIKU__)
#include <OS.h>
size_t zmalloc_get_rss(void) {
area_info info;
thread_info th;
size_t rss = 0;
ssize_t cookie = 0;
if (get_thread_info(find_thread(0), &th) != B_OK)
return 0;
while (get_next_area_info(th.team, &cookie, &info) == B_OK)
rss += info.ram_size;
return rss;
}
#elif defined(HAVE_PSINFO)
#include <unistd.h>
#include <sys/procfs.h>
......@@ -731,7 +773,6 @@ size_t zmalloc_get_memory_size(void) {
}
#ifdef REDIS_TEST
#define UNUSED(x) ((void)(x))
int zmalloc_test(int argc, char **argv, int flags) {
void *ptr;
......
......@@ -136,6 +136,8 @@ size_t zmalloc_usable_size(void *ptr);
#define zmalloc_usable_size(p) zmalloc_size(p)
#endif
int get_proc_stat_ll(int i, long long *res);
#ifdef REDIS_TEST
int zmalloc_test(int argc, char **argv, int flags);
#endif
......
......@@ -38,7 +38,7 @@ The following compatibility and capability tags are currently used:
| `external:skip` | Not compatible with external servers. |
| `cluster:skip` | Not compatible with `--cluster-mode`. |
| `large-memory` | Test that requires more than 100mb |
| `tls:skip` | Not campatible with `--tls`. |
| `tls:skip` | Not compatible with `--tls`. |
| `needs:repl` | Uses replication and needs to be able to `SYNC` from server. |
| `needs:debug` | Uses the `DEBUG` command or other debugging focused commands (like `OBJECT`). |
| `needs:pfdebug` | Uses the `PFDEBUG` command. |
......
......@@ -13,9 +13,8 @@ databases 16
latency-monitor-threshold 1
repl-diskless-sync-delay 0
# Note the infrastructure in server.tcl uses a dict, we can't provide several save directives
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
......
......@@ -29,7 +29,7 @@ test "Migrate a slot, verify client receives sunsubscribe on primary serving the
# Verify subscribe is still valid, able to receive messages.
$nodefrom(link) spublish $channelname hello
assert_equal {message mychannel hello} [$subscribeclient read]
assert_equal {smessage mychannel hello} [$subscribeclient read]
assert_equal {OK} [$nodefrom(link) cluster setslot $slot node $nodeto(id)]
......@@ -66,7 +66,7 @@ test "Client subscribes to multiple channels, migrate a slot, verify client rece
# Verify subscribe is still valid, able to receive messages.
$nodefrom(link) spublish $channelname hello
assert_equal {message ch3 hello} [$subscribeclient read]
assert_equal {smessage ch3 hello} [$subscribeclient read]
assert_equal {OK} [$nodefrom(link) cluster setslot $slot node $nodeto(id)]
......@@ -82,7 +82,7 @@ test "Client subscribes to multiple channels, migrate a slot, verify client rece
# Verify the client is still connected and receives message from the other channel.
set msg [$subscribeclient read]
assert {"message" eq [lindex $msg 0]}
assert {"smessage" eq [lindex $msg 0]}
assert {$anotherchannelname eq [lindex $msg 1]}
assert {"hello" eq [lindex $msg 2]}
......@@ -114,7 +114,7 @@ test "Migrate a slot, verify client receives sunsubscribe on replica serving the
# Verify subscribe is still valid, able to receive messages.
$nodefrom(link) spublish $channelname hello
assert_equal {message mychannel1 hello} [$subscribeclient read]
assert_equal {smessage mychannel1 hello} [$subscribeclient read]
assert_equal {OK} [$nodefrom(link) cluster setslot $slot node $nodeto(id)]
assert_equal {OK} [$nodeto(link) cluster setslot $slot node $nodeto(id)]
......
......@@ -441,7 +441,7 @@ proc run_tests {} {
file delete $::leaked_fds_file
}
if {[llength $::run_matching] != 0 && [search_pattern_list $test $::run_matching true] == -1} {
if {[llength $::run_matching] != 0 && ![search_pattern_list $test $::run_matching true]} {
continue
}
if {[file isdirectory $test]} continue
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment