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);
......
...@@ -47,44 +47,62 @@ struct redisCommandArg BITCOUNT_Args[] = { ...@@ -47,44 +47,62 @@ struct redisCommandArg BITCOUNT_Args[] = {
/* BITFIELD tips */ /* BITFIELD tips */
#define BITFIELD_tips NULL #define BITFIELD_tips NULL
/* BITFIELD encoding_offset argument table */ /* BITFIELD operation encoding_offset argument table */
struct redisCommandArg BITFIELD_encoding_offset_Subargs[] = { struct redisCommandArg BITFIELD_operation_encoding_offset_Subargs[] = {
{"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* BITFIELD encoding_offset_value argument table */ /* BITFIELD operation write wrap_sat_fail argument table */
struct redisCommandArg BITFIELD_encoding_offset_value_Subargs[] = { struct redisCommandArg BITFIELD_operation_write_wrap_sat_fail_Subargs[] = {
{"wrap",ARG_TYPE_PURE_TOKEN,-1,"WRAP",NULL,NULL,CMD_ARG_NONE},
{"sat",ARG_TYPE_PURE_TOKEN,-1,"SAT",NULL,NULL,CMD_ARG_NONE},
{"fail",ARG_TYPE_PURE_TOKEN,-1,"FAIL",NULL,NULL,CMD_ARG_NONE},
{0}
};
/* BITFIELD operation write write_operation encoding_offset_value argument table */
struct redisCommandArg BITFIELD_operation_write_write_operation_encoding_offset_value_Subargs[] = {
{"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"value",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"value",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* BITFIELD encoding_offset_increment argument table */ /* BITFIELD operation write write_operation encoding_offset_increment argument table */
struct redisCommandArg BITFIELD_encoding_offset_increment_Subargs[] = { struct redisCommandArg BITFIELD_operation_write_write_operation_encoding_offset_increment_Subargs[] = {
{"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"encoding",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"offset",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"increment",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"increment",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* BITFIELD wrap_sat_fail argument table */ /* BITFIELD operation write write_operation argument table */
struct redisCommandArg BITFIELD_wrap_sat_fail_Subargs[] = { struct redisCommandArg BITFIELD_operation_write_write_operation_Subargs[] = {
{"wrap",ARG_TYPE_PURE_TOKEN,-1,"WRAP",NULL,NULL,CMD_ARG_NONE}, {"encoding_offset_value",ARG_TYPE_BLOCK,-1,"SET",NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_operation_write_write_operation_encoding_offset_value_Subargs},
{"sat",ARG_TYPE_PURE_TOKEN,-1,"SAT",NULL,NULL,CMD_ARG_NONE}, {"encoding_offset_increment",ARG_TYPE_BLOCK,-1,"INCRBY",NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_operation_write_write_operation_encoding_offset_increment_Subargs},
{"fail",ARG_TYPE_PURE_TOKEN,-1,"FAIL",NULL,NULL,CMD_ARG_NONE}, {0}
};
/* BITFIELD operation write argument table */
struct redisCommandArg BITFIELD_operation_write_Subargs[] = {
{"wrap_sat_fail",ARG_TYPE_ONEOF,-1,"OVERFLOW",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=BITFIELD_operation_write_wrap_sat_fail_Subargs},
{"write_operation",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_operation_write_write_operation_Subargs},
{0}
};
/* BITFIELD operation argument table */
struct redisCommandArg BITFIELD_operation_Subargs[] = {
{"encoding_offset",ARG_TYPE_BLOCK,-1,"GET",NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_operation_encoding_offset_Subargs},
{"write",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_operation_write_Subargs},
{0} {0}
}; };
/* BITFIELD argument table */ /* BITFIELD argument table */
struct redisCommandArg BITFIELD_Args[] = { struct redisCommandArg BITFIELD_Args[] = {
{"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"encoding_offset",ARG_TYPE_BLOCK,-1,"GET",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=BITFIELD_encoding_offset_Subargs}, {"operation",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_MULTIPLE,.subargs=BITFIELD_operation_Subargs},
{"encoding_offset_value",ARG_TYPE_BLOCK,-1,"SET",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=BITFIELD_encoding_offset_value_Subargs},
{"encoding_offset_increment",ARG_TYPE_BLOCK,-1,"INCRBY",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=BITFIELD_encoding_offset_increment_Subargs},
{"wrap_sat_fail",ARG_TYPE_ONEOF,-1,"OVERFLOW",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=BITFIELD_wrap_sat_fail_Subargs},
{0} {0}
}; };
...@@ -106,7 +124,7 @@ struct redisCommandArg BITFIELD_RO_encoding_offset_Subargs[] = { ...@@ -106,7 +124,7 @@ struct redisCommandArg BITFIELD_RO_encoding_offset_Subargs[] = {
/* BITFIELD_RO argument table */ /* BITFIELD_RO argument table */
struct redisCommandArg BITFIELD_RO_Args[] = { struct redisCommandArg BITFIELD_RO_Args[] = {
{"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"encoding_offset",ARG_TYPE_BLOCK,-1,"GET",NULL,NULL,CMD_ARG_NONE,.subargs=BITFIELD_RO_encoding_offset_Subargs}, {"encoding_offset",ARG_TYPE_BLOCK,-1,"GET",NULL,NULL,CMD_ARG_MULTIPLE,.subargs=BITFIELD_RO_encoding_offset_Subargs},
{0} {0}
}; };
...@@ -1313,13 +1331,20 @@ struct redisCommandArg MIGRATE_key_or_empty_string_Subargs[] = { ...@@ -1313,13 +1331,20 @@ struct redisCommandArg MIGRATE_key_or_empty_string_Subargs[] = {
{0} {0}
}; };
/* MIGRATE username_password argument table */ /* MIGRATE authentication username_password argument table */
struct redisCommandArg MIGRATE_username_password_Subargs[] = { struct redisCommandArg MIGRATE_authentication_username_password_Subargs[] = {
{"username",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"username",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"password",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"password",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* MIGRATE authentication argument table */
struct redisCommandArg MIGRATE_authentication_Subargs[] = {
{"password",ARG_TYPE_STRING,-1,"AUTH",NULL,"4.0.7",CMD_ARG_OPTIONAL},
{"username_password",ARG_TYPE_BLOCK,-1,"AUTH2",NULL,"6.0.0",CMD_ARG_OPTIONAL,.subargs=MIGRATE_authentication_username_password_Subargs},
{0}
};
/* MIGRATE argument table */ /* MIGRATE argument table */
struct redisCommandArg MIGRATE_Args[] = { struct redisCommandArg MIGRATE_Args[] = {
{"host",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"host",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
...@@ -1329,8 +1354,7 @@ struct redisCommandArg MIGRATE_Args[] = { ...@@ -1329,8 +1354,7 @@ struct redisCommandArg MIGRATE_Args[] = {
{"timeout",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"timeout",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"copy",ARG_TYPE_PURE_TOKEN,-1,"COPY",NULL,"3.0.0",CMD_ARG_OPTIONAL}, {"copy",ARG_TYPE_PURE_TOKEN,-1,"COPY",NULL,"3.0.0",CMD_ARG_OPTIONAL},
{"replace",ARG_TYPE_PURE_TOKEN,-1,"REPLACE",NULL,"3.0.0",CMD_ARG_OPTIONAL}, {"replace",ARG_TYPE_PURE_TOKEN,-1,"REPLACE",NULL,"3.0.0",CMD_ARG_OPTIONAL},
{"password",ARG_TYPE_STRING,-1,"AUTH",NULL,"4.0.7",CMD_ARG_OPTIONAL}, {"authentication",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=MIGRATE_authentication_Subargs},
{"username_password",ARG_TYPE_BLOCK,-1,"AUTH2",NULL,"6.0.0",CMD_ARG_OPTIONAL,.subargs=MIGRATE_username_password_Subargs},
{"key",ARG_TYPE_KEY,1,"KEYS",NULL,"3.0.6",CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE}, {"key",ARG_TYPE_KEY,1,"KEYS",NULL,"3.0.6",CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE},
{0} {0}
}; };
...@@ -2089,15 +2113,22 @@ struct redisCommandArg GEORADIUS_RO_Args[] = { ...@@ -2089,15 +2113,22 @@ struct redisCommandArg GEORADIUS_RO_Args[] = {
/* GEOSEARCH tips */ /* GEOSEARCH tips */
#define GEOSEARCH_tips NULL #define GEOSEARCH_tips NULL
/* GEOSEARCH longitude_latitude argument table */ /* GEOSEARCH from longitude_latitude argument table */
struct redisCommandArg GEOSEARCH_longitude_latitude_Subargs[] = { struct redisCommandArg GEOSEARCH_from_longitude_latitude_Subargs[] = {
{"longitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"longitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"latitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"latitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* GEOSEARCH circle unit argument table */ /* GEOSEARCH from argument table */
struct redisCommandArg GEOSEARCH_circle_unit_Subargs[] = { struct redisCommandArg GEOSEARCH_from_Subargs[] = {
{"member",ARG_TYPE_STRING,-1,"FROMMEMBER",NULL,NULL,CMD_ARG_NONE},
{"longitude_latitude",ARG_TYPE_BLOCK,-1,"FROMLONLAT",NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_from_longitude_latitude_Subargs},
{0}
};
/* GEOSEARCH by circle unit argument table */
struct redisCommandArg GEOSEARCH_by_circle_unit_Subargs[] = {
{"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE}, {"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE},
{"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE}, {"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE},
{"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE}, {"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE},
...@@ -2105,15 +2136,15 @@ struct redisCommandArg GEOSEARCH_circle_unit_Subargs[] = { ...@@ -2105,15 +2136,15 @@ struct redisCommandArg GEOSEARCH_circle_unit_Subargs[] = {
{0} {0}
}; };
/* GEOSEARCH circle argument table */ /* GEOSEARCH by circle argument table */
struct redisCommandArg GEOSEARCH_circle_Subargs[] = { struct redisCommandArg GEOSEARCH_by_circle_Subargs[] = {
{"radius",ARG_TYPE_DOUBLE,-1,"BYRADIUS",NULL,NULL,CMD_ARG_NONE}, {"radius",ARG_TYPE_DOUBLE,-1,"BYRADIUS",NULL,NULL,CMD_ARG_NONE},
{"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_circle_unit_Subargs}, {"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_by_circle_unit_Subargs},
{0} {0}
}; };
/* GEOSEARCH box unit argument table */ /* GEOSEARCH by box unit argument table */
struct redisCommandArg GEOSEARCH_box_unit_Subargs[] = { struct redisCommandArg GEOSEARCH_by_box_unit_Subargs[] = {
{"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE}, {"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE},
{"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE}, {"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE},
{"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE}, {"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE},
...@@ -2121,11 +2152,18 @@ struct redisCommandArg GEOSEARCH_box_unit_Subargs[] = { ...@@ -2121,11 +2152,18 @@ struct redisCommandArg GEOSEARCH_box_unit_Subargs[] = {
{0} {0}
}; };
/* GEOSEARCH box argument table */ /* GEOSEARCH by box argument table */
struct redisCommandArg GEOSEARCH_box_Subargs[] = { struct redisCommandArg GEOSEARCH_by_box_Subargs[] = {
{"width",ARG_TYPE_DOUBLE,-1,"BYBOX",NULL,NULL,CMD_ARG_NONE}, {"width",ARG_TYPE_DOUBLE,-1,"BYBOX",NULL,NULL,CMD_ARG_NONE},
{"height",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"height",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_box_unit_Subargs}, {"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_by_box_unit_Subargs},
{0}
};
/* GEOSEARCH by argument table */
struct redisCommandArg GEOSEARCH_by_Subargs[] = {
{"circle",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_by_circle_Subargs},
{"box",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_by_box_Subargs},
{0} {0}
}; };
...@@ -2146,10 +2184,8 @@ struct redisCommandArg GEOSEARCH_count_Subargs[] = { ...@@ -2146,10 +2184,8 @@ struct redisCommandArg GEOSEARCH_count_Subargs[] = {
/* GEOSEARCH argument table */ /* GEOSEARCH argument table */
struct redisCommandArg GEOSEARCH_Args[] = { struct redisCommandArg GEOSEARCH_Args[] = {
{"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"member",ARG_TYPE_STRING,-1,"FROMMEMBER",NULL,NULL,CMD_ARG_OPTIONAL}, {"from",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_from_Subargs},
{"longitude_latitude",ARG_TYPE_BLOCK,-1,"FROMLONLAT",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_longitude_latitude_Subargs}, {"by",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCH_by_Subargs},
{"circle",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_circle_Subargs},
{"box",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_box_Subargs},
{"order",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_order_Subargs}, {"order",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_order_Subargs},
{"count",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_count_Subargs}, {"count",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCH_count_Subargs},
{"withcoord",ARG_TYPE_PURE_TOKEN,-1,"WITHCOORD",NULL,NULL,CMD_ARG_OPTIONAL}, {"withcoord",ARG_TYPE_PURE_TOKEN,-1,"WITHCOORD",NULL,NULL,CMD_ARG_OPTIONAL},
...@@ -2166,15 +2202,22 @@ struct redisCommandArg GEOSEARCH_Args[] = { ...@@ -2166,15 +2202,22 @@ struct redisCommandArg GEOSEARCH_Args[] = {
/* GEOSEARCHSTORE tips */ /* GEOSEARCHSTORE tips */
#define GEOSEARCHSTORE_tips NULL #define GEOSEARCHSTORE_tips NULL
/* GEOSEARCHSTORE longitude_latitude argument table */ /* GEOSEARCHSTORE from longitude_latitude argument table */
struct redisCommandArg GEOSEARCHSTORE_longitude_latitude_Subargs[] = { struct redisCommandArg GEOSEARCHSTORE_from_longitude_latitude_Subargs[] = {
{"longitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"longitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"latitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"latitude",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{0} {0}
}; };
/* GEOSEARCHSTORE circle unit argument table */ /* GEOSEARCHSTORE from argument table */
struct redisCommandArg GEOSEARCHSTORE_circle_unit_Subargs[] = { struct redisCommandArg GEOSEARCHSTORE_from_Subargs[] = {
{"member",ARG_TYPE_STRING,-1,"FROMMEMBER",NULL,NULL,CMD_ARG_NONE},
{"longitude_latitude",ARG_TYPE_BLOCK,-1,"FROMLONLAT",NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_from_longitude_latitude_Subargs},
{0}
};
/* GEOSEARCHSTORE by circle unit argument table */
struct redisCommandArg GEOSEARCHSTORE_by_circle_unit_Subargs[] = {
{"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE}, {"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE},
{"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE}, {"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE},
{"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE}, {"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE},
...@@ -2182,15 +2225,15 @@ struct redisCommandArg GEOSEARCHSTORE_circle_unit_Subargs[] = { ...@@ -2182,15 +2225,15 @@ struct redisCommandArg GEOSEARCHSTORE_circle_unit_Subargs[] = {
{0} {0}
}; };
/* GEOSEARCHSTORE circle argument table */ /* GEOSEARCHSTORE by circle argument table */
struct redisCommandArg GEOSEARCHSTORE_circle_Subargs[] = { struct redisCommandArg GEOSEARCHSTORE_by_circle_Subargs[] = {
{"radius",ARG_TYPE_DOUBLE,-1,"BYRADIUS",NULL,NULL,CMD_ARG_NONE}, {"radius",ARG_TYPE_DOUBLE,-1,"BYRADIUS",NULL,NULL,CMD_ARG_NONE},
{"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_circle_unit_Subargs}, {"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_by_circle_unit_Subargs},
{0} {0}
}; };
/* GEOSEARCHSTORE box unit argument table */ /* GEOSEARCHSTORE by box unit argument table */
struct redisCommandArg GEOSEARCHSTORE_box_unit_Subargs[] = { struct redisCommandArg GEOSEARCHSTORE_by_box_unit_Subargs[] = {
{"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE}, {"m",ARG_TYPE_PURE_TOKEN,-1,"M",NULL,NULL,CMD_ARG_NONE},
{"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE}, {"km",ARG_TYPE_PURE_TOKEN,-1,"KM",NULL,NULL,CMD_ARG_NONE},
{"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE}, {"ft",ARG_TYPE_PURE_TOKEN,-1,"FT",NULL,NULL,CMD_ARG_NONE},
...@@ -2198,11 +2241,18 @@ struct redisCommandArg GEOSEARCHSTORE_box_unit_Subargs[] = { ...@@ -2198,11 +2241,18 @@ struct redisCommandArg GEOSEARCHSTORE_box_unit_Subargs[] = {
{0} {0}
}; };
/* GEOSEARCHSTORE box argument table */ /* GEOSEARCHSTORE by box argument table */
struct redisCommandArg GEOSEARCHSTORE_box_Subargs[] = { struct redisCommandArg GEOSEARCHSTORE_by_box_Subargs[] = {
{"width",ARG_TYPE_DOUBLE,-1,"BYBOX",NULL,NULL,CMD_ARG_NONE}, {"width",ARG_TYPE_DOUBLE,-1,"BYBOX",NULL,NULL,CMD_ARG_NONE},
{"height",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"height",ARG_TYPE_DOUBLE,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_box_unit_Subargs}, {"unit",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_by_box_unit_Subargs},
{0}
};
/* GEOSEARCHSTORE by argument table */
struct redisCommandArg GEOSEARCHSTORE_by_Subargs[] = {
{"circle",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_by_circle_Subargs},
{"box",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_by_box_Subargs},
{0} {0}
}; };
...@@ -2224,10 +2274,8 @@ struct redisCommandArg GEOSEARCHSTORE_count_Subargs[] = { ...@@ -2224,10 +2274,8 @@ struct redisCommandArg GEOSEARCHSTORE_count_Subargs[] = {
struct redisCommandArg GEOSEARCHSTORE_Args[] = { struct redisCommandArg GEOSEARCHSTORE_Args[] = {
{"destination",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"destination",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"source",ARG_TYPE_KEY,1,NULL,NULL,NULL,CMD_ARG_NONE}, {"source",ARG_TYPE_KEY,1,NULL,NULL,NULL,CMD_ARG_NONE},
{"member",ARG_TYPE_STRING,-1,"FROMMEMBER",NULL,NULL,CMD_ARG_OPTIONAL}, {"from",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_from_Subargs},
{"longitude_latitude",ARG_TYPE_BLOCK,-1,"FROMLONLAT",NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_longitude_latitude_Subargs}, {"by",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_NONE,.subargs=GEOSEARCHSTORE_by_Subargs},
{"circle",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_circle_Subargs},
{"box",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_box_Subargs},
{"order",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_order_Subargs}, {"order",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_order_Subargs},
{"count",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_count_Subargs}, {"count",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=GEOSEARCHSTORE_count_Subargs},
{"storedist",ARG_TYPE_PURE_TOKEN,-1,"STOREDIST",NULL,NULL,CMD_ARG_OPTIONAL}, {"storedist",ARG_TYPE_PURE_TOKEN,-1,"STOREDIST",NULL,NULL,CMD_ARG_OPTIONAL},
...@@ -4790,7 +4838,7 @@ struct redisCommandArg MODULE_LOADEX_args_Subargs[] = { ...@@ -4790,7 +4838,7 @@ struct redisCommandArg MODULE_LOADEX_args_Subargs[] = {
/* MODULE LOADEX argument table */ /* MODULE LOADEX argument table */
struct redisCommandArg MODULE_LOADEX_Args[] = { struct redisCommandArg MODULE_LOADEX_Args[] = {
{"path",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"path",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"configs",ARG_TYPE_BLOCK,-1,"CONFIG",NULL,NULL,CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,.subargs=MODULE_LOADEX_configs_Subargs}, {"configs",ARG_TYPE_BLOCK,-1,"CONFIG",NULL,NULL,CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE|CMD_ARG_MULTIPLE_TOKEN,.subargs=MODULE_LOADEX_configs_Subargs},
{"args",ARG_TYPE_BLOCK,-1,"ARGS",NULL,NULL,CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,.subargs=MODULE_LOADEX_args_Subargs}, {"args",ARG_TYPE_BLOCK,-1,"ARGS",NULL,NULL,CMD_ARG_OPTIONAL|CMD_ARG_MULTIPLE,.subargs=MODULE_LOADEX_args_Subargs},
{0} {0}
}; };
...@@ -6919,6 +6967,13 @@ commandHistory SET_History[] = { ...@@ -6919,6 +6967,13 @@ commandHistory SET_History[] = {
/* SET tips */ /* SET tips */
#define SET_tips NULL #define SET_tips NULL
/* SET condition argument table */
struct redisCommandArg SET_condition_Subargs[] = {
{"nx",ARG_TYPE_PURE_TOKEN,-1,"NX",NULL,NULL,CMD_ARG_NONE},
{"xx",ARG_TYPE_PURE_TOKEN,-1,"XX",NULL,NULL,CMD_ARG_NONE},
{0}
};
/* SET expiration argument table */ /* SET expiration argument table */
struct redisCommandArg SET_expiration_Subargs[] = { struct redisCommandArg SET_expiration_Subargs[] = {
{"seconds",ARG_TYPE_INTEGER,-1,"EX",NULL,"2.6.12",CMD_ARG_NONE}, {"seconds",ARG_TYPE_INTEGER,-1,"EX",NULL,"2.6.12",CMD_ARG_NONE},
...@@ -6929,20 +6984,13 @@ struct redisCommandArg SET_expiration_Subargs[] = { ...@@ -6929,20 +6984,13 @@ struct redisCommandArg SET_expiration_Subargs[] = {
{0} {0}
}; };
/* SET condition argument table */
struct redisCommandArg SET_condition_Subargs[] = {
{"nx",ARG_TYPE_PURE_TOKEN,-1,"NX",NULL,NULL,CMD_ARG_NONE},
{"xx",ARG_TYPE_PURE_TOKEN,-1,"XX",NULL,NULL,CMD_ARG_NONE},
{0}
};
/* SET argument table */ /* SET argument table */
struct redisCommandArg SET_Args[] = { struct redisCommandArg SET_Args[] = {
{"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE}, {"key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE},
{"value",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE}, {"value",ARG_TYPE_STRING,-1,NULL,NULL,NULL,CMD_ARG_NONE},
{"expiration",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=SET_expiration_Subargs},
{"condition",ARG_TYPE_ONEOF,-1,NULL,NULL,"2.6.12",CMD_ARG_OPTIONAL,.subargs=SET_condition_Subargs}, {"condition",ARG_TYPE_ONEOF,-1,NULL,NULL,"2.6.12",CMD_ARG_OPTIONAL,.subargs=SET_condition_Subargs},
{"get",ARG_TYPE_PURE_TOKEN,-1,"GET",NULL,"6.2.0",CMD_ARG_OPTIONAL}, {"get",ARG_TYPE_PURE_TOKEN,-1,"GET",NULL,"6.2.0",CMD_ARG_OPTIONAL},
{"expiration",ARG_TYPE_ONEOF,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,.subargs=SET_expiration_Subargs},
{0} {0}
}; };
...@@ -7268,7 +7316,7 @@ struct redisCommand redisCommandTable[] = { ...@@ -7268,7 +7316,7 @@ struct redisCommand redisCommandTable[] = {
{"zpopmin","Remove and return members with the lowest scores in a sorted set","O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZPOPMIN_History,ZPOPMIN_tips,zpopminCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_DELETE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZPOPMIN_Args}, {"zpopmin","Remove and return members with the lowest scores in a sorted set","O(log(N)*M) with N being the number of elements in the sorted set, and M being the number of elements popped.","5.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZPOPMIN_History,ZPOPMIN_tips,zpopminCommand,-2,CMD_WRITE|CMD_FAST,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RW|CMD_KEY_ACCESS|CMD_KEY_DELETE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZPOPMIN_Args},
{"zrandmember","Get one or multiple random elements from a sorted set","O(N) where N is the number of elements returned","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANDMEMBER_History,ZRANDMEMBER_tips,zrandmemberCommand,-2,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANDMEMBER_Args}, {"zrandmember","Get one or multiple random elements from a sorted set","O(N) where N is the number of elements returned","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANDMEMBER_History,ZRANDMEMBER_tips,zrandmemberCommand,-2,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANDMEMBER_Args},
{"zrange","Return a range of members in a sorted set","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANGE_History,ZRANGE_tips,zrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGE_Args}, {"zrange","Return a range of members in a sorted set","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.","1.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANGE_History,ZRANGE_tips,zrangeCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGE_Args},
{"zrangebylex","Return a range of members in a sorted set, by lexicographical range","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.8.9",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYSCORE` argument","6.2.0",COMMAND_GROUP_SORTED_SET,ZRANGEBYLEX_History,ZRANGEBYLEX_tips,zrangebylexCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGEBYLEX_Args}, {"zrangebylex","Return a range of members in a sorted set, by lexicographical range","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","2.8.9",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYLEX` argument","6.2.0",COMMAND_GROUP_SORTED_SET,ZRANGEBYLEX_History,ZRANGEBYLEX_tips,zrangebylexCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGEBYLEX_Args},
{"zrangebyscore","Return a range of members in a sorted set, by score","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","1.0.5",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYSCORE` argument","6.2.0",COMMAND_GROUP_SORTED_SET,ZRANGEBYSCORE_History,ZRANGEBYSCORE_tips,zrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGEBYSCORE_Args}, {"zrangebyscore","Return a range of members in a sorted set, by score","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).","1.0.5",CMD_DOC_DEPRECATED,"`ZRANGE` with the `BYSCORE` argument","6.2.0",COMMAND_GROUP_SORTED_SET,ZRANGEBYSCORE_History,ZRANGEBYSCORE_tips,zrangebyscoreCommand,-4,CMD_READONLY,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGEBYSCORE_Args},
{"zrangestore","Store a range of members from sorted set into another key","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements stored into the destination key.","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANGESTORE_History,ZRANGESTORE_tips,zrangestoreCommand,-5,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_OW|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}},{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGESTORE_Args}, {"zrangestore","Store a range of members from sorted set into another key","O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements stored into the destination key.","6.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANGESTORE_History,ZRANGESTORE_tips,zrangestoreCommand,-5,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_OW|CMD_KEY_UPDATE,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}},{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={2},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANGESTORE_Args},
{"zrank","Determine the index of a member in a sorted set","O(log(N))","2.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANK_History,ZRANK_tips,zrankCommand,3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANK_Args}, {"zrank","Determine the index of a member in a sorted set","O(log(N))","2.0.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_SORTED_SET,ZRANK_History,ZRANK_tips,zrankCommand,3,CMD_READONLY|CMD_FAST,ACL_CATEGORY_SORTEDSET,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=ZRANK_Args},
......
...@@ -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