Beispiel #1
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 #2
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 #3
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 #4
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 #5
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 #6
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);
}