Beispiel #1
0
static void
asc_process_aggregate(struct conn *c, struct token *token, int ntoken)
{
    int32_t interval;

    if (ntoken != 4) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_AGGR_COMMAND].val, &interval)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid option '%.*s'", c->sd, c->req_type,
                  token[TOKEN_AGGR_COMMAND].len, token[TOKEN_AGGR_COMMAND].val);

        asc_write_client_error(c);
        return;
    }

    if (interval > 0) {
        stats_set_interval(interval);
        asc_write_ok(c);
    } else if (interval == 0) {
        stats_set_interval(STATS_DEFAULT_INTVL);
        asc_write_ok(c);
    } else {
        stats_set_interval(-1000000);
        asc_write_ok(c);
    }
}
Beispiel #2
0
static void
asc_process_evict(struct conn *c, struct token *token, int ntoken)
{
    int32_t option;

    if (ntoken != 4) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_EVICT_COMMAND].val, &option)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid option '%.*s'", c->sd, c->req_type,
                  token[TOKEN_EVICT_COMMAND].len,token[TOKEN_EVICT_COMMAND].val);

        asc_write_client_error(c);
        return;
    }

    if (option >= EVICT_NONE && option < EVICT_INVALID) {
        settings.evict_opt = option;
        asc_write_ok(c);
        return;
    }

    log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
              "invalid option %"PRId32"", c->sd, c->req_type, option);

    asc_write_client_error(c);
}
Beispiel #3
0
static void
asc_process_verbosity(struct conn *c, struct token *token, int ntoken)
{
    uint32_t level;

    asc_set_noreply_maybe(c, token, ntoken);

    if (ntoken != 3 && ntoken != 4) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtoul(token[TOKEN_SUBCOMMAND].val, &level)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid level '%.*s'", c->sd, c->req_type,
                  token[TOKEN_SUBCOMMAND].len, token[TOKEN_SUBCOMMAND].val);

        asc_write_client_error(c);
        return;
    }

    log_level_set(level);

    asc_write_ok(c);
}
Beispiel #4
0
static void
asc_process_flushall(struct conn *c, struct token *token, int ntoken)
{
    struct bound *t = &ntoken_bound[REQ_FLUSHALL];
    int32_t exptime_int;
    time_t exptime;

    time_update();

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    if (ntoken == t->b[c->noreply].min) {
        settings.oldest_live = time_now() - 1;
        item_flush_expired();
        asc_write_ok(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_SUBCOMMAND].val, &exptime_int)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid numeric value '%.*s'", c->sd, c->req_type,
                  token[TOKEN_SUBCOMMAND].len, token[TOKEN_SUBCOMMAND].val);

        asc_write_client_error(c);
        return;
    }

    exptime = (time_t)exptime_int;

    /*
     * If exptime is zero time_reltime() would return zero too, and
     * time_reltime(exptime) - 1 would overflow to the max unsigned value.
     * So we process exptime == 0 the same way we do when no delay is
     * given at all.
     */
    if (exptime > 0) {
        settings.oldest_live = time_reltime(exptime) - 1;
    } else {
        /* exptime == 0 */
        settings.oldest_live = time_now() - 1;
    }

    item_flush_expired();
    asc_write_ok(c);
}
Beispiel #5
0
static void
asc_process_delete(struct conn *c, struct token *token, int ntoken)
{
    char *key;       /* key to be deleted */
    size_t nkey;     /* # key bytes */
    struct item *it; /* item for this key */

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    key = token[TOKEN_KEY].val;
    nkey = token[TOKEN_KEY].len;

    if (nkey > KEY_MAX_LEN) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d "
                  "length key", c->sd, c->req_type, nkey);

        asc_write_client_error(c);
        return;
    }

    /*
     * FIXME: This is not thread-safe, two threads could try to delete the same
     * item twice after succeeding in item_get, leading to erroneous stats
     */
    it = item_get(key, nkey);
    if (it != NULL) {
        stats_slab_incr(it->id, delete_hit);
        item_delete(it);
        asc_write_deleted(c);
    } else {
        stats_thread_incr(delete_miss);
        asc_write_not_found(c);
    }
}
Beispiel #6
0
static void
asc_process_delete(struct conn *c, struct token *token, int ntoken)
{
    char *key;       /* key to be deleted */
    size_t nkey;     /* # key bytes */
    struct item *it; /* item for this key */

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_INFO, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);
        asc_write_client_error(c);
        return;
    }

    key = token[TOKEN_KEY].val;
    nkey = token[TOKEN_KEY].len;

    if (nkey > KEY_MAX_LEN) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and %d "
                  "length key", c->sd, c->req_type, nkey);
        asc_write_client_error(c);
        return;
    }

    it = item_get(key, nkey);
    if (it != NULL) {
        stats_slab_incr(it->id, delete_hit);
        item_unlink(it);
        item_remove(it);
        asc_write_deleted(c);
    } else {
        stats_thread_incr(delete_miss);
        asc_write_not_found(c);
    }
}
Beispiel #7
0
/*
 * We get here after reading the value in update commands. The command
 * is stored in c->req_type, and the item is ready in c->item.
 */
void
asc_complete_nread(struct conn *c)
{
    item_store_result_t ret;
    struct item *it;
    char *end;

    it = c->item;
    end = item_data(it) + it->nbyte;

    if (!strcrlf(end)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with missing crlf", c->sd, c->req_type);

        asc_write_client_error(c);
    } else {
      ret = item_store(it, c->req_type, c);
      switch (ret) {
      case STORED:
          asc_write_stored(c);
          break;

      case EXISTS:
          asc_write_exists(c);
          break;

      case NOT_FOUND:
          asc_write_not_found(c);
          break;

      case NOT_STORED:
          asc_write_not_stored(c);
          break;

      default:
          log_warn("server error on c %d for req of type %d with unknown "
                   "store result %d", c->sd, c->req_type, ret);

          asc_write_server_error(c);
          break;
      }
    }

    item_remove(c->item);
    c->item = NULL;
}
Beispiel #8
0
static void
asc_process_stats(struct conn *c, struct token *token, int ntoken)
{
    struct token *t = &token[TOKEN_SUBCOMMAND];

    if (!stats_enabled()) {
        log_warn("server error on c %d for req of type %d because stats is "
                 "disabled", c->sd, c->req_type);

        asc_write_server_error(c);
        return;
    }

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);


        asc_write_client_error(c);
        return;
    }

    if (ntoken == 2) {
        stats_default(c);
    } else if (strncmp(t->val, "reset", t->len) == 0) {
        log_warn("server error on c %d for req of type %d because stats reset "
                 "is not supported", c->sd, c->req_type);
        asc_write_server_error(c);
        return;
    } else if (strncmp(t->val, "settings", t->len) == 0) {
        stats_settings(c);
    } else if (strncmp(t->val, "cachedump", t->len) == 0) {
        char *buf;
        unsigned int bytes, id, limit = 0;

        if (ntoken < 5) {
            log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d "
                        "for req of type %d with %d invalid tokens", c->sd,
                        c->req_type, ntoken);

            asc_write_client_error(c);
            return;
        }

        if (!mc_strtoul(token[TOKEN_CACHEDUMP_ID].val, &id) ||
            !mc_strtoul(token[TOKEN_CACHEDUMP_LIMIT].val, &limit)) {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                      "because either id '%.*s' or limit '%.*s' is invalid",
                      c->sd, c->req_type, token[TOKEN_CACHEDUMP_ID].len,
                      token[TOKEN_CACHEDUMP_ID].val, token[TOKEN_CACHEDUMP_LIMIT].len,
                      token[TOKEN_CACHEDUMP_LIMIT].val);

            asc_write_client_error(c);
            return;
        }

        if (id < SLABCLASS_MIN_ID || id > SLABCLASS_MAX_ID) {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                      "because %d is an illegal slab id", c->sd, c->req_type,
                      id);

            asc_write_client_error(c);
            return;
        }

        buf = item_cache_dump(id, limit, &bytes);
        core_write_and_free(c, buf, bytes);
        return;
    } else {
        /*
         * Getting here means that the sub command is either engine specific
         * or is invalid. query the engine and see
         */
        if (strncmp(t->val, "slabs", t->len) == 0) {
            stats_slabs(c);
        } else if (strncmp(t->val, "sizes", t->len) == 0) {
            stats_sizes(c);
        } else {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                      "invalid stats subcommand '%.*s", c->sd, c->req_type,
                      t->len, t->val);

            asc_write_client_error(c);
            return;
        }

        if (c->stats.buffer == NULL) {
            log_warn("server error on c %d for req of type %d because of oom "
                     "writing stats", c->sd, c->req_type);

            asc_write_server_error(c);
        } else {
            core_write_and_free(c, c->stats.buffer, c->stats.offset);
            c->stats.buffer = NULL;
        }

        return;
    }

    /* append terminator and start the transfer */
    stats_append(c, NULL, 0, NULL, 0);

    if (c->stats.buffer == NULL) {
        log_warn("server error on c %d for req of type %d because of oom "
                 "writing stats", c->sd, c->req_type);

        asc_write_server_error(c);
    } else {
        core_write_and_free(c, c->stats.buffer, c->stats.offset);
        c->stats.buffer = NULL;
    }
}
Beispiel #9
0
static void
asc_process_arithmetic(struct conn *c, struct token *token, int ntoken)
{
    item_delta_result_t res;
    char temp[INCR_MAX_STORAGE_LEN];
    uint64_t delta;
    char *key;
    size_t nkey;
    bool incr;

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    incr = (c->req_type == REQ_INCR) ? true : false;
    key = token[TOKEN_KEY].val;
    nkey = token[TOKEN_KEY].len;

    if (nkey > KEY_MAX_LEN) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d "
                  "length key", c->sd, c->req_type, nkey);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtoull(token[TOKEN_DELTA].val, &delta)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid delta '%.*s'", c->sd, c->req_type,
                  token[TOKEN_DELTA].len, token[TOKEN_DELTA].val);

        asc_write_client_error(c);
        return;
    }

    res = item_add_delta(c, key, nkey, incr, delta, temp);
    switch (res) {
    case DELTA_OK:
        asc_write_string(c, temp, strlen(temp));
        klog_write(c->peer, c->req_type, c->req, c->req_len, res, strlen(temp));
        break;

    case DELTA_NON_NUMERIC:
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "non-numeric value", c->sd, c->req_type);

        asc_write_client_error(c);
        break;

    case DELTA_EOM:
        log_warn("server error on c %d for req of type %d because of oom",
                 c->sd, c->req_type);

        asc_write_server_error(c);
        break;

    case DELTA_NOT_FOUND:
        if (incr) {
            stats_thread_incr(incr_miss);
        } else {
            stats_thread_incr(decr_miss);
        }
        asc_write_not_found(c);
        break;

    default:
        NOT_REACHED();
        break;
    }
}
Beispiel #10
0
static void
asc_process_update(struct conn *c, struct token *token, int ntoken)
{
    char *key;
    size_t nkey;
    uint32_t flags, vlen;
    int32_t exptime_int;
    time_t exptime;
    uint64_t req_cas_id = 0;
    struct item *it;
    bool handle_cas;
    req_type_t type;
    uint8_t id;

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    type = c->req_type;
    handle_cas = (type == REQ_CAS) ? true : false;
    key = token[TOKEN_KEY].val;
    nkey = token[TOKEN_KEY].len;

    if (nkey > KEY_MAX_LEN) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and %d "
                  "length key", c->sd, c->req_type, nkey);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtoul(token[TOKEN_FLAGS].val, &flags)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and "
                  "invalid flags '%.*s'", c->sd, c->req_type,
                  token[TOKEN_FLAGS].len, token[TOKEN_FLAGS].val);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_EXPIRY].val, &exptime_int)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and "
                  "invalid expiry '%.*s'", c->sd, c->req_type,
                  token[TOKEN_EXPIRY].len, token[TOKEN_EXPIRY].val);

        asc_write_client_error(c);
        return;
    }

    if (!mc_strtoul(token[TOKEN_VLEN].val, &vlen)) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and "
                  "invalid vlen '%.*s'", c->sd, c->req_type,
                  token[TOKEN_VLEN].len, token[TOKEN_VLEN].val);

        asc_write_client_error(c);
        return;
    }

    id = item_slabid(nkey, vlen);
    if (id == SLABCLASS_INVALID_ID) {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d and "
                  "slab id out of range for key size %"PRIu8" and value size "
                  "%"PRIu32, c->sd, c->req_type, nkey, vlen);

        asc_write_client_error(c);
        return;
    }

    exptime = (time_t)exptime_int;

    /* does cas value exist? */
    if (handle_cas) {
        if (!mc_strtoull(token[TOKEN_CAS].val, &req_cas_id)) {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d and "
                      "invalid cas '%.*s'", c->sd, c->req_type,
                      token[TOKEN_CAS].len, token[TOKEN_CAS].val);

            asc_write_client_error(c);
            return;
        }
    }

    it = item_alloc(id, key, nkey, flags, time_reltime(exptime), vlen);
    if (it == NULL) {
        log_warn("server error on c %d for req of type %d because of oom in "
                 "storing item", c->sd, c->req_type);

        asc_write_server_error(c);

        /* swallow the data line */
        c->write_and_go = CONN_SWALLOW;
        c->sbytes = vlen + CRLF_LEN;

        /*
         * Avoid stale data persisting in cache because we failed alloc.
         * Unacceptable for SET. Anywhere else too?
         *
         * FIXME: either don't delete anything or should be unacceptable for
         * all but add.
         */
        if (type == REQ_SET) {
            it = item_get(key, nkey);
            if (it != NULL) {
                item_delete(it);
            }
        }
        return;
    }

    item_set_cas(it, req_cas_id);

    c->item = it;
    c->ritem = item_data(it);
    c->rlbytes = it->nbyte + CRLF_LEN;
    conn_set_state(c, CONN_NREAD);
}
Beispiel #11
0
static inline void
asc_process_read(struct conn *c, struct token *token, int ntoken)
{
    rstatus_t status;
    char *key;
    size_t nkey;
    unsigned valid_key_iter = 0;
    struct item *it;
    struct token *key_token;
    bool return_cas;

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    return_cas = (c->req_type == REQ_GETS) ? true : false;
    key_token = &token[TOKEN_KEY];

    do {
        while (key_token->len != 0) {

            key = key_token->val;
            nkey = key_token->len;

            if (nkey > KEY_MAX_LEN) {
                log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                          "and %d length key", c->sd, c->req_type, nkey);

                asc_write_client_error(c);
                return;
            }

            if (return_cas) {
                stats_thread_incr(gets);
            } else {
                stats_thread_incr(get);
            }

            it = item_get(key, nkey);
            if (it != NULL) {
                /* item found */
                if (return_cas) {
                    stats_slab_incr(it->id, gets_hit);
                } else {
                    stats_slab_incr(it->id, get_hit);
                }

                if (valid_key_iter >= c->isize) {
                    struct item **new_list;

                    new_list = mc_realloc(c->ilist, sizeof(struct item *) * c->isize * 2);
                    if (new_list != NULL) {
                        c->isize *= 2;
                        c->ilist = new_list;
                    } else {
                        item_remove(it);
                        break;
                    }
                }

                status = asc_respond_get(c, valid_key_iter, it, return_cas);
                if (status != MC_OK) {
                    log_debug(LOG_NOTICE, "client error on c %d for req of type "
                              "%d with %d tokens", c->sd, c->req_type, ntoken);

                    stats_thread_incr(cmd_error);
                    item_remove(it);
                    break;
                }

                log_debug(LOG_VVERB, ">%d sending key %.*s", c->sd, it->nkey,
                          item_key(it));

                item_touch(it);
                *(c->ilist + valid_key_iter) = it;
                valid_key_iter++;
            } else {
                /* item not found */
                if (return_cas) {
                    stats_thread_incr(gets_miss);
                } else {
                    stats_thread_incr(get_miss);
                }
                klog_write(c->peer, c->req_type, key, nkey, 1, 0);
            }

            key_token++;
        }

        /*
         * If the command string hasn't been fully processed, get the next set
         * of token.
         */
        if (key_token->val != NULL) {
            ntoken = asc_tokenize(key_token->val, token, TOKEN_MAX);
            /* ntoken is unused */
            key_token = token;
        }

    } while (key_token->val != NULL);

    c->icurr = c->ilist;
    c->ileft = valid_key_iter;
    if (return_cas) {
        c->scurr = c->slist;
        c->sleft = valid_key_iter;
    }

    log_debug(LOG_VVERB, ">%d END", c->sd);

    /*
     * If the loop was terminated because of out-of-memory, it is not
     * reliable to add END\r\n to the buffer, because it might not end
     * in \r\n. So we send SERVER_ERROR instead.
     */
    if (key_token->val != NULL || conn_add_iov(c, "END\r\n", 5) != MC_OK ||
        (c->udp && conn_build_udp_headers(c) != MC_OK)) {
        log_warn("server error on c %d for req of type %d with enomem", c->sd,
                 c->req_type);

        asc_write_server_error(c);
    } else {
        conn_set_state(c, CONN_MWRITE);
        c->msg_curr = 0;
    }
}
Beispiel #12
0
static void
asc_dispatch(struct conn *c)
{
    rstatus_t status;
    struct token token[TOKEN_MAX];
    int ntoken;

    /*
     * For commands set, add, or replace, we build an item and read the data
     * directly into it, then continue in asc_complete_nread().
     */

    c->msg_curr = 0;
    c->msg_used = 0;
    c->iov_used = 0;
    status = conn_add_msghdr(c);
    if (status != MC_OK) {
        log_warn("server error on c %d for req of type %d because of oom in "
                 "preparing response", c->sd, c->req_type);

        asc_write_server_error(c);
        return;
    }

    ntoken = asc_tokenize(c->req, token, TOKEN_MAX);

    c->req_type = asc_parse_type(c, token, ntoken);
    switch (c->req_type) {
    case REQ_GET:
    case REQ_GETS:
        /* we do not update stats metrics here because of multi-get */
        asc_process_read(c, token, ntoken);
        break;

    case REQ_SET:
        stats_thread_incr(set);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_ADD:
        stats_thread_incr(add);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_REPLACE:
        stats_thread_incr(replace);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_APPEND:
        stats_thread_incr(append);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_PREPEND:
        stats_thread_incr(prepend);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_CAS:
        stats_thread_incr(cas);
        asc_process_update(c, token, ntoken);
        break;

    case REQ_INCR:
        stats_thread_incr(incr);
        asc_process_arithmetic(c, token, ntoken);
        break;

    case REQ_DECR:
        stats_thread_incr(decr);
        asc_process_arithmetic(c, token, ntoken);
        break;

    case REQ_DELETE:
        stats_thread_incr(delete);
        asc_process_delete(c, token, ntoken);
        break;

    case REQ_STATS:
        stats_thread_incr(stats);
        asc_process_stats(c, token, ntoken);
        break;

    case REQ_FLUSHALL:
        stats_thread_incr(flush);
        asc_process_flushall(c, token, ntoken);
        break;

    case REQ_VERSION:
        asc_write_version(c);
        break;

    case REQ_QUIT:
        conn_set_state(c, CONN_CLOSE);
        break;

    case REQ_VERBOSITY:
        asc_process_verbosity(c, token, ntoken);
        break;

    case REQ_CONFIG:
        asc_process_config(c, token, ntoken);
        break;

    case REQ_UNKNOWN:
    default:
        log_hexdump(LOG_INFO, c->req, c->req_len, "req on c %d with %d "
                    "invalid tokens", c->sd, ntoken);
        asc_write_client_error(c);
        break;
    }
}
Beispiel #13
0
static void
asc_process_klog(struct conn *c, struct token *token, int ntoken)
{
    struct token *t;

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_NOTICE, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);

        asc_write_client_error(c);
        return;
    }

    t = &token[TOKEN_KLOG_COMMAND];

    if (strncmp(t->val, "run", t->len) == 0) {
        if (settings.klog_name == NULL) {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                      "with klog filename not set", c->sd, c->req_type);

            asc_write_client_error(c);
            return;
        }

        t = &token[TOKEN_KLOG_SUBCOMMAND];
        if (strncmp(t->val, "start", t->len) == 0) {
            log_debug(LOG_NOTICE, "klog start at epoch %u", time_now());
            settings.klog_running = true;
            asc_write_ok(c);
        } else if (strncmp(t->val, "stop", t->len) == 0) {
            log_debug(LOG_NOTICE, "klog stops at epoch %u", time_now());
            settings.klog_running = false;
            asc_write_ok(c);
        } else {
            log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                      "with invalid klog run subcommand '%.*s'", c->sd,
                      c->req_type, t->len, t->val);

            asc_write_client_error(c);
        }
    } else if (strncmp(t->val, "interval", t->len) == 0) {
        t = &token[TOKEN_KLOG_SUBCOMMAND];
        if (strncmp(t->val, "reset", t->len) == 0) {
            stats_set_interval(STATS_DEFAULT_INTVL);
            asc_write_ok(c);
        } else {
            int32_t interval;

            if (!mc_strtol(t->val, &interval)) {
                log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                          "with invalid klog interval '%.*s'", c->sd,
                          c->req_type, t->len, t->val);

                asc_write_client_error(c);
            } else if (interval < KLOG_MIN_INTVL) {
                log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                          "with invalid klog interval %"PRId32"", c->sd,
                          c->req_type, interval);

                asc_write_client_error(c);
            } else {
                stats_set_interval(interval);
                asc_write_ok(c);
            }
        }
    } else if (strncmp(t->val, "sampling", t->len) == 0) {
        t = &token[TOKEN_KLOG_SUBCOMMAND];
        if (strncmp(t->val, "reset", t->len) == 0) {
            settings.klog_sampling_rate = KLOG_DEFAULT_SMP_RATE;
            asc_write_ok(c);
        } else {
            int32_t sampling;

            if (!mc_strtol(t->val, &sampling)) {
                log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                          "with invalid klog sampling '%.*s'", c->sd,
                          c->req_type, t->len, t->val);

                asc_write_client_error(c);
            } else if (sampling <= 0) {
                log_debug(LOG_NOTICE, "client error on c %d for req of type %d "
                          "with invalid klog sampling %"PRId32"", c->sd,
                          c->req_type, sampling);

                asc_write_client_error(c);
            } else {
                settings.klog_sampling_rate = sampling;
                asc_write_ok(c);
            }
        }
    } else {
        log_debug(LOG_NOTICE, "client error on c %d for req of type %d with "
                  "invalid klog subcommand '%.*s'", c->sd, c->req_type,
                  t->len, t->val);

        asc_write_client_error(c);
    }
}
Beispiel #14
0
static void
asc_process_update(struct conn *c, struct token *token, int ntoken)
{
    char *key;
    size_t nkey;
    unsigned int flags;
    int32_t exptime_int;
    time_t exptime;
    int vlen;
    uint64_t req_cas_id = 0;
    struct item *it;
    bool handle_cas;
    req_type_t type;

    asc_set_noreply_maybe(c, token, ntoken);

    if (!asc_ntoken_valid(c, ntoken)) {
        log_hexdump(LOG_INFO, c->req, c->req_len, "client error on c %d for "
                    "req of type %d with %d invalid tokens", c->sd,
                    c->req_type, ntoken);
        asc_write_client_error(c);
        return;
    }

    type = c->req_type;
    handle_cas = (type == REQ_CAS) ? true : false;
    key = token[TOKEN_KEY].val;
    nkey = token[TOKEN_KEY].len;

    if (nkey > KEY_MAX_LEN) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and %d "
                  "length key", c->sd, c->req_type, nkey);
        asc_write_client_error(c);
        return;
    }

    if (!mc_strtoul(token[TOKEN_FLAGS].val, (uint32_t *)&flags)) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and "
                  "invalid flags '%.*s'", c->sd, c->req_type,
                  token[TOKEN_FLAGS].len, token[TOKEN_FLAGS].val);
        asc_write_client_error(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_EXPIRY].val, &exptime_int)) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and "
                  "invalid expiry '%.*s'", c->sd, c->req_type,
                  token[TOKEN_EXPIRY].len, token[TOKEN_EXPIRY].val);
        asc_write_client_error(c);
        return;
    }

    if (!mc_strtol(token[TOKEN_VLEN].val, (int32_t *)&vlen)) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and "
                  "invalid vlen '%.*s'", c->sd, c->req_type,
                  token[TOKEN_VLEN].len, token[TOKEN_VLEN].val);
        asc_write_client_error(c);
        return;
    }

    exptime = (time_t)exptime_int;

    /* does cas value exist? */
    if (handle_cas) {
        if (!mc_strtoull(token[TOKEN_CAS].val, &req_cas_id)) {
            log_debug(LOG_INFO, "client error on c %d for req of type %d and "
                      "invalid cas '%.*s'", c->sd, c->req_type,
                      token[TOKEN_CAS].len, token[TOKEN_CAS].val);
            asc_write_client_error(c);
            return;
        }
    }

    if (vlen < 0) {
        log_debug(LOG_INFO, "client error on c %d for req of type %d and "
                  "invalid vlen %d", c->sd, c->req_type, vlen);
        asc_write_client_error(c);
        return;
    }

    vlen += CRLF_LEN;

    it = item_alloc(key, nkey, flags, time_reltime(exptime), vlen);
    if (it == NULL) {
        log_debug(LOG_DEBUG, "server error on c %d for req of type %d because "
                  "of oom in storing item", c->sd, c->req_type);
        asc_write_server_error(c);

        /* swallow the data line */
        c->write_and_go = CONN_SWALLOW;
        c->sbytes = vlen;

        /*
         * Avoid stale data persisting in cache because we failed alloc.
         * Unacceptable for SET. Anywhere else too?
         */
        if (type == REQ_SET) {
            it = item_get(key, nkey);
            if (it != NULL) {
                item_unlink(it);
                item_remove(it);
            }
        }
        return;
    }

    item_set_cas(it, req_cas_id);

    c->item = it;
    c->ritem = item_data(it);
    c->rlbytes = it->nbyte;
    conn_set_state(c, CONN_NREAD);
}