mirror of
https://github.com/fluencelabs/redis
synced 2025-06-12 00:31:21 +00:00
Merge remote-tracking branch 'antirez/unstable' into modules_info
This commit is contained in:
179
src/server.c
179
src/server.c
@ -146,6 +146,8 @@ volatile unsigned long lru_clock; /* Server global current LRU time. */
|
||||
* in this condition but just a few.
|
||||
*
|
||||
* no-monitor: Do not automatically propagate the command on MONITOR.
|
||||
*
|
||||
* no-slowlog: Do not automatically propagate the command to the slowlog.
|
||||
*
|
||||
* cluster-asking: Perform an implicit ASKING for this command, so the
|
||||
* command will be accepted in cluster mode if the slot is marked
|
||||
@ -627,7 +629,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"auth",authCommand,-2,
|
||||
"no-script ok-loading ok-stale fast @connection",
|
||||
"no-script ok-loading ok-stale fast no-monitor no-slowlog @connection",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
/* We don't allow PING during loading since in Redis PING is used as
|
||||
@ -670,7 +672,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"exec",execCommand,1,
|
||||
"no-script no-monitor @transaction",
|
||||
"no-script no-monitor no-slowlog @transaction",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"discard",discardCommand,1,
|
||||
@ -822,7 +824,7 @@ struct redisCommand redisCommandTable[] = {
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
{"hello",helloCommand,-2,
|
||||
"no-script fast @connection",
|
||||
"no-script fast no-monitor no-slowlog @connection",
|
||||
0,NULL,0,0,0,0,0,0},
|
||||
|
||||
/* EVAL can modify the dataset, however it is not flagged as a write
|
||||
@ -1447,12 +1449,18 @@ int incrementallyRehash(int dbid) {
|
||||
* for dict.c to resize the hash tables accordingly to the fact we have o not
|
||||
* running childs. */
|
||||
void updateDictResizePolicy(void) {
|
||||
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
|
||||
if (!hasActiveChildProcess())
|
||||
dictEnableResize();
|
||||
else
|
||||
dictDisableResize();
|
||||
}
|
||||
|
||||
int hasActiveChildProcess() {
|
||||
return server.rdb_child_pid != -1 ||
|
||||
server.aof_child_pid != -1 ||
|
||||
server.module_child_pid != -1;
|
||||
}
|
||||
|
||||
/* ======================= Cron: called every 100 ms ======================== */
|
||||
|
||||
/* Add a sample to the operations per second array of samples. */
|
||||
@ -1689,7 +1697,7 @@ void databasesCron(void) {
|
||||
/* Perform hash tables rehashing if needed, but only if there are no
|
||||
* other processes saving the DB on disk. Otherwise rehashing is bad
|
||||
* as will cause a lot of copy-on-write of memory pages. */
|
||||
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
|
||||
if (!hasActiveChildProcess()) {
|
||||
/* We use global counters so if we stop the computation at a given
|
||||
* DB we'll be able to start from the successive in the next
|
||||
* cron loop iteration. */
|
||||
@ -1886,15 +1894,14 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
|
||||
/* Start a scheduled AOF rewrite if this was requested by the user while
|
||||
* a BGSAVE was in progress. */
|
||||
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 &&
|
||||
if (!hasActiveChildProcess() &&
|
||||
server.aof_rewrite_scheduled)
|
||||
{
|
||||
rewriteAppendOnlyFileBackground();
|
||||
}
|
||||
|
||||
/* Check if a background saving or AOF rewrite in progress terminated. */
|
||||
if (server.rdb_child_pid != -1 || server.aof_child_pid != -1 ||
|
||||
ldbPendingChildren())
|
||||
if (hasActiveChildProcess() || ldbPendingChildren())
|
||||
{
|
||||
int statloc;
|
||||
pid_t pid;
|
||||
@ -1905,18 +1912,32 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
|
||||
if (WIFSIGNALED(statloc)) bysignal = WTERMSIG(statloc);
|
||||
|
||||
/* sigKillChildHandler catches the signal and calls exit(), but we
|
||||
* must make sure not to flag lastbgsave_status, etc incorrectly.
|
||||
* We could directly terminate the child process via SIGUSR1
|
||||
* without handling it, but in this case Valgrind will log an
|
||||
* annoying error. */
|
||||
if (exitcode == SERVER_CHILD_NOERROR_RETVAL) {
|
||||
bysignal = SIGUSR1;
|
||||
exitcode = 1;
|
||||
}
|
||||
|
||||
if (pid == -1) {
|
||||
serverLog(LL_WARNING,"wait3() returned an error: %s. "
|
||||
"rdb_child_pid = %d, aof_child_pid = %d",
|
||||
"rdb_child_pid = %d, aof_child_pid = %d, module_child_pid = %d",
|
||||
strerror(errno),
|
||||
(int) server.rdb_child_pid,
|
||||
(int) server.aof_child_pid);
|
||||
(int) server.aof_child_pid,
|
||||
(int) server.module_child_pid);
|
||||
} else if (pid == server.rdb_child_pid) {
|
||||
backgroundSaveDoneHandler(exitcode,bysignal);
|
||||
if (!bysignal && exitcode == 0) receiveChildInfo();
|
||||
} else if (pid == server.aof_child_pid) {
|
||||
backgroundRewriteDoneHandler(exitcode,bysignal);
|
||||
if (!bysignal && exitcode == 0) receiveChildInfo();
|
||||
} else if (pid == server.module_child_pid) {
|
||||
ModuleForkDoneHandler(exitcode,bysignal);
|
||||
if (!bysignal && exitcode == 0) receiveChildInfo();
|
||||
} else {
|
||||
if (!ldbRemoveChild(pid)) {
|
||||
serverLog(LL_WARNING,
|
||||
@ -1954,8 +1975,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
|
||||
/* Trigger an AOF rewrite if needed. */
|
||||
if (server.aof_state == AOF_ON &&
|
||||
server.rdb_child_pid == -1 &&
|
||||
server.aof_child_pid == -1 &&
|
||||
!hasActiveChildProcess() &&
|
||||
server.aof_rewrite_perc &&
|
||||
server.aof_current_size > server.aof_rewrite_min_size)
|
||||
{
|
||||
@ -2013,7 +2033,7 @@ int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
|
||||
* Note: this code must be after the replicationCron() call above so
|
||||
* make sure when refactoring this file to keep this order. This is useful
|
||||
* because we want to give priority to RDB savings for replication. */
|
||||
if (server.rdb_child_pid == -1 && server.aof_child_pid == -1 &&
|
||||
if (!hasActiveChildProcess() &&
|
||||
server.rdb_bgsave_scheduled &&
|
||||
(server.unixtime-server.lastbgsave_try > CONFIG_BGSAVE_RETRY_DELAY ||
|
||||
server.lastbgsave_status == C_OK))
|
||||
@ -2159,6 +2179,16 @@ void createSharedObjects(void) {
|
||||
shared.nullarray[2] = createObject(OBJ_STRING,sdsnew("*-1\r\n"));
|
||||
shared.nullarray[3] = createObject(OBJ_STRING,sdsnew("_\r\n"));
|
||||
|
||||
shared.emptymap[0] = NULL;
|
||||
shared.emptymap[1] = NULL;
|
||||
shared.emptymap[2] = createObject(OBJ_STRING,sdsnew("*0\r\n"));
|
||||
shared.emptymap[3] = createObject(OBJ_STRING,sdsnew("%0\r\n"));
|
||||
|
||||
shared.emptyset[0] = NULL;
|
||||
shared.emptyset[1] = NULL;
|
||||
shared.emptyset[2] = createObject(OBJ_STRING,sdsnew("*0\r\n"));
|
||||
shared.emptyset[3] = createObject(OBJ_STRING,sdsnew("~0\r\n"));
|
||||
|
||||
for (j = 0; j < PROTO_SHARED_SELECT_CMDS; j++) {
|
||||
char dictid_str[64];
|
||||
int dictid_len;
|
||||
@ -2403,6 +2433,9 @@ void initServerConfig(void) {
|
||||
/* Latency monitor */
|
||||
server.latency_monitor_threshold = CONFIG_DEFAULT_LATENCY_MONITOR_THRESHOLD;
|
||||
|
||||
/* Tracking. */
|
||||
server.tracking_table_max_fill = CONFIG_DEFAULT_TRACKING_TABLE_MAX_FILL;
|
||||
|
||||
/* Debugging */
|
||||
server.assert_failed = "<no assertion failed>";
|
||||
server.assert_file = "<no file>";
|
||||
@ -2784,6 +2817,7 @@ void initServer(void) {
|
||||
server.cronloops = 0;
|
||||
server.rdb_child_pid = -1;
|
||||
server.aof_child_pid = -1;
|
||||
server.module_child_pid = -1;
|
||||
server.rdb_child_type = RDB_CHILD_TYPE_NONE;
|
||||
server.rdb_bgsave_scheduled = 0;
|
||||
server.child_info_pipe[0] = -1;
|
||||
@ -2802,6 +2836,7 @@ void initServer(void) {
|
||||
server.stat_peak_memory = 0;
|
||||
server.stat_rdb_cow_bytes = 0;
|
||||
server.stat_aof_cow_bytes = 0;
|
||||
server.stat_module_cow_bytes = 0;
|
||||
server.cron_malloc_stats.zmalloc_used = 0;
|
||||
server.cron_malloc_stats.process_rss = 0;
|
||||
server.cron_malloc_stats.allocator_allocated = 0;
|
||||
@ -2909,6 +2944,8 @@ int populateCommandTableParseFlags(struct redisCommand *c, char *strflags) {
|
||||
c->flags |= CMD_STALE;
|
||||
} else if (!strcasecmp(flag,"no-monitor")) {
|
||||
c->flags |= CMD_SKIP_MONITOR;
|
||||
} else if (!strcasecmp(flag,"no-slowlog")) {
|
||||
c->flags |= CMD_SKIP_SLOWLOG;
|
||||
} else if (!strcasecmp(flag,"cluster-asking")) {
|
||||
c->flags |= CMD_ASKING;
|
||||
} else if (!strcasecmp(flag,"fast")) {
|
||||
@ -3193,7 +3230,7 @@ void call(client *c, int flags) {
|
||||
|
||||
/* Log the command into the Slow log if needed, and populate the
|
||||
* per-command statistics that we show in INFO commandstats. */
|
||||
if (flags & CMD_CALL_SLOWLOG && c->cmd->proc != execCommand) {
|
||||
if (flags & CMD_CALL_SLOWLOG && !(c->cmd->flags & CMD_SKIP_SLOWLOG)) {
|
||||
char *latency_event = (c->cmd->flags & CMD_FAST) ?
|
||||
"fast-command" : "command";
|
||||
latencyAddSampleIfNeeded(latency_event,duration/1000);
|
||||
@ -3324,9 +3361,10 @@ int processCommand(client *c) {
|
||||
|
||||
/* Check if the user is authenticated. This check is skipped in case
|
||||
* the default user is flagged as "nopass" and is active. */
|
||||
int auth_required = !(DefaultUser->flags & USER_FLAG_NOPASS) &&
|
||||
int auth_required = (!(DefaultUser->flags & USER_FLAG_NOPASS) ||
|
||||
DefaultUser->flags & USER_FLAG_DISABLED) &&
|
||||
!c->authenticated;
|
||||
if (auth_required || DefaultUser->flags & USER_FLAG_DISABLED) {
|
||||
if (auth_required) {
|
||||
/* AUTH and HELLO are valid even in non authenticated state. */
|
||||
if (c->cmd->proc != authCommand || c->cmd->proc == helloCommand) {
|
||||
flagTransaction(c);
|
||||
@ -3394,13 +3432,20 @@ int processCommand(client *c) {
|
||||
* is in MULTI/EXEC context? Error. */
|
||||
if (out_of_memory &&
|
||||
(c->cmd->flags & CMD_DENYOOM ||
|
||||
(c->flags & CLIENT_MULTI && c->cmd->proc != execCommand))) {
|
||||
(c->flags & CLIENT_MULTI &&
|
||||
c->cmd->proc != execCommand &&
|
||||
c->cmd->proc != discardCommand)))
|
||||
{
|
||||
flagTransaction(c);
|
||||
addReply(c, shared.oomerr);
|
||||
return C_OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure to use a reasonable amount of memory for client side
|
||||
* caching metadata. */
|
||||
if (server.tracking_clients) trackingLimitUsedSlots();
|
||||
|
||||
/* Don't accept write commands if there are problems persisting on disk
|
||||
* and if this is a master instance. */
|
||||
int deny_write_type = writeCommandsDeniedByDiskError();
|
||||
@ -3541,6 +3586,12 @@ int prepareForShutdown(int flags) {
|
||||
killRDBChild();
|
||||
}
|
||||
|
||||
/* Kill module child if there is one. */
|
||||
if (server.module_child_pid != -1) {
|
||||
serverLog(LL_WARNING,"There is a module fork child. Killing it!");
|
||||
TerminateModuleForkChild(server.module_child_pid,0);
|
||||
}
|
||||
|
||||
if (server.aof_state != AOF_OFF) {
|
||||
/* Kill the AOF saving child as the AOF we already have may be longer
|
||||
* but contains the full dataset anyway. */
|
||||
@ -3695,6 +3746,7 @@ void addReplyCommand(client *c, struct redisCommand *cmd) {
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_LOADING, "loading");
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_STALE, "stale");
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_SKIP_MONITOR, "skip_monitor");
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_SKIP_SLOWLOG, "skip_slowlog");
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_ASKING, "asking");
|
||||
flagcount += addReplyCommandFlag(c,cmd,CMD_FAST, "fast");
|
||||
if ((cmd->getkeys_proc && !(cmd->flags & CMD_MODULE)) ||
|
||||
@ -4009,8 +4061,11 @@ sds genRedisInfoString(char *section) {
|
||||
mh->allocator_rss_bytes,
|
||||
mh->rss_extra,
|
||||
mh->rss_extra_bytes,
|
||||
mh->total_frag, /* this is the total RSS overhead, including fragmentation, */
|
||||
mh->total_frag_bytes, /* named so for backwards compatibility */
|
||||
mh->total_frag, /* This is the total RSS overhead, including
|
||||
fragmentation, but not just it. This field
|
||||
(and the next one) is named like that just
|
||||
for backward compatibility. */
|
||||
mh->total_frag_bytes,
|
||||
freeMemoryGetNotCountedMemory(),
|
||||
mh->repl_backlog,
|
||||
mh->clients_slaves,
|
||||
@ -4043,7 +4098,9 @@ sds genRedisInfoString(char *section) {
|
||||
"aof_current_rewrite_time_sec:%jd\r\n"
|
||||
"aof_last_bgrewrite_status:%s\r\n"
|
||||
"aof_last_write_status:%s\r\n"
|
||||
"aof_last_cow_size:%zu\r\n",
|
||||
"aof_last_cow_size:%zu\r\n"
|
||||
"module_fork_in_progress:%d\r\n"
|
||||
"module_fork_last_cow_size:%zu\r\n",
|
||||
server.loading,
|
||||
server.dirty,
|
||||
server.rdb_child_pid != -1,
|
||||
@ -4061,7 +4118,9 @@ sds genRedisInfoString(char *section) {
|
||||
-1 : time(NULL)-server.aof_rewrite_time_start),
|
||||
(server.aof_lastbgrewrite_status == C_OK) ? "ok" : "err",
|
||||
(server.aof_last_write_status == C_OK) ? "ok" : "err",
|
||||
server.stat_aof_cow_bytes);
|
||||
server.stat_aof_cow_bytes,
|
||||
server.module_child_pid != -1,
|
||||
server.stat_module_cow_bytes);
|
||||
|
||||
if (server.aof_enabled) {
|
||||
info = sdscatprintf(info,
|
||||
@ -4143,7 +4202,8 @@ sds genRedisInfoString(char *section) {
|
||||
"active_defrag_hits:%lld\r\n"
|
||||
"active_defrag_misses:%lld\r\n"
|
||||
"active_defrag_key_hits:%lld\r\n"
|
||||
"active_defrag_key_misses:%lld\r\n",
|
||||
"active_defrag_key_misses:%lld\r\n"
|
||||
"tracking_used_slots:%lld\r\n",
|
||||
server.stat_numconnections,
|
||||
server.stat_numcommands,
|
||||
getInstantaneousMetric(STATS_METRIC_COMMAND),
|
||||
@ -4169,7 +4229,8 @@ sds genRedisInfoString(char *section) {
|
||||
server.stat_active_defrag_hits,
|
||||
server.stat_active_defrag_misses,
|
||||
server.stat_active_defrag_key_hits,
|
||||
server.stat_active_defrag_key_misses);
|
||||
server.stat_active_defrag_key_misses,
|
||||
trackingGetUsedSlots());
|
||||
}
|
||||
|
||||
/* Replication */
|
||||
@ -4315,6 +4376,13 @@ sds genRedisInfoString(char *section) {
|
||||
(long)c_ru.ru_utime.tv_sec, (long)c_ru.ru_utime.tv_usec);
|
||||
}
|
||||
|
||||
/* Modules */
|
||||
if (allsections || defsections || !strcasecmp(section,"modules")) {
|
||||
if (sections++) info = sdscat(info,"\r\n");
|
||||
info = sdscatprintf(info,"# Modules\r\n");
|
||||
info = genModulesInfoString(info);
|
||||
}
|
||||
|
||||
/* Command statistics */
|
||||
if (allsections || !strcasecmp(section,"commandstats")) {
|
||||
if (sections++) info = sdscat(info,"\r\n");
|
||||
@ -4381,7 +4449,9 @@ void infoCommand(client *c) {
|
||||
addReply(c,shared.syntaxerr);
|
||||
return;
|
||||
}
|
||||
addReplyBulkSds(c, genRedisInfoString(section));
|
||||
sds info = genRedisInfoString(section);
|
||||
addReplyVerbatim(c,info,sdslen(info),"txt");
|
||||
sdsfree(info);
|
||||
}
|
||||
|
||||
void monitorCommand(client *c) {
|
||||
@ -4568,6 +4638,61 @@ void setupSignalHandlers(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is the signal handler for children process. It is currently useful
|
||||
* in order to track the SIGUSR1, that we send to a child in order to terminate
|
||||
* it in a clean way, without the parent detecting an error and stop
|
||||
* accepting writes because of a write error condition. */
|
||||
static void sigKillChildHandler(int sig) {
|
||||
UNUSED(sig);
|
||||
serverLogFromHandler(LL_WARNING, "Received SIGUSR1 in child, exiting now.");
|
||||
exitFromChild(SERVER_CHILD_NOERROR_RETVAL);
|
||||
}
|
||||
|
||||
void setupChildSignalHandlers(void) {
|
||||
struct sigaction act;
|
||||
|
||||
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction is used.
|
||||
* Otherwise, sa_handler is used. */
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
act.sa_handler = sigKillChildHandler;
|
||||
sigaction(SIGUSR1, &act, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int redisFork() {
|
||||
int childpid;
|
||||
long long start = ustime();
|
||||
if ((childpid = fork()) == 0) {
|
||||
/* Child */
|
||||
closeListeningSockets(0);
|
||||
setupChildSignalHandlers();
|
||||
} else {
|
||||
/* Parent */
|
||||
server.stat_fork_time = ustime()-start;
|
||||
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);
|
||||
if (childpid == -1) {
|
||||
return -1;
|
||||
}
|
||||
updateDictResizePolicy();
|
||||
}
|
||||
return childpid;
|
||||
}
|
||||
|
||||
void sendChildCOWInfo(int ptype, char *pname) {
|
||||
size_t private_dirty = zmalloc_get_private_dirty(-1);
|
||||
|
||||
if (private_dirty) {
|
||||
serverLog(LL_NOTICE,
|
||||
"%s: %zu MB of memory used by copy-on-write",
|
||||
pname, private_dirty/(1024*1024));
|
||||
}
|
||||
|
||||
server.child_info_data.cow_size = private_dirty;
|
||||
sendChildInfo(ptype);
|
||||
}
|
||||
|
||||
void memtest(size_t megabytes, int passes);
|
||||
|
||||
/* Returns 1 if there is --sentinel among the arguments or if
|
||||
@ -4775,9 +4900,9 @@ int main(int argc, char **argv) {
|
||||
srand(time(NULL)^getpid());
|
||||
gettimeofday(&tv,NULL);
|
||||
|
||||
char hashseed[16];
|
||||
getRandomHexChars(hashseed,sizeof(hashseed));
|
||||
dictSetHashFunctionSeed((uint8_t*)hashseed);
|
||||
uint8_t hashseed[16];
|
||||
getRandomBytes(hashseed,sizeof(hashseed));
|
||||
dictSetHashFunctionSeed(hashseed);
|
||||
server.sentinel_mode = checkForSentinelMode(argc,argv);
|
||||
initServerConfig();
|
||||
ACLInit(); /* The ACL subsystem must be initialized ASAP because the
|
||||
|
Reference in New Issue
Block a user