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_--;
    });
}
Пример #3
0
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);
  }
}
Пример #4
0
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);
  }
}
Пример #5
0
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
}
Пример #6
0
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));
}
Пример #7
0
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);
}
Пример #8
0
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);
}
Пример #9
0
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_--;
    });
}
Пример #11
0
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();
}
Пример #12
0
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;
}