Add basic GET command for both mc and redis

This commit is contained in:
Roman Gershman 2021-11-23 17:49:40 +02:00
parent 5ebbfa5a64
commit 9a6e8e31be
6 changed files with 64 additions and 6 deletions

View file

@ -12,4 +12,8 @@ ConnectionContext::ConnectionContext(::io::Sink* stream, Connection* owner)
: ReplyBuilder(owner->protocol(), stream), owner_(owner) {
}
Protocol ConnectionContext::protocol() const {
return owner_->protocol();
}
} // namespace dfly

View file

@ -24,6 +24,8 @@ class ConnectionContext : public ReplyBuilder {
return owner_;
}
Protocol protocol() const;
private:
Connection* owner_;
};

View file

@ -146,6 +146,9 @@ void Service::DispatchMC(const MemcacheParser::Command& cmd, std::string_view va
strcpy(cmd_name, "SET");
strcpy(set_opt, "NX");
break;
case MemcacheParser::GET:
strcpy(cmd_name, "GET");
break;
default:
cntx->SendMCClientError("bad command line format");
return;
@ -168,7 +171,6 @@ void Service::DispatchMC(const MemcacheParser::Command& cmd, std::string_view va
DispatchCommand(arg_list, cntx);
}
void Service::RegisterHttp(HttpListenerBase* listener) {
CHECK_NOTNULL(listener);
}
@ -191,8 +193,8 @@ void Service::Ping(CmdArgList args, ConnectionContext* cntx) {
void Service::Set(CmdArgList args, ConnectionContext* cntx) {
set_qps.Inc();
std::string_view key = ArgS(args, 1);
std::string_view val = ArgS(args, 2);
string_view key = ArgS(args, 1);
string_view val = ArgS(args, 2);
VLOG(2) << "Set " << key << " " << val;
ShardId sid = Shard(key, shard_count());
@ -205,6 +207,29 @@ void Service::Set(CmdArgList args, ConnectionContext* cntx) {
cntx->SendStored();
}
void Service::Get(CmdArgList args, ConnectionContext* cntx) {
string_view key = ArgS(args, 1);
ShardId sid = Shard(key, shard_count());
OpResult<string> opres;
shard_set_.Await(sid, [&] {
EngineShard* es = EngineShard::tlocal();
OpResult<DbSlice::MainIterator> res = es->db_slice.Find(0, key);
if (res) {
opres.value() = res.value()->second;
} else {
opres = res.status();
}
});
if (opres) {
cntx->SendGetReply(key, 0, opres.value());
} else if (opres.status() == OpStatus::KEY_NOTFOUND) {
cntx->SendGetNotFound();
}
cntx->EndMultilineReply();
}
VarzValue::Map Service::GetVarzStats() {
VarzValue::Map res;
@ -227,7 +252,8 @@ void Service::RegisterCommands() {
using CI = CommandId;
registry_ << CI{"PING", CO::STALE | CO::FAST, -1, 0, 0, 0}.HFUNC(Ping)
<< CI{"SET", CO::WRITE | CO::DENYOOM, -3, 1, 1, 1}.HFUNC(Set);
<< CI{"SET", CO::WRITE | CO::DENYOOM, -3, 1, 1, 1}.HFUNC(Set)
<< CI{"GET", CO::READONLY | CO::FAST, 2, 1, 1, 1}.HFUNC(Get);
}
} // namespace dfly

View file

@ -48,6 +48,7 @@ class Service {
private:
void Ping(CmdArgList args, ConnectionContext* cntx);
void Set(CmdArgList args, ConnectionContext* cntx);
void Get(CmdArgList args, ConnectionContext* cntx);
void RegisterCommands();

View file

@ -56,7 +56,6 @@ void RespSerializer::SendSimpleString(std::string_view str) {
Send(v, ABSL_ARRAYSIZE(v));
}
void RespSerializer::SendBulkString(std::string_view str) {
char tmp[absl::numbers_internal::kFastToBufferSize + 3];
tmp[0] = '$'; // Format length
@ -97,7 +96,6 @@ void ReplyBuilder::SendStored() {
}
}
void ReplyBuilder::SendMCClientError(string_view str) {
DCHECK(protocol_ == Protocol::MEMCACHE);
@ -105,6 +103,12 @@ void ReplyBuilder::SendMCClientError(string_view str) {
serializer_->Send(v, ABSL_ARRAYSIZE(v));
}
void ReplyBuilder::EndMultilineReply() {
if (protocol_ == Protocol::MEMCACHE) {
serializer_->SendDirect("END\r\n");
}
}
void ReplyBuilder::SendError(string_view str) {
DCHECK(protocol_ == Protocol::REDIS);
@ -134,4 +138,20 @@ void ReplyBuilder::SendError(OpStatus status) {
}
}
void ReplyBuilder::SendGetReply(std::string_view key, uint32_t flags, std::string_view value) {
if (protocol_ == Protocol::REDIS) {
as_resp()->SendBulkString(value);
} else {
string first = absl::StrCat("VALUE ", key, " ", flags, " ", value.size(), "\r\n");
iovec v[] = {IoVec(first), IoVec(value), IoVec(kCRLF)};
serializer_->Send(v, ABSL_ARRAYSIZE(v));
}
}
void ReplyBuilder::SendGetNotFound() {
if (protocol_ == Protocol::REDIS) {
as_resp()->SendNull();
}
}
} // namespace dfly

View file

@ -76,6 +76,7 @@ class ReplyBuilder {
}
void SendMCClientError(std::string_view str);
void EndMultilineReply();
void SendSimpleRespString(std::string_view str) {
as_resp()->SendSimpleString(str);
@ -84,6 +85,10 @@ class ReplyBuilder {
void SendRespBlob(std::string_view str) {
as_resp()->SendDirect(str);
}
void SendGetReply(std::string_view key, uint32_t flags, std::string_view value);
void SendGetNotFound();
private:
RespSerializer* as_resp() {
return static_cast<RespSerializer*>(serializer_.get());