void TestServerOnRequest::onRequest( McServerRequestContext&& ctx, McRequestWithMcOp<mc_op_get>&& req) { if (req.fullKey() == "sleep") { /* sleep override */ std::this_thread::sleep_for(std::chrono::seconds(1)); processReply(std::move(ctx), McReply(mc_res_notfound)); } else if (req.fullKey() == "shutdown") { shutdown_.store(true); processReply(std::move(ctx), McReply(mc_res_notfound)); flushQueue(); } else { std::string value = req.fullKey() == "empty" ? "" : req.fullKey().str(); McReply foundReply = McReply(mc_res_found, createMcMsgRef(req.fullKey(), value)); if (req.fullKey() == "hold") { waitingReplies_.emplace_back(std::move(ctx), std::move(foundReply)); } else if (req.fullKey() == "flush") { processReply(std::move(ctx), std::move(foundReply)); flushQueue(); } else { processReply(std::move(ctx), std::move(foundReply)); } } }
void TestClient::sendGet(std::string key, mc_res_t expectedResult, uint32_t timeoutMs) { inflight_++; fm_.addTask([key, expectedResult, this, timeoutMs]() { auto msg = createMcMsgRef(key.c_str()); msg->op = mc_op_get; McRequestWithMcOp<mc_op_get> req{std::move(msg)}; try { auto reply = client_->sendSync(req, std::chrono::milliseconds(timeoutMs)); if (reply.result() == mc_res_found) { auto value = getRange(reply.value()); if (req.fullKey() == "empty") { checkLogic(reply.hasValue(), "Reply has no value"); checkLogic(value.empty(), "Expected empty value, got {}", value); } else { checkLogic(value == req.fullKey(), "Expected {}, got {}", req.fullKey(), value); } } checkLogic(expectedResult == reply.result(), "Expected {}, got {}", mc_res_to_string(expectedResult), mc_res_to_string(reply.result())); } catch (const std::exception& e) { CHECK(false) << "Failed: " << e.what(); } inflight_--; }); }
McMsgRef McRequest::dependentMsg(mc_op_t op) const { ensureMsgExists(op); auto is_key_set = hasSameMemoryRegion(keyData_, to<folly::StringPiece>(msg_->key)); auto is_value_set = hasSameMemoryRegion(valueData_, to<folly::StringPiece>(msg_->value)); if (msg_->op == op && msg_->exptime == exptime_ && msg_->flags == flags_ && msg_->delta == delta_ && msg_->lease_id == leaseToken_ && msg_->cas == cas_ && #ifndef LIBMC_FBTRACE_DISABLE msg_->fbtrace_info == fbtraceInfo_.get() && #endif is_key_set && is_value_set) { /* msg_ is an object with the same fields we expect. In addition, we want to keep routing prefix. We can simply return the reference. */ return msg_.clone(); } else { /* Out of luck. The best we can do is make the copy reference key/value fields from the backing store. */ auto toRelease = createMcMsgRef(); dependentHelper(op, getRange(keyData_), coalesceAndGetRange(const_cast<folly::IOBuf&>(valueData_)), toRelease); return std::move(toRelease); } }
McMsgRef McReplyBase::releasedMsg(mc_op_t op) const { if (msg_.get() != nullptr && msg_->op == op && msg_->result == result_ && msg_->flags == flags_ && msg_->lease_id == leaseToken_ && msg_->delta == delta_ && msg_->err_code == errCode_ && hasSameMemoryRegion(value(), to<folly::StringPiece>(msg_->value))) { return msg_.clone(); } else { auto len = value().computeChainDataLength(); auto toRelease = createMcMsgRef(len + 1); if (msg_.get() != nullptr) { mc_msg_shallow_copy(toRelease.get(), msg_.get()); // TODO: fbtrace? } toRelease->key.str = nullptr; toRelease->key.len = 0; toRelease->value.str = static_cast<char*>(static_cast<void*>(toRelease.get() + 1)); copyInto(toRelease->value.str, value()); toRelease->value.len = len; toRelease->op = op; toRelease->result = result_; toRelease->flags = flags_; toRelease->lease_id = leaseToken_; toRelease->delta = delta_; toRelease->cas = cas_; toRelease->err_code = errCode_; return std::move(toRelease); } }
McRequest::McRequest(const McRequest& other) : exptime_(other.exptime_), flags_(other.flags_), delta_(other.delta_), leaseToken_(other.leaseToken_), cas_(other.cas_) { // Key is always a single piece, so it's safe to do cloneOneInto. other.keyData_.cloneOneInto(keyData_); keys_ = Keys(getRange(keyData_)); other.valueData_.cloneInto(valueData_); if (hasSameMemoryRegion(keyData_, other.keyData_) && hasSameMemoryRegion(valueData_, other.valueData_)) { msg_ = other.msg_.clone(); } else { msg_ = createMcMsgRef( other.msg_, getRange(keyData_), coalesceAndGetRange(valueData_)); } #ifndef LIBMC_FBTRACE_DISABLE if (other.fbtraceInfo_.get()) { fbtraceInfo_ = McFbtraceRef::moveRef( mc_fbtrace_info_deep_copy(other.fbtraceInfo_.get())); } #endif }
McReply StatsReply::getMcReply() { /* In a single allocation, we store: |- mc_msg_t --|- stats_array --|- stats_key[0] --|- stats_val[0] --...| array --^ strings --^ limit --^ */ size_t arraySize = sizeof(nstring_t) * stats_.size() * 2; size_t stringsSize = 0; for (auto& s : stats_) { stringsSize += s.first.size() + s.second.size(); } auto packedMsg = createMcMsgRef(arraySize + stringsSize); packedMsg->op = mc_op_stats; packedMsg->result = mc_res_ok; packedMsg->number = stats_.size(); unsigned char* array = reinterpret_cast<unsigned char*>(packedMsg.get() + 1); unsigned char* strings = array + arraySize; unsigned char* limit = strings + stringsSize; packedMsg->stats = reinterpret_cast<nstring_t*>(array); size_t i = 0; for (auto& s : stats_) { copy(packedMsg->stats[i++], s.first, strings, limit); copy(packedMsg->stats[i++], s.second, strings, limit); } assert(strings == limit); return McReply(mc_res_ok, std::move(packedMsg)); }
McRequest::McRequest(folly::IOBuf keyData) : keyData_(std::move(keyData)) { keyData_.coalesce(); keys_.update(getRange(keyData_)); auto msg = createMcMsgRef(); msg->key = to<nstring_t>(getRange(keyData_)); msg_ = std::move(msg); }
McRequest::McRequest(folly::StringPiece key) : keyData_(folly::IOBuf(folly::IOBuf::COPY_BUFFER, key)) { keyData_.coalesce(); keys_.update(getRange(keyData_)); auto msg = createMcMsgRef(); msg->key = to<nstring_t>(getRange(keyData_)); msg_ = std::move(msg); }
void McRequest::ensureMsgExists(mc_op_t op) const { /* dependentMsg* functions assume msg_ exists, so create one if necessary. */ if (!msg_.get()) { auto msg = createMcMsgRef(); dependentHelper(op, getRange(keyData_), coalesceAndGetRange(const_cast<folly::IOBuf&>(valueData_)), msg); const_cast<McMsgRef&>(msg_) = std::move(msg); } }
void TestClient::sendSet(std::string key, std::string value, mc_res_t expectedResult) { inflight_++; fm_.addTask([key, value, expectedResult, this]() { auto msg = createMcMsgRef(key.c_str(), value.c_str()); msg->op = mc_op_set; McRequestWithMcOp<mc_op_set> req{std::move(msg)}; auto reply = client_->sendSync(req, std::chrono::milliseconds(200)); CHECK(expectedResult == reply.result()) << "Expected: " << mc_res_to_string(expectedResult) << " got " << mc_res_to_string(reply.result()); inflight_--; }); }
void McServerSession::parseError(McReply reply) { DestructorGuard dg(this); auto sharedThis = weakThis_.lock(); if (!sharedThis) { /* This session is being destroyed, can't create new transactions */ close(); return; } auto& transaction = unansweredRequests_.pushBack( folly::make_unique<McServerTransaction>( sharedThis, McRequest(createMcMsgRef()), mc_op_unknown, 0) ); transaction.sendReply(std::move(reply)); close(); }
bool McParser::umMessageReady( const uint8_t* header, const uint8_t* body, const folly::IOBuf& bodyBuffer) { switch (type_) { case ParserType::SERVER: { try { mc_op_t op; uint64_t reqid; auto req = umbrellaParseRequest(bodyBuffer, header, umMsgInfo_.header_size, body, umMsgInfo_.body_size, op, reqid); /* Umbrella requests never include a result and are never 'noreply' */ requestReadyHelper(std::move(req), op, reqid, /* result= */ mc_res_unknown, /* noreply= */ false); } catch (const std::runtime_error& e) { errorHelper( McReply(mc_res_remote_error, std::string("Error parsing Umbrella message: ") + e.what())); return false; } } break; case ParserType::CLIENT: { auto mutMsg = createMcMsgRef(); uint64_t reqid; auto st = um_consume_no_copy(header, umMsgInfo_.header_size, body, umMsgInfo_.body_size, &reqid, mutMsg.get()); if (st != um_ok) { errorHelper(McReply(mc_res_remote_error, "Error parsing Umbrella message")); return false; } folly::IOBuf value; if (mutMsg->value.len != 0) { if (!cloneInto(value, bodyBuffer, reinterpret_cast<uint8_t*>(mutMsg->value.str), mutMsg->value.len)) { errorHelper(McReply(mc_res_remote_error, "Error parsing Umbrella value")); return false; } // Reset msg->value, or it will confuse McReply::releasedMsg mutMsg->value.str = nullptr; mutMsg->value.len = 0; } McMsgRef msg(std::move(mutMsg)); auto reply = McReply(msg->result, msg.clone()); if (value.length() != 0) { reply.setValue(std::move(value)); } replyReadyHelper(std::move(reply), msg->op, reqid); } break; } return true; }