예제 #1
0
파일: vr_listen.c 프로젝트: qianyunlai/vire
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;
}
예제 #2
0
파일: vr_command.c 프로젝트: yanww-hz/vire
/* 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);
}
예제 #3
0
파일: vr_server.c 프로젝트: qianyunlai/vire
/* 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;
}