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) { : ReplyBuilder(owner->protocol(), stream), owner_(owner) {
} }
Protocol ConnectionContext::protocol() const {
return owner_->protocol();
}
} // namespace dfly } // namespace dfly

View file

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

View file

@ -146,6 +146,9 @@ void Service::DispatchMC(const MemcacheParser::Command& cmd, std::string_view va
strcpy(cmd_name, "SET"); strcpy(cmd_name, "SET");
strcpy(set_opt, "NX"); strcpy(set_opt, "NX");
break; break;
case MemcacheParser::GET:
strcpy(cmd_name, "GET");
break;
default: default:
cntx->SendMCClientError("bad command line format"); cntx->SendMCClientError("bad command line format");
return; return;
@ -168,7 +171,6 @@ void Service::DispatchMC(const MemcacheParser::Command& cmd, std::string_view va
DispatchCommand(arg_list, cntx); DispatchCommand(arg_list, cntx);
} }
void Service::RegisterHttp(HttpListenerBase* listener) { void Service::RegisterHttp(HttpListenerBase* listener) {
CHECK_NOTNULL(listener); CHECK_NOTNULL(listener);
} }
@ -191,8 +193,8 @@ void Service::Ping(CmdArgList args, ConnectionContext* cntx) {
void Service::Set(CmdArgList args, ConnectionContext* cntx) { void Service::Set(CmdArgList args, ConnectionContext* cntx) {
set_qps.Inc(); set_qps.Inc();
std::string_view key = ArgS(args, 1); string_view key = ArgS(args, 1);
std::string_view val = ArgS(args, 2); string_view val = ArgS(args, 2);
VLOG(2) << "Set " << key << " " << val; VLOG(2) << "Set " << key << " " << val;
ShardId sid = Shard(key, shard_count()); ShardId sid = Shard(key, shard_count());
@ -205,6 +207,29 @@ void Service::Set(CmdArgList args, ConnectionContext* cntx) {
cntx->SendStored(); 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 Service::GetVarzStats() {
VarzValue::Map res; VarzValue::Map res;
@ -227,7 +252,8 @@ void Service::RegisterCommands() {
using CI = CommandId; using CI = CommandId;
registry_ << CI{"PING", CO::STALE | CO::FAST, -1, 0, 0, 0}.HFUNC(Ping) 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 } // namespace dfly

View file

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

View file

@ -56,7 +56,6 @@ void RespSerializer::SendSimpleString(std::string_view str) {
Send(v, ABSL_ARRAYSIZE(v)); Send(v, ABSL_ARRAYSIZE(v));
} }
void RespSerializer::SendBulkString(std::string_view str) { void RespSerializer::SendBulkString(std::string_view str) {
char tmp[absl::numbers_internal::kFastToBufferSize + 3]; char tmp[absl::numbers_internal::kFastToBufferSize + 3];
tmp[0] = '$'; // Format length tmp[0] = '$'; // Format length
@ -97,7 +96,6 @@ void ReplyBuilder::SendStored() {
} }
} }
void ReplyBuilder::SendMCClientError(string_view str) { void ReplyBuilder::SendMCClientError(string_view str) {
DCHECK(protocol_ == Protocol::MEMCACHE); DCHECK(protocol_ == Protocol::MEMCACHE);
@ -105,6 +103,12 @@ void ReplyBuilder::SendMCClientError(string_view str) {
serializer_->Send(v, ABSL_ARRAYSIZE(v)); serializer_->Send(v, ABSL_ARRAYSIZE(v));
} }
void ReplyBuilder::EndMultilineReply() {
if (protocol_ == Protocol::MEMCACHE) {
serializer_->SendDirect("END\r\n");
}
}
void ReplyBuilder::SendError(string_view str) { void ReplyBuilder::SendError(string_view str) {
DCHECK(protocol_ == Protocol::REDIS); 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 } // namespace dfly

View file

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