int vr_listen_accept(vr_listen *vlisten) { rstatus_t status; int sd; ASSERT(vlisten->sd > 0); log_debug(LOG_DEBUG,"client_accept"); for (;;) { sd = accept(vlisten->sd, NULL, NULL); if (sd < 0) { if (errno == EINTR) { log_debug(LOG_VERB, "accept on p %d not ready - eintr", vlisten->sd); continue; } if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ECONNABORTED) { log_debug(LOG_VERB, "accept on p %d not ready - eagain", vlisten->sd); return -1; } if (errno == EMFILE || errno == ENFILE) { log_debug(LOG_CRIT, "accept on p %d " "used connections %"PRIu32" max client connections %u " "curr client connections %"PRIu32" failed: %s", vlisten->sd, conn_ncurr_conn(), server.maxclients, conn_ncurr_cconn(), strerror(errno)); return -1; } log_error("accept on p %d failed: %s", vlisten->sd, strerror(errno)); return -1; } break; } if (conn_ncurr_cconn() >= server.maxclients) { log_debug(LOG_CRIT, "client connections %"PRIu32" exceed limit %"PRIu32, conn_ncurr_cconn(), server.maxclients); status = close(sd); if (status < 0) { log_error("close c %d failed, ignored: %s", sd, strerror(errno)); } update_stats_add(master.vel.stats, rejected_conn, 1); return -1; } return sd; }
/* Call() is the core of Redis execution of a command. * * The following flags can be passed: * CMD_CALL_NONE No flags. * CMD_CALL_SLOWLOG Check command speed and log in the slow log if needed. * CMD_CALL_STATS Populate command stats. * CMD_CALL_PROPAGATE_AOF Append command to AOF if it modified the dataset * or if the client flags are forcing propagation. * CMD_CALL_PROPAGATE_REPL Send command to salves if it modified the dataset * or if the client flags are forcing propagation. * CMD_CALL_PROPAGATE Alias for PROPAGATE_AOF|PROPAGATE_REPL. * CMD_CALL_FULL Alias for SLOWLOG|STATS|PROPAGATE. * * The exact propagation behavior depends on the client flags. * Specifically: * * 1. If the client flags CLIENT_FORCE_AOF or CLIENT_FORCE_REPL are set * and assuming the corresponding CMD_CALL_PROPAGATE_AOF/REPL is set * in the call flags, then the command is propagated even if the * dataset was not affected by the command. * 2. If the client flags CLIENT_PREVENT_REPL_PROP or CLIENT_PREVENT_AOF_PROP * are set, the propagation into AOF or to slaves is not performed even * if the command modified the dataset. * * Note that regardless of the client flags, if CMD_CALL_PROPAGATE_AOF * or CMD_CALL_PROPAGATE_REPL are not set, then respectively AOF or * slaves propagation will never occur. * * Client flags are modified by the implementation of a given command * using the following API: * * forceCommandPropagation(client *c, int flags); * preventCommandPropagation(client *c); * preventCommandAOF(client *c); * preventCommandReplication(client *c); * */ void call(client *c, int flags) { long long dirty, start, duration; int client_old_flags = c->flags; /* Sent the command to clients in MONITOR mode, only if the commands are * not generated from reading an AOF. */ if (listLength(server.monitors) && !server.loading && !(c->cmd->flags & (CMD_SKIP_MONITOR|CMD_ADMIN))) { replicationFeedMonitors(c,server.monitors,c->db->id,c->argv,c->argc); } /* Initialization: clear the flags that must be set by the command on * demand, and initialize the array for additional commands propagation. */ c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); redisOpArrayInit(&server.also_propagate); /* Call the command. */ dirty = c->vel->dirty; start = vr_usec_now(); c->cmd->proc(c); duration = vr_usec_now()-start; dirty = c->vel->dirty-dirty; if (dirty < 0) dirty = 0; /* When EVAL is called loading the AOF we don't want commands called * from Lua to go into the slowlog or to populate statistics. */ if (server.loading && c->flags & CLIENT_LUA) flags &= ~(CMD_CALL_SLOWLOG | CMD_CALL_STATS); /* If the caller is Lua, we want to force the EVAL caller to propagate * the script if the command flag or client flag are forcing the * propagation. */ if (c->flags & CLIENT_LUA && server.lua_caller) { if (c->flags & CLIENT_FORCE_REPL) server.lua_caller->flags |= CLIENT_FORCE_REPL; if (c->flags & CLIENT_FORCE_AOF) server.lua_caller->flags |= CLIENT_FORCE_AOF; } /* 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) { //char *latency_event = (c->cmd->flags & CMD_FAST) ? // "fast-command" : "command"; //latencyAddSampleIfNeeded(latency_event,duration/1000); slowlogPushEntryIfNeeded(c->argv,c->argc,duration); } if (flags & CMD_CALL_STATS) { c->lastcmd->microseconds += duration; c->lastcmd->calls++; } /* Propagate the command into the AOF and replication link */ if (flags & CMD_CALL_PROPAGATE && (c->flags & CLIENT_PREVENT_PROP) != CLIENT_PREVENT_PROP) { int propagate_flags = PROPAGATE_NONE; /* Check if the command operated changes in the data set. If so * set for replication / AOF propagation. */ if (dirty) propagate_flags |= (PROPAGATE_AOF|PROPAGATE_REPL); /* If the client forced AOF / replication of the command, set * the flags regardless of the command effects on the data set. */ if (c->flags & CLIENT_FORCE_REPL) propagate_flags |= PROPAGATE_REPL; if (c->flags & CLIENT_FORCE_AOF) propagate_flags |= PROPAGATE_AOF; /* However prevent AOF / replication propagation if the command * implementatino called preventCommandPropagation() or similar, * or if we don't have the call() flags to do so. */ if (c->flags & CLIENT_PREVENT_REPL_PROP || !(flags & CMD_CALL_PROPAGATE_REPL)) propagate_flags &= ~PROPAGATE_REPL; if (c->flags & CLIENT_PREVENT_AOF_PROP || !(flags & CMD_CALL_PROPAGATE_AOF)) propagate_flags &= ~PROPAGATE_AOF; /* Call propagate() only if at least one of AOF / replication * propagation is needed. */ if (propagate_flags != PROPAGATE_NONE) propagate(c->cmd,c->db->id,c->argv,c->argc,propagate_flags); } /* Restore the old replication flags, since call() can be executed * recursively. */ c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); c->flags |= client_old_flags & (CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP); /* Handle the alsoPropagate() API to handle commands that want to propagate * multiple separated commands. Note that alsoPropagate() is not affected * by CLIENT_PREVENT_PROP flag. */ if (server.also_propagate.numops) { int j; redisOp *rop; if (flags & CMD_CALL_PROPAGATE) { for (j = 0; j < server.also_propagate.numops; j++) { rop = &server.also_propagate.ops[j]; int target = rop->target; /* Whatever the command wish is, we honor the call() flags. */ if (!(flags&CMD_CALL_PROPAGATE_AOF)) target &= ~PROPAGATE_AOF; if (!(flags&CMD_CALL_PROPAGATE_REPL)) target &= ~PROPAGATE_REPL; if (target) propagate(rop->cmd,rop->dbid,rop->argv,rop->argc,target); } } redisOpArrayFree(&server.also_propagate); } update_stats_add(c->vel->stats, numcommands, 1); }
/* Create the string returned by the INFO command. This is decoupled * by the INFO command itself as we need to report the same information * on memory corruption problems. */ sds genVireInfoString(char *section) { sds info = sdsempty(); time_t uptime = time(NULL)-server.starttime; int j, numcommands; struct rusage self_ru; unsigned long lol, bib; int allsections = 0, defsections = 0; int sections = 0; long long keys_all, vkeys_all, avg_ttl_all; int nexit = 0; keys_all = vkeys_all = avg_ttl_all = 0; if (section == NULL) section = "default"; allsections = strcasecmp(section,"all") == 0; defsections = strcasecmp(section,"default") == 0; getrusage(RUSAGE_SELF, &self_ru); /* Server */ if (allsections || defsections || !strcasecmp(section,"server")) { static int call_uname = 1; static struct utsname name; char *mode; mode = "standalone"; if (sections++) info = sdscat(info,"\r\n"); if (call_uname) { /* Uname can be slow and is always the same output. Cache it. */ uname(&name); call_uname = 0; } info = sdscatprintf(info, "# Server\r\n" "vire_version:%s\r\n" "vire_mode:%s\r\n" "os:%s %s %s\r\n" "arch_bits:%d\r\n" "multiplexing_api:%s\r\n" "gcc_version:%d.%d.%d\r\n" "process_id:%ld\r\n" "run_id:%s\r\n" "tcp_port:%d\r\n" "uptime_in_seconds:%jd\r\n" "uptime_in_days:%jd\r\n" "hz:%d\r\n" "executable:%s\r\n" "config_file:%s\r\n", VR_VERSION_STRING, mode, name.sysname, name.release, name.machine, server.arch_bits, aeGetApiName(), #ifdef __GNUC__ __GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__, #else 0,0,0, #endif (long) getpid(), server.runid, server.port, (intmax_t)uptime, (intmax_t)(uptime/(3600*24)), server.hz, server.executable ? server.executable : "", server.configfile ? server.configfile : ""); } /* Memory */ if (allsections || defsections || !strcasecmp(section,"memory")) { char hmem[64]; char peak_hmem[64]; char total_system_hmem[64]; char used_memory_lua_hmem[64]; char used_memory_rss_hmem[64]; char maxmemory_hmem[64]; size_t vr_used_memory = vr_alloc_used_memory(); size_t total_system_mem = server.system_memory_size; /* Peak memory is updated from time to time by serverCron() so it * may happen that the instantaneous value is slightly bigger than * the peak value. This may confuse users, so we update the peak * if found smaller than the current memory usage. */ if (vr_used_memory > server.stat_peak_memory) server.stat_peak_memory = vr_used_memory; bytesToHuman(hmem,vr_used_memory); bytesToHuman(peak_hmem,server.stat_peak_memory); bytesToHuman(total_system_hmem,total_system_mem); bytesToHuman(maxmemory_hmem,server.maxmemory); if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Memory\r\n" "used_memory:%zu\r\n" "used_memory_human:%s\r\n" "used_memory_peak:%zu\r\n" "used_memory_peak_human:%s\r\n" "total_system_memory:%lu\r\n" "total_system_memory_human:%s\r\n" "maxmemory:%lld\r\n" "maxmemory_human:%s\r\n" "mem_allocator:%s\r\n", vr_used_memory, hmem, server.stat_peak_memory, peak_hmem, (unsigned long)total_system_mem, total_system_hmem, server.maxmemory, maxmemory_hmem, VR_MALLOC_LIB ); } /* Stats */ if (allsections || defsections || !strcasecmp(section,"stats")) { uint32_t idx; vr_worker *worker; vr_stats *stats; long long stat_numconnections=0, stat_numcommands=0; long long stat_net_input_bytes=0, stat_net_output_bytes=0; long long stat_rejected_conn=0; long long stat_expiredkeys=0; long long stat_keyspace_hits=0, stat_keyspace_misses=0; for (idx = 0; idx < array_n(&workers); idx ++) { worker = array_get(&workers, idx); stats = worker->vel.stats; #if (defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)) && defined(STATS_ATOMIC_FIRST) stat_numcommands += update_stats_add(stats, numcommands, 0); stat_numconnections += update_stats_add(stats, numconnections, 0); stat_expiredkeys += update_stats_add(stats, expiredkeys, 0); stat_net_input_bytes += update_stats_add(stats, net_input_bytes, 0); stat_net_output_bytes += update_stats_add(stats, net_output_bytes, 0); stat_keyspace_hits += update_stats_add(stats, keyspace_hits, 0); stat_keyspace_misses += update_stats_add(stats, keyspace_misses, 0); #else pthread_spin_lock(&stats->statslock); stat_numcommands += stats->numcommands; stat_numconnections += stats->numconnections; stat_expiredkeys += stats->expiredkeys; stat_net_input_bytes += stats->net_input_bytes; stat_net_output_bytes += stats->net_output_bytes; stat_keyspace_hits += stats->keyspace_hits; stat_keyspace_misses += stats->keyspace_misses; pthread_spin_unlock(&stats->statslock); #endif } #if (defined(__ATOMIC_RELAXED) || defined(HAVE_ATOMIC)) && defined(STATS_ATOMIC_FIRST) stat_rejected_conn += update_stats_add(master.vel.stats, rejected_conn, 0); #else pthread_spin_lock(&master.vel.stats->statslock); stat_rejected_conn = master.vel.stats->rejected_conn; pthread_spin_unlock(&master.vel.stats->statslock); #endif if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Stats\r\n" "total_connections_received:%lld\r\n" "total_commands_processed:%lld\r\n" "total_net_input_bytes:%lld\r\n" "total_net_output_bytes:%lld\r\n" "rejected_connections:%lld\r\n" "expired_keys:%lld\r\n" "keyspace_hits:%lld\r\n" "keyspace_misses:%lld\r\n", stat_numconnections, stat_numcommands, stat_net_input_bytes, stat_net_output_bytes, stat_rejected_conn, stat_expiredkeys, stat_keyspace_hits, stat_keyspace_misses); } /* CPU */ if (allsections || defsections || !strcasecmp(section,"cpu")) { if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# CPU\r\n" "used_cpu_sys:%.2f\r\n" "used_cpu_user:%.2f\r\n", (float)self_ru.ru_stime.tv_sec+(float)self_ru.ru_stime.tv_usec/1000000, (float)self_ru.ru_utime.tv_sec+(float)self_ru.ru_utime.tv_usec/1000000); } /* Internal */ if (allsections || !strcasecmp(section,"internal")) { redisDb *db; long long keys, vkeys, avg_ttl; if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Internal\r\n"); for (j = 0; j < server.dbnum; j++) { db = array_get(&server.dbs, j); pthread_rwlock_rdlock(&db->rwl); keys = dictSize(db->dict); vkeys = dictSize(db->expires); avg_ttl = db->avg_ttl; pthread_rwlock_unlock(&db->rwl); if (keys || vkeys) { info = sdscatprintf(info, "db%d:keys=%lld,expires=%lld,avg_ttl=%lld\r\n", j, keys, vkeys, db->avg_ttl); } keys_all += keys; vkeys_all += vkeys; avg_ttl_all += avg_ttl; if (avg_ttl > 0) nexit ++; } } /* Key space */ if (allsections || defsections || !strcasecmp(section,"keyspace")) { redisDb *db; if (sections++) info = sdscat(info,"\r\n"); info = sdscatprintf(info, "# Keyspace\r\n"); if (keys_all == 0) { for (j = 0; j < server.dbnum; j++) { db = array_get(&server.dbs, j); pthread_rwlock_rdlock(&db->rwl); keys_all += dictSize(db->dict); vkeys_all += dictSize(db->expires); avg_ttl_all += db->avg_ttl; if (db->avg_ttl > 0) nexit ++; pthread_rwlock_unlock(&db->rwl); } } if (keys_all || vkeys_all) { info = sdscatprintf(info, "keys=%lld,expires=%lld,avg_ttl=%lld\r\n", keys_all, vkeys_all, nexit > 0 ? (avg_ttl_all/nexit) : 0); } } return info; }