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); } }
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; }
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); }
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); }