summaryrefslogtreecommitdiff
path: root/src/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.c')
-rw-r--r--src/server.c97
1 files changed, 75 insertions, 22 deletions
diff --git a/src/server.c b/src/server.c
index 96ceb0122..de32ff847 100644
--- a/src/server.c
+++ b/src/server.c
@@ -48,6 +48,7 @@
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/file.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/uio.h>
@@ -634,7 +635,7 @@ void resetChildState() {
NULL);
}
-/* Return if child type is mutual exclusive with other fork children */
+/* Return if child type is mutually exclusive with other fork children */
int isMutuallyExclusiveChildType(int type) {
return type == CHILD_TYPE_RDB || type == CHILD_TYPE_AOF || type == CHILD_TYPE_MODULE;
}
@@ -2793,8 +2794,23 @@ int populateArgsStructure(struct redisCommandArg *args) {
return count;
}
-/* Recursively populate the command structure. */
-void populateCommandStructure(struct redisCommand *c) {
+/* Recursively populate the command structure.
+ *
+ * On success, the function return C_OK. Otherwise C_ERR is returned and we won't
+ * add this command in the commands dict. */
+int populateCommandStructure(struct redisCommand *c) {
+ /* If the command marks with CMD_SENTINEL, it exists in sentinel. */
+ if (!(c->flags & CMD_SENTINEL) && server.sentinel_mode)
+ return C_ERR;
+
+ /* If the command marks with CMD_ONLY_SENTINEL, it only exists in sentinel. */
+ if (c->flags & CMD_ONLY_SENTINEL && !server.sentinel_mode)
+ return C_ERR;
+
+ /* Translate the command string flags description into an actual
+ * set of flags. */
+ setImplicitACLCategories(c);
+
/* Redis commands don't need more args than STATIC_KEY_SPECS_NUM (Number of keys
* specs can be greater than STATIC_KEY_SPECS_NUM only for module commands) */
c->key_specs = c->key_specs_static;
@@ -2828,14 +2844,15 @@ void populateCommandStructure(struct redisCommand *c) {
for (int j = 0; c->subcommands[j].declared_name; j++) {
struct redisCommand *sub = c->subcommands+j;
- /* Translate the command string flags description into an actual
- * set of flags. */
- setImplicitACLCategories(sub);
sub->fullname = catSubCommandFullname(c->declared_name, sub->declared_name);
- populateCommandStructure(sub);
+ if (populateCommandStructure(sub) == C_ERR)
+ continue;
+
commandAddSubcommand(c, sub, sub->declared_name);
}
}
+
+ return C_OK;
}
extern struct redisCommand redisCommandTable[];
@@ -2853,16 +2870,9 @@ void populateCommandTable(void) {
int retval1, retval2;
- setImplicitACLCategories(c);
-
- if (!(c->flags & CMD_SENTINEL) && server.sentinel_mode)
- continue;
-
- if (c->flags & CMD_ONLY_SENTINEL && !server.sentinel_mode)
- continue;
-
c->fullname = sdsnew(c->declared_name);
- populateCommandStructure(c);
+ if (populateCommandStructure(c) == C_ERR)
+ continue;
retval1 = dictAdd(server.commands, sdsdup(c->fullname), c);
/* Populate an additional dictionary that will be unaffected
@@ -3584,8 +3594,8 @@ int commandCheckArity(client *c, sds *err) {
* if C_ERR is returned the client was destroyed (i.e. after QUIT). */
int processCommand(client *c) {
if (!scriptIsTimedout()) {
- /* Both EXEC and EVAL call call() directly so there should be
- * no way in_exec or in_eval is 1.
+ /* Both EXEC and scripts call call() directly so there should be
+ * no way in_exec or scriptIsRunning() is 1.
* That is unless lua_timedout, in which case client may run
* some commands. */
serverAssert(!server.in_exec);
@@ -4207,6 +4217,12 @@ int finishShutdown(void) {
/* Close the listening sockets. Apparently this allows faster restarts. */
closeListeningSockets(1);
+
+ /* Unlock the cluster config file before shutdown */
+ if (server.cluster_enabled && server.cluster_config_file_lock_fd != -1) {
+ flock(server.cluster_config_file_lock_fd, LOCK_UN|LOCK_NB);
+ }
+
serverLog(LL_WARNING,"%s is now ready to exit, bye bye...",
server.sentinel_mode ? "Sentinel" : "Redis");
return C_OK;
@@ -5645,6 +5661,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
"keyspace_misses:%lld\r\n"
"pubsub_channels:%ld\r\n"
"pubsub_patterns:%lu\r\n"
+ "pubsubshard_channels:%lu\r\n"
"latest_fork_usec:%lld\r\n"
"total_forks:%lld\r\n"
"migrate_cached_sockets:%ld\r\n"
@@ -5694,6 +5711,7 @@ sds genRedisInfoString(dict *section_dict, int all_sections, int everything) {
server.stat_keyspace_misses,
dictSize(server.pubsub_channels),
dictSize(server.pubsub_patterns),
+ dictSize(server.pubsubshard_channels),
server.stat_fork_time,
server.stat_total_forks,
dictSize(server.migrate_cached_sockets),
@@ -6094,9 +6112,12 @@ void usage(void) {
fprintf(stderr," ./redis-server - (read config from stdin)\n");
fprintf(stderr," ./redis-server -v or --version\n");
fprintf(stderr," ./redis-server -h or --help\n");
- fprintf(stderr," ./redis-server --test-memory <megabytes>\n\n");
+ fprintf(stderr," ./redis-server --test-memory <megabytes>\n");
+ fprintf(stderr," ./redis-server --check-system\n");
+ fprintf(stderr,"\n");
fprintf(stderr,"Examples:\n");
fprintf(stderr," ./redis-server (run the server with default conf)\n");
+ fprintf(stderr," echo 'maxmemory 128mb' | ./redis-server -\n");
fprintf(stderr," ./redis-server /etc/redis/6379.conf\n");
fprintf(stderr," ./redis-server --port 7777\n");
fprintf(stderr," ./redis-server --port 7777 --replicaof 127.0.0.1 8888\n");
@@ -6347,7 +6368,7 @@ int redisFork(int purpose) {
server.stat_fork_rate = (double) zmalloc_used_memory() * 1000000 / server.stat_fork_time / (1024*1024*1024); /* GB per second. */
latencyAddSampleIfNeeded("fork",server.stat_fork_time/1000);
- /* The child_pid and child_type are only for mutual exclusive children.
+ /* The child_pid and child_type are only for mutually exclusive children.
* other child types should handle and store their pid's in dedicated variables.
*
* Today, we allows CHILD_TYPE_LDB to run in parallel with the other fork types:
@@ -6433,7 +6454,7 @@ void dismissClientMemory(client *c) {
/* In the child process, we don't need some buffers anymore, and these are
* likely to change in the parent when there's heavy write traffic.
- * We dismis them right away, to avoid CoW.
+ * We dismiss them right away, to avoid CoW.
* see dismissMemeory(). */
void dismissMemoryInChild(void) {
/* madvise(MADV_DONTNEED) may not work if Transparent Huge Pages is enabled. */
@@ -6880,6 +6901,8 @@ int main(int argc, char **argv) {
server.exec_argv[1] = zstrdup(server.configfile);
j = 2; // Skip this arg when parsing options
}
+ sds *argv_tmp;
+ int argc_tmp;
int handled_last_config_arg = 1;
while(j < argc) {
/* Either first or last argument - Should we read config from stdin? */
@@ -6897,7 +6920,37 @@ int main(int argc, char **argv) {
/* argv[j]+2 for removing the preceding `--` */
options = sdscat(options,argv[j]+2);
options = sdscat(options," ");
- handled_last_config_arg = 0;
+
+ argv_tmp = sdssplitargs(argv[j], &argc_tmp);
+ if (argc_tmp == 1) {
+ /* Means that we only have one option name, like --port or "--port " */
+ handled_last_config_arg = 0;
+
+ if ((j != argc-1) && argv[j+1][0] == '-' && argv[j+1][1] == '-' &&
+ !strcasecmp(argv[j], "--save"))
+ {
+ /* Special case: handle some things like `--save --config value`.
+ * In this case, if next argument starts with `--`, we will reset
+ * handled_last_config_arg flag and append an empty "" config value
+ * to the options, so it will become `--save "" --config value`.
+ * We are doing it to be compatible with pre 7.0 behavior (which we
+ * break it in #10660, 7.0.1), since there might be users who generate
+ * a command line from an array and when it's empty that's what they produce. */
+ options = sdscat(options, "\"\"");
+ handled_last_config_arg = 1;
+ }
+ else if ((j == argc-1) && !strcasecmp(argv[j], "--save")) {
+ /* Special case: when empty save is the last argument.
+ * In this case, we append an empty "" config value to the options,
+ * so it will become `--save ""` and will follow the same reset thing. */
+ options = sdscat(options, "\"\"");
+ }
+ } else {
+ /* Means that we are passing both config name and it's value in the same arg,
+ * like "--port 6380", so we need to reset handled_last_config_arg flag. */
+ handled_last_config_arg = 1;
+ }
+ sdsfreesplitres(argv_tmp, argc_tmp);
} else {
/* Option argument */
options = sdscatrepr(options,argv[j],strlen(argv[j]));