예제 #1
0
static void ramcloudSet(struct ramcloudData *d, wstr key, struct array *vals, uint32_t vlen, uint16_t flag, struct RejectRules *rule)
{
    wheatLog(WHEAT_DEBUG, "%s set key %s", __func__, key);
    uint64_t version;
    int i = 0;
    struct slice *slice;
    wstr val = wstrNewLen(NULL, vlen+sizeof(flag));
    while (i < narray(vals)) {
        slice = arrayIndex(vals, i);
        val = wstrCatLen(val, (char*)slice->data, slice->len);
        ++i;
    }
    val = wstrCatLen(val, (char*)&flag, FLAG_SIZE);

    Status s = rc_write(global.client, d->table_id, key, wstrlen(key), val, wstrlen(val),
                        rule, &version);
    wstrFree(val);
    if (s != STATUS_OK) {
        // cas command
        if (rule->versionNeGiven) {
            if (s == STATUS_WRONG_VERSION)
                sliceTo(&d->storage_response, (uint8_t*)EXISTS, sizeof(EXISTS)-1);
            else if (s == STATUS_OBJECT_DOESNT_EXIST)
                sliceTo(&d->storage_response, (uint8_t*)NOT_FOUND, sizeof(NOT_FOUND)-1);
        } else if ((rule->doesntExist && s == STATUS_OBJECT_DOESNT_EXIST) ||
                   (rule->exists && s == STATUS_OBJECT_EXISTS)) {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
        } else {
            wheatLog(WHEAT_WARNING, "%s failed to set %s: %s", __func__, key, statusToString(s));
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        }
    } else {
        sliceTo(&d->storage_response, (uint8_t*)STORED, sizeof(STORED)-1);
    }
}
예제 #2
0
static ssize_t memcacheParseReq(struct memcacheProcData *r, struct slice *s)
{
    char *m;
    char ch;
    size_t command_len;

    size_t pos = 0;
    uint64_t left = 0;
    struct slice val_s;
    enum reqStage state = r->stage;
    r->token_pos = 0;
    while (pos < s->len) {
        ch = s->data[pos];

        switch (state) {
        case SW_START:
            if (!islower(ch)) {
                goto error;
            }

            r->token_pos = pos;
            state = SW_REQ_TYPE;
            break;

        case SW_REQ_TYPE:
            if (ch == ' ' || ch == CR) {
                r->type = UNKNOWN;
                if (wstrlen(r->command)) {
                    r->command = wstrCatLen(r->command, (char *)&s->data[r->token_pos], pos);
                    command_len = wstrlen(r->command);
                    m = (char*)&r->command;
                } else {
                    command_len = pos - r->token_pos;
                    m = (char*)&s->data[r->token_pos];
                }

                switch (command_len) {

                case 3:
                    if (str4icmp(m, 'g', 'e', 't', ' ')) {
                        r->type = REQ_MC_GET;
                        break;
                    }

                    if (str4icmp(m, 's', 'e', 't', ' ')) {
                        r->type = REQ_MC_SET;
                        break;
                    }

                    if (str4icmp(m, 'a', 'd', 'd', ' ')) {
                        r->type = REQ_MC_ADD;
                        break;
                    }

                    if (str4icmp(m, 'c', 'a', 's', ' ')) {
                        r->type = REQ_MC_CAS;
                        break;
                    }

                    break;

                case 4:
                    if (str4icmp(m, 'g', 'e', 't', 's')) {
                        r->type = REQ_MC_GETS;
                        break;
                    }

                    if (str4icmp(m, 'i', 'n', 'c', 'r')) {
                        r->type = REQ_MC_INCR;
                        break;
                    }

                    if (str4icmp(m, 'd', 'e', 'c', 'r')) {
                        r->type = REQ_MC_DECR;
                        break;
                    }

                    if (str4icmp(m, 'q', 'u', 'i', 't')) {
                        r->type = REQ_MC_QUIT;
                        r->quit = 1;
                        break;
                    }

                    break;

                case 6:
                    if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) {
                        r->type = REQ_MC_APPEND;
                        break;
                    }

                    if (str6icmp(m, 'd', 'e', 'l', 'e', 't', 'e')) {
                        r->type = REQ_MC_DELETE;
                        break;
                    }

                    break;

                case 7:
                    if (str7icmp(m, 'p', 'r', 'e', 'p', 'e', 'n', 'd')) {
                        r->type = REQ_MC_PREPEND;
                        break;
                    }

                    if (str7icmp(m, 'r', 'e', 'p', 'l', 'a', 'c', 'e')) {
                        r->type = REQ_MC_REPLACE;
                        break;
                    }

                    break;
                }

                switch (r->type) {
                case REQ_MC_GET:
                case REQ_MC_GETS:
                case REQ_MC_DELETE:
                case REQ_MC_CAS:
                case REQ_MC_SET:
                case REQ_MC_ADD:
                case REQ_MC_REPLACE:
                case REQ_MC_APPEND:
                case REQ_MC_PREPEND:
                case REQ_MC_INCR:
                case REQ_MC_DECR:
                    if (ch == CR) {
                        goto error;
                    }
                    state = SW_SPACES_BEFORE_KEY;
                    break;

                case REQ_MC_QUIT:
                    pos--; /* go back by 1 byte */
                    state = SW_CRLF;
                    break;

                case UNKNOWN:
                    goto error;

                default:
                    ASSERT(0);
                }
            } else if (!islower(ch)) {
                goto error;
            }

            break;

        case SW_SPACES_BEFORE_KEY:
            if (ch != ' ') {
                pos--; /* go back by 1 byte */
                r->token_pos = -1;
                state = SW_KEY;
            }
            break;

        case SW_KEY:
            if (r->token_pos == -1) {
                r->token_pos = pos;
            }
            if (ch == ' ' || ch == CR) {
                if (wstrlen(r->key) + (pos - r->token_pos) > MEMCACHE_MAX_KEY_LENGTH) {
                    wheatLog(WHEAT_WARNING,
                             "parsed bad type %d with key prefix '%d' and length %d that exceeds "
                             "maximum key length", r->type, r->token_pos, pos);
                    goto error;
                }

                r->key = wstrCatLen(r->key, (char*)&s->data[r->token_pos], pos - r->token_pos);
                arrayPush(r->keys, &r->key);
                r->key = wstrNewLen(NULL, 64);

                r->token_pos = -1;

                /* get next state */
                if (memcache_storage(r)) {
                    state = SW_SPACES_BEFORE_FLAGS;
                } else if (memcache_arithmetic(r)) {
                    state = SW_SPACES_BEFORE_NUM;
                } else if (memcache_delete(r)) {
                    // whether exist delay time
                    if (ch == ' ')
                        state = SW_SPACES_BEFORE_NUM;
                    else
                        state = SW_RUNTO_CRLF;
                } else if (memcache_retrieval(r)) {
                    state = SW_SPACES_BEFORE_KEYS;
                } else {
                    state = SW_RUNTO_CRLF;
                }

                if (ch == CR) {
                    if (memcache_storage(r) || memcache_arithmetic(r)) {
                        goto error;
                    }
                    pos--; /* go back by 1 byte */
                }
            }

            break;

        case SW_SPACES_BEFORE_KEYS:
            ASSERT(memcache_retrieval(r));
            switch (ch) {
            case ' ':
                break;

            case CR:
                state = SW_ALMOST_DONE;
                break;

            default:
                r->token_pos = -1;
                pos--; /* go back by 1 byte */
                state = SW_KEY;
            }

            break;

        case SW_SPACES_BEFORE_FLAGS:
            if (ch != ' ') {
                if (!isdigit(ch)) {
                    goto error;
                }
                r->flag = ch - '0';
                state = SW_FLAGS;
            }

            break;

        case SW_FLAGS:
            if (isdigit(ch)) {
                r->flag = r->flag * 10 + (ch - '0');
            } else if (ch == ' ') {
                state = SW_SPACES_BEFORE_EXPIRY;
            } else {
                goto error;
            }

            break;

        case SW_SPACES_BEFORE_EXPIRY:
            if (ch != ' ') {
                if (!isdigit(ch)) {
                    goto error;
                }
                /* expiry_start <- p; expiry <- ch - '0' */
                r->expire = ch - '0';
                state = SW_EXPIRY;
            }

            break;

        case SW_EXPIRY:
            if (isdigit(ch)) {
                r->expire = r->expire * 10 + (ch - '0');
            } else if (ch == ' ') {
                state = SW_SPACES_BEFORE_VLEN;
            } else {
                goto error;
            }

            break;

        case SW_SPACES_BEFORE_VLEN:
            if (ch != ' ') {
                if (!isdigit(ch)) {
                    goto error;
                }
                /* vlen_start <- p */
                r->vlen = ch - '0';
                state = SW_VLEN;
            }

            break;

        case SW_VLEN:
            if (isdigit(ch)) {
                r->vlen = r->vlen * 10 + (uint32_t)(ch - '0');
            } else if (memcache_cas(r)) {
                if (ch != ' ') {
                    goto error;
                }
                pos--; /* go back by 1 byte */
                state = SW_SPACES_BEFORE_CAS;
            } else if (ch == ' ' || ch == CR) {
                pos--; /* go back by 1 byte */
                state = SW_RUNTO_CRLF;
            } else {
                goto error;
            }

            break;

        case SW_SPACES_BEFORE_CAS:
            if (ch != ' ') {
                if (!isdigit(ch)) {
                    goto error;
                }
                /* cas_start <- p; cas <- ch - '0' */
                r->cas = ch - '0';
                state = SW_CAS;
            }

            break;

        case SW_CAS:
            if (isdigit(ch)) {
                r->cas = r->cas * 10 + (ch - '0');
            } else if (ch == ' ' || ch == CR) {
                pos--; /* go back by 1 byte */
                state = SW_RUNTO_CRLF;
            } else {
                goto error;
            }

            break;


        case SW_RUNTO_VAL:
            switch (ch) {
            case LF:
                /* val_start <- p + 1 */
                state = SW_VAL;
                r->vlen_left = r->vlen;
                break;

            default:
                goto error;
            }

            break;

        case SW_VAL:
            if (r->vlen_left) {
                left = (s->len - pos) >= r->vlen ? (r->vlen) : (s->len-pos);
                val_s.len = left;
                val_s.data = &s->data[pos];
                arrayPush(r->vals, &val_s);
                r->vlen_left -= left;
                pos += left;
            }
            switch (s->data[pos]) {
            case CR:
                state = SW_ALMOST_DONE;
                break;

            default:
                goto error;
            }

            break;

        case SW_SPACES_BEFORE_NUM:
            if (ch != ' ') {
                if (!isdigit(ch)) {
                    goto error;
                }
                r->num = ch - '0';
                state = SW_NUM;
            }

            break;

        case SW_NUM:
            if (isdigit(ch)) {
                r->num = r->num * 10 + ch - '0';
            } else if (ch == ' ' || ch == CR) {
                pos--; /* go back by 1 byte */
                state = SW_RUNTO_CRLF;
            } else {
                goto error;
            }

            break;

        case SW_RUNTO_CRLF:
            switch (ch) {
            case ' ':
                break;

            case 'n':
                if (memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r)) {
                    state = SW_NOREPLY;
                    r->noreply_banner = wstrNewLen(NULL, 8);
                    r->token_pos = pos;
                } else {
                    goto error;
                }

                break;

            case CR:
                if (memcache_storage(r)) {
                    state = SW_RUNTO_VAL;
                } else {
                    state = SW_ALMOST_DONE;
                }

                break;

            default:
                goto error;
            }

            break;

        case SW_NOREPLY:
            switch (ch) {
            case ' ':
            case CR:
                r->noreply_banner = wstrCatLen(r->noreply_banner, (char*)&s->data[r->token_pos], pos - r->token_pos);
                if (str7icmp(r->noreply_banner, 'n', 'o', 'r', 'e', 'p', 'l', 'y')) {
                    ASSERT(memcache_storage(r) || memcache_arithmetic(r) || memcache_delete(r));
                    /* noreply_end <- p - 1 */
                    r->noreply = 1;
                    state = SW_AFTER_NOREPLY;
                    pos--; /* go back by 1 byte */
                } else {
                    goto error;
                }
            }

            break;

        case SW_AFTER_NOREPLY:
            switch (ch) {
            case ' ':
                break;

            case CR:
                if (memcache_storage(r)) {
                    state = SW_RUNTO_VAL;
                } else {
                    state = SW_ALMOST_DONE;
                }
                break;

            default:
                goto error;
            }

            break;

        case SW_CRLF:
            switch (ch) {
            case ' ':
                break;

            case CR:
                state = SW_ALMOST_DONE;
                break;

            default:
                goto error;
            }

            break;

        case SW_ALMOST_DONE:
            switch (ch) {
            case LF:
                /* req_end <- p */
                pos++;
                goto done;

            default:
                goto error;
            }

            break;

        case SW_SENTINEL:
        default:
            ASSERT(0);
            break;

        }
        pos++;
    }

    if (state == SW_REQ_TYPE) {
        r->command = wstrCatLen(r->command, (char*)&s->data[r->token_pos], pos - r->token_pos);
    } else if (state == SW_KEY) {
        r->key = wstrCatLen(r->key, (char*)&s->data[r->token_pos], pos - r->token_pos);
    } else if (state == SW_NOREPLY) {
        r->noreply_banner = wstrCatLen(r->noreply_banner, (char*)&s->data[r->token_pos], pos - r->token_pos);
    }

done:
    r->stage = state;
    wheatLog(WHEAT_DEBUG, "parsed successfully type %d state %d", r->type, r->stage);
    return pos;

error:
    wheatLog(WHEAT_DEBUG, "parsed failed type %d state %d: %s", r->type, r->stage,
             s->data);
    return -1;
}
예제 #3
0
static void ramcloudAppend(struct ramcloudData *d, wstr key, struct array *vals, uint32_t vlen, uint16_t flag, int append)
{
    uint32_t actual_len;
    uint64_t version;
    uint64_t len = RAMCLOUD_DEFAULT_VALUE_LEN;

again:
    wheatLog(WHEAT_DEBUG, "%s read key %s", __func__, key);

    wstr origin_val = wstrNewLen(NULL, len);
    wstr val;
    Status s = rc_read(global.client, d->table_id, key, wstrlen(key), NULL, &version, origin_val, len, &actual_len);
    if (s != STATUS_OK) {
        if (s != STATUS_OBJECT_DOESNT_EXIST) {
            wheatLog(WHEAT_WARNING, " failed to read %s: %s", key, statusToString(s));
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        } else {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
        }
        wstrFree(origin_val);
        return ;
    }

    while (actual_len > len) {
        wstrFree(origin_val);
        len = actual_len;
        origin_val = wstrNewLen(NULL, actual_len);
        if (origin_val == NULL) {
            sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
            wheatLog(WHEAT_WARNING, " failed to alloc memory");
            return ;
        }

        s = rc_read(global.client, d->table_id, key, wstrlen(key), NULL, &version, origin_val, len, &actual_len);
        if (s != STATUS_OK) {
            if (s != STATUS_OBJECT_DOESNT_EXIST) {
                wheatLog(WHEAT_WARNING, " failed to read %s: %s", key, statusToString(s));
                sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
            } else {
                sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
            }
            wstrFree(origin_val);
            return ;
        }
    }

    wstrupdatelen(origin_val, actual_len-FLAG_SIZE);
    if (append) {
        val = origin_val;
        // reduce flag size
    } else {
        val = wstrNewLen(NULL, vlen);
    }

    int i = 0;
    while (i < narray(vals)) {
        struct slice *slice;
        slice = arrayIndex(vals, i);
        val = wstrCatLen(val, (char*)slice->data, slice->len);
        len += slice->len;
        ++i;
    }

    if (!append) {
        val = wstrCatLen(val, origin_val, wstrlen(origin_val));
        wstrFree(origin_val);
    }
    val = wstrCatLen(val, (char*)&flag, FLAG_SIZE);

    struct RejectRules rule;
    memset(&rule, 0, sizeof(rule));
    rule.doesntExist = 1;
    rule.versionNeGiven = 1;
    rule.givenVersion = version;
    s = rc_write(global.client, d->table_id, key, wstrlen(key), val, wstrlen(val),
                        &rule, NULL);
    wstrFree(val);
    if (s != STATUS_OK) {
        if (s == STATUS_OBJECT_DOESNT_EXIST) {
            sliceTo(&d->storage_response, (uint8_t*)NOT_STORED, sizeof(NOT_STORED)-1);
            return ;
        } else if (s == STATUS_WRONG_VERSION) {
            goto again;
        }

        wheatLog(WHEAT_WARNING, " failed to write %s: %s", key, statusToString(s));
        sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1);
        return ;
    }
    sliceTo(&d->storage_response, (uint8_t*)STORED, sizeof(STORED)-1);
}
예제 #4
0
static void buildRetrievalResponse(struct ramcloudData *d, int cas)
{
    int i = 0;
    char buf[64];
    ASSERT(!d->retrieval_response);
    // Estimate value avoid realloc
    d->retrieval_response = wstrNewLen(NULL, d->retrieval_len+narray(d->retrievals_vals)*64);
    for (; i < narray(d->retrievals_vals); ++i) {
        struct slice *val = arrayIndex(d->retrievals_vals, i);
        struct slice *key = arrayIndex(d->retrievals_keys, i);
        uint16_t *flag = arrayIndex(d->retrievals_flags, i);
        uint64_t *v = arrayIndex(d->retrievals_versions, i);
        d->retrieval_response = wstrCatLen(d->retrieval_response, VALUE, 5);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        d->retrieval_response = wstrCatLen(d->retrieval_response, (char*)key->data, key->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        int l = sprintf(buf, "%d", *flag);
        d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
        l = sprintf(buf, "%ld", val->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        if (cas) {
            d->retrieval_response = wstrCatLen(d->retrieval_response, " ", 1);
            l = sprintf(buf, "%llu", *v);
            d->retrieval_response = wstrCatLen(d->retrieval_response, buf, l);
        }
        d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
        d->retrieval_response = wstrCatLen(d->retrieval_response, (char*)val->data, val->len);
        d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
    }

    d->retrieval_response = wstrCatLen(d->retrieval_response, END, 3);
    d->retrieval_response = wstrCatLen(d->retrieval_response, CRLF, 2);
}