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 void ramcloudDelete(struct ramcloudData* d, wstr key, struct RejectRules *rule) { wheatLog(WHEAT_DEBUG, "%s delete key %s", __func__, key); uint64_t version; Status s = rc_remove(global.client, d->table_id, key, wstrlen(key), rule, &version); if (s != STATUS_OK) { if (s == STATUS_OBJECT_DOESNT_EXIST) { sliceTo(&d->storage_response, (uint8_t*)NOT_FOUND, sizeof(NOT_FOUND)-1); } else { wheatLog(WHEAT_WARNING, "%s failed to remove %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*)DELETED, sizeof(DELETED)-1); } }
static void appendSliceToSendQueue(struct conn *conn, struct slice *s) { struct sendPacket *packet = wmalloc(sizeof(*packet)); if (!packet) setClientUnvalid(conn->client); packet->type = SLICE; sliceTo(&packet->target.slice, s->data, s->len); appendToListTail(conn->send_queue, packet); }
int callRamcloud(struct conn *c, void *arg) { enum memcacheCommand command = getMemcacheCommand(c->protocol_data); struct RejectRules rule; struct ramcloudData *d = c->app_private_data; int owner = c->client->owner; uint64_t table_id; ASSERT(owner); if (getTableId(owner, &table_id) < 0) { sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1); sendMemcacheResponse(c, &d->storage_response); return WHEAT_OK; } d->table_id = table_id; memset(&rule, 0, sizeof(rule)); switch (command) { case REQ_MC_GET: case REQ_MC_GETS: d->retrievals = arrayCreate(sizeof(wstr), 1); d->retrievals_keys = arrayCreate(sizeof(struct slice), 1); d->retrievals_vals = arrayCreate(sizeof(struct slice), 1); d->retrievals_flags = arrayCreate(FLAG_SIZE, 1); d->retrievals_versions = arrayCreate(sizeof(uint64_t), 1); arrayEach2(getMemcacheKeys(c->protocol_data), ramcloudRead, d); buildRetrievalResponse(d, command == REQ_MC_GETS ? 1 : 0); sliceTo(&d->storage_response, (uint8_t*)d->retrieval_response, wstrlen(d->retrieval_response)); break; case REQ_MC_DELETE: rule.doesntExist = 1; ramcloudDelete(d, getMemcacheKey(c->protocol_data), &rule); break; case REQ_MC_ADD: rule.exists = 1; ramcloudSet(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), &rule); break; case REQ_MC_REPLACE: rule.doesntExist = 1; ramcloudSet(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), &rule); break; case REQ_MC_CAS: rule.givenVersion = getMemcacheCas(c->protocol_data); rule.versionNeGiven = 1; rule.doesntExist = 1; ramcloudSet(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), &rule); break; case REQ_MC_SET: ramcloudSet(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), &rule); break; case REQ_MC_INCR: ramcloudIncr(d, getMemcacheKey(c->protocol_data), getMemcacheNum(c->protocol_data), 1); break; case REQ_MC_DECR: ramcloudIncr(d, getMemcacheKey(c->protocol_data), getMemcacheNum(c->protocol_data), 0); break; case REQ_MC_APPEND: ramcloudAppend(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), 1); break; case REQ_MC_PREPEND: ramcloudAppend(d, getMemcacheKey(c->protocol_data), getMemcacheVal(c->protocol_data), getMemcacheValLen(c->protocol_data), getMemcacheFlag(c->protocol_data), 0); break; default: ASSERT(0); } sendMemcacheResponse(c, &d->storage_response); return WHEAT_OK; }
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 ramcloudIncr(struct ramcloudData *d, wstr key, uint64_t num, int positive) { if (num > INT64_MAX) { wheatLog(WHEAT_WARNING, "%s num %ld can't larger than %ld", __func__, num, INT64_MAX); sliceTo(&d->storage_response, (uint8_t*)CLIENT_ERROR, sizeof(CLIENT_ERROR)-1); return ; } static int max_len = 100; char value[max_len]; uint32_t actual_len; uint64_t version; uint16_t flag; again: wheatLog(WHEAT_DEBUG, "%s incr key %s %ld", __func__, key, num); Status s = rc_read(global.client, d->table_id, key, wstrlen(key), NULL, &version, value, max_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_FOUND, sizeof(NOT_FOUND)-1); } return ; } if (actual_len > max_len) { sliceTo(&d->storage_response, (uint8_t*)CLIENT_ERROR, sizeof(CLIENT_ERROR)-1); return ; } flag = *(uint16_t*)&value[actual_len-FLAG_SIZE]; value[actual_len-FLAG_SIZE] = '\0'; long long n = atoll(value); if (n == 0) { if (value[0] != '0') { sliceTo(&d->storage_response, (uint8_t*)CLIENT_ERROR, sizeof(CLIENT_ERROR)-1); return ; } } if (positive) { n += num; } else { if (num > n) n = 0; else n -= num; } int l = sprintf(value, "%llu", n); memcpy(&value[l], &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), value, l+FLAG_SIZE, &rule, &version); if (s != STATUS_OK) { if (s == STATUS_WRONG_VERSION) { goto again; } if (s == STATUS_OBJECT_DOESNT_EXIST) { sliceTo(&d->storage_response, (uint8_t*)NOT_FOUND, sizeof(NOT_FOUND)-1); return ; } sliceTo(&d->storage_response, (uint8_t*)SERVER_ERROR, sizeof(SERVER_ERROR)-1); wheatLog(WHEAT_WARNING, "%s failed to incr %s: %s", __func__, key, statusToString(s)); return ; } else { l = sprintf(value, "%llu\r\n", n); d->retrieval_response = wstrNewLen(value, l); sliceTo(&d->storage_response, (uint8_t*)d->retrieval_response, wstrlen(d->retrieval_response)); } }