static void ramcloudRead(void *item, void *data) { wstr i = *(wstr*)item; struct ramcloudData *d = data; uint32_t actual_len; uint64_t version; uint64_t len = RAMCLOUD_DEFAULT_VALUE_LEN; wheatLog(WHEAT_DEBUG, "%s read key %s", __func__, i); wstr val = wstrNewLen(NULL, len); Status s = rc_read(global.client, d->table_id, i, wstrlen(i), NULL, &version, val, len, &actual_len); if (s != STATUS_OK) { if (s != STATUS_OBJECT_DOESNT_EXIST) { wheatLog(WHEAT_WARNING, " failed to read %s: %s", i, statusToString(s)); } wstrFree(val); return ; } while (actual_len > len) { wstrFree(val); len = actual_len; val = wstrNewLen(NULL, actual_len); if (val == NULL) { wheatLog(WHEAT_WARNING, " failed to alloc memory"); return ; } s = rc_read(global.client, d->table_id, i, wstrlen(i), NULL, &version, val, len, &actual_len); if (s != STATUS_OK) { if (s != STATUS_OBJECT_DOESNT_EXIST) { wheatLog(WHEAT_WARNING, " failed to read %s: %s", i, statusToString(s)); } wstrFree(val); return ; } } d->retrieval_len += actual_len; arrayPush(d->retrievals, &val); struct slice ss = {(uint8_t*)(i), wstrlen(i)}; arrayPush(d->retrievals_keys, &ss); ss.data = (uint8_t*)val; ss.len = actual_len - FLAG_SIZE; arrayPush(d->retrievals_vals, &ss); arrayPush(d->retrievals_flags, &val[actual_len-FLAG_SIZE]); arrayPush(d->retrievals_versions, &version); }
void registerConnFree(struct conn *conn, void (*clean)(void*), void *data) { struct callback cleanup; cleanup.func = clean; cleanup.data = data; arrayPush(conn->cleanup, &cleanup); }
// hashAdd is used when a new redis server add to rebalance tokens int hashAdd(struct redisServer *server, wstr ip, int port, int id) { size_t ninstance, ntoken_per_instance, extra_ntoken, target_idx, ntoken; struct token *token, *tokens; struct redisInstance *instance, *target_instance; struct redisInstance add_instance; size_t *sub_ntoken; int i; if (initInstance(&add_instance, id, ip, port, DIRTY) == WHEAT_WRONG) return WHEAT_WRONG; arrayPush(server->instances, &add_instance); // `sub_ntoken`'s element is the amount of tokens every instance should // take out ninstance = narray(server->instances); sub_ntoken = wmalloc(sizeof(int)*ninstance); ntoken_per_instance = WHEAT_KEYSPACE / ninstance; extra_ntoken = WHEAT_KEYSPACE % ninstance; for (i = 0; i < ninstance; i++) { instance = arrayIndex(server->instances,i); sub_ntoken[i] = instance->ntoken - ntoken_per_instance; } if (!extra_ntoken) { for (i = 0; i < extra_ntoken; i++) { sub_ntoken[i]--; } } target_idx = ninstance-1; extra_ntoken = sub_ntoken[target_idx]; target_instance = arrayIndex(server->instances, target_idx); token = tokens = &server->tokens[0]; while (extra_ntoken) { size_t skip = random() % ntoken_per_instance + 1; while (skip--) { token = &tokens[token->next_instance]; } if (token->instance_id != target_idx && sub_ntoken[token->instance_id]) { wheatLog(WHEAT_DEBUG, "token: %d", token->pos); instance = arrayIndex(server->instances, token->instance_id); token->instance_id = target_idx; instance->ntoken--; target_instance->ntoken++; } } ntoken = 0; for (i = 0; i < ninstance; i++) { instance = arrayIndex(server->instances,i); ntoken += instance->ntoken; } ASSERT(ntoken == WHEAT_KEYSPACE); wfree(sub_ntoken); return WHEAT_OK; }
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; }