Beispiel #1
0
int slowlog_parse_option(char *options)
{
    char *pos, *begin, *end;
    int value;

    if (options == NULL)
        return NC_ERROR;

    begin = options;
    end = options + strlen(options);

    pos = strstr(begin, ",");
    if (pos == NULL)
        return NC_ERROR;
    if (pos == begin) {
        slowlog_log_slower_than = SLOWLOG_LOG_SLOWER_THAN;
    } else {
        value = nc_atoi(begin,pos-begin);
        if (value < 0)
            return NC_ERROR;
        slowlog_log_slower_than = (long long)value;
    }

    begin = pos+1;
    if (begin > end)
        return NC_ERROR;
    pos = strstr(begin, ",");
    if (pos == NULL)
        return NC_ERROR;
    if (pos == begin) {
        statistics_period = SLOWLOG_STATISTICS_PERIOD;
    } else {
        value = nc_atoi(begin,pos-begin);
        if (value < 0)
            return NC_ERROR;
        if (value != 12 && value != 24 && 
            value != 48 && value != 96) {
            return NC_ERROR;
        }
        statistics_period = value;
    }

    begin = pos+1;
    if (begin > end) {
        statistics_days = SLOWLOG_STATISTICS_DAYS;
        return NC_OK;
    }
    value = nc_atoi(begin,end-begin);
    if (value < 0)
        return NC_ERROR;
    statistics_days = value;

    return NC_OK;    
}
Beispiel #2
0
char *
conf_set_num(struct conf *cf, struct command *cmd, void *conf)
{
    uint8_t *p;
    int num, *np;
    struct string *value;

    p = conf;
    np = (int *)(p + cmd->offset);

    if (*np != CONF_UNSET_NUM) {
        return "is a duplicate";
    }

    value = array_top(&cf->arg);

    num = nc_atoi(value->data, value->len);
    if (num < 0) {
        return "is not a number";
    }

    *np = num;

    return CONF_OK;
}
Beispiel #3
0
char *
conf_add_server(struct conf *cf, struct command *cmd, void *conf)
{
    rstatus_t status;
    struct array *a;
    struct string *value;
    struct conf_server *field;
    uint8_t *p, *q, *start;
    uint8_t *name, *port, *weight;
    uint32_t k, namelen, portlen, weightlen;

    p = conf;
    a = (struct array *)(p + cmd->offset);

    field = array_push(a);
    if (field == NULL) {
        return CONF_ERROR;
    }

    conf_server_init(field);

    value = array_top(&cf->arg);

    status = string_duplicate(&field->pname, value);
    if (status != NC_OK) {
        array_pop(a);
        return CONF_ERROR;
    }

    /* parse "hostname:port:weight" from the end */
    p = value->data + value->len - 1;
    start = value->data;
    name = NULL;
    namelen = 0;
    weight = NULL;
    weightlen = 0;
    port = NULL;
    portlen = 0;

    for (k = 0; k < 2; k++) {
        q = nc_strrchr(p, start, ':');
        if (q == NULL) {
            break;
        }

        switch (k) {
        case 0:
            weight = q + 1;
            weightlen = (uint32_t)(p - weight + 1);
            break;

        case 1:
            port = q + 1;
            portlen = (uint32_t)(p - port + 1);
            break;

        default:
            NOT_REACHED();
        }

        p = q - 1;
    }

    if (k != 2) {
        return "has an invalid \"hostname:port:weight\" format string";
    }

    name = start;
    namelen = (uint32_t)(p - start + 1);

    field->weight = nc_atoi(weight, weightlen);
    if (field->weight < 0) {
        return "has an invalid weight in \"hostname:port:weight\" format string";
    }

    field->port = nc_atoi(port, portlen);
    if (field->port < 0 || !nc_valid_port(field->port)) {
        return "has an invalid port in \"hostname:port:weight\" format string";
    }

    status = string_copy(&field->name, name, namelen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = nc_resolve(&field->name, field->port, &field->info);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    field->valid = 1;

    return CONF_OK;
}
Beispiel #4
0
char *
conf_set_listen(struct conf *cf, struct command *cmd, void *conf)
{
    rstatus_t status;
    struct string *value;
    struct conf_listen *field;
    uint8_t *p, *name;
    uint32_t namelen;

    p = conf;
    field = (struct conf_listen *)(p + cmd->offset);

    if (field->valid == 1) {
        return "is a duplicate";
    }

    value = array_top(&cf->arg);

    status = string_duplicate(&field->pname, value);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    if (value->data[0] == '/') {
        name = value->data;
        namelen = value->len;
    } else {
        uint8_t *q, *start, *port;
        uint32_t portlen;

        /* parse "hostname:port" from the end */
        p = value->data + value->len - 1;
        start = value->data;
        q = nc_strrchr(p, start, ':');
        if (q == NULL) {
            return "has an invalid \"hostname:port\" format string";
        }

        port = q + 1;
        portlen = (uint32_t)(p - port + 1);

        p = q - 1;

        name = start;
        namelen = (uint32_t)(p - start + 1);

        field->port = nc_atoi(port, portlen);
        if (field->port < 0 || !nc_valid_port(field->port)) {
            return "has an invalid port in \"hostname:port\" format string";
        }
    }

    status = string_copy(&field->name, name, namelen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = nc_resolve(&field->name, field->port, &field->info);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    field->valid = 1;

    return CONF_OK;
}
Beispiel #5
0
static rstatus_t
nc_get_options(int argc, char **argv, struct instance *nci)
{
    int c, value;

    opterr = 0;

    for (;;) {
        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            /* no more options */
            break;
        }

        switch (c) {
        case 'h':
            show_version = 1;
            show_help = 1;
            break;

        case 'V':
            show_version = 1;
            break;

        case 't':
            test_conf = 1;
            break;

        case 'd':
            daemonize = 1;
            break;

        case 'D':
            describe_stats = 1;
            show_version = 1;
            break;

        case 'v':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -v requires a number");
                return NC_ERROR;
            }
            nci->log_level = value;
            break;

        case 'o':
            nci->log_filename = optarg;
            break;

        case 'c':
            nci->conf_filename = optarg;
            break;

        case 's':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -s requires a number");
                return NC_ERROR;
            }
            if (!nc_valid_port(value)) {
                log_stderr("nutcracker: option -s value %d is not a valid "
                           "port", value);
                return NC_ERROR;
            }

            nci->stats_port = (uint16_t)value;
            break;

        case 'i':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -i requires a number");
                return NC_ERROR;
            }

            nci->stats_interval = value;
            break;

        case 'a':
            nci->stats_addr = optarg;
            break;

        case 'p':
            nci->pid_filename = optarg;
            break;

        case 'm':
            value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -m requires a non-zero number");
                return NC_ERROR;
            }

            if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) {
                log_stderr("nutcracker: mbuf chunk size must be between %zu and"
                           " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE);
                return NC_ERROR;
            }

            nci->mbuf_chunk_size = (size_t)value;
            break;

        case 'M':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -M requires a non-negative number");
                return NC_ERROR;
            }

            nci->mbuf_pool_size = (unsigned)value;
            break;

        case '?':
            switch (optopt) {
            case 'o':
            case 'c':
            case 'p':
                log_stderr("nutcracker: option -%c requires a file name",
                           optopt);
                break;

            case 'm':
            case 'M':
            case 'v':
            case 's':
            case 'i':
                log_stderr("nutcracker: option -%c requires a number", optopt);
                break;

            case 'a':
                log_stderr("nutcracker: option -%c requires a string", optopt);
                break;

            default:
                log_stderr("nutcracker: invalid option -- '%c'", optopt);
                break;
            }
            return NC_ERROR;

        default:
            log_stderr("nutcracker: invalid option -- '%c'", optopt);
            return NC_ERROR;

        }
    }

    return NC_OK;
}
Beispiel #6
0
static rstatus_t
sentinel_proc_pub(struct context *ctx, struct msg *msg)
{
    rstatus_t status;
    struct string pool_name, server_name, server_ip,
                  tmp_string, pub_titile, pub_event;
    struct mbuf *line_buf;
    int server_port;

    string_init(&tmp_string);
    string_init(&pool_name);
    string_init(&server_name);
    string_init(&server_ip);

    string_set_text(&pub_titile, "pmessage");
    string_set_text(&pub_event, "+switch-master");

    line_buf = mbuf_get();
    if (line_buf == NULL) {
        goto error;
    }

    /* get line in line num 3  for pub titile */
    msg_read_line(msg, line_buf, 3);
    if (mbuf_length(line_buf) == 0) {
        log_error("read line failed from sentinel pmessage when skip line not used.");
        goto error;
    }
    status = mbuf_read_string(line_buf, CR, &tmp_string);
    if (status != NC_OK || string_compare(&pub_titile, &tmp_string)) {
        log_error("pub title error(lineinfo %.*s)", tmp_string.len, tmp_string.data);
        goto error;
    }

    /* get line in line num 7  for pub event */
    msg_read_line(msg, line_buf, 4);
    if (mbuf_length(line_buf) == 0) {
        log_error("read line failed from sentinel pmessage when skip line not used.");
        goto error;
    }
    status = mbuf_read_string(line_buf, CR, &tmp_string);
    if (status != NC_OK || string_compare(&pub_event, &tmp_string)) {
        log_error("pub channel error(lineinfo %.*s)", tmp_string.len, tmp_string.data);
        goto error;
    }

    /* get line in line num 9 for pub info */
    msg_read_line(msg, line_buf, 2);
    if (mbuf_length(line_buf) == 0) {
        log_error("read line failed from sentinel pmessage when skip line not used.");
        goto error;
    }

    /* parse switch master info */
    /* get pool name */
    status = mbuf_read_string(line_buf, SENTINEL_SERVERNAME_SPLIT, &pool_name);
    if (status != NC_OK) {
        log_error("get pool name string failed.");
        goto error;
    }

    /* get server name */
    status = mbuf_read_string(line_buf, ' ', &server_name);
    if (status != NC_OK) {
        log_error("get server name string failed.");
        goto error;
    }

    /* skip old ip and port string */
    status = mbuf_read_string(line_buf, ' ', NULL);
    if (status != NC_OK) {
        log_error("skip old ip string failed.");
        goto error;
    }
    status = mbuf_read_string(line_buf, ' ', NULL);
    if (status != NC_OK) {
        log_error("skip old port string failed.");
        goto error;
    }

    /* get new server ip string */
    status = mbuf_read_string(line_buf, ' ', &server_ip);
    if (status != NC_OK) {
        log_error("get new server ip string failed.");
        goto error;
    }

    /* get new server port */
    status = mbuf_read_string(line_buf, CR, &tmp_string);
    if (status != NC_OK) {
        log_error("get new server port string failed.");
        goto error;
    }
    server_port = nc_atoi(tmp_string.data, tmp_string.len);
    if (server_port < 0) {
        log_error("tanslate server port string to int failed.");
        goto error;
    }

    status = server_switch(ctx, &pool_name, &server_name, &server_ip, server_port);
    if (status == NC_OK) {
        conf_rewrite(ctx);
    }

    status = NC_OK;

done:
    if (line_buf != NULL) {
        mbuf_put(line_buf);
    }
    string_deinit(&tmp_string);
    string_deinit(&server_ip);
    string_deinit(&server_name);
    string_deinit(&pool_name);
    return status;

error:
    status = NC_ERROR;
    goto done;
}
Beispiel #7
0
rstatus_t
slowlog_command_make_reply(struct context *ctx, 
	struct conn *conn, struct msg *msg, struct msg *pmsg)
{
	rstatus_t status;
	uint32_t nkeys;
	struct keypos *kp;
	char *contents;
    uint32_t subcmdlen;
	
	ASSERT(conn->client && !conn->proxy);
    ASSERT(msg->request);
	ASSERT(pmsg != NULL && !pmsg->request);
    ASSERT(msg->owner == conn);
	ASSERT(conn->owner == ctx->manager);

	nkeys = array_n(msg->keys);
	ASSERT(nkeys >= 1);

	kp = array_get(msg->keys, 0);
    subcmdlen = (uint32_t)(kp->end-kp->start);
    if (subcmdlen==strlen("reset")&&!memcmp(kp->start,"reset",subcmdlen)){
        if (nkeys != 1) {
            goto format_error;
        }
        
        slowlog_reset();
        status = msg_append_full(pmsg, (uint8_t*)"OK", 2);
        if (status != NC_OK) {
    		conn->err = ENOMEM;
            return status;
        }
        
        goto done;
    } else if (subcmdlen==strlen("id")&&!memcmp(kp->start,"id",subcmdlen)){
        int buf_len;
        uint8_t buf[30];
        long long id;

        if (nkeys != 1) {
            goto format_error;
        }

        pthread_rwlock_rdlock(&rwlocker);
        id = slowlog_entry_id;
        pthread_rwlock_unlock(&rwlocker);
        
        buf_len = nc_scnprintf(buf,30,"%lld",id);
        status = msg_append_full(pmsg, buf, (size_t)buf_len);
        if (status != NC_OK) {
    		conn->err = ENOMEM;
            return status;
        }
        goto done;
    } else if (subcmdlen==strlen("len")&&!memcmp(kp->start,"len",subcmdlen)){
        int len, buf_len;
        uint8_t buf[20];

        if (nkeys != 1) {
            goto format_error;
        }

        pthread_rwlock_rdlock(&rwlocker);
        len = slowlog_len;
        pthread_rwlock_unlock(&rwlocker);
        
        buf_len = nc_scnprintf(buf,20,"%d",len);
        status = msg_append_full(pmsg, buf, (size_t)buf_len);
        if (status != NC_OK) {
    		conn->err = ENOMEM;
            return status;
        }
        goto done;
    } else if (subcmdlen==strlen("get")&&!memcmp(kp->start,"get",subcmdlen)){
        int count, sent = 0, buf_len;
        uint8_t buf[50];
        slowlog_entry *se;
        struct string *str;
        
        if (nkeys == 1) {
            count = 10;
        } else if (nkeys == 2) {
            kp = array_get(msg->keys, 1);
            count = nc_atoi(kp->start, (kp->end-kp->start));
            if (count < 0) {
                goto format_error;
            }
        } else {
            goto format_error;
        }

        pthread_rwlock_rdlock(&rwlocker);
        se = STAILQ_FIRST(&slowlog);
        while(count-- && se != NULL) {
            int nfield;
            uint32_t j;            

            sent++;
            buf_len = nc_scnprintf(buf,50,"%d) 1) %lld\r\n",sent, se->id);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_rwlock_unlock(&rwlocker);
        		conn->err = ENOMEM;
                return status;
            }
            buf_len = nc_scnprintf(buf,50,"    2) %lld\r\n",se->time);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_rwlock_unlock(&rwlocker);
        		conn->err = ENOMEM;
                return status;
            }
            buf_len = nc_scnprintf(buf,50,"    3) %lld\r\n",se->duration);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_rwlock_unlock(&rwlocker);
        		conn->err = ENOMEM;
                return status;
            }
            str = msg_type_string(se->cmdtype);
            nfield = 1;
            buf_len = nc_scnprintf(buf,50,"    4) %d) %s\r\n",nfield++,str->data);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_rwlock_unlock(&rwlocker);
        		conn->err = ENOMEM;
                return status;
            }
            buf_len = nc_scnprintf(buf,50,"       %d) %d\r\n",nfield++,se->keys_count);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_rwlock_unlock(&rwlocker);
        		conn->err = ENOMEM;
                return status;
            }
            if (se->keys != NULL) {
                for (j = 0; j < array_n(se->keys); j ++) {
                    str = array_get(se->keys, j);
                    
                    buf_len = nc_scnprintf(buf,50,"       %d) ",nfield++);
                    status = msg_append_full(pmsg, buf, (size_t)buf_len);
                    if (status != NC_OK) {
                        pthread_rwlock_unlock(&rwlocker);
                		conn->err = ENOMEM;
                        return status;
                    }
                    status = msg_append_full(pmsg, str->data, (size_t)str->len);
                    if (status != NC_OK) {
                        pthread_rwlock_unlock(&rwlocker);
                		conn->err = ENOMEM;
                        return status;
                    }
                    status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN);
                    if (status != NC_OK) {
                        pthread_rwlock_unlock(&rwlocker);
                		conn->err = ENOMEM;
                        return status;
                    }
                }
            }
            se = STAILQ_NEXT(se, next);
        }
        pthread_rwlock_unlock(&rwlocker);
        
        if (msg_empty(pmsg)) {
            status = msg_append_full(pmsg, (uint8_t*)"END", 3);
            if (status != NC_OK) {
        		conn->err = ENOMEM;
                return status;
            }
            goto done;
        }
        return NC_OK;
    } else if (subcmdlen==strlen("overview") &&
        !memcmp(kp->start,"overview",subcmdlen)) {
        int count, buf_len;
        uint8_t buf[50];
        int j, idx, id;
        struct statistics_oneday *so;
        
        if (nkeys == 1) {
            count = 10;
        } else if (nkeys == 2) {
            kp = array_get(msg->keys, 1);
            count = nc_atoi(kp->start, (kp->end-kp->start));
            if (count < 0) {
                goto format_error;
            }
        } else {
            goto format_error;
        }

        if (slowlog_statistics == NULL) {
            status = msg_append_full(pmsg, (uint8_t*)"END", 3);
            if (status != NC_OK) {
        		conn->err = ENOMEM;
                return status;
            }
            goto done;
        }

        if (count > statistics_days)
            count = statistics_days;
        pthread_mutex_lock(&statistics_locker);
        idx = today_idx;
        id = 1;
        while (count--) {
            so = &slowlog_statistics[idx];

            if (so->year == 0)
                break;

            buf_len = nc_scnprintf(buf,50,"%d) %d-%d-%d ",id++,so->year+1900,so->mon+1,so->day);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_mutex_unlock(&statistics_locker);
        		conn->err = ENOMEM;
                return status;
            }

            for (j = 0; j < statistics_period-1; j ++) {
                buf_len = nc_scnprintf(buf,50,"%lld ",so->periods[j]);
                status = msg_append_full(pmsg, buf, (size_t)buf_len);
                if (status != NC_OK) {
                    pthread_mutex_unlock(&statistics_locker);
            		conn->err = ENOMEM;
                    return status;
                }
            }
            buf_len = nc_scnprintf(buf,50,"%lld\r\n",so->periods[statistics_period-1]);
            status = msg_append_full(pmsg, buf, (size_t)buf_len);
            if (status != NC_OK) {
                pthread_mutex_unlock(&statistics_locker);
        		conn->err = ENOMEM;
                return status;
            }
            
            if (--idx < 0) {
                idx = statistics_days - 1;
            }
        }
        pthread_mutex_unlock(&statistics_locker);

        if (msg_empty(pmsg)) {
            status = msg_append_full(pmsg, (uint8_t*)"END", 3);
            if (status != NC_OK) {
        		conn->err = ENOMEM;
                return status;
            }
            goto done;
        }
        return NC_OK;
    } else {
        goto format_error;
    }

format_error:
    contents = "ERR: slowlog command format is error.";
    status = msg_append_full(pmsg, (uint8_t *)contents, strlen(contents));
    if (status != NC_OK) {
		conn->err = ENOMEM;
        return status;
    }
    
    goto done;
done:
    status = msg_append_full(pmsg, (uint8_t *)CRLF, CRLF_LEN);
    if (status != NC_OK) {
		conn->err = ENOMEM;
        return status;
    }
	return NC_OK;
}
Beispiel #8
0
static rstatus_t
sentinel_proc_sentinel_info(struct context *ctx, struct msg *msg)
{
    rstatus_t status;
    int i, master_num, switch_num;
    struct string pool_name, server_name, server_ip,
                  tmp_string, sentinel_masters_prefix, master_ok;
    struct mbuf *line_buf;
    int server_port;

    string_init(&tmp_string);
    string_init(&pool_name);
    string_init(&server_name);
    string_init(&server_ip);
    string_set_text(&sentinel_masters_prefix, "sentinel_masters");
    string_set_text(&master_ok, "status=ok");

    line_buf = mbuf_get();
    if (line_buf == NULL) {
        goto error;
    }

    /* get sentinel master num at line 3 */
    msg_read_line(msg, line_buf, 3);
    if (mbuf_length(line_buf) == 0) {
        log_error("read line failed from sentinel ack info when skip line not used.");
        goto error;
    }
    status = mbuf_read_string(line_buf, ':', &tmp_string);
    if (status != NC_OK || string_compare(&sentinel_masters_prefix, &tmp_string)) {
        goto error;
    }
    status = mbuf_read_string(line_buf, CR, &tmp_string);
    if (status != NC_OK) {
        goto error;
    }
    master_num = nc_atoi(tmp_string.data, tmp_string.len);
    if (master_num < 0) {
        log_error("parse master number from sentinel ack info failed.");
        goto error;
    }

    /* skip 3 line in ack info which is not used. */
    msg_read_line(msg, line_buf, 3);
    if (mbuf_length(line_buf) == 0) {
        log_error("read line failed from sentinel ack info when skip line not used.");
        goto error;
    }

    /* parse master info from sentinel ack info */
    switch_num = 0;
    for (i = 0; i < master_num; i++) {
        msg_read_line(msg, line_buf, 1);
        if (mbuf_length(line_buf) == 0) {
            log_error("read line failed from sentinel ack info when parse master item.");
            goto error;
        }
        log_debug(LOG_INFO, "master item line : %.*s", mbuf_length(line_buf), line_buf->pos);

        /* skip master item prefix */
        status = mbuf_read_string(line_buf, ':', NULL);
        if (status != NC_OK) {
            log_error("skip master item prefix failed");
            goto error;
        }

        /* skip master item server name prefix */
        status = mbuf_read_string(line_buf, '=', NULL);
        if (status != NC_OK) {
            log_error("skip master item server name prefix failed.");
            goto error;
        }

        /* get server pool name */
        status = mbuf_read_string(line_buf, SENTINEL_SERVERNAME_SPLIT, &pool_name);
        if (status != NC_OK) {
            log_error("get server pool name failed.");
            goto error;
        }

        /* get server name */
        status = mbuf_read_string(line_buf, ',', &server_name);
        if (status != NC_OK) {
            log_error("get server name failed.");
            goto error;
        }

        /* get master status */
        status = mbuf_read_string(line_buf, ',', &tmp_string);
        if (status != NC_OK) {
            log_error("get master status failed.");
            goto error;
        }
        if (string_compare(&master_ok, &tmp_string)) { 
            log_error("master item status is not ok, use it anyway");
        }

        /* skip ip string prefix name */
        status = mbuf_read_string(line_buf, '=', NULL);
        if (status != NC_OK) {
            log_error("skip master item address prefix failed.");
            goto error;
        }

        /* get server ip string */
        status = mbuf_read_string(line_buf, ':', &server_ip);
        if (status != NC_OK) {
            log_error("get server ip string failed.");
            goto error;
        }

        /* get server port */
        status = mbuf_read_string(line_buf, ',', &tmp_string);
        if (status != NC_OK) {
            log_error("get server port string failed.");
            goto error;
        }
        server_port = nc_atoi(tmp_string.data, tmp_string.len);
        if (server_port < 0) {
            log_error("tanslate server port string to int failed.");
            goto error;
        }

        status = server_switch(ctx, &pool_name, &server_name, &server_ip, server_port);
        /* if server is switched, add switch number */
        if (status == NC_OK) {
            switch_num++;
        }
    }

    if (switch_num > 0) {
        conf_rewrite(ctx);
    }

    status = NC_OK;

done:
    if (line_buf != NULL) {
        mbuf_put(line_buf);
    }
    string_deinit(&tmp_string);
    string_deinit(&pool_name);
    string_deinit(&server_name);
    string_deinit(&server_ip);
    return status;

error:
    status = NC_ERROR;
    goto done;
}
Beispiel #9
0
char *
conf_add_server(struct conf *cf, struct command *cmd, void *conf)
{
    rstatus_t status;
    struct array *a;
    struct string *value;
    struct conf_server *field;
    uint8_t *p, *q, *start;
    uint8_t *pname, *addr, *port, *weight, *name;
    uint32_t k, delimlen, pnamelen, addrlen, portlen, weightlen, namelen;
    char delim[] = " ::";

    p = conf;
    a = (struct array *)(p + cmd->offset);

    field = array_push(a);
    if (field == NULL) {
        return CONF_ERROR;
    }

    conf_server_init(field);

    value = array_top(&cf->arg);

    /* parse "hostname:port:weight [name]" or "/path/unix_socket:weight [name]" from the end */
    p = value->data + value->len - 1;
    start = value->data;
    addr = NULL;
    addrlen = 0;
    weight = NULL;
    weightlen = 0;
    port = NULL;
    portlen = 0;
    name = NULL;
    namelen = 0;

    delimlen = value->data[0] == '/' ? 2 : 3;

    for (k = 0; k < sizeof(delim); k++) {
        q = nc_strrchr(p, start, delim[k]);
        if (q == NULL) {
            if (k == 0) {
                /*
                 * name in "hostname:port:weight [name]" format string is
                 * optional
                 */
                continue;
            }
            break;
        }

        switch (k) {
        case 0:
            name = q + 1;
            namelen = (uint32_t)(p - name + 1);
            break;

        case 1:
            weight = q + 1;
            weightlen = (uint32_t)(p - weight + 1);
            break;

        case 2:
            port = q + 1;
            portlen = (uint32_t)(p - port + 1);
            break;

        default:
            NOT_REACHED();
        }

        p = q - 1;
    }

    if (k != delimlen) {
        return "has an invalid \"hostname:port:weight [name]\"or \"/path/unix_socket:weight [name]\" format string";
    }

    pname = value->data;
    pnamelen = namelen > 0 ? value->len - (namelen + 1) : value->len;
    status = string_copy(&field->pname, pname, pnamelen);
    if (status != NC_OK) {
        array_pop(a);
        return CONF_ERROR;
    }

    addr = start;
    addrlen = (uint32_t)(p - start + 1);

    field->weight = nc_atoi(weight, weightlen);
    if (field->weight < 0) {
        return "has an invalid weight in \"hostname:port:weight [name]\" format string";
    } else if (field->weight == 0) {
        return "has a zero weight in \"hostname:port:weight [name]\" format string";
    }

    if (value->data[0] != '/') {
        field->port = nc_atoi(port, portlen);
        if (field->port < 0 || !nc_valid_port(field->port)) {
            return "has an invalid port in \"hostname:port:weight [name]\" format string";
        }
    }

    if (name == NULL) {
        /*
         * To maintain backward compatibility with libmemcached, we don't
         * include the port as the part of the input string to the consistent
         * hashing algorithm, when it is equal to 11211.
         */
        if (field->port == CONF_DEFAULT_KETAMA_PORT) {
            name = addr;
            namelen = addrlen;
        } else {
            name = addr;
            namelen = addrlen + 1 + portlen;
        }
    }

    status = string_copy(&field->name, name, namelen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = string_copy(&field->addrstr, (uint8_t *)addr, addrlen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    /*
     * The address resolution of the backend server hostname is lazy.
     * The resolution occurs when a new connection to the server is
     * created, which could either be the first time or every time
     * the server gets re-added to the pool after an auto ejection
     */

    field->valid = 1;

    return CONF_OK;
}
Beispiel #10
0
char *
conf_set_listen(struct conf *cf, struct command *cmd, void *conf)
{
    rstatus_t status;
    struct string *value;
    struct conf_listen *field;
    uint8_t *p, *name;
    uint32_t namelen;

    p = conf;
    field = (struct conf_listen *)(p + cmd->offset);

    if (field->valid == 1) {
        return "is a duplicate";
    }

    value = array_top(&cf->arg);

    status = string_duplicate(&field->pname, value);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    if (value->data[0] == '/') {
        uint8_t *q, *start, *perm;
        uint32_t permlen;


        /* parse "socket_path permissions" from the end */
        p = value->data + value->len -1;
        start = value->data;
        q = nc_strrchr(p, start, ' ');
        if (q == NULL) {
            /* no permissions field, so use defaults */
            name = value->data;
            namelen = value->len;
        } else {
            perm = q + 1;
            permlen = (uint32_t)(p - perm + 1);

            p = q - 1;
            name = start;
            namelen = (uint32_t)(p - start + 1);

            errno = 0;
            field->perm = (mode_t)strtol((char *)perm, NULL, 8);
            if (errno || field->perm > 0777) {
                return "has an invalid file permission in \"socket_path permission\" format string";
            }
        }
    } else {
        uint8_t *q, *start, *port;
        uint32_t portlen;

        /* parse "hostname:port" from the end */
        p = value->data + value->len - 1;
        start = value->data;
        q = nc_strrchr(p, start, ':');
        if (q == NULL) {
            return "has an invalid \"hostname:port\" format string";
        }

        port = q + 1;
        portlen = (uint32_t)(p - port + 1);

        p = q - 1;

        name = start;
        namelen = (uint32_t)(p - start + 1);

        field->port = nc_atoi(port, portlen);
        if (field->port < 0 || !nc_valid_port(field->port)) {
            return "has an invalid port in \"hostname:port\" format string";
        }
    }

    status = string_copy(&field->name, name, namelen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = nc_resolve(&field->name, field->port, &field->info);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    field->valid = 1;

    return CONF_OK;
}
Beispiel #11
0
char *
conf_add_server(struct conf *cf, struct command *cmd, void *conf)
{
    rstatus_t status;
    struct array *a;
    struct string *value;
    struct conf_server *field;
    uint8_t *p, *q, *start;
    uint8_t *pname, *addr, *port, *weight, *name;
    uint32_t k, pnamelen, addrlen, portlen, weightlen, namelen;
    struct string address;
    char delim[] = " ::";

    string_init(&address);
    p = conf;
    a = (struct array *)(p + cmd->offset);

    field = array_push(a);
    if (field == NULL) {
        return CONF_ERROR;
    }

    conf_server_init(field);

    value = array_top(&cf->arg);

    /* parse "hostname:port:weight [name]" from the end */
    p = value->data + value->len - 1;
    start = value->data;
    addr = NULL;
    addrlen = 0;
    weight = NULL;
    weightlen = 0;
    port = NULL;
    portlen = 0;
    name = NULL;
    namelen = 0;

    for (k = 0; k < sizeof(delim); k++) {
        q = nc_strrchr(p, start, delim[k]);
        if (q == NULL) {
            if (k == 0) {
                /*
                 * name in "hostname:port:weight [name]" format string is
                 * optional
                 */
                continue;
            }
            break;
        }

        switch (k) {
        case 0:
            name = q + 1;
            namelen = (uint32_t)(p - name + 1);
            break;

        case 1:
            weight = q + 1;
            weightlen = (uint32_t)(p - weight + 1);
            break;

        case 2:
            port = q + 1;
            portlen = (uint32_t)(p - port + 1);
            break;

        default:
            NOT_REACHED();
        }

        p = q - 1;
    }

    if (k != 3) {
        return "has an invalid \"hostname:port:weight [name]\" format string";
    }

    pname = value->data;
    pnamelen = namelen > 0 ? value->len - (namelen + 1) : value->len;
    status = string_copy(&field->pname, pname, pnamelen);
    if (status != NC_OK) {
        array_pop(a);
        return CONF_ERROR;
    }

    addr = start;
    addrlen = (uint32_t)(p - start + 1);

    field->weight = nc_atoi(weight, weightlen);
    if (field->weight < 0) {
        return "has an invalid weight in \"hostname:port:weight [name]\" format string";
    }

    field->port = nc_atoi(port, portlen);
    if (field->port < 0 || !nc_valid_port(field->port)) {
        return "has an invalid port in \"hostname:port:weight [name]\" format string";
    }

    if (name == NULL) {
        /*
         * To maintain backward compatibility with libmemcached, we don't
         * include the port as the part of the input string to the consistent
         * hashing algorithm, when it is equal to 11211.
         */
        if (field->port == CONF_DEFAULT_KETAMA_PORT) {
            name = addr;
            namelen = addrlen;
        } else {
            name = addr;
            namelen = addrlen + 1 + portlen;
        }
    }

    status = string_copy(&field->name, name, namelen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = string_copy(&address, addr, addrlen);
    if (status != NC_OK) {
        return CONF_ERROR;
    }

    status = nc_resolve(&address, field->port, &field->info);
    if (status != NC_OK) {
        string_deinit(&address);
        return CONF_ERROR;
    }

    string_deinit(&address);
    field->valid = 1;

    return CONF_OK;
}
Beispiel #12
0
static rstatus_t
nc_get_options(int argc, char **argv, struct env_master *env)
{
    int c, value;
	int len;
	int cores;

    opterr = 0;
	//ASSERT(0);
	
    for (;;) {
        c = getopt_long(argc, argv, short_options, long_options, NULL);
        if (c == -1) {
            /* no more options */
            break;
        }

        switch (c) {
        case 'h':
            show_version = 1;
            show_help = 1;
            break;

        case 'V':
            show_version = 1;
            break;

        case 't':
            test_conf = 1;
            break;

        case 'd':
            daemonize = 1;
            break;

        case 'D':
            describe_stats = 1;
            show_version = 1;
            break;

        case 'v':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -v requires a number");
                return NC_ERROR;
            }
            env->log_level = value;
            break;

        case 'o':
            env->log_filename = optarg;
			len = nc_strlen(optarg) + 1;
        	log_filename_global = malloc(len);
	        if (log_filename_global == NULL) {
	            return NC_ERROR;
	        }
            nc_cpystrn((u_char *) log_filename_global, (u_char *) optarg, len);
            break;

        case 'c':
            env->conf_filename = optarg;
			len = nc_strlen(optarg) + 1;
        	conf_filename_global = malloc(len);
	        if (conf_filename_global == NULL) {
	            return NC_ERROR;
	        }
            nc_cpystrn((u_char *) conf_filename_global, (u_char *) optarg, len);
			break;

        case 's':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -s requires a number");
                return NC_ERROR;
            }
            if (!nc_valid_port(value)) {
                log_stderr("nutcracker: option -s value %d is not a valid "
                           "port", value);
                return NC_ERROR;
            }

            env->stats_port = (uint16_t)value;
            break;

        case 'i':
            value = nc_atoi(optarg, strlen(optarg));
            if (value < 0) {
                log_stderr("nutcracker: option -i requires a number");
                return NC_ERROR;
            }

            env->stats_interval = value;
            break;

        case 'a':
            env->stats_addr = optarg;
            break;

        case 'p':
            env->pid_filename = optarg;
            break;

        case 'm':
            value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -m requires a non-zero number");
                return NC_ERROR;
            }

            if (value < NC_MBUF_MIN_SIZE || value > NC_MBUF_MAX_SIZE) {
                log_stderr("nutcracker: mbuf chunk size must be between %zu and" \
                           " %zu bytes", NC_MBUF_MIN_SIZE, NC_MBUF_MAX_SIZE);
                return NC_ERROR;
            }

            env->mbuf_chunk_size = (size_t)value;
            break;

		case 'n':
			value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -n requires a non-zero number");
                return NC_ERROR;
            }
			
			cores = sysconf(_SC_NPROCESSORS_ONLN);
			
            if (value > cores || value < 1) {
                log_stderr("bilitw: bilitw worker process number should be between %d and" \
                           " %d", 1, cores);
                return NC_ERROR;
            }
            env->worker_processes= value;			
			break;
		case 'M':
			value = nc_atoi(optarg, strlen(optarg));
            if (value <= 0) {
                log_stderr("nutcracker: option -M requires a non-zero number");
                return NC_ERROR;
            }
			cores = sysconf(_SC_NPROCESSORS_ONLN);
			cores = (1<<cores) -1;

            if (value > cores || value < 1) {
                log_stderr("bilitw: bilitw worker process cpu mask should be set between %d and" \
                           " %d", 1, cores);
                return NC_ERROR;
            } 
			env->cpu_mask = value;
			break;

        case '?':
            switch (optopt) {
            case 'o':
            case 'c':
            case 'p':
                log_stderr("nutcracker: option -%c requires a file name",
                           optopt);
                break;

            case 'm':
            case 'v':
            case 's':
            case 'i':
			case 'n':
			case 'M':
                log_stderr("nutcracker: option -%c requires a number", optopt);
                break;

            case 'a':
                log_stderr("nutcracker: option -%c requires a string", optopt);
                break;

            default:
                log_stderr("nutcracker: invalid option -- '%c'", optopt);
                break;
            }
            return NC_ERROR;

        default:
            log_stderr("nutcracker: invalid option -- '%c'", optopt);
            return NC_ERROR;

        }
    }

    return NC_OK;
}