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); }
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); } }
// Only called when config-server is not specifyed. Means that WheatRedis is // firstly running on your system. int hashInit(struct redisServer *server) { ASSERT(narray(server->instances) >= server->nbackup); struct redisInstance *instance; size_t ntoken, ninstance, swap; int i, prev_idx; struct token *tokens = server->tokens, *last_token = NULL; ntoken = WHEAT_KEYSPACE; tokens = wmalloc(sizeof(struct token)*ntoken); if (!tokens) return WHEAT_WRONG; server->tokens = tokens; ninstance = narray(server->instances); for (i = 0; i < ntoken; ++i) { instance = arrayIndex(server->instances, i%ninstance); tokens[i].next_instance = UINT32_MAX; // An impossible value tokens[i].pos = i; tokens[i].instance_id = i%ninstance; instance->ntoken++; } // shuffle for (i = 0; i < ntoken; i++) { size_t j = i + rand() / (RAND_MAX / (ntoken - i) + 1); swap = tokens[j].instance_id; tokens[j].instance_id = tokens[i].instance_id; tokens[i].instance_id = swap; } // Populate each token.next_instance to quicker search node process prev_idx = 0; i = 1; last_token = &tokens[ntoken-1]; while (last_token->next_instance == UINT32_MAX) { if (tokens[i%ntoken].instance_id != tokens[prev_idx].instance_id) { for (; prev_idx < i && prev_idx < ntoken; ++prev_idx) tokens[prev_idx].next_instance = i%ntoken; } ++i; } server->ntoken = ntoken; return WHEAT_OK; }
wstr getMemcacheKey(void *data) { struct memcacheProcData *d = data; if (narray(d->keys)) return *(wstr*)arrayTop(d->keys); else return d->key; }
// 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; }
void initWorkerProcess(struct workerProcess *worker, char *worker_name) { struct configuration *conf; int i; struct app *app; struct moduleAttr *module; if (Server.stat_fd != 0) close(Server.stat_fd); setProctitle(worker_name); worker->pid = getpid(); worker->ppid = getppid(); worker->alive = 1; worker->start_time = Server.cron_time; worker->worker = spotWorker(worker_name); worker->master_stat_fd = 0; ASSERT(worker->worker); worker->stats = NULL; initWorkerSignals(); worker->center = eventcenterInit(WHEAT_CLIENT_MAX); if (!worker->center) { wheatLog(WHEAT_WARNING, "eventcenter_init failed"); halt(1); } if (createEvent(worker->center, Server.ipfd, EVENT_READABLE, acceptClient, NULL) == WHEAT_WRONG) { wheatLog(WHEAT_WARNING, "createEvent failed"); halt(1); } // It may nonblock after fork??? if (wheatNonBlock(Server.neterr, Server.ipfd) == NET_WRONG) { wheatLog(WHEAT_WARNING, "Set nonblock %d failed: %s", Server.ipfd, Server.neterr); halt(1); } module = NULL; conf = getConfiguration("protocol"); if (conf->target.ptr) { module = getModule(PROTOCOL, conf->target.ptr); if (module && getProtocol(module)->initProtocol() == WHEAT_WRONG) { wheatLog(WHEAT_WARNING, "init protocol failed"); halt(1); } } if (!module) { wheatLog(WHEAT_WARNING, "find protocol %s failed", conf->target.ptr); halt(1); } worker->protocol = getProtocol(module); StatTotalClient = getStatItemByName("Total client"); gettimeofday(&Server.cron_time, NULL); if (worker->worker->setup) worker->worker->setup(); WorkerProcess->refresh_time = Server.cron_time.tv_sec; FreeClients = createAndFillPool(); Clients = createList(); StatBufferSize = getStatItemByName("Max buffer size"); StatTotalRequest = getStatItemByName("Total request"); StatFailedRequest = getStatItemByName("Total failed request"); StatRunTime = getStatItemByName("Worker run time"); worker->apps = arrayCreate(sizeof(struct app*), 3); if (!worker->apps) { wheatLog(WHEAT_WARNING, "array create failed"); halt(1); } getAppsByProtocol(worker->apps, worker->protocol); for (i = 0; i < narray(worker->apps); i++) { app = *(struct app**)arrayIndex(worker->apps, i); if (app->initApp(worker->protocol) == WHEAT_WRONG) { wheatLog(WHEAT_WARNING, "init app failed %s", getModuleName(APP, app)); halt(1); } } sendStatPacket(WorkerProcess); }
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); }