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

Merge pull request #10652 from oranagra/redis-7.0.0

Redis 7.0.0
parents fb4e0d40 c1f30206
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#include "anet.h" #include "anet.h"
#include "config.h" #include "config.h"
#define UNUSED(x) (void)(x)
static void anetSetError(char *err, const char *fmt, ...) static void anetSetError(char *err, const char *fmt, ...)
{ {
va_list ap; va_list ap;
...@@ -680,3 +682,18 @@ error: ...@@ -680,3 +682,18 @@ error:
close(fds[1]); close(fds[1]);
return -1; return -1;
} }
int anetSetSockMarkId(char *err, int fd, uint32_t id) {
#ifdef HAVE_SOCKOPTMARKID
if (setsockopt(fd, SOL_SOCKET, SOCKOPTMARKID, (void *)&id, sizeof(id)) == -1) {
anetSetError(err, "setsockopt: %s", strerror(errno));
return ANET_ERR;
}
return ANET_OK;
#else
UNUSED(fd);
UNUSED(id);
anetSetError(err,"anetSetSockMarkid unsupported on this platform");
return ANET_OK;
#endif
}
...@@ -73,5 +73,6 @@ int anetKeepAlive(char *err, int fd, int interval); ...@@ -73,5 +73,6 @@ int anetKeepAlive(char *err, int fd, int interval);
int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port); int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port);
int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type); int anetFormatFdAddr(int fd, char *buf, size_t buf_len, int fd_to_str_type);
int anetPipe(int fds[2], int read_flags, int write_flags); int anetPipe(int fds[2], int read_flags, int write_flags);
int anetSetSockMarkId(char *err, int fd, uint32_t id);
#endif #endif
...@@ -87,7 +87,7 @@ void aofManifestFreeAndUpdate(aofManifest *am); ...@@ -87,7 +87,7 @@ void aofManifestFreeAndUpdate(aofManifest *am);
#define RDB_FORMAT_SUFFIX ".rdb" #define RDB_FORMAT_SUFFIX ".rdb"
#define AOF_FORMAT_SUFFIX ".aof" #define AOF_FORMAT_SUFFIX ".aof"
#define MANIFEST_NAME_SUFFIX ".manifest" #define MANIFEST_NAME_SUFFIX ".manifest"
#define MANIFEST_TEMP_NAME_PREFIX "temp_" #define TEMP_FILE_NAME_PREFIX "temp-"
/* AOF manifest key. */ /* AOF manifest key. */
#define AOF_MANIFEST_KEY_FILE_NAME "file" #define AOF_MANIFEST_KEY_FILE_NAME "file"
...@@ -169,7 +169,7 @@ sds getAofManifestFileName() { ...@@ -169,7 +169,7 @@ sds getAofManifestFileName() {
} }
sds getTempAofManifestFileName() { sds getTempAofManifestFileName() {
return sdscatprintf(sdsempty(), "%s%s%s", MANIFEST_TEMP_NAME_PREFIX, return sdscatprintf(sdsempty(), "%s%s%s", TEMP_FILE_NAME_PREFIX,
server.aof_filename, MANIFEST_NAME_SUFFIX); server.aof_filename, MANIFEST_NAME_SUFFIX);
} }
...@@ -462,6 +462,12 @@ sds getNewIncrAofName(aofManifest *am) { ...@@ -462,6 +462,12 @@ sds getNewIncrAofName(aofManifest *am) {
return ai->file_name; return ai->file_name;
} }
/* Get temp INCR type AOF name. */
sds getTempIncrAofName() {
return sdscatprintf(sdsempty(), "%s%s%s", TEMP_FILE_NAME_PREFIX, server.aof_filename,
INCR_FILE_SUFFIX);
}
/* Get the last INCR AOF name or create a new one. */ /* Get the last INCR AOF name or create a new one. */
sds getLastIncrAofName(aofManifest *am) { sds getLastIncrAofName(aofManifest *am) {
serverAssert(am != NULL); serverAssert(am != NULL);
...@@ -674,6 +680,17 @@ int aofDelHistoryFiles(void) { ...@@ -674,6 +680,17 @@ int aofDelHistoryFiles(void) {
return persistAofManifest(server.aof_manifest); return persistAofManifest(server.aof_manifest);
} }
/* Used to clean up temp INCR AOF when AOFRW fails. */
void aofDelTempIncrAofFile() {
sds aof_filename = getTempIncrAofName();
sds aof_filepath = makePath(server.aof_dirname, aof_filename);
serverLog(LL_NOTICE, "Removing the temp incr aof file %s in the background", aof_filename);
bg_unlink(aof_filepath);
sdsfree(aof_filepath);
sdsfree(aof_filename);
return;
}
/* Called after `loadDataFromDisk` when redis start. If `server.aof_state` is /* Called after `loadDataFromDisk` when redis start. If `server.aof_state` is
* 'AOF_ON', It will do three things: * 'AOF_ON', It will do three things:
* 1. Force create a BASE file when redis starts with an empty dataset * 1. Force create a BASE file when redis starts with an empty dataset
...@@ -739,44 +756,52 @@ int aofFileExist(char *filename) { ...@@ -739,44 +756,52 @@ int aofFileExist(char *filename) {
} }
/* Called in `rewriteAppendOnlyFileBackground`. If `server.aof_state` /* Called in `rewriteAppendOnlyFileBackground`. If `server.aof_state`
* is 'AOF_ON' or 'AOF_WAIT_REWRITE', It will do two things: * is 'AOF_ON', It will do two things:
* 1. Open a new INCR type AOF for writing * 1. Open a new INCR type AOF for writing
* 2. Synchronously update the manifest file to the disk * 2. Synchronously update the manifest file to the disk
* *
* The above two steps of modification are atomic, that is, if * The above two steps of modification are atomic, that is, if
* any step fails, the entire operation will rollback and returns * any step fails, the entire operation will rollback and returns
* C_ERR, and if all succeeds, it returns C_OK. * C_ERR, and if all succeeds, it returns C_OK.
*
* If `server.aof_state` is 'AOF_WAIT_REWRITE', It will open a temporary INCR AOF
* file to accumulate data during AOF_WAIT_REWRITE, and it will eventually be
* renamed in the `backgroundRewriteDoneHandler` and written to the manifest file.
* */ * */
int openNewIncrAofForAppend(void) { int openNewIncrAofForAppend(void) {
serverAssert(server.aof_manifest != NULL); serverAssert(server.aof_manifest != NULL);
int newfd; int newfd = -1;
aofManifest *temp_am = NULL;
sds new_aof_name = NULL;
/* Only open new INCR AOF when AOF enabled. */ /* Only open new INCR AOF when AOF enabled. */
if (server.aof_state == AOF_OFF) return C_OK; if (server.aof_state == AOF_OFF) return C_OK;
/* Dup a temp aof_manifest to modify. */
aofManifest *temp_am = aofManifestDup(server.aof_manifest);
/* Open new AOF. */ /* Open new AOF. */
sds new_aof_name = getNewIncrAofName(temp_am); if (server.aof_state == AOF_WAIT_REWRITE) {
/* Use a temporary INCR AOF file to accumulate data during AOF_WAIT_REWRITE. */
new_aof_name = getTempIncrAofName();
} else {
/* Dup a temp aof_manifest to modify. */
temp_am = aofManifestDup(server.aof_manifest);
new_aof_name = sdsdup(getNewIncrAofName(temp_am));
}
sds new_aof_filepath = makePath(server.aof_dirname, new_aof_name); sds new_aof_filepath = makePath(server.aof_dirname, new_aof_name);
newfd = open(new_aof_filepath, O_WRONLY|O_TRUNC|O_CREAT, 0644); newfd = open(new_aof_filepath, O_WRONLY|O_TRUNC|O_CREAT, 0644);
sdsfree(new_aof_filepath); sdsfree(new_aof_filepath);
if (newfd == -1) { if (newfd == -1) {
serverLog(LL_WARNING, "Can't open the append-only file %s: %s", serverLog(LL_WARNING, "Can't open the append-only file %s: %s",
new_aof_name, strerror(errno)); new_aof_name, strerror(errno));
goto cleanup;
aofManifestFree(temp_am);
return C_ERR;
} }
/* Persist AOF Manifest. */ if (temp_am) {
int ret = persistAofManifest(temp_am); /* Persist AOF Manifest. */
if (ret == C_ERR) { if (persistAofManifest(temp_am) == C_ERR) {
close(newfd); goto cleanup;
aofManifestFree(temp_am); }
return C_ERR;
} }
sdsfree(new_aof_name);
/* If reaches here, we can safely modify the `server.aof_manifest` /* If reaches here, we can safely modify the `server.aof_manifest`
* and `server.aof_fd`. */ * and `server.aof_fd`. */
...@@ -788,8 +813,14 @@ int openNewIncrAofForAppend(void) { ...@@ -788,8 +813,14 @@ int openNewIncrAofForAppend(void) {
/* Reset the aof_last_incr_size. */ /* Reset the aof_last_incr_size. */
server.aof_last_incr_size = 0; server.aof_last_incr_size = 0;
/* Update `server.aof_manifest`. */ /* Update `server.aof_manifest`. */
aofManifestFreeAndUpdate(temp_am); if (temp_am) aofManifestFreeAndUpdate(temp_am);
return C_OK; return C_OK;
cleanup:
if (new_aof_name) sdsfree(new_aof_name);
if (newfd != -1) close(newfd);
if (temp_am) aofManifestFree(temp_am);
return C_ERR;
} }
/* Whether to limit the execution of Background AOF rewrite. /* Whether to limit the execution of Background AOF rewrite.
...@@ -815,38 +846,35 @@ int openNewIncrAofForAppend(void) { ...@@ -815,38 +846,35 @@ int openNewIncrAofForAppend(void) {
#define AOF_REWRITE_LIMITE_THRESHOLD 3 #define AOF_REWRITE_LIMITE_THRESHOLD 3
#define AOF_REWRITE_LIMITE_MAX_MINUTES 60 /* 1 hour */ #define AOF_REWRITE_LIMITE_MAX_MINUTES 60 /* 1 hour */
int aofRewriteLimited(void) { int aofRewriteLimited(void) {
int limit = 0; static int next_delay_minutes = 0;
static int limit_delay_minutes = 0;
static time_t next_rewrite_time = 0; static time_t next_rewrite_time = 0;
unsigned long incr_aof_num = listLength(server.aof_manifest->incr_aof_list); if (server.stat_aofrw_consecutive_failures < AOF_REWRITE_LIMITE_THRESHOLD) {
if (incr_aof_num >= AOF_REWRITE_LIMITE_THRESHOLD) { /* We may be recovering from limited state, so reset all states. */
next_delay_minutes = 0;
next_rewrite_time = 0;
return 0;
}
/* if it is in the limiting state, then check if the next_rewrite_time is reached */
if (next_rewrite_time != 0) {
if (server.unixtime < next_rewrite_time) { if (server.unixtime < next_rewrite_time) {
limit = 1; return 1;
} else { } else {
if (limit_delay_minutes == 0) { next_rewrite_time = 0;
limit = 1; return 0;
limit_delay_minutes = 1;
} else {
limit_delay_minutes *= 2;
}
if (limit_delay_minutes > AOF_REWRITE_LIMITE_MAX_MINUTES) {
limit_delay_minutes = AOF_REWRITE_LIMITE_MAX_MINUTES;
}
next_rewrite_time = server.unixtime + limit_delay_minutes * 60;
serverLog(LL_WARNING,
"Background AOF rewrite has repeatedly failed %ld times and triggered the limit, will retry in %d minutes",
incr_aof_num, limit_delay_minutes);
} }
} else {
limit_delay_minutes = 0;
next_rewrite_time = 0;
} }
return limit; next_delay_minutes = (next_delay_minutes == 0) ? 1 : (next_delay_minutes * 2);
if (next_delay_minutes > AOF_REWRITE_LIMITE_MAX_MINUTES) {
next_delay_minutes = AOF_REWRITE_LIMITE_MAX_MINUTES;
}
next_rewrite_time = server.unixtime + next_delay_minutes * 60;
serverLog(LL_WARNING,
"Background AOF rewrite has repeatedly failed and triggered the limit, will retry in %d minutes", next_delay_minutes);
return 1;
} }
/* ---------------------------------------------------------------------------- /* ----------------------------------------------------------------------------
...@@ -1265,7 +1293,7 @@ void feedAppendOnlyFile(int dictid, robj **argv, int argc) { ...@@ -1265,7 +1293,7 @@ void feedAppendOnlyFile(int dictid, robj **argv, int argc) {
* of re-entering the event loop, so before the client will get a * of re-entering the event loop, so before the client will get a
* positive reply about the operation performed. */ * positive reply about the operation performed. */
if (server.aof_state == AOF_ON || if (server.aof_state == AOF_ON ||
server.child_type == CHILD_TYPE_AOF) (server.aof_state == AOF_WAIT_REWRITE && server.child_type == CHILD_TYPE_AOF))
{ {
server.aof_buf = sdscatlen(server.aof_buf, buf, sdslen(buf)); server.aof_buf = sdscatlen(server.aof_buf, buf, sdslen(buf));
} }
...@@ -1558,7 +1586,7 @@ int loadAppendOnlyFiles(aofManifest *am) { ...@@ -1558,7 +1586,7 @@ int loadAppendOnlyFiles(aofManifest *am) {
serverAssert(am != NULL); serverAssert(am != NULL);
int status, ret = C_OK; int status, ret = C_OK;
long long start; long long start;
off_t total_size = 0; off_t total_size = 0, base_size = 0;
sds aof_name; sds aof_name;
int total_num, aof_num = 0, last_file; int total_num, aof_num = 0, last_file;
...@@ -1607,6 +1635,7 @@ int loadAppendOnlyFiles(aofManifest *am) { ...@@ -1607,6 +1635,7 @@ int loadAppendOnlyFiles(aofManifest *am) {
serverAssert(am->base_aof_info->file_type == AOF_FILE_TYPE_BASE); serverAssert(am->base_aof_info->file_type == AOF_FILE_TYPE_BASE);
aof_name = (char*)am->base_aof_info->file_name; aof_name = (char*)am->base_aof_info->file_name;
updateLoadingFileName(aof_name); updateLoadingFileName(aof_name);
base_size = getAppendOnlyFileSize(aof_name, NULL);
last_file = ++aof_num == total_num; last_file = ++aof_num == total_num;
start = ustime(); start = ustime();
ret = loadSingleAppendOnlyFile(aof_name); ret = loadSingleAppendOnlyFile(aof_name);
...@@ -1659,7 +1688,16 @@ int loadAppendOnlyFiles(aofManifest *am) { ...@@ -1659,7 +1688,16 @@ int loadAppendOnlyFiles(aofManifest *am) {
} }
server.aof_current_size = total_size; server.aof_current_size = total_size;
server.aof_rewrite_base_size = server.aof_current_size; /* Ideally, the aof_rewrite_base_size variable should hold the size of the
* AOF when the last rewrite ended, this should include the size of the
* incremental file that was created during the rewrite since otherwise we
* risk the next automatic rewrite to happen too soon (or immediately if
* auto-aof-rewrite-percentage is low). However, since we do not persist
* aof_rewrite_base_size information anywhere, we initialize it on restart
* to the size of BASE AOF file. This might cause the first AOFRW to be
* executed early, but that shouldn't be a problem since everything will be
* fine after the first AOFRW. */
server.aof_rewrite_base_size = base_size;
server.aof_fsync_offset = server.aof_current_size; server.aof_fsync_offset = server.aof_current_size;
cleanup: cleanup:
...@@ -2393,6 +2431,9 @@ void bgrewriteaofCommand(client *c) { ...@@ -2393,6 +2431,9 @@ void bgrewriteaofCommand(client *c) {
addReplyError(c,"Background append only file rewriting already in progress"); addReplyError(c,"Background append only file rewriting already in progress");
} else if (hasActiveChildProcess() || server.in_exec) { } else if (hasActiveChildProcess() || server.in_exec) {
server.aof_rewrite_scheduled = 1; server.aof_rewrite_scheduled = 1;
/* When manually triggering AOFRW we reset the count
* so that it can be executed immediately. */
server.stat_aofrw_consecutive_failures = 0;
addReplyStatus(c,"Background append only file rewriting scheduled"); addReplyStatus(c,"Background append only file rewriting scheduled");
} else if (rewriteAppendOnlyFileBackground() == C_OK) { } else if (rewriteAppendOnlyFileBackground() == C_OK) {
addReplyStatus(c,"Background append only file rewriting started"); addReplyStatus(c,"Background append only file rewriting started");
...@@ -2476,7 +2517,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2476,7 +2517,8 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
if (!bysignal && exitcode == 0) { if (!bysignal && exitcode == 0) {
char tmpfile[256]; char tmpfile[256];
long long now = ustime(); long long now = ustime();
sds new_base_filename; sds new_base_filepath = NULL;
sds new_incr_filepath = NULL;
aofManifest *temp_am; aofManifest *temp_am;
mstime_t latency; mstime_t latency;
...@@ -2493,9 +2535,9 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2493,9 +2535,9 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
/* Get a new BASE file name and mark the previous (if we have) /* Get a new BASE file name and mark the previous (if we have)
* as the HISTORY type. */ * as the HISTORY type. */
new_base_filename = getNewBaseFileNameAndMarkPreAsHistory(temp_am); sds new_base_filename = getNewBaseFileNameAndMarkPreAsHistory(temp_am);
serverAssert(new_base_filename != NULL); serverAssert(new_base_filename != NULL);
sds new_base_filepath = makePath(server.aof_dirname, new_base_filename); new_base_filepath = makePath(server.aof_dirname, new_base_filename);
/* Rename the temporary aof file to 'new_base_filename'. */ /* Rename the temporary aof file to 'new_base_filename'. */
latencyStartMonitor(latency); latencyStartMonitor(latency);
...@@ -2503,7 +2545,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2503,7 +2545,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
serverLog(LL_WARNING, serverLog(LL_WARNING,
"Error trying to rename the temporary AOF file %s into %s: %s", "Error trying to rename the temporary AOF file %s into %s: %s",
tmpfile, tmpfile,
new_base_filename, new_base_filepath,
strerror(errno)); strerror(errno));
aofManifestFree(temp_am); aofManifestFree(temp_am);
sdsfree(new_base_filepath); sdsfree(new_base_filepath);
...@@ -2512,6 +2554,34 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2512,6 +2554,34 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
latencyEndMonitor(latency); latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-rename", latency); latencyAddSampleIfNeeded("aof-rename", latency);
/* Rename the temporary incr aof file to 'new_incr_filename'. */
if (server.aof_state == AOF_WAIT_REWRITE) {
/* Get temporary incr aof name. */
sds temp_incr_aof_name = getTempIncrAofName();
sds temp_incr_filepath = makePath(server.aof_dirname, temp_incr_aof_name);
sdsfree(temp_incr_aof_name);
/* Get next new incr aof name. */
sds new_incr_filename = getNewIncrAofName(temp_am);
new_incr_filepath = makePath(server.aof_dirname, new_incr_filename);
latencyStartMonitor(latency);
if (rename(temp_incr_filepath, new_incr_filepath) == -1) {
serverLog(LL_WARNING,
"Error trying to rename the temporary incr AOF file %s into %s: %s",
temp_incr_filepath,
new_incr_filepath,
strerror(errno));
bg_unlink(new_base_filepath);
sdsfree(new_base_filepath);
aofManifestFree(temp_am);
sdsfree(temp_incr_filepath);
sdsfree(new_incr_filepath);
goto cleanup;
}
latencyEndMonitor(latency);
latencyAddSampleIfNeeded("aof-rename", latency);
sdsfree(temp_incr_filepath);
}
/* Change the AOF file type in 'incr_aof_list' from AOF_FILE_TYPE_INCR /* Change the AOF file type in 'incr_aof_list' from AOF_FILE_TYPE_INCR
* to AOF_FILE_TYPE_HIST, and move them to the 'history_aof_list'. */ * to AOF_FILE_TYPE_HIST, and move them to the 'history_aof_list'. */
markRewrittenIncrAofAsHistory(temp_am); markRewrittenIncrAofAsHistory(temp_am);
...@@ -2521,9 +2591,14 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2521,9 +2591,14 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
bg_unlink(new_base_filepath); bg_unlink(new_base_filepath);
aofManifestFree(temp_am); aofManifestFree(temp_am);
sdsfree(new_base_filepath); sdsfree(new_base_filepath);
if (new_incr_filepath) {
bg_unlink(new_incr_filepath);
sdsfree(new_incr_filepath);
}
goto cleanup; goto cleanup;
} }
sdsfree(new_base_filepath); sdsfree(new_base_filepath);
if (new_incr_filepath) sdsfree(new_incr_filepath);
/* We can safely let `server.aof_manifest` point to 'temp_am' and free the previous one. */ /* We can safely let `server.aof_manifest` point to 'temp_am' and free the previous one. */
aofManifestFreeAndUpdate(temp_am); aofManifestFreeAndUpdate(temp_am);
...@@ -2542,6 +2617,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2542,6 +2617,7 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
aofDelHistoryFiles(); aofDelHistoryFiles();
server.aof_lastbgrewrite_status = C_OK; server.aof_lastbgrewrite_status = C_OK;
server.stat_aofrw_consecutive_failures = 0;
serverLog(LL_NOTICE, "Background AOF rewrite finished successfully"); serverLog(LL_NOTICE, "Background AOF rewrite finished successfully");
/* Change state from WAIT_REWRITE to ON if needed */ /* Change state from WAIT_REWRITE to ON if needed */
...@@ -2552,14 +2628,17 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2552,14 +2628,17 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
"Background AOF rewrite signal handler took %lldus", ustime()-now); "Background AOF rewrite signal handler took %lldus", ustime()-now);
} else if (!bysignal && exitcode != 0) { } else if (!bysignal && exitcode != 0) {
server.aof_lastbgrewrite_status = C_ERR; server.aof_lastbgrewrite_status = C_ERR;
server.stat_aofrw_consecutive_failures++;
serverLog(LL_WARNING, serverLog(LL_WARNING,
"Background AOF rewrite terminated with error"); "Background AOF rewrite terminated with error");
} else { } else {
/* SIGUSR1 is whitelisted, so we have a way to kill a child without /* SIGUSR1 is whitelisted, so we have a way to kill a child without
* triggering an error condition. */ * triggering an error condition. */
if (bysignal != SIGUSR1) if (bysignal != SIGUSR1) {
server.aof_lastbgrewrite_status = C_ERR; server.aof_lastbgrewrite_status = C_ERR;
server.stat_aofrw_consecutive_failures++;
}
serverLog(LL_WARNING, serverLog(LL_WARNING,
"Background AOF rewrite terminated by signal %d", bysignal); "Background AOF rewrite terminated by signal %d", bysignal);
...@@ -2567,6 +2646,12 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) { ...@@ -2567,6 +2646,12 @@ void backgroundRewriteDoneHandler(int exitcode, int bysignal) {
cleanup: cleanup:
aofRemoveTempFile(server.child_pid); aofRemoveTempFile(server.child_pid);
/* Clear AOF buffer and delete temp incr aof for next rewrite. */
if (server.aof_state == AOF_WAIT_REWRITE) {
sdsfree(server.aof_buf);
server.aof_buf = sdsempty();
aofDelTempIncrAofFile();
}
server.aof_rewrite_time_last = time(NULL)-server.aof_rewrite_time_start; server.aof_rewrite_time_last = time(NULL)-server.aof_rewrite_time_start;
server.aof_rewrite_time_start = -1; server.aof_rewrite_time_start = -1;
/* Schedule a new rewrite if we are waiting for it to switch the AOF ON. */ /* Schedule a new rewrite if we are waiting for it to switch the AOF ON. */
......
...@@ -430,7 +430,7 @@ int getBitOffsetFromArgument(client *c, robj *o, uint64_t *offset, int hash, int ...@@ -430,7 +430,7 @@ int getBitOffsetFromArgument(client *c, robj *o, uint64_t *offset, int hash, int
if (usehash) loffset *= bits; if (usehash) loffset *= bits;
/* Limit offset to server.proto_max_bulk_len (512MB in bytes by default) */ /* Limit offset to server.proto_max_bulk_len (512MB in bytes by default) */
if (loffset < 0 || (!(c->flags & CLIENT_MASTER) && (loffset >> 3) >= server.proto_max_bulk_len)) if (loffset < 0 || (!mustObeyClient(c) && (loffset >> 3) >= server.proto_max_bulk_len))
{ {
addReplyError(c,err); addReplyError(c,err);
return C_ERR; return C_ERR;
...@@ -1002,7 +1002,7 @@ void bitposCommand(client *c) { ...@@ -1002,7 +1002,7 @@ void bitposCommand(client *c) {
} }
} }
/* BITFIELD key subcommmand-1 arg ... subcommand-2 arg ... subcommand-N ... /* BITFIELD key subcommand-1 arg ... subcommand-2 arg ... subcommand-N ...
* *
* Supported subcommands: * Supported subcommands:
* *
......
...@@ -390,7 +390,7 @@ sds escapeJsonString(sds s, const char *p, size_t len) { ...@@ -390,7 +390,7 @@ sds escapeJsonString(sds s, const char *p, size_t len) {
case '\t': s = sdscatlen(s,"\\t",2); break; case '\t': s = sdscatlen(s,"\\t",2); break;
case '\b': s = sdscatlen(s,"\\b",2); break; case '\b': s = sdscatlen(s,"\\b",2); break;
default: default:
s = sdscatprintf(s,(*p >= 0 && *p <= 0x1f) ? "\\u%04x" : "%c",*p); s = sdscatprintf(s,*(unsigned char *)p <= 0x1f ? "\\u%04x" : "%c",*p);
} }
p++; p++;
} }
......
...@@ -960,7 +960,6 @@ clusterNode *createClusterNode(char *nodename, int flags) { ...@@ -960,7 +960,6 @@ clusterNode *createClusterNode(char *nodename, int flags) {
memset(node->slots,0,sizeof(node->slots)); memset(node->slots,0,sizeof(node->slots));
node->slot_info_pairs = NULL; node->slot_info_pairs = NULL;
node->slot_info_pairs_count = 0; node->slot_info_pairs_count = 0;
node->slot_info_pairs_alloc = 0;
node->numslots = 0; node->numslots = 0;
node->numslaves = 0; node->numslaves = 0;
node->slaves = NULL; node->slaves = NULL;
...@@ -2507,11 +2506,7 @@ int clusterProcessPacket(clusterLink *link) { ...@@ -2507,11 +2506,7 @@ int clusterProcessPacket(clusterLink *link) {
message = createStringObject( message = createStringObject(
(char*)hdr->data.publish.msg.bulk_data+channel_len, (char*)hdr->data.publish.msg.bulk_data+channel_len,
message_len); message_len);
if (type == CLUSTERMSG_TYPE_PUBLISHSHARD) { pubsubPublishMessage(channel, message, type == CLUSTERMSG_TYPE_PUBLISHSHARD);
pubsubPublishMessageShard(channel, message);
} else {
pubsubPublishMessage(channel,message);
}
decrRefCount(channel); decrRefCount(channel);
decrRefCount(message); decrRefCount(message);
} }
...@@ -3200,20 +3195,19 @@ int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uin ...@@ -3200,20 +3195,19 @@ int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uin
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* CLUSTER Pub/Sub support * CLUSTER Pub/Sub support
* *
* For now we do very little, just propagating PUBLISH messages across the whole * If `sharded` is 0:
* For now we do very little, just propagating [S]PUBLISH messages across the whole
* cluster. In the future we'll try to get smarter and avoiding propagating those * cluster. In the future we'll try to get smarter and avoiding propagating those
* messages to hosts without receives for a given channel. * messages to hosts without receives for a given channel.
* -------------------------------------------------------------------------- */ * Otherwise:
void clusterPropagatePublish(robj *channel, robj *message) {
clusterSendPublish(NULL, channel, message, CLUSTERMSG_TYPE_PUBLISH);
}
/* -----------------------------------------------------------------------------
* CLUSTER Pub/Sub shard support
*
* Publish this message across the slot (primary/replica). * Publish this message across the slot (primary/replica).
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
void clusterPropagatePublishShard(robj *channel, robj *message) { void clusterPropagatePublish(robj *channel, robj *message, int sharded) {
if (!sharded) {
clusterSendPublish(NULL, channel, message, CLUSTERMSG_TYPE_PUBLISH);
return;
}
list *nodes_for_slot = clusterGetNodesServingMySlots(server.cluster->myself); list *nodes_for_slot = clusterGetNodesServingMySlots(server.cluster->myself);
if (listLength(nodes_for_slot) != 0) { if (listLength(nodes_for_slot) != 0) {
listIter li; listIter li;
...@@ -4726,13 +4720,10 @@ void clusterGenNodesSlotsInfo(int filter) { ...@@ -4726,13 +4720,10 @@ void clusterGenNodesSlotsInfo(int filter) {
* or end of slot. */ * or end of slot. */
if (i == CLUSTER_SLOTS || n != server.cluster->slots[i]) { if (i == CLUSTER_SLOTS || n != server.cluster->slots[i]) {
if (!(n->flags & filter)) { if (!(n->flags & filter)) {
if (n->slot_info_pairs_count+2 > n->slot_info_pairs_alloc) { if (!n->slot_info_pairs) {
if (n->slot_info_pairs_alloc == 0) n->slot_info_pairs = zmalloc(2 * n->numslots * sizeof(uint16_t));
n->slot_info_pairs_alloc = 8;
else
n->slot_info_pairs_alloc *= 2;
n->slot_info_pairs = zrealloc(n->slot_info_pairs, n->slot_info_pairs_alloc * sizeof(uint16_t));
} }
serverAssert((n->slot_info_pairs_count + 1) < (2 * n->numslots));
n->slot_info_pairs[n->slot_info_pairs_count++] = start; n->slot_info_pairs[n->slot_info_pairs_count++] = start;
n->slot_info_pairs[n->slot_info_pairs_count++] = i-1; n->slot_info_pairs[n->slot_info_pairs_count++] = i-1;
} }
...@@ -4747,7 +4738,6 @@ void clusterFreeNodesSlotsInfo(clusterNode *n) { ...@@ -4747,7 +4738,6 @@ void clusterFreeNodesSlotsInfo(clusterNode *n) {
zfree(n->slot_info_pairs); zfree(n->slot_info_pairs);
n->slot_info_pairs = NULL; n->slot_info_pairs = NULL;
n->slot_info_pairs_count = 0; n->slot_info_pairs_count = 0;
n->slot_info_pairs_alloc = 0;
} }
/* Generate a csv-alike representation of the nodes we are aware of, /* Generate a csv-alike representation of the nodes we are aware of,
......
...@@ -120,7 +120,6 @@ typedef struct clusterNode { ...@@ -120,7 +120,6 @@ typedef struct clusterNode {
unsigned char slots[CLUSTER_SLOTS/8]; /* slots handled by this node */ unsigned char slots[CLUSTER_SLOTS/8]; /* slots handled by this node */
uint16_t *slot_info_pairs; /* Slots info represented as (start/end) pair (consecutive index). */ uint16_t *slot_info_pairs; /* Slots info represented as (start/end) pair (consecutive index). */
int slot_info_pairs_count; /* Used number of slots in slot_info_pairs */ int slot_info_pairs_count; /* Used number of slots in slot_info_pairs */
int slot_info_pairs_alloc; /* Allocated number of slots in slot_info_pairs */
int numslots; /* Number of slots handled by this node */ int numslots; /* Number of slots handled by this node */
int numslaves; /* Number of slave nodes, if this is a master */ int numslaves; /* Number of slave nodes, if this is a master */
struct clusterNode **slaves; /* pointers to slave nodes */ struct clusterNode **slaves; /* pointers to slave nodes */
...@@ -385,8 +384,7 @@ void migrateCloseTimedoutSockets(void); ...@@ -385,8 +384,7 @@ void migrateCloseTimedoutSockets(void);
int verifyClusterConfigWithData(void); int verifyClusterConfigWithData(void);
unsigned long getClusterConnectionsCount(void); unsigned long getClusterConnectionsCount(void);
int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uint8_t type, const char *payload, uint32_t len); int clusterSendModuleMessageToTarget(const char *target, uint64_t module_id, uint8_t type, const char *payload, uint32_t len);
void clusterPropagatePublish(robj *channel, robj *message); void clusterPropagatePublish(robj *channel, robj *message, int sharded);
void clusterPropagatePublishShard(robj *channel, robj *message);
unsigned int keyHashSlot(char *key, int keylen); unsigned int keyHashSlot(char *key, int keylen);
void slotToKeyAddEntry(dictEntry *entry, redisDb *db); void slotToKeyAddEntry(dictEntry *entry, redisDb *db);
void slotToKeyDelEntry(dictEntry *entry, redisDb *db); void slotToKeyDelEntry(dictEntry *entry, redisDb *db);
......
This diff is collapsed.
...@@ -44,84 +44,100 @@ ...@@ -44,84 +44,100 @@
"key_spec_index": 0 "key_spec_index": 0
}, },
{ {
"token": "GET", "name": "operation",
"name": "encoding_offset",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
}
]
},
{
"token": "SET",
"name": "encoding_offset_value",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "value",
"type": "integer"
}
]
},
{
"token": "INCRBY",
"name": "encoding_offset_increment",
"type": "block",
"optional": true,
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "increment",
"type": "integer"
}
]
},
{
"token": "OVERFLOW",
"name": "wrap_sat_fail",
"type": "oneof", "type": "oneof",
"optional": true, "multiple": "true",
"arguments": [ "arguments": [
{ {
"name": "wrap", "token": "GET",
"type": "pure-token", "name": "encoding_offset",
"token": "WRAP" "type": "block",
}, "arguments": [
{ {
"name": "sat", "name": "encoding",
"type": "pure-token", "type": "string"
"token": "SAT" },
{
"name": "offset",
"type": "integer"
}
]
}, },
{ {
"name": "fail", "name": "write",
"type": "pure-token", "type": "block",
"token": "FAIL" "arguments": [
{
"token": "OVERFLOW",
"name": "wrap_sat_fail",
"type": "oneof",
"optional": true,
"arguments": [
{
"name": "wrap",
"type": "pure-token",
"token": "WRAP"
},
{
"name": "sat",
"type": "pure-token",
"token": "SAT"
},
{
"name": "fail",
"type": "pure-token",
"token": "FAIL"
}
]
},
{
"name": "write_operation",
"type": "oneof",
"arguments": [
{
"token": "SET",
"name": "encoding_offset_value",
"type": "block",
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "value",
"type": "integer"
}
]
},
{
"token": "INCRBY",
"name": "encoding_offset_increment",
"type": "block",
"arguments": [
{
"name": "encoding",
"type": "string"
},
{
"name": "offset",
"type": "integer"
},
{
"name": "increment",
"type": "integer"
}
]
}
]
}
]
} }
] ]
} }
] ]
} }
} }
\ No newline at end of file
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
"token": "GET", "token": "GET",
"name": "encoding_offset", "name": "encoding_offset",
"type": "block", "type": "block",
"multiple": "true",
"arguments": [ "arguments": [
{ {
"name": "encoding", "name": "encoding",
......
...@@ -39,102 +39,110 @@ ...@@ -39,102 +39,110 @@
"key_spec_index": 0 "key_spec_index": 0
}, },
{ {
"token": "FROMMEMBER", "name": "from",
"name": "member", "type": "oneof",
"type": "string",
"optional": true
},
{
"token": "FROMLONLAT",
"name": "longitude_latitude",
"type": "block",
"optional": true,
"arguments": [
{
"name": "longitude",
"type": "double"
},
{
"name": "latitude",
"type": "double"
}
]
},
{
"name": "circle",
"type": "block",
"optional": true,
"arguments": [ "arguments": [
{ {
"token": "BYRADIUS", "token": "FROMMEMBER",
"name": "radius", "name": "member",
"type": "double" "type": "string"
}, },
{ {
"name": "unit", "token": "FROMLONLAT",
"type": "oneof", "name": "longitude_latitude",
"type": "block",
"arguments": [ "arguments": [
{ {
"name": "m", "name": "longitude",
"type": "pure-token", "type": "double"
"token": "m"
}, },
{ {
"name": "km", "name": "latitude",
"type": "pure-token", "type": "double"
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
} }
] ]
} }
] ]
}, },
{ {
"name": "box", "name": "by",
"type": "block", "type": "oneof",
"optional": true,
"arguments": [ "arguments": [
{ {
"token": "BYBOX", "name": "circle",
"name": "width", "type": "block",
"type": "double"
},
{
"name": "height",
"type": "double"
},
{
"name": "unit",
"type": "oneof",
"arguments": [ "arguments": [
{ {
"name": "m", "token": "BYRADIUS",
"type": "pure-token", "name": "radius",
"token": "m" "type": "double"
}, },
{ {
"name": "km", "name": "unit",
"type": "pure-token", "type": "oneof",
"token": "km" "arguments": [
{
"name": "m",
"type": "pure-token",
"token": "m"
},
{
"name": "km",
"type": "pure-token",
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
}
]
}
]
},
{
"name": "box",
"type": "block",
"arguments": [
{
"token": "BYBOX",
"name": "width",
"type": "double"
}, },
{ {
"name": "ft", "name": "height",
"type": "pure-token", "type": "double"
"token": "ft"
}, },
{ {
"name": "mi", "name": "unit",
"type": "pure-token", "type": "oneof",
"token": "mi" "arguments": [
{
"name": "m",
"type": "pure-token",
"token": "m"
},
{
"name": "km",
"type": "pure-token",
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
}
]
} }
] ]
} }
...@@ -195,4 +203,4 @@ ...@@ -195,4 +203,4 @@
} }
] ]
} }
} }
\ No newline at end of file
...@@ -63,102 +63,110 @@ ...@@ -63,102 +63,110 @@
"key_spec_index": 1 "key_spec_index": 1
}, },
{ {
"token": "FROMMEMBER", "name": "from",
"name": "member", "type": "oneof",
"type": "string",
"optional": true
},
{
"token": "FROMLONLAT",
"name": "longitude_latitude",
"type": "block",
"optional": true,
"arguments": [
{
"name": "longitude",
"type": "double"
},
{
"name": "latitude",
"type": "double"
}
]
},
{
"name": "circle",
"type": "block",
"optional": true,
"arguments": [ "arguments": [
{ {
"token": "BYRADIUS", "token": "FROMMEMBER",
"name": "radius", "name": "member",
"type": "double" "type": "string"
}, },
{ {
"name": "unit", "token": "FROMLONLAT",
"type": "oneof", "name": "longitude_latitude",
"type": "block",
"arguments": [ "arguments": [
{ {
"name": "m", "name": "longitude",
"type": "pure-token", "type": "double"
"token": "m"
}, },
{ {
"name": "km", "name": "latitude",
"type": "pure-token", "type": "double"
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
} }
] ]
} }
] ]
}, },
{ {
"name": "box", "name": "by",
"type": "block", "type": "oneof",
"optional": true,
"arguments": [ "arguments": [
{ {
"token": "BYBOX", "name": "circle",
"name": "width", "type": "block",
"type": "double"
},
{
"name": "height",
"type": "double"
},
{
"name": "unit",
"type": "oneof",
"arguments": [ "arguments": [
{ {
"name": "m", "token": "BYRADIUS",
"type": "pure-token", "name": "radius",
"token": "m" "type": "double"
}, },
{ {
"name": "km", "name": "unit",
"type": "pure-token", "type": "oneof",
"token": "km" "arguments": [
{
"name": "m",
"type": "pure-token",
"token": "m"
},
{
"name": "km",
"type": "pure-token",
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
}
]
}
]
},
{
"name": "box",
"type": "block",
"arguments": [
{
"token": "BYBOX",
"name": "width",
"type": "double"
}, },
{ {
"name": "ft", "name": "height",
"type": "pure-token", "type": "double"
"token": "ft"
}, },
{ {
"name": "mi", "name": "unit",
"type": "pure-token", "type": "oneof",
"token": "mi" "arguments": [
{
"name": "m",
"type": "pure-token",
"token": "m"
},
{
"name": "km",
"type": "pure-token",
"token": "km"
},
{
"name": "ft",
"type": "pure-token",
"token": "ft"
},
{
"name": "mi",
"type": "pure-token",
"token": "mi"
}
]
} }
] ]
} }
...@@ -207,4 +215,4 @@ ...@@ -207,4 +215,4 @@
} }
] ]
} }
} }
\ No newline at end of file
...@@ -125,27 +125,33 @@ ...@@ -125,27 +125,33 @@
"since": "3.0.0" "since": "3.0.0"
}, },
{ {
"token": "AUTH", "name": "authentication",
"name": "password", "type": "oneof",
"type": "string",
"optional": true,
"since": "4.0.7"
},
{
"token": "AUTH2",
"name": "username_password",
"type": "block",
"optional": true, "optional": true,
"since": "6.0.0",
"arguments": [ "arguments": [
{ {
"name": "username", "token": "AUTH",
"type": "string" "name": "password",
"type": "string",
"optional": true,
"since": "4.0.7"
}, },
{ {
"name": "password", "token": "AUTH2",
"type": "string" "name": "username_password",
"type": "block",
"optional": true,
"since": "6.0.0",
"arguments": [
{
"name": "username",
"type": "string"
},
{
"name": "password",
"type": "string"
}
]
} }
] ]
}, },
...@@ -160,4 +166,4 @@ ...@@ -160,4 +166,4 @@
} }
] ]
} }
} }
\ No newline at end of file
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
"token": "CONFIG", "token": "CONFIG",
"type": "block", "type": "block",
"multiple": true, "multiple": true,
"multiple_token": true,
"optional": true, "optional": true,
"arguments": [ "arguments": [
{ {
......
...@@ -65,6 +65,31 @@ ...@@ -65,6 +65,31 @@
"name": "value", "name": "value",
"type": "string" "type": "string"
}, },
{
"name": "condition",
"type": "oneof",
"optional": true,
"since": "2.6.12",
"arguments": [
{
"name": "nx",
"type": "pure-token",
"token": "NX"
},
{
"name": "xx",
"type": "pure-token",
"token": "XX"
}
]
},
{
"name": "get",
"token": "GET",
"type": "pure-token",
"optional": true,
"since": "6.2.0"
},
{ {
"name": "expiration", "name": "expiration",
"type": "oneof", "type": "oneof",
...@@ -101,31 +126,6 @@ ...@@ -101,31 +126,6 @@
"since": "6.0.0" "since": "6.0.0"
} }
] ]
},
{
"name": "condition",
"type": "oneof",
"optional": true,
"since": "2.6.12",
"arguments": [
{
"name": "nx",
"type": "pure-token",
"token": "NX"
},
{
"name": "xx",
"type": "pure-token",
"token": "XX"
}
]
},
{
"name": "get",
"token": "GET",
"type": "pure-token",
"optional": true,
"since": "6.2.0"
} }
] ]
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
"arity": -4, "arity": -4,
"function": "zrangebylexCommand", "function": "zrangebylexCommand",
"deprecated_since": "6.2.0", "deprecated_since": "6.2.0",
"replaced_by": "`ZRANGE` with the `BYSCORE` argument", "replaced_by": "`ZRANGE` with the `BYLEX` argument",
"doc_flags": [ "doc_flags": [
"DEPRECATED" "DEPRECATED"
], ],
......
...@@ -94,6 +94,15 @@ configEnum aof_fsync_enum[] = { ...@@ -94,6 +94,15 @@ configEnum aof_fsync_enum[] = {
{NULL, 0} {NULL, 0}
}; };
configEnum shutdown_on_sig_enum[] = {
{"default", 0},
{"save", SHUTDOWN_SAVE},
{"nosave", SHUTDOWN_NOSAVE},
{"now", SHUTDOWN_NOW},
{"force", SHUTDOWN_FORCE},
{NULL, 0}
};
configEnum repl_diskless_load_enum[] = { configEnum repl_diskless_load_enum[] = {
{"disabled", REPL_DISKLESS_LOAD_DISABLED}, {"disabled", REPL_DISKLESS_LOAD_DISABLED},
{"on-empty-db", REPL_DISKLESS_LOAD_WHEN_DB_EMPTY}, {"on-empty-db", REPL_DISKLESS_LOAD_WHEN_DB_EMPTY},
...@@ -143,6 +152,13 @@ configEnum cluster_preferred_endpoint_type_enum[] = { ...@@ -143,6 +152,13 @@ configEnum cluster_preferred_endpoint_type_enum[] = {
{NULL, 0} {NULL, 0}
}; };
configEnum propagation_error_behavior_enum[] = {
{"ignore", PROPAGATION_ERR_BEHAVIOR_IGNORE},
{"panic", PROPAGATION_ERR_BEHAVIOR_PANIC},
{"panic-on-replicas", PROPAGATION_ERR_BEHAVIOR_PANIC_ON_REPLICAS},
{NULL, 0}
};
/* Output buffer limits presets. */ /* Output buffer limits presets. */
clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = { clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {
{0, 0, 0}, /* normal */ {0, 0, 0}, /* normal */
...@@ -276,33 +292,50 @@ static standardConfig *lookupConfig(sds name) { ...@@ -276,33 +292,50 @@ static standardConfig *lookupConfig(sds name) {
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
/* Get enum value from name. If there is no match INT_MIN is returned. */ /* Get enum value from name. If there is no match INT_MIN is returned. */
int configEnumGetValue(configEnum *ce, char *name) { int configEnumGetValue(configEnum *ce, sds *argv, int argc, int bitflags) {
while(ce->name != NULL) { if (argc == 0 || (!bitflags && argc != 1)) return INT_MIN;
if (!strcasecmp(ce->name,name)) return ce->val; int values = 0;
ce++; for (int i = 0; i < argc; i++) {
int matched = 0;
for (configEnum *ceItem = ce; ceItem->name != NULL; ceItem++) {
if (!strcasecmp(argv[i],ceItem->name)) {
values |= ceItem->val;
matched = 1;
}
}
if (!matched) return INT_MIN;
} }
return INT_MIN; return values;
} }
/* Get enum name from value. If no match is found NULL is returned. */ /* Get enum name/s from value. If no matches are found "unknown" is returned. */
const char *configEnumGetName(configEnum *ce, int val) { static sds configEnumGetName(configEnum *ce, int values, int bitflags) {
while(ce->name != NULL) { sds names = NULL;
if (ce->val == val) return ce->name; int matches = 0;
ce++; for( ; ce->name != NULL; ce++) {
if (values == ce->val) { /* Short path for perfect match */
sdsfree(names);
return sdsnew(ce->name);
}
if (bitflags && (values & ce->val)) {
names = names ? sdscatfmt(names, " %s", ce->name) : sdsnew(ce->name);
matches |= ce->val;
}
} }
return NULL; if (!names || values != matches) {
} sdsfree(names);
return sdsnew("unknown");
/* Wrapper for configEnumGetName() returning "unknown" instead of NULL if }
* there is no match. */ return names;
const char *configEnumGetNameOrUnknown(configEnum *ce, int val) {
const char *name = configEnumGetName(ce,val);
return name ? name : "unknown";
} }
/* Used for INFO generation. */ /* Used for INFO generation. */
const char *evictPolicyToString(void) { const char *evictPolicyToString(void) {
return configEnumGetNameOrUnknown(maxmemory_policy_enum,server.maxmemory_policy); for (configEnum *ce = maxmemory_policy_enum; ce->name != NULL; ce++) {
if (server.maxmemory_policy == ce->val)
return ce->name;
}
serverPanic("unknown eviction policy");
} }
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
...@@ -514,12 +547,15 @@ void loadServerConfigFromString(char *config) { ...@@ -514,12 +547,15 @@ void loadServerConfigFromString(char *config) {
} else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) { } else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) {
queueLoadModule(argv[1],&argv[2],argc-2); queueLoadModule(argv[1],&argv[2],argc-2);
} else if (strchr(argv[0], '.')) { } else if (strchr(argv[0], '.')) {
if (argc != 2) { if (argc < 2) {
err = "Module config specified without value"; err = "Module config specified without value";
goto loaderr; goto loaderr;
} }
sds name = sdsdup(argv[0]); sds name = sdsdup(argv[0]);
if (!dictReplace(server.module_configs_queue, name, sdsdup(argv[1]))) sdsfree(name); sds val = sdsdup(argv[1]);
for (int i = 2; i < argc; i++)
val = sdscatfmt(val, " %S", argv[i]);
if (!dictReplace(server.module_configs_queue, name, val)) sdsfree(name);
} else if (!strcasecmp(argv[0],"sentinel")) { } else if (!strcasecmp(argv[0],"sentinel")) {
/* argc == 1 is handled by main() as we need to enter the sentinel /* argc == 1 is handled by main() as we need to enter the sentinel
* mode ASAP. */ * mode ASAP. */
...@@ -1297,12 +1333,13 @@ void rewriteConfigOctalOption(struct rewriteConfigState *state, const char *opti ...@@ -1297,12 +1333,13 @@ void rewriteConfigOctalOption(struct rewriteConfigState *state, const char *opti
/* Rewrite an enumeration option. It takes as usually state and option name, /* Rewrite an enumeration option. It takes as usually state and option name,
* and in addition the enumeration array and the default value for the * and in addition the enumeration array and the default value for the
* option. */ * option. */
void rewriteConfigEnumOption(struct rewriteConfigState *state, const char *option, int value, configEnum *ce, int defval) { void rewriteConfigEnumOption(struct rewriteConfigState *state, const char *option, int value, standardConfig *config) {
sds line; int multiarg = config->flags & MULTI_ARG_CONFIG;
const char *name = configEnumGetNameOrUnknown(ce,value); sds names = configEnumGetName(config->data.enumd.enum_value,value,multiarg);
int force = value != defval; sds line = sdscatfmt(sdsempty(),"%s %s",option,names);
sdsfree(names);
int force = value != config->data.enumd.default_value;
line = sdscatprintf(sdsempty(),"%s %s",option,name);
rewriteConfigRewriteLine(state,option,line,force); rewriteConfigRewriteLine(state,option,line,force);
} }
...@@ -1821,10 +1858,16 @@ static int sdsConfigSet(standardConfig *config, sds *argv, int argc, const char ...@@ -1821,10 +1858,16 @@ static int sdsConfigSet(standardConfig *config, sds *argv, int argc, const char
UNUSED(argc); UNUSED(argc);
if (config->data.sds.is_valid_fn && !config->data.sds.is_valid_fn(argv[0], err)) if (config->data.sds.is_valid_fn && !config->data.sds.is_valid_fn(argv[0], err))
return 0; return 0;
sds prev = config->flags & MODULE_CONFIG ? getModuleStringConfig(config->privdata) : *config->data.sds.config; sds prev = config->flags & MODULE_CONFIG ? getModuleStringConfig(config->privdata) : *config->data.sds.config;
sds new = (config->data.string.convert_empty_to_null && (sdslen(argv[0]) == 0)) ? NULL : argv[0]; sds new = (config->data.string.convert_empty_to_null && (sdslen(argv[0]) == 0)) ? NULL : argv[0];
/* if prev and new configuration are not equal, set the new one */
if (new != prev && (new == NULL || prev == NULL || sdscmp(prev, new))) { if (new != prev && (new == NULL || prev == NULL || sdscmp(prev, new))) {
/* If MODULE_CONFIG flag is set, then free temporary prev getModuleStringConfig returned.
* Otherwise, free the actual previous config value Redis held (Same action, different reasons) */
sdsfree(prev); sdsfree(prev);
if (config->flags & MODULE_CONFIG) { if (config->flags & MODULE_CONFIG) {
return setModuleStringConfig(config->privdata, new, err); return setModuleStringConfig(config->privdata, new, err);
} }
...@@ -1848,7 +1891,7 @@ static sds sdsConfigGet(standardConfig *config) { ...@@ -1848,7 +1891,7 @@ static sds sdsConfigGet(standardConfig *config) {
static void sdsConfigRewrite(standardConfig *config, const char *name, struct rewriteConfigState *state) { static void sdsConfigRewrite(standardConfig *config, const char *name, struct rewriteConfigState *state) {
sds val = config->flags & MODULE_CONFIG ? getModuleStringConfig(config->privdata) : *config->data.sds.config; sds val = config->flags & MODULE_CONFIG ? getModuleStringConfig(config->privdata) : *config->data.sds.config;
rewriteConfigSdsOption(state, name, val, config->data.sds.default_value); rewriteConfigSdsOption(state, name, val, config->data.sds.default_value);
if (val) sdsfree(val); if ((val) && (config->flags & MODULE_CONFIG)) sdsfree(val);
} }
...@@ -1885,10 +1928,12 @@ static void enumConfigInit(standardConfig *config) { ...@@ -1885,10 +1928,12 @@ static void enumConfigInit(standardConfig *config) {
} }
static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char **err) { static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char **err) {
UNUSED(argc); int enumval;
int enumval = configEnumGetValue(config->data.enumd.enum_value, argv[0]); int bitflags = !!(config->flags & MULTI_ARG_CONFIG);
enumval = configEnumGetValue(config->data.enumd.enum_value, argv, argc, bitflags);
if (enumval == INT_MIN) { if (enumval == INT_MIN) {
sds enumerr = sdsnew("argument must be one of the following: "); sds enumerr = sdsnew("argument(s) must be one of the following: ");
configEnum *enumNode = config->data.enumd.enum_value; configEnum *enumNode = config->data.enumd.enum_value;
while(enumNode->name != NULL) { while(enumNode->name != NULL) {
enumerr = sdscatlen(enumerr, enumNode->name, enumerr = sdscatlen(enumerr, enumNode->name,
...@@ -1919,12 +1964,13 @@ static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char ...@@ -1919,12 +1964,13 @@ static int enumConfigSet(standardConfig *config, sds *argv, int argc, const char
static sds enumConfigGet(standardConfig *config) { static sds enumConfigGet(standardConfig *config) {
int val = config->flags & MODULE_CONFIG ? getModuleEnumConfig(config->privdata) : *(config->data.enumd.config); int val = config->flags & MODULE_CONFIG ? getModuleEnumConfig(config->privdata) : *(config->data.enumd.config);
return sdsnew(configEnumGetNameOrUnknown(config->data.enumd.enum_value,val)); int bitflags = !!(config->flags & MULTI_ARG_CONFIG);
return configEnumGetName(config->data.enumd.enum_value,val,bitflags);
} }
static void enumConfigRewrite(standardConfig *config, const char *name, struct rewriteConfigState *state) { static void enumConfigRewrite(standardConfig *config, const char *name, struct rewriteConfigState *state) {
int val = config->flags & MODULE_CONFIG ? getModuleEnumConfig(config->privdata) : *(config->data.enumd.config); int val = config->flags & MODULE_CONFIG ? getModuleEnumConfig(config->privdata) : *(config->data.enumd.config);
rewriteConfigEnumOption(state, name, val, config->data.enumd.enum_value, config->data.enumd.default_value); rewriteConfigEnumOption(state, name, val, config);
} }
#define createEnumConfig(name, alias, flags, enum, config_addr, default, is_valid, apply) { \ #define createEnumConfig(name, alias, flags, enum, config_addr, default, is_valid, apply) { \
...@@ -2284,6 +2330,16 @@ static int isValidAOFdirname(char *val, const char **err) { ...@@ -2284,6 +2330,16 @@ static int isValidAOFdirname(char *val, const char **err) {
return 1; return 1;
} }
static int isValidShutdownOnSigFlags(int val, const char **err) {
/* Individual arguments are validated by createEnumConfig logic.
* We just need to ensure valid combinations here. */
if (val & SHUTDOWN_NOSAVE && val & SHUTDOWN_SAVE) {
*err = "shutdown options SAVE and NOSAVE can't be used simultaneously";
return 0;
}
return 1;
}
static int isValidAnnouncedHostname(char *val, const char **err) { static int isValidAnnouncedHostname(char *val, const char **err) {
if (strlen(val) >= NET_HOST_STR_LEN) { if (strlen(val) >= NET_HOST_STR_LEN) {
*err = "Hostnames must be less than " *err = "Hostnames must be less than "
...@@ -2641,7 +2697,7 @@ static int setConfigOOMScoreAdjValuesOption(standardConfig *config, sds *argv, i ...@@ -2641,7 +2697,7 @@ static int setConfigOOMScoreAdjValuesOption(standardConfig *config, sds *argv, i
if (*eptr != '\0' || val < -2000 || val > 2000) { if (*eptr != '\0' || val < -2000 || val > 2000) {
if (err) *err = "Invalid oom-score-adj-values, elements must be between -2000 and 2000."; if (err) *err = "Invalid oom-score-adj-values, elements must be between -2000 and 2000.";
return -1; return 0;
} }
values[i] = val; values[i] = val;
...@@ -2691,7 +2747,7 @@ static int setConfigNotifyKeyspaceEventsOption(standardConfig *config, sds *argv ...@@ -2691,7 +2747,7 @@ static int setConfigNotifyKeyspaceEventsOption(standardConfig *config, sds *argv
} }
int flags = keyspaceEventsStringToFlags(argv[0]); int flags = keyspaceEventsStringToFlags(argv[0]);
if (flags == -1) { if (flags == -1) {
*err = "Invalid event class character. Use 'Ag$lshzxeKEtmd'."; *err = "Invalid event class character. Use 'Ag$lshzxeKEtmdn'.";
return 0; return 0;
} }
server.notify_keyspace_events = flags; server.notify_keyspace_events = flags;
...@@ -2887,7 +2943,8 @@ standardConfig static_configs[] = { ...@@ -2887,7 +2943,8 @@ standardConfig static_configs[] = {
createBoolConfig("replica-announced", NULL, MODIFIABLE_CONFIG, server.replica_announced, 1, NULL, NULL), createBoolConfig("replica-announced", NULL, MODIFIABLE_CONFIG, server.replica_announced, 1, NULL, NULL),
createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL), createBoolConfig("latency-tracking", NULL, MODIFIABLE_CONFIG, server.latency_tracking_enabled, 1, NULL, NULL),
createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled), createBoolConfig("aof-disable-auto-gc", NULL, MODIFIABLE_CONFIG, server.aof_disable_auto_gc, 0, NULL, updateAofAutoGCEnabled),
createBoolConfig("replica-ignore-disk-write-errors", NULL, MODIFIABLE_CONFIG, server.repl_ignore_disk_write_error, 0, NULL, NULL),
/* String Configs */ /* String Configs */
createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL), createStringConfig("aclfile", NULL, IMMUTABLE_CONFIG, ALLOW_EMPTY_STRING, server.acl_filename, "", NULL, NULL),
createStringConfig("unixsocket", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, server.unixsocket, NULL, NULL, NULL), createStringConfig("unixsocket", NULL, IMMUTABLE_CONFIG, EMPTY_STRING_IS_NULL, server.unixsocket, NULL, NULL, NULL),
...@@ -2928,6 +2985,9 @@ standardConfig static_configs[] = { ...@@ -2928,6 +2985,9 @@ standardConfig static_configs[] = {
createEnumConfig("enable-debug-command", NULL, IMMUTABLE_CONFIG, protected_action_enum, server.enable_debug_cmd, PROTECTED_ACTION_ALLOWED_NO, NULL, NULL), createEnumConfig("enable-debug-command", NULL, IMMUTABLE_CONFIG, protected_action_enum, server.enable_debug_cmd, PROTECTED_ACTION_ALLOWED_NO, NULL, NULL),
createEnumConfig("enable-module-command", NULL, IMMUTABLE_CONFIG, protected_action_enum, server.enable_module_cmd, PROTECTED_ACTION_ALLOWED_NO, NULL, NULL), createEnumConfig("enable-module-command", NULL, IMMUTABLE_CONFIG, protected_action_enum, server.enable_module_cmd, PROTECTED_ACTION_ALLOWED_NO, NULL, NULL),
createEnumConfig("cluster-preferred-endpoint-type", NULL, MODIFIABLE_CONFIG, cluster_preferred_endpoint_type_enum, server.cluster_preferred_endpoint_type, CLUSTER_ENDPOINT_TYPE_IP, NULL, NULL), createEnumConfig("cluster-preferred-endpoint-type", NULL, MODIFIABLE_CONFIG, cluster_preferred_endpoint_type_enum, server.cluster_preferred_endpoint_type, CLUSTER_ENDPOINT_TYPE_IP, NULL, NULL),
createEnumConfig("propagation-error-behavior", NULL, MODIFIABLE_CONFIG, propagation_error_behavior_enum, server.propagation_error_behavior, PROPAGATION_ERR_BEHAVIOR_IGNORE, NULL, NULL),
createEnumConfig("shutdown-on-sigint", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, shutdown_on_sig_enum, server.shutdown_on_sigint, 0, isValidShutdownOnSigFlags, NULL),
createEnumConfig("shutdown-on-sigterm", NULL, MODIFIABLE_CONFIG | MULTI_ARG_CONFIG, shutdown_on_sig_enum, server.shutdown_on_sigterm, 0, isValidShutdownOnSigFlags, NULL),
/* Integer configs */ /* Integer configs */
createIntConfig("databases", NULL, IMMUTABLE_CONFIG, 1, INT_MAX, server.dbnum, 16, INTEGER_CONFIG, NULL, NULL), createIntConfig("databases", NULL, IMMUTABLE_CONFIG, 1, INT_MAX, server.dbnum, 16, INTEGER_CONFIG, NULL, NULL),
...@@ -2971,6 +3031,7 @@ standardConfig static_configs[] = { ...@@ -2971,6 +3031,7 @@ standardConfig static_configs[] = {
/* Unsigned int configs */ /* Unsigned int configs */
createUIntConfig("maxclients", NULL, MODIFIABLE_CONFIG, 1, UINT_MAX, server.maxclients, 10000, INTEGER_CONFIG, NULL, updateMaxclients), createUIntConfig("maxclients", NULL, MODIFIABLE_CONFIG, 1, UINT_MAX, server.maxclients, 10000, INTEGER_CONFIG, NULL, updateMaxclients),
createUIntConfig("unixsocketperm", NULL, IMMUTABLE_CONFIG, 0, 0777, server.unixsocketperm, 0, OCTAL_CONFIG, NULL, NULL), createUIntConfig("unixsocketperm", NULL, IMMUTABLE_CONFIG, 0, 0777, server.unixsocketperm, 0, OCTAL_CONFIG, NULL, NULL),
createUIntConfig("socket-mark-id", NULL, IMMUTABLE_CONFIG, 0, UINT_MAX, server.socket_mark_id, 0, INTEGER_CONFIG, NULL, NULL),
/* Unsigned Long configs */ /* Unsigned Long configs */
createULongConfig("active-defrag-max-scan-fields", NULL, MODIFIABLE_CONFIG, 1, LONG_MAX, server.active_defrag_max_scan_fields, 1000, INTEGER_CONFIG, NULL, NULL), /* Default: keys with more than 1000 fields will be processed separately */ createULongConfig("active-defrag-max-scan-fields", NULL, MODIFIABLE_CONFIG, 1, LONG_MAX, server.active_defrag_max_scan_fields, 1000, INTEGER_CONFIG, NULL, NULL), /* Default: keys with more than 1000 fields will be processed separately */
......
...@@ -80,6 +80,10 @@ ...@@ -80,6 +80,10 @@
/* MSG_NOSIGNAL. */ /* MSG_NOSIGNAL. */
#ifdef __linux__ #ifdef __linux__
#define HAVE_MSG_NOSIGNAL 1 #define HAVE_MSG_NOSIGNAL 1
#if defined(SO_MARK)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_MARK
#endif
#endif #endif
/* Test for polling API */ /* Test for polling API */
...@@ -113,6 +117,20 @@ ...@@ -113,6 +117,20 @@
#define redis_fsync(fd) fsync(fd) #define redis_fsync(fd) fsync(fd)
#endif #endif
#if defined(__FreeBSD__)
#if defined(SO_USER_COOKIE)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_USER_COOKIE
#endif
#endif
#if defined(__OpenBSD__)
#if defined(SO_RTABLE)
#define HAVE_SOCKOPTMARKID 1
#define SOCKOPTMARKID SO_RTABLE
#endif
#endif
#if __GNUC__ >= 4 #if __GNUC__ >= 4
#define redis_unreachable __builtin_unreachable #define redis_unreachable __builtin_unreachable
#else #else
......
...@@ -182,6 +182,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) { ...@@ -182,6 +182,7 @@ void dbAdd(redisDb *db, robj *key, robj *val) {
dictSetVal(db->dict, de, val); dictSetVal(db->dict, de, val);
signalKeyAsReady(db, key, val->type); signalKeyAsReady(db, key, val->type);
if (server.cluster_enabled) slotToKeyAddEntry(de, db); if (server.cluster_enabled) slotToKeyAddEntry(de, db);
notifyKeyspaceEvent(NOTIFY_NEW,"new",key,db->id);
} }
/* This is a special version of dbAdd() that is used only when loading /* This is a special version of dbAdd() that is used only when loading
......
...@@ -416,6 +416,8 @@ void debugCommand(client *c) { ...@@ -416,6 +416,8 @@ void debugCommand(client *c) {
" Like HTSTATS but for the hash table stored at <key>'s value.", " Like HTSTATS but for the hash table stored at <key>'s value.",
"LOADAOF", "LOADAOF",
" Flush the AOF buffers on disk and reload the AOF in memory.", " Flush the AOF buffers on disk and reload the AOF in memory.",
"REPLICATE <string>",
" Replicates the provided string to replicas, allowing data divergence.",
#ifdef USE_JEMALLOC #ifdef USE_JEMALLOC
"MALLCTL <key> [<val>]", "MALLCTL <key> [<val>]",
" Get or set a malloc tuning integer.", " Get or set a malloc tuning integer.",
...@@ -849,6 +851,10 @@ NULL ...@@ -849,6 +851,10 @@ NULL
{ {
server.aof_flush_sleep = atoi(c->argv[2]->ptr); server.aof_flush_sleep = atoi(c->argv[2]->ptr);
addReply(c,shared.ok); addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"replicate") && c->argc >= 3) {
replicationFeedSlaves(server.slaves, server.slaveseldb,
c->argv + 2, c->argc - 2);
addReply(c,shared.ok);
} else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) { } else if (!strcasecmp(c->argv[1]->ptr,"error") && c->argc == 3) {
sds errstr = sdsnewlen("-",1); sds errstr = sdsnewlen("-",1);
......
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