Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions mcrouter/lib/mc/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#pragma once

#include <cstdint>
#include <inttypes.h>
#include <stdint.h>

Expand Down Expand Up @@ -48,6 +49,7 @@ typedef enum mc_op_e {
mc_op_touch,
mc_op_gat,
mc_op_gats,
mc_op_meta_commands_get,
mc_nops // placeholder
} mc_op_t;

Expand Down Expand Up @@ -114,6 +116,8 @@ static inline const char* mc_op_to_string(const mc_op_t op) {
return "gat";
case mc_op_gats:
return "gats";
case mc_op_meta_commands_get:
return "mg";
case mc_nops:
return "unknown";
}
Expand Down Expand Up @@ -402,6 +406,7 @@ static inline int mc_op_has_key(mc_op_t op) {
case mc_op_gets:
case mc_op_gat:
case mc_op_gats:
case mc_op_meta_commands_get:
return 1;

default:
Expand Down Expand Up @@ -440,3 +445,19 @@ const char* mc_req_err_to_string(const mc_req_err_t err);
* @return mc_res_t code
*/
mc_res_t mc_res_from_string(const char* result);

constexpr uint64_t MC_META_COMMANDS_FLAG_BASE64_ENCODED_KEY = 1;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_CAS_TOKEN = 1ull << 1;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_CLIENT_FLAGS = 1ull << 2;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_WAS_HIT = 1ull << 3;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_KEY = 1ull << 4;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_TIME_SINCE_LAST_ACCESS = 1ull << 5;
constexpr uint64_t MC_META_COMMANDS_FLAG_USE_NOREPLY_SEMANTICS = 1ull << 6;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_ITEM_SIZE = 1ull << 7;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_ITEM_TTL = 1ull << 8;
constexpr uint64_t MC_META_COMMANDS_FLAG_DO_NOT_BUMP_LRU = 1ull << 9;
constexpr uint64_t MC_META_COMMANDS_FLAG_RETURN_VALUE = 1ull << 10;
constexpr uint64_t MC_META_COMMANDS_FLAG_WON_RECACHE = 1ull << 11;
constexpr uint64_t MC_META_COMMANDS_FLAG_ITEM_IS_STALE = 1ull << 12;
constexpr uint64_t MC_META_COMMANDS_FLAG_LOST_RECACHE = 1ull << 13;
constexpr uint64_t MC_META_COMMANDS_FLAG_INVALIDATE_IF_OLDER_CAS = 1ull << 14;
156 changes: 156 additions & 0 deletions mcrouter/lib/network/AsciiSerialized.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

#include "mcrouter/lib/IOBufUtil.h"
#include "mcrouter/lib/McResUtil.h"
#include "mcrouter/lib/mc/msg.h"
#include <cstdio>
#include <folly/Range.h>

namespace facebook {
namespace memcache {
Expand Down Expand Up @@ -144,6 +147,81 @@ void AsciiSerializedRequest::prepareImpl(const McGatsRequest& request) {
"\r\n");
}

void serializeBooleanMetaCommandFlags(char** pos, char** end, uint64_t flags) {
struct FlagBit {
uint64_t bit;
char ch;
};
static constexpr FlagBit booleanFlags[] = {
{MC_META_COMMANDS_FLAG_BASE64_ENCODED_KEY, 'b'},
{MC_META_COMMANDS_FLAG_RETURN_CAS_TOKEN, 'c'},
{MC_META_COMMANDS_FLAG_RETURN_CLIENT_FLAGS, 'f'},
{MC_META_COMMANDS_FLAG_RETURN_WAS_HIT, 'h'},
{MC_META_COMMANDS_FLAG_RETURN_KEY, 'k'},
{MC_META_COMMANDS_FLAG_RETURN_TIME_SINCE_LAST_ACCESS, 'l'},
{MC_META_COMMANDS_FLAG_USE_NOREPLY_SEMANTICS, 'q'},
{MC_META_COMMANDS_FLAG_RETURN_ITEM_SIZE, 's'},
{MC_META_COMMANDS_FLAG_RETURN_ITEM_TTL, 't'},
{MC_META_COMMANDS_FLAG_DO_NOT_BUMP_LRU, 'u'},
{MC_META_COMMANDS_FLAG_RETURN_VALUE, 'v'},
{MC_META_COMMANDS_FLAG_WON_RECACHE, 'W'},
{MC_META_COMMANDS_FLAG_ITEM_IS_STALE, 'X'},
{MC_META_COMMANDS_FLAG_LOST_RECACHE, 'Z'},
{MC_META_COMMANDS_FLAG_INVALIDATE_IF_OLDER_CAS, 'I'},
};

for (const auto& f : booleanFlags) {
if (flags & f.bit) {
auto n = snprintf(*pos, *end - *pos, " %c", f.ch);
*pos += n;
}
}
}

// Meta commands get.
void AsciiSerializedRequest::prepareImpl(
const McMetaCommandsGetRequest& request) {
// Build flags string into printBuffer_
char* pos = printBuffer_;
char* end = printBuffer_ + kMaxBufferLength;
uint64_t flags = *request.flags_ref();

serializeBooleanMetaCommandFlags(&pos, &end, flags);

if (request.casToken_ref().has_value()) {
auto n = snprintf(pos, end - pos, " C%lu", *request.casToken_ref());
pos += n;
}
if (request.newCasToken_ref().has_value()) {
auto n = snprintf(pos, end - pos, " E%lu", *request.newCasToken_ref());
pos += n;
}
if (request.vivifyOnMissTTL_ref().has_value()) {
auto n =
snprintf(pos, end - pos, " N%d", *request.vivifyOnMissTTL_ref());
pos += n;
}
if (request.refreshIfTTLLessThan_ref().has_value()) {
auto n = snprintf(
pos, end - pos, " R%d", *request.refreshIfTTLLessThan_ref());
pos += n;
}
if (request.newTTL_ref().has_value()) {
auto n = snprintf(pos, end - pos, " T%d", *request.newTTL_ref());
pos += n;
}

assert(pos < end);
addStrings(
"mg ",
request.key_ref()->fullKey(),
folly::StringPiece(printBuffer_, pos));
if (request.opaqueToken_ref().has_value()) {
addStrings(" O", *request.opaqueToken_ref());
}
addString("\r\n");
}

// Update-like ops.
void AsciiSerializedRequest::prepareImpl(const McSetRequest& request) {
keyValueRequestCommon("set ", request);
Expand Down Expand Up @@ -269,6 +347,7 @@ void AsciiSerializedRequest::prepareImpl(const McFlushAllRequest& request) {
void AsciiSerializedReply::clear() {
iovsCount_ = 0;
iobuf_.reset();
iobuf2_.reset();
auxString_.reset();
}

Expand Down Expand Up @@ -856,6 +935,83 @@ void AsciiSerializedReply::prepareImpl(McExecReply&& reply) {
}
}

// Meta commands get
void AsciiSerializedReply::prepareImpl(
McMetaCommandsGetReply&& reply,
folly::StringPiece /* key */) {
if (isHitResult(*reply.result_ref())) {
char* pos = printBuffer_;
char* end = printBuffer_ + kMaxBufferLength;

folly::StringPiece valueStr;
if (reply.value_ref().has_value() && !reply.value_ref()->empty()) {
valueStr = coalesceAndGetRange(reply.value_ref());
pos += snprintf(
pos,
end - pos,
" %zu",
valueStr.size());
}

serializeBooleanMetaCommandFlags(&pos, &end, *reply.flags_ref());

if (reply.casToken_ref().has_value()) {
pos += snprintf(pos, end - pos, " c%lu", *reply.casToken_ref());
}

if (reply.clientFlags_ref().has_value()) {
pos += snprintf(pos, end - pos, " f%lu", *reply.clientFlags_ref());
}

if (reply.itemSize_ref().has_value()) {
pos += snprintf(pos, end - pos, " s%lu", *reply.itemSize_ref());
}

if (reply.remainingTTL_ref().has_value()) {
pos += snprintf(pos, end - pos, " t%d", *reply.remainingTTL_ref());
}

if (reply.wasHitBefore_ref().has_value()) {
pos += snprintf(pos, end - pos, " h%d", *reply.wasHitBefore_ref());
}

if (reply.lastAccessTime_ref().has_value()) {
pos += snprintf(pos, end - pos, " l%d", *reply.lastAccessTime_ref());
}

assert(pos < end);
addStrings(
valueStr.empty() ? "HD" : "VA",
folly::StringPiece(printBuffer_, pos));

if (reply.opaqueToken_ref().has_value() && !reply.opaqueToken_ref()->empty()) {
auxString_ = std::move(*reply.opaqueToken_ref());
addStrings(" O", *auxString_);
}

if (reply.key_ref().has_value() && !reply.key_ref()->empty()) {
const auto keyStr = reply.key_ref()->fullKey();
assert(!iobuf_.has_value());
iobuf_ = std::move(reply.key_ref().value().raw());
addStrings(" k", keyStr);
}

addString("\r\n");

if (!valueStr.empty()) {
assert(!iobuf2_.has_value());
iobuf2_ = std::move(reply.value_ref().value());
addStrings(valueStr, "\r\n");
}
} else if (isMissResult(*reply.result_ref())) {
addString("EN\r\n");
} else if (isErrorResult(*reply.result_ref())) {
handleError(*reply.result_ref(), 0, std::string());
} else {
handleUnexpected(*reply.result_ref(), "mg");
}
}

// Shutdown
void AsciiSerializedReply::prepareImpl(McShutdownReply&& reply) {
if (*reply.result_ref() == carbon::Result::OK) {
Expand Down
21 changes: 13 additions & 8 deletions mcrouter/lib/network/AsciiSerialized.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ class AsciiSerializedRequest {
// We need at most 5 iovecs (lease-set):
// command + key + printBuffer + value + "\r\n"
static constexpr size_t kMaxIovs = 8;
// The longest print buffer we need is for lease-set/cas operations.
// It requires 2 uint64, 2 uint32 + 4 spaces + "\r\n" + '\0' = 67 chars.
static constexpr size_t kMaxBufferLength = 80;
// The longest print buffer we need is for OSS mg.
// It requires 2 uint64, 3 uint32, 11 char + 16 spaces + "\r\n" + '\0' = 105 chars.
static constexpr size_t kMaxBufferLength = 105;

struct iovec iovs_[kMaxIovs];
size_t iovsCount_{0};
Expand Down Expand Up @@ -98,6 +98,8 @@ class AsciiSerializedRequest {
void prepareImpl(const McVersionRequest& request);
// FlushAll op.
void prepareImpl(const McFlushAllRequest& request);
// Meta commands.
void prepareImpl(const McMetaCommandsGetRequest& request);

// Everything else is false.
template <class Request>
Expand Down Expand Up @@ -160,18 +162,19 @@ class AsciiSerializedReply {

private:
// See comment in prepareImpl for McMetagetReply for explanation
static constexpr size_t kMaxBufferLength = 100;
static constexpr size_t kMaxBufferLength = 113;

static const size_t kMaxIovs = 16;
struct iovec iovs_[kMaxIovs];
size_t iovsCount_{0};
char printBuffer_[kMaxBufferLength];
// Used to keep alive the reply's IOBuf field (value, stats, etc.). For now,
// replies have at most one IOBuf, so we only need one here. Note that one of
// the iovs_ will point into the data managed by this IOBuf. A serialized
// reply should not set iobuf_ more than once.
// Used to keep alive the reply's IOBuf fields (value, stats, etc.). For now,
// replies have at most two IOBufs. Note that one of
// the iovs_ will point into the data managed by these IOBufs. A serialized
// reply should not set a given iobuf_ more than once.
// We also keep an auxiliary string for a similar purpose.
folly::Optional<folly::IOBuf> iobuf_;
folly::Optional<folly::IOBuf> iobuf2_;
folly::Optional<std::string> auxString_;

void addString(folly::ByteRange range);
Expand Down Expand Up @@ -225,6 +228,8 @@ class AsciiSerializedReply {
void prepareImpl(McExecReply&&);
void prepareImpl(McFlushReReply&&);
void prepareImpl(McFlushAllReply&&);
// Meta commands
void prepareImpl(McMetaCommandsGetReply&& reply, folly::StringPiece key);
// Server and client error helper
void
handleError(carbon::Result result, uint16_t errorCode, std::string&& message);
Expand Down
9 changes: 6 additions & 3 deletions mcrouter/lib/network/CarbonMessageList.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ using RequestReplyPairs = List<
Pair<McFlushReRequest, McFlushReReply>,
Pair<McFlushAllRequest, McFlushAllReply>,
Pair<McGatRequest, McGatReply>,
Pair<McGatsRequest, McGatsReply>>;
Pair<McGatsRequest, McGatsReply>,
Pair<McMetaCommandsGetRequest, McMetaCommandsGetReply>>;

using McRequestList = PairListFirstT<RequestReplyPairs>;

Expand Down Expand Up @@ -73,7 +74,8 @@ using RequestOpMapping = List<
KV<mc_op_flushre, McFlushReRequest>,
KV<mc_op_flushall, McFlushAllRequest>,
KV<mc_op_gat, McGatRequest>,
KV<mc_op_gats, McGatsRequest>>;
KV<mc_op_gats, McGatsRequest>,
KV<mc_op_meta_commands_get, McMetaCommandsGetRequest>>;

using ReplyOpMapping = List<
KV<mc_op_get, McGetReply>,
Expand All @@ -99,7 +101,8 @@ using ReplyOpMapping = List<
KV<mc_op_flushre, McFlushReReply>,
KV<mc_op_flushall, McFlushAllReply>,
KV<mc_op_gat, McGatReply>,
KV<mc_op_gats, McGatsReply>>;
KV<mc_op_gats, McGatsReply>,
KV<mc_op_meta_commands_get, McMetaCommandsGetReply>>;

/**
* Given a Request Type T and a Mapping of mc_op_t to Request Type,
Expand Down
3 changes: 3 additions & 0 deletions mcrouter/lib/network/McAsciiParser-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ void McClientAsciiParser::initializeReplyParser<McAppendRequest>();
template <>
void McClientAsciiParser::initializeReplyParser<McPrependRequest>();

template <>
void McClientAsciiParser::initializeReplyParser<McMetaCommandsGetRequest>();

template <class Request>
void McClientAsciiParser::initializeReplyParser() {
throwLogic(
Expand Down
8 changes: 6 additions & 2 deletions mcrouter/lib/network/McAsciiParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class McAsciiParserBase {
State state_{State::UNINIT};
bool negative_{false};

const char* keyPieceStart_{nullptr};
folly::IOBuf currentKey_;

// Variables used by ragel.
int savedCs_;
int errorCs_;
Expand Down Expand Up @@ -232,6 +235,9 @@ class McServerAsciiParser : public McAsciiParserBase {
void consumeStats(folly::IOBuf& buffer);
void consumeExec(folly::IOBuf& buffer);

// Meta commands.
void consumeMetaCommandsGet(folly::IOBuf& buffer);

// Flush.
void consumeFlushRe(folly::IOBuf& buffer);
void consumeFlushAll(folly::IOBuf& buffer);
Expand All @@ -240,8 +246,6 @@ class McServerAsciiParser : public McAsciiParserBase {

std::unique_ptr<detail::CallbackBase<McRequestList>> callback_;

const char* keyPieceStart_{nullptr};
folly::IOBuf currentKey_;
bool noreply_{false};

using RequestVariant = carbon::makeVariantFromList<McRequestList>;
Expand Down
Loading
Loading