mirror of
https://github.com/joyieldInc/predixy.git
synced 2025-12-24 22:46:41 +08:00
improve performance
fix scan for sentinel groups
This commit is contained in:
parent
9d86d04374
commit
ecc63e5586
@ -28,7 +28,7 @@
|
|||||||
# Auth bcd {
|
# Auth bcd {
|
||||||
# Mode admin
|
# Mode admin
|
||||||
# }
|
# }
|
||||||
#### password is "abc", the client must send command Auth bcd
|
#### password is "bcd", the client must send command Auth bcd
|
||||||
#### Mode admin, client connection can read and write and admin,
|
#### Mode admin, client connection can read and write and admin,
|
||||||
#### the CONFIG command need admin permission
|
#### the CONFIG command need admin permission
|
||||||
#### No KeyPrefix, ReadKeyPrefix, WriteKeyPrefix define, all key can be visit
|
#### No KeyPrefix, ReadKeyPrefix, WriteKeyPrefix define, all key can be visit
|
||||||
@ -47,7 +47,7 @@
|
|||||||
# ReadKeyPrefix User Stats
|
# ReadKeyPrefix User Stats
|
||||||
# WriteKeyPrefix User
|
# WriteKeyPrefix User
|
||||||
# }
|
# }
|
||||||
#### password is "cde", the client must send command Auth cde
|
#### password is "def", the client must send command Auth def
|
||||||
#### Mode read, client connection can read and write, but read and write
|
#### Mode read, client connection can read and write, but read and write
|
||||||
#### keyspace is diffrent, client can GET User.123 and also
|
#### keyspace is diffrent, client can GET User.123 and also
|
||||||
#### SET User.123 SomeValue, but SET Stats.123 will be deny
|
#### SET User.123 SomeValue, but SET Stats.123 will be deny
|
||||||
|
|||||||
@ -10,8 +10,8 @@
|
|||||||
## see latency monitor for specify server
|
## see latency monitor for specify server
|
||||||
## redis> INFO ServerLatency ServAddr [name]
|
## redis> INFO ServerLatency ServAddr [name]
|
||||||
##
|
##
|
||||||
## reset all stats info, include latency monitor
|
## reset all stats info, include latency monitor, require admin permission
|
||||||
## redis> INFO ResetStats
|
## redis> CONFIG ResetStat
|
||||||
##
|
##
|
||||||
## Examples:
|
## Examples:
|
||||||
## LatencyMonitor name {
|
## LatencyMonitor name {
|
||||||
|
|||||||
@ -198,11 +198,10 @@ void AcceptConnection::parse(Handler* h, Buffer* buf, int pos)
|
|||||||
req->set(mParser);
|
req->set(mParser);
|
||||||
h->handleRequest(req);
|
h->handleRequest(req);
|
||||||
} else {
|
} else {
|
||||||
SegmentStr<RequestParser::MaxCmdLen> cmd(mParser.cmd());
|
|
||||||
ResponsePtr res = ResponseAlloc::create();
|
ResponsePtr res = ResponseAlloc::create();
|
||||||
char err[1024];
|
char err[1024];
|
||||||
int len = snprintf(err, sizeof(err), "unknown command '%.*s'",
|
int len = snprintf(err, sizeof(err), "unknown command '%s'",
|
||||||
cmd.length(), cmd.data());
|
mParser.cmd());
|
||||||
res->setErr(err, len);
|
res->setErr(err, len);
|
||||||
h->handleResponse(nullptr, req, res);
|
h->handleResponse(nullptr, req, res);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class AcceptConnection :
|
|||||||
public Subscribe,
|
public Subscribe,
|
||||||
public ListNode<AcceptConnection, SharePtr<AcceptConnection>>,
|
public ListNode<AcceptConnection, SharePtr<AcceptConnection>>,
|
||||||
public DequeNode<AcceptConnection, SharePtr<AcceptConnection>>,
|
public DequeNode<AcceptConnection, SharePtr<AcceptConnection>>,
|
||||||
public RefCntObj<AcceptConnection>
|
public RefCntObj<AcceptConnection, AtomicInt>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef AcceptConnection Value;
|
typedef AcceptConnection Value;
|
||||||
|
|||||||
@ -122,7 +122,7 @@ thread_local T* Alloc<T, CacheSize>::Free[CacheSize];
|
|||||||
template<class T, int CacheSize>
|
template<class T, int CacheSize>
|
||||||
thread_local int Alloc<T, CacheSize>::Size = 0;
|
thread_local int Alloc<T, CacheSize>::Size = 0;
|
||||||
|
|
||||||
template<class T>
|
template<class T, class CntType = int>
|
||||||
class RefCntObj
|
class RefCntObj
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -138,6 +138,7 @@ public:
|
|||||||
}
|
}
|
||||||
void ref()
|
void ref()
|
||||||
{
|
{
|
||||||
|
FuncCallTimer();
|
||||||
++mCnt;
|
++mCnt;
|
||||||
}
|
}
|
||||||
void unref()
|
void unref()
|
||||||
@ -156,7 +157,7 @@ protected:
|
|||||||
mCnt = 0;
|
mCnt = 0;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
AtomicInt mCnt;
|
CntType mCnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|||||||
@ -192,7 +192,7 @@ public:
|
|||||||
}
|
}
|
||||||
bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return mCur.buf == mEnd.buf && mCur.pos == mEnd.pos;
|
return mBegin.buf == mEnd.buf && mBegin.pos == mEnd.pos;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
BufferPos mBegin;
|
BufferPos mBegin;
|
||||||
|
|||||||
@ -33,7 +33,7 @@ ClusterServerPool::~ClusterServerPool()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Server* ClusterServerPool::getServer(Handler* h, Request* req) const
|
Server* ClusterServerPool::getServer(Handler* h, Request* req, const String& key) const
|
||||||
{
|
{
|
||||||
FuncCallTimer();
|
FuncCallTimer();
|
||||||
switch (req->type()) {
|
switch (req->type()) {
|
||||||
@ -43,7 +43,6 @@ Server* ClusterServerPool::getServer(Handler* h, Request* req) const
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SegmentStr<Const::MaxKeyLen> key(req->key());
|
|
||||||
int i = mHash.hash(key.data(), key.length(), HashTag);
|
int i = mHash.hash(key.data(), key.length(), HashTag);
|
||||||
i &= Const::RedisClusterSlotsMask;
|
i &= Const::RedisClusterSlotsMask;
|
||||||
ServerGroup* g = mSlots[i];
|
ServerGroup* g = mSlots[i];
|
||||||
|
|||||||
@ -26,7 +26,7 @@ public:
|
|||||||
return mServPool;
|
return mServPool;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
Server* getServer(Handler* h, Request* req) const;
|
Server* getServer(Handler* h, Request* req, const String& key) const;
|
||||||
void refreshRequest(Handler* h);
|
void refreshRequest(Handler* h);
|
||||||
void handleResponse(Handler* h, ConnectConnection* s, Request* req, Response* res);
|
void handleResponse(Handler* h, ConnectConnection* s, Request* req, Response* res);
|
||||||
ServerGroup* getGroup(const String& nodeid) const
|
ServerGroup* getGroup(const String& nodeid) const
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
#include "Command.h"
|
#include "Command.h"
|
||||||
|
|
||||||
const Command Command::CmdPool[Sentinel] = {
|
const Command Command::CmdPool[Sentinel] = {
|
||||||
{None, "", 0, 0, Read},
|
{None, "", 0, MaxArgs, Read},
|
||||||
{Ping, "ping", 1, 2, Read},
|
{Ping, "ping", 1, 2, Read},
|
||||||
{PingServ, "ping", 1, 2, Inner},
|
{PingServ, "ping", 1, 2, Inner},
|
||||||
{Echo, "echo", 2, 2, Read},
|
{Echo, "echo", 2, 2, Read},
|
||||||
@ -24,7 +24,7 @@ const Command Command::CmdPool[Sentinel] = {
|
|||||||
{SentinelSlaves, "sentinel slaves", 3, 3, Inner},
|
{SentinelSlaves, "sentinel slaves", 3, 3, Inner},
|
||||||
{Cmd, "command", 1, 1, Read},
|
{Cmd, "command", 1, 1, Read},
|
||||||
{Info, "info", 1, 4, Read},
|
{Info, "info", 1, 4, Read},
|
||||||
{Config, "config", 3, 4, Admin},
|
{Config, "config", 2, 4, Admin},
|
||||||
{Cluster, "cluster", 2, 2, Inner},
|
{Cluster, "cluster", 2, 2, Inner},
|
||||||
{ClusterNodes, "cluster nodes", 2, 2, SubCmd|Inner},
|
{ClusterNodes, "cluster nodes", 2, 2, SubCmd|Inner},
|
||||||
{Asking, "asking", 1, 1, Inner},
|
{Asking, "asking", 1, 1, Inner},
|
||||||
@ -171,7 +171,6 @@ const Command Command::CmdPool[Sentinel] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Command::CommandMap Command::CmdMap;
|
Command::CommandMap Command::CmdMap;
|
||||||
|
|
||||||
void Command::init()
|
void Command::init()
|
||||||
{
|
{
|
||||||
int type = 0;
|
int type = 0;
|
||||||
|
|||||||
@ -7,7 +7,9 @@
|
|||||||
#ifndef _PREDIXY_COMMAND_H_
|
#ifndef _PREDIXY_COMMAND_H_
|
||||||
#define _PREDIXY_COMMAND_H_
|
#define _PREDIXY_COMMAND_H_
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
|
#include "HashFunc.h"
|
||||||
|
|
||||||
class Command
|
class Command
|
||||||
{
|
{
|
||||||
@ -224,6 +226,10 @@ public:
|
|||||||
{
|
{
|
||||||
return mode & MultiKeyVal;
|
return mode & MultiKeyVal;
|
||||||
}
|
}
|
||||||
|
bool isAnyMulti() const
|
||||||
|
{
|
||||||
|
return mode & (MultiKey|SMultiKey|MultiKeyVal);
|
||||||
|
}
|
||||||
static void init();
|
static void init();
|
||||||
static const Command& get(Type type)
|
static const Command& get(Type type)
|
||||||
{
|
{
|
||||||
@ -244,7 +250,15 @@ public:
|
|||||||
private:
|
private:
|
||||||
static const int MaxArgs = 100000000;
|
static const int MaxArgs = 100000000;
|
||||||
static const Command CmdPool[Sentinel];
|
static const Command CmdPool[Sentinel];
|
||||||
typedef std::map<String, const Command*, StringCaseCmp> CommandMap;
|
class H
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
size_t operator()(const String& s) const
|
||||||
|
{
|
||||||
|
return Hash::crc16(s.data(), s.length());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::unordered_map<String, const Command*, H> CommandMap;
|
||||||
static CommandMap CmdMap;
|
static CommandMap CmdMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -29,6 +29,7 @@ namespace Const
|
|||||||
static const int MaxAddrLen = 128;
|
static const int MaxAddrLen = 128;
|
||||||
static const int MaxDcLen = 32;
|
static const int MaxDcLen = 32;
|
||||||
static const int MaxIOVecLen = IOV_MAX;
|
static const int MaxIOVecLen = IOV_MAX;
|
||||||
|
static const int MaxCmdLen = 32;
|
||||||
static const int MaxKeyLen = 512;
|
static const int MaxKeyLen = 512;
|
||||||
static const int BufferAllocCacheSize = 64;
|
static const int BufferAllocCacheSize = 64;
|
||||||
static const int RequestAllocCacheSize = 32;
|
static const int RequestAllocCacheSize = 32;
|
||||||
|
|||||||
@ -218,14 +218,6 @@ void ConnectConnection::handleResponse(Handler* h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectConnection::send(Handler* h, Request* req)
|
|
||||||
{
|
|
||||||
FuncCallTimer();
|
|
||||||
mSendRequests.push_back(req);
|
|
||||||
logDebug("h %d s %s %d pend req %ld",
|
|
||||||
h->id(), peer(), fd(), req->id());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConnectConnection::close(Handler* h)
|
void ConnectConnection::close(Handler* h)
|
||||||
{
|
{
|
||||||
SendRequestList* reqs[2] = {&mSentRequests, &mSendRequests};
|
SendRequestList* reqs[2] = {&mSentRequests, &mSendRequests};
|
||||||
|
|||||||
@ -28,8 +28,11 @@ public:
|
|||||||
~ConnectConnection();
|
~ConnectConnection();
|
||||||
bool writeEvent(Handler* h);
|
bool writeEvent(Handler* h);
|
||||||
void readEvent(Handler* h);
|
void readEvent(Handler* h);
|
||||||
void send(Handler* h, Request* req);
|
|
||||||
void close(Handler* h);
|
void close(Handler* h);
|
||||||
|
void send(Handler* h, Request* req)
|
||||||
|
{
|
||||||
|
mSendRequests.push_back(req);
|
||||||
|
}
|
||||||
Server* server() const
|
Server* server() const
|
||||||
{
|
{
|
||||||
return mServ;
|
return mServ;
|
||||||
|
|||||||
@ -46,6 +46,8 @@ Handler::~Handler()
|
|||||||
|
|
||||||
void Handler::run()
|
void Handler::run()
|
||||||
{
|
{
|
||||||
|
Request::init();
|
||||||
|
Response::init();
|
||||||
auto conf = mProxy->conf();
|
auto conf = mProxy->conf();
|
||||||
refreshServerPool();
|
refreshServerPool();
|
||||||
while (!mStop) {
|
while (!mStop) {
|
||||||
@ -134,7 +136,7 @@ void Handler::postEvent()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::addPostEvent(AcceptConnection* c, int evts)
|
inline void Handler::addPostEvent(AcceptConnection* c, int evts)
|
||||||
{
|
{
|
||||||
if (!c->getPostEvent()) {
|
if (!c->getPostEvent()) {
|
||||||
mPostAcceptConns.push_back(c);
|
mPostAcceptConns.push_back(c);
|
||||||
@ -143,12 +145,12 @@ void Handler::addPostEvent(AcceptConnection* c, int evts)
|
|||||||
c->addPostEvent(evts);
|
c->addPostEvent(evts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::addPostEvent(ConnectConnection* c, int evts)
|
inline void Handler::addPostEvent(ConnectConnection* s, int evts)
|
||||||
{
|
{
|
||||||
if (!c->getPostEvent()) {
|
if (!s->getPostEvent()) {
|
||||||
mPostConnectConns.push_back(c);
|
mPostConnectConns.push_back(s);
|
||||||
}
|
}
|
||||||
c->addPostEvent(evts);
|
s->addPostEvent(evts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::postAcceptConnectionEvent()
|
void Handler::postAcceptConnectionEvent()
|
||||||
@ -353,7 +355,6 @@ void Handler::handleAcceptConnectionEvent(AcceptConnection* c, int evts)
|
|||||||
try {
|
try {
|
||||||
if (c->good() && (evts & Multiplexor::ReadEvent)) {
|
if (c->good() && (evts & Multiplexor::ReadEvent)) {
|
||||||
c->readEvent(this);
|
c->readEvent(this);
|
||||||
setAcceptConnectionActiveTime(c);
|
|
||||||
}
|
}
|
||||||
if (c->good() && (evts & Multiplexor::WriteEvent)) {
|
if (c->good() && (evts & Multiplexor::WriteEvent)) {
|
||||||
addPostEvent(c, Multiplexor::WriteEvent);
|
addPostEvent(c, Multiplexor::WriteEvent);
|
||||||
@ -483,7 +484,7 @@ void Handler::handleRequest(Request* req)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto sp = mProxy->serverPool();
|
auto sp = mProxy->serverPool();
|
||||||
Server* serv = sp->getServer(this, req);
|
Server* serv = sp->getServer(this, req, key);
|
||||||
if (!serv) {
|
if (!serv) {
|
||||||
directResponse(req, Response::NoServer);
|
directResponse(req, Response::NoServer);
|
||||||
return;
|
return;
|
||||||
@ -634,6 +635,7 @@ bool Handler::preHandleRequest(Request* req, const String& key)
|
|||||||
|
|
||||||
void Handler::postHandleRequest(Request* req, ConnectConnection* s)
|
void Handler::postHandleRequest(Request* req, ConnectConnection* s)
|
||||||
{
|
{
|
||||||
|
FuncCallTimer();
|
||||||
auto c = req->connection();
|
auto c = req->connection();
|
||||||
if (!c) {
|
if (!c) {
|
||||||
return;
|
return;
|
||||||
@ -1127,6 +1129,9 @@ void Handler::configRequest(Request* req, const String& key)
|
|||||||
configGetRequest(req);
|
configGetRequest(req);
|
||||||
} else if (key.equal("set", true)) {
|
} else if (key.equal("set", true)) {
|
||||||
configSetRequest(req);
|
configSetRequest(req);
|
||||||
|
} else if (key.equal("resetstat", true)) {
|
||||||
|
mProxy->incrStatsVer();
|
||||||
|
directResponse(req, Response::Ok);
|
||||||
} else {
|
} else {
|
||||||
directResponse(req, Response::ConfigSubCmdUnknown);
|
directResponse(req, Response::ConfigSubCmdUnknown);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,19 +45,6 @@ const char* Hash::hashTagStr(const char* buf, int& len, const char* tag)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
long Hash::hash(const char* buf, int len) const
|
|
||||||
{
|
|
||||||
switch (mType) {
|
|
||||||
case Atol:
|
|
||||||
return atol(buf, len);
|
|
||||||
case Crc16:
|
|
||||||
return crc16(buf, len);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
long Hash::atol(const char* buf, int len)
|
long Hash::atol(const char* buf, int len)
|
||||||
{
|
{
|
||||||
long v = 0;
|
long v = 0;
|
||||||
|
|||||||
@ -33,7 +33,18 @@ public:
|
|||||||
{
|
{
|
||||||
return mType;
|
return mType;
|
||||||
}
|
}
|
||||||
long hash(const char* buf, int len) const;
|
long hash(const char* buf, int len) const
|
||||||
|
{
|
||||||
|
switch (mType) {
|
||||||
|
case Atol:
|
||||||
|
return atol(buf, len);
|
||||||
|
case Crc16:
|
||||||
|
return crc16(buf, len);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
long hash(const char* buf, int len, const char* tag) const
|
long hash(const char* buf, int len, const char* tag) const
|
||||||
{
|
{
|
||||||
buf = hashTagStr(buf, len, tag);
|
buf = hashTagStr(buf, len, tag);
|
||||||
|
|||||||
@ -102,8 +102,6 @@ bool Proxy::init(int argc, char* argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
mLatencyMonitorSet.init(mConf->latencyMonitors());
|
mLatencyMonitorSet.init(mConf->latencyMonitors());
|
||||||
Request::init();
|
|
||||||
Response::init();
|
|
||||||
ListenSocket* s = new ListenSocket(mConf->bind(), SOCK_STREAM);
|
ListenSocket* s = new ListenSocket(mConf->bind(), SOCK_STREAM);
|
||||||
if (!s->setNonBlock()) {
|
if (!s->setNonBlock()) {
|
||||||
logError("proxy listener set nonblock fail:%s", StrError());
|
logError("proxy listener set nonblock fail:%s", StrError());
|
||||||
|
|||||||
@ -13,39 +13,40 @@ struct GenericRequest
|
|||||||
Request::GenericCode code;
|
Request::GenericCode code;
|
||||||
Command::Type type;
|
Command::Type type;
|
||||||
const char* content;
|
const char* content;
|
||||||
const Request* req;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static GenericRequest GenericRequests[] = {
|
static const GenericRequest GenericRequestDefs[] = {
|
||||||
{Request::Ping, Command::Ping, "*1\r\n$4\r\nping\r\n", nullptr},
|
{Request::Ping, Command::Ping, "*1\r\n$4\r\nping\r\n"},
|
||||||
{Request::PingServ, Command::PingServ, "*1\r\n$4\r\nping\r\n", nullptr},
|
{Request::PingServ, Command::PingServ, "*1\r\n$4\r\nping\r\n"},
|
||||||
{Request::ClusterNodes, Command::ClusterNodes, "*2\r\n$7\r\ncluster\r\n$5\r\nnodes\r\n", nullptr},
|
{Request::ClusterNodes, Command::ClusterNodes, "*2\r\n$7\r\ncluster\r\n$5\r\nnodes\r\n"},
|
||||||
{Request::Asking, Command::Asking, "*1\r\n$6\r\nasking\r\n", nullptr},
|
{Request::Asking, Command::Asking, "*1\r\n$6\r\nasking\r\n"},
|
||||||
{Request::Readonly, Command::Readonly, "*1\r\n$8\r\nreadonly\r\n", nullptr},
|
{Request::Readonly, Command::Readonly, "*1\r\n$8\r\nreadonly\r\n"},
|
||||||
{Request::UnwatchServ, Command::UnwatchServ, "*1\r\n$7\r\nunwatch\r\n", nullptr},
|
{Request::UnwatchServ, Command::UnwatchServ, "*1\r\n$7\r\nunwatch\r\n"},
|
||||||
{Request::DiscardServ, Command::DiscardServ, "*1\r\n$7\r\ndiscard\r\n", nullptr},
|
{Request::DiscardServ, Command::DiscardServ, "*1\r\n$7\r\ndiscard\r\n"},
|
||||||
{Request::MgetHead, Command::Mget, "*2\r\n$4\r\nmget\r\n", nullptr},
|
{Request::MgetHead, Command::Mget, "*2\r\n$4\r\nmget\r\n"},
|
||||||
{Request::MsetHead, Command::Mset, "*3\r\n$4\r\nmset\r\n", nullptr},
|
{Request::MsetHead, Command::Mset, "*3\r\n$4\r\nmset\r\n"},
|
||||||
{Request::MsetnxHead, Command::Msetnx, "*3\r\n$6\r\nmsetnx\r\n", nullptr},
|
{Request::MsetnxHead, Command::Msetnx, "*3\r\n$6\r\nmsetnx\r\n"},
|
||||||
{Request::TouchHead, Command::Touch, "*2\r\n$5\r\ntouch\r\n", nullptr},
|
{Request::TouchHead, Command::Touch, "*2\r\n$5\r\ntouch\r\n"},
|
||||||
{Request::ExistsHead, Command::Exists, "*2\r\n$6\r\nexists\r\n", nullptr},
|
{Request::ExistsHead, Command::Exists, "*2\r\n$6\r\nexists\r\n"},
|
||||||
{Request::DelHead, Command::Del, "*2\r\n$3\r\ndel\r\n", nullptr},
|
{Request::DelHead, Command::Del, "*2\r\n$3\r\ndel\r\n"},
|
||||||
{Request::UnlinkHead, Command::Unlink, "*2\r\n$6\r\nunlink\r\n", nullptr},
|
{Request::UnlinkHead, Command::Unlink, "*2\r\n$6\r\nunlink\r\n"},
|
||||||
{Request::PsubscribeHead,Command::Psubscribe, "*2\r\n$10\r\npsubscribe\r\n", nullptr},
|
{Request::PsubscribeHead,Command::Psubscribe, "*2\r\n$10\r\npsubscribe\r\n"},
|
||||||
{Request::SubscribeHead,Command::Subscribe, "*2\r\n$9\r\nsubscribe\r\n", nullptr}
|
{Request::SubscribeHead,Command::Subscribe, "*2\r\n$9\r\nsubscribe\r\n"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
thread_local static Request* GenericRequests[Request::CodeSentinel];
|
||||||
|
|
||||||
void Request::init()
|
void Request::init()
|
||||||
{
|
{
|
||||||
BufferPtr buf = BufferAlloc::create();
|
BufferPtr buf = BufferAlloc::create();
|
||||||
for (auto& r : GenericRequests) {
|
for (auto& r : GenericRequestDefs) {
|
||||||
Request* req = new Request();
|
Request* req = new Request();
|
||||||
req->mType= r.type;
|
req->mType= r.type;
|
||||||
if (buf->room() < (int)strlen(r.content)) {
|
if (buf->room() < (int)strlen(r.content)) {
|
||||||
buf = BufferAlloc::create();
|
buf = BufferAlloc::create();
|
||||||
}
|
}
|
||||||
buf = req->mReq.set(buf, r.content);
|
buf = req->mReq.set(buf, r.content);
|
||||||
r.req = req;
|
GenericRequests[r.code] = req;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +86,7 @@ Request::Request(GenericCode code):
|
|||||||
mCreateTime(Util::elapsedUSec()),
|
mCreateTime(Util::elapsedUSec()),
|
||||||
mData(nullptr)
|
mData(nullptr)
|
||||||
{
|
{
|
||||||
auto r = GenericRequests[code].req;
|
auto r = GenericRequests[code];
|
||||||
mType = r->mType;
|
mType = r->mType;
|
||||||
mReq = r->mReq;
|
mReq = r->mReq;
|
||||||
}
|
}
|
||||||
@ -110,38 +111,38 @@ void Request::set(const RequestParser& p, Request* leader)
|
|||||||
const Request* r = nullptr;
|
const Request* r = nullptr;
|
||||||
switch (mType) {
|
switch (mType) {
|
||||||
case Command::Mget:
|
case Command::Mget:
|
||||||
r = GenericRequests[MgetHead].req;
|
r = GenericRequests[MgetHead];
|
||||||
break;
|
break;
|
||||||
case Command::Mset:
|
case Command::Mset:
|
||||||
r = GenericRequests[MsetHead].req;
|
r = GenericRequests[MsetHead];
|
||||||
break;
|
break;
|
||||||
case Command::Msetnx:
|
case Command::Msetnx:
|
||||||
r = GenericRequests[MsetnxHead].req;
|
r = GenericRequests[MsetnxHead];
|
||||||
break;
|
break;
|
||||||
case Command::Touch:
|
case Command::Touch:
|
||||||
r = GenericRequests[TouchHead].req;
|
r = GenericRequests[TouchHead];
|
||||||
break;
|
break;
|
||||||
case Command::Exists:
|
case Command::Exists:
|
||||||
r = GenericRequests[ExistsHead].req;
|
r = GenericRequests[ExistsHead];
|
||||||
break;
|
break;
|
||||||
case Command::Del:
|
case Command::Del:
|
||||||
r = GenericRequests[DelHead].req;
|
r = GenericRequests[DelHead];
|
||||||
break;
|
break;
|
||||||
case Command::Unlink:
|
case Command::Unlink:
|
||||||
r = GenericRequests[UnlinkHead].req;
|
r = GenericRequests[UnlinkHead];
|
||||||
break;
|
break;
|
||||||
case Command::Psubscribe:
|
case Command::Psubscribe:
|
||||||
r = GenericRequests[PsubscribeHead].req;
|
r = GenericRequests[PsubscribeHead];
|
||||||
break;
|
break;
|
||||||
case Command::Subscribe:
|
case Command::Subscribe:
|
||||||
r = GenericRequests[SubscribeHead].req;
|
r = GenericRequests[SubscribeHead];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
//should never reach
|
//should never reach
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mHead = r->mReq;
|
mHead = r->mReq;
|
||||||
mReq = p.arg();
|
mReq = p.request();
|
||||||
mLeader = leader;
|
mLeader = leader;
|
||||||
if (leader == this) {
|
if (leader == this) {
|
||||||
if (mType == Command::Mset || mType == Command::Msetnx) {
|
if (mType == Command::Mset || mType == Command::Msetnx) {
|
||||||
|
|||||||
@ -43,7 +43,9 @@ public:
|
|||||||
DelHead,
|
DelHead,
|
||||||
UnlinkHead,
|
UnlinkHead,
|
||||||
PsubscribeHead,
|
PsubscribeHead,
|
||||||
SubscribeHead
|
SubscribeHead,
|
||||||
|
|
||||||
|
CodeSentinel
|
||||||
};
|
};
|
||||||
static void init();
|
static void init();
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -21,8 +21,6 @@ void RequestParser::reset()
|
|||||||
mType = Command::None;
|
mType = Command::None;
|
||||||
mCommand = nullptr;
|
mCommand = nullptr;
|
||||||
mReq.clear();
|
mReq.clear();
|
||||||
mCmd.clear();
|
|
||||||
mArg.clear();
|
|
||||||
mKey.clear();
|
mKey.clear();
|
||||||
mStatus = Normal;
|
mStatus = Normal;
|
||||||
mState = Idle;
|
mState = Idle;
|
||||||
@ -34,23 +32,31 @@ void RequestParser::reset()
|
|||||||
mByteCnt = 0;
|
mByteCnt = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RequestParser::isKey(bool split) const
|
inline bool RequestParser::isKey(bool split) const
|
||||||
{
|
{
|
||||||
if (mCommand) {
|
switch (mCommand->mode & Command::KeyMask) {
|
||||||
switch (mCommand->mode & Command::KeyMask) {
|
case Command::NoKey:
|
||||||
case Command::NoKey:
|
return false;
|
||||||
return false;
|
case Command::MultiKey:
|
||||||
case Command::MultiKey:
|
return split ? mArgCnt > 0 : mArgCnt == 1;
|
||||||
return split ? mArgCnt > 0 : mArgCnt == 1;
|
case Command::SMultiKey:
|
||||||
case Command::SMultiKey:
|
return mArgCnt > 0;
|
||||||
return mArgCnt > 0;
|
case Command::MultiKeyVal:
|
||||||
case Command::MultiKeyVal:
|
return split ? (mArgCnt & 1) : mArgCnt == 1;
|
||||||
return split ? (mArgCnt & 1) : mArgCnt == 1;
|
case Command::KeyAt3:
|
||||||
case Command::KeyAt3:
|
return mArgCnt == 3;
|
||||||
return mArgCnt == 3;
|
default:
|
||||||
default:
|
return mArgCnt == 1;
|
||||||
return mArgCnt == 1;
|
}
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool RequestParser::isSplit(bool split) const
|
||||||
|
{
|
||||||
|
if (mCommand->mode & (Command::MultiKey|Command::MultiKeyVal)) {
|
||||||
|
return split && mStatus == Normal && isKey(true);
|
||||||
|
} else if (mCommand->mode & Command::SMultiKey) {
|
||||||
|
return mStatus == Normal;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -88,16 +94,21 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
|
|||||||
} else if (!isspace(ch)) {
|
} else if (!isspace(ch)) {
|
||||||
mReq.begin().buf = buf;
|
mReq.begin().buf = buf;
|
||||||
mReq.begin().pos = pos;
|
mReq.begin().pos = pos;
|
||||||
mCmd.begin() = mReq.begin();
|
mCmd[0] = tolower(ch);
|
||||||
|
mArgLen = 1;
|
||||||
mState = InlineCmd;
|
mState = InlineCmd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineCmd:
|
case InlineCmd:
|
||||||
if (isspace(ch)) {
|
if (isspace(ch)) {
|
||||||
mCmd.end().buf = buf;
|
mCmd[mArgLen < Const::MaxCmdLen ? mArgLen : Const::MaxCmdLen - 1] = '\0';
|
||||||
mCmd.end().pos = pos;
|
|
||||||
parseCmd();
|
parseCmd();
|
||||||
mState = ch == '\r' ? InlineLF : InlineArg;
|
mState = ch == '\r' ? InlineLF : InlineArg;
|
||||||
|
} else {
|
||||||
|
if (mArgLen < Const::MaxCmdLen) {
|
||||||
|
mCmd[mArgLen] = tolower(ch);
|
||||||
|
}
|
||||||
|
++mArgLen;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case InlineArg:
|
case InlineArg:
|
||||||
@ -117,7 +128,6 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
|
|||||||
if (ch >= '0' && ch <= '9') {
|
if (ch >= '0' && ch <= '9') {
|
||||||
mArgNum = mArgNum * 10 + (ch - '0');
|
mArgNum = mArgNum * 10 + (ch - '0');
|
||||||
} else if (ch == '\r') {
|
} else if (ch == '\r') {
|
||||||
//mState = mArgNum > 0 ? ArgNumLF : Error;
|
|
||||||
mArgNum > 0 ? mState = ArgNumLF : error = __LINE__;
|
mArgNum > 0 ? mState = ArgNumLF : error = __LINE__;
|
||||||
} else {
|
} else {
|
||||||
error = __LINE__;
|
error = __LINE__;
|
||||||
@ -125,26 +135,128 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
|
|||||||
break;
|
break;
|
||||||
case ArgNumLF:
|
case ArgNumLF:
|
||||||
mArgCnt = 0;
|
mArgCnt = 0;
|
||||||
//mState = ch == '\n' ? ArgTag : Error;
|
ch == '\n' ? mState = CmdTag : error = __LINE__;
|
||||||
ch == '\n' ? mState = ArgTag : error = __LINE__;
|
|
||||||
break;
|
break;
|
||||||
case ArgTag:
|
case CmdTag:
|
||||||
mArgLen = 0;
|
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
mState = ArgLen;
|
mArgLen = 0;
|
||||||
if (isKey(split)) {
|
mState = CmdLen;
|
||||||
mArg.begin().buf = buf;
|
} else {
|
||||||
mArg.begin().pos = pos;
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CmdLen:
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
mArgLen = mArgLen * 10 + (ch - '0');
|
||||||
|
} else if (ch == '\r') {
|
||||||
|
mArgLen > 0 ? mState = CmdLenLF : error = __LINE__;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CmdLenLF:
|
||||||
|
if (ch == '\n') {
|
||||||
|
mArgBodyCnt = 0;
|
||||||
|
mState = mArgLen < Const::MaxCmdLen ? CmdBody : CmdBodyTooLong;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CmdBody:
|
||||||
|
if (mArgBodyCnt == mArgLen) {
|
||||||
|
mCmd[mArgLen] = '\0';
|
||||||
|
ch == '\r' ? mState = CmdBodyLF : error = __LINE__;
|
||||||
|
} else {
|
||||||
|
mCmd[mArgBodyCnt++] = tolower(ch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CmdBodyTooLong:
|
||||||
|
if (mArgBodyCnt == mArgLen) {
|
||||||
|
mCmd[Const::MaxCmdLen - 1] = '\0';
|
||||||
|
ch == '\r' ? mState = CmdBodyLF : error = __LINE__;
|
||||||
|
} else {
|
||||||
|
if (mArgBodyCnt < Const::MaxCmdLen) {
|
||||||
|
mCmd[mArgBodyCnt] = ch;
|
||||||
|
}
|
||||||
|
++mArgBodyCnt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CmdBodyLF:
|
||||||
|
if (ch == '\n') {
|
||||||
|
parseCmd();
|
||||||
|
if (++mArgCnt == mArgNum) {
|
||||||
|
mState = Finished;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
if (mCommand->mode & Command::KeyMask) {
|
||||||
|
mState = SArgTag;
|
||||||
|
} else {
|
||||||
|
mState = KeyTag;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = __LINE__;
|
error = __LINE__;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case KeyTag:
|
||||||
|
mArgLen = 0;
|
||||||
|
ch == '$' ? mState = KeyLen : error = __LINE__;
|
||||||
|
break;
|
||||||
|
case KeyLen:
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
mArgLen = mArgLen * 10 + (ch - '0');
|
||||||
|
} else if (ch == '\r') {
|
||||||
|
mArgLen >= 0 ? mState = KeyLenLF : error = __LINE__;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyLenLF:
|
||||||
|
if (ch == '\n') {
|
||||||
|
mArgBodyCnt = 0;
|
||||||
|
mState = KeyBody;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyBody:
|
||||||
|
if (mArgBodyCnt == 0) {
|
||||||
|
mKey.begin().buf = buf;
|
||||||
|
mKey.begin().pos = pos;
|
||||||
|
}
|
||||||
|
if (mArgBodyCnt + (end - cursor) > mArgLen) {
|
||||||
|
pos += mArgLen - mArgBodyCnt;
|
||||||
|
cursor = buf->data() + pos;
|
||||||
|
if (*cursor == '\r') {
|
||||||
|
mState = KeyBodyLF;
|
||||||
|
mKey.end().buf = buf;
|
||||||
|
mKey.end().pos = pos;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mArgBodyCnt += end - cursor;
|
||||||
|
pos = buf->length() - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KeyBodyLF:
|
||||||
|
if (ch == '\n') {
|
||||||
|
if (++mArgCnt == mArgNum) {
|
||||||
|
mState = Finished;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
mState = ArgTag;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ArgTag:
|
||||||
|
mArgLen = 0;
|
||||||
|
ch == '$' ? mState = ArgLen : error = __LINE__;
|
||||||
|
break;
|
||||||
case ArgLen:
|
case ArgLen:
|
||||||
if (ch >= '0' && ch <= '9') {
|
if (ch >= '0' && ch <= '9') {
|
||||||
mArgLen = mArgLen * 10 + (ch - '0');
|
mArgLen = mArgLen * 10 + (ch - '0');
|
||||||
} else if (ch == '\r') {
|
} else if (ch == '\r') {
|
||||||
//mState = mArgLen >= 0 ? ArgLenLF : Error;
|
|
||||||
mArgLen >= 0 ? mState = ArgLenLF : error = __LINE__;
|
mArgLen >= 0 ? mState = ArgLenLF : error = __LINE__;
|
||||||
} else {
|
} else {
|
||||||
error = __LINE__;
|
error = __LINE__;
|
||||||
@ -155,31 +267,10 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
|
|||||||
ch == '\n' ? mState = ArgBody : error = __LINE__;
|
ch == '\n' ? mState = ArgBody : error = __LINE__;
|
||||||
break;
|
break;
|
||||||
case ArgBody:
|
case ArgBody:
|
||||||
if (mArgBodyCnt == 0) {
|
|
||||||
if (mArgCnt == 0) {
|
|
||||||
mCmd.begin().buf = buf;
|
|
||||||
mCmd.begin().pos = pos;
|
|
||||||
} else if (isKey(split)) {
|
|
||||||
mKey.begin().buf = buf;
|
|
||||||
mKey.begin().pos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mArgBodyCnt + (end - cursor) > mArgLen) {
|
if (mArgBodyCnt + (end - cursor) > mArgLen) {
|
||||||
pos += mArgLen - mArgBodyCnt;
|
pos += mArgLen - mArgBodyCnt;
|
||||||
cursor = buf->data() + pos;
|
cursor = buf->data() + pos;
|
||||||
if (*cursor == '\r') {
|
*cursor == '\r' ? mState = ArgBodyLF : error = __LINE__;
|
||||||
mState = ArgBodyLF;
|
|
||||||
if (mArgCnt == 0) {
|
|
||||||
mCmd.end().buf = buf;
|
|
||||||
mCmd.end().pos = pos;
|
|
||||||
parseCmd();
|
|
||||||
} else if (isKey(split)) {
|
|
||||||
mKey.end().buf = buf;
|
|
||||||
mKey.end().pos = pos;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error = __LINE__;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mArgBodyCnt += end - cursor;
|
mArgBodyCnt += end - cursor;
|
||||||
pos = buf->length() - 1;
|
pos = buf->length() - 1;
|
||||||
@ -192,16 +283,69 @@ RequestParser::Status RequestParser::parse(Buffer* buf, int& pos, bool split)
|
|||||||
goto Done;
|
goto Done;
|
||||||
} else {
|
} else {
|
||||||
mState = ArgTag;
|
mState = ArgTag;
|
||||||
if (mArgCnt > 1 && isKey(split) && mStatus == Normal &&
|
}
|
||||||
(mCommand->mode&(Command::MultiKey|Command::SMultiKey|Command::MultiKeyVal))) {
|
} else {
|
||||||
goto Done;
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SArgTag:
|
||||||
|
mArgLen = 0;
|
||||||
|
if (ch == '$') {
|
||||||
|
mState = SArgLen;
|
||||||
|
if (isSplit(split)) {
|
||||||
|
mReq.begin().buf = buf;
|
||||||
|
mReq.begin().pos = pos;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SArgLen:
|
||||||
|
if (ch >= '0' && ch <= '9') {
|
||||||
|
mArgLen = mArgLen * 10 + (ch - '0');
|
||||||
|
} else if (ch == '\r') {
|
||||||
|
mArgLen >= 0 ? mState = SArgLenLF : error = __LINE__;
|
||||||
|
} else {
|
||||||
|
error = __LINE__;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SArgLenLF:
|
||||||
|
mArgBodyCnt = 0;
|
||||||
|
ch == '\n' ? mState = SArgBody : error = __LINE__;
|
||||||
|
break;
|
||||||
|
case SArgBody:
|
||||||
|
if (mArgBodyCnt == 0) {
|
||||||
|
if (isKey(split)) {
|
||||||
|
mKey.begin().buf = buf;
|
||||||
|
mKey.begin().pos = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mArgBodyCnt + (end - cursor) > mArgLen) {
|
||||||
|
pos += mArgLen - mArgBodyCnt;
|
||||||
|
cursor = buf->data() + pos;
|
||||||
|
if (*cursor == '\r') {
|
||||||
|
mState = SArgBodyLF;
|
||||||
|
if (isKey(split)) {
|
||||||
|
mKey.end().buf = buf;
|
||||||
|
mKey.end().pos = pos;
|
||||||
}
|
}
|
||||||
if (mArgCnt > 1 && mCommand && mStatus == Normal && split) {
|
} else {
|
||||||
if (mCommand->isMultiKey()) {
|
error = __LINE__;
|
||||||
goto Done;
|
}
|
||||||
} else if (mCommand->isMultiKeyVal() && (mArgCnt & 1)) {
|
} else {
|
||||||
goto Done;
|
mArgBodyCnt += end - cursor;
|
||||||
}
|
pos = buf->length() - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SArgBodyLF:
|
||||||
|
if (ch == '\n') {
|
||||||
|
if (++mArgCnt == mArgNum) {
|
||||||
|
mState = Finished;
|
||||||
|
goto Done;
|
||||||
|
} else {
|
||||||
|
mState = SArgTag;
|
||||||
|
if (isSplit(split)) {
|
||||||
|
goto Done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -230,8 +374,6 @@ Done:
|
|||||||
mReq.end().buf = buf;
|
mReq.end().buf = buf;
|
||||||
mReq.end().pos = ++pos;
|
mReq.end().pos = ++pos;
|
||||||
mReq.rewind();
|
mReq.rewind();
|
||||||
mArg.end() = mReq.end();
|
|
||||||
mArg.rewind();
|
|
||||||
if (mState == Finished) {
|
if (mState == Finished) {
|
||||||
return mStatus == Normal ? Complete : mStatus;
|
return mStatus == Normal ? Complete : mStatus;
|
||||||
} else {
|
} else {
|
||||||
@ -242,19 +384,18 @@ Done:
|
|||||||
void RequestParser::parseCmd()
|
void RequestParser::parseCmd()
|
||||||
{
|
{
|
||||||
FuncCallTimer();
|
FuncCallTimer();
|
||||||
SegmentStr<MaxCmdLen> cmd(mCmd);
|
if (mArgLen >= Const::MaxCmdLen) {
|
||||||
if (!cmd.complete()) {
|
|
||||||
mStatus = CmdError;
|
mStatus = CmdError;
|
||||||
mType = Command::None;
|
mType = Command::None;
|
||||||
logNotice("unknown request cmd too long:%.*s...",
|
logNotice("unknown request cmd too long:%s...", mCmd);
|
||||||
cmd.length(), cmd.data());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto c = Command::find(cmd);
|
auto c = Command::find(mCmd);
|
||||||
if (!c) {
|
if (!c) {
|
||||||
|
mCommand = &Command::get(Command::None);
|
||||||
mStatus = CmdError;
|
mStatus = CmdError;
|
||||||
mType = Command::None;
|
mType = Command::None;
|
||||||
logNotice("unknown request cmd:%.*s", cmd.length(), cmd.data());
|
logNotice("unknown request cmd:%s", mCmd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mType = c->type;
|
mType = c->type;
|
||||||
@ -269,8 +410,8 @@ void RequestParser::parseCmd()
|
|||||||
}
|
}
|
||||||
if (mArgNum < c->minArgs || mArgNum > c->maxArgs) {
|
if (mArgNum < c->minArgs || mArgNum > c->maxArgs) {
|
||||||
mStatus = ArgError;
|
mStatus = ArgError;
|
||||||
logNotice("request argument is invalid cmd %.*s argnum %d",
|
logNotice("request argument is invalid cmd %s argnum %d",
|
||||||
cmd.length(), cmd.data(), mArgNum);
|
mCmd, mArgNum);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (mType) {
|
switch (mType) {
|
||||||
@ -278,9 +419,8 @@ void RequestParser::parseCmd()
|
|||||||
case Command::Msetnx:
|
case Command::Msetnx:
|
||||||
if (!(mArgNum & 1)) {
|
if (!(mArgNum & 1)) {
|
||||||
mStatus = ArgError;
|
mStatus = ArgError;
|
||||||
logNotice("request argument is invalid cmd %.*s argnum %d",
|
logNotice("request argument is invalid cmd %s argnum %d",
|
||||||
cmd.length(), cmd.data(), mArgNum);
|
mCmd, mArgNum);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -14,7 +14,6 @@ class RequestParser
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static const int MaxAllowInvalidByteCount = 1024;
|
static const int MaxAllowInvalidByteCount = 1024;
|
||||||
static const int MaxCmdLen = 32;
|
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
Idle, // * or inline command
|
Idle, // * or inline command
|
||||||
@ -24,11 +23,27 @@ public:
|
|||||||
InlineArg,
|
InlineArg,
|
||||||
ArgNum, // 2
|
ArgNum, // 2
|
||||||
ArgNumLF, // \r\n
|
ArgNumLF, // \r\n
|
||||||
|
CmdTag,
|
||||||
|
CmdLen,
|
||||||
|
CmdLenLF,
|
||||||
|
CmdBody,
|
||||||
|
CmdBodyTooLong,
|
||||||
|
CmdBodyLF,
|
||||||
|
KeyTag,
|
||||||
|
KeyLen,
|
||||||
|
KeyLenLF,
|
||||||
|
KeyBody,
|
||||||
|
KeyBodyLF,
|
||||||
ArgTag, // $ $
|
ArgTag, // $ $
|
||||||
ArgLen, // 3 5
|
ArgLen, // 3 5
|
||||||
ArgLenLF, // \r\n \r\n
|
ArgLenLF, // \r\n \r\n
|
||||||
ArgBody, // get hello
|
ArgBody, // get hello
|
||||||
ArgBodyLF, // \r\n \r\n
|
ArgBodyLF, // \r\n \r\n
|
||||||
|
SArgTag, // $ $
|
||||||
|
SArgLen, // 3 5
|
||||||
|
SArgLenLF, // \r\n \r\n
|
||||||
|
SArgBody, // get hello
|
||||||
|
SArgBodyLF, // \r\n \r\n
|
||||||
Finished,
|
Finished,
|
||||||
|
|
||||||
Error
|
Error
|
||||||
@ -76,19 +91,7 @@ public:
|
|||||||
{
|
{
|
||||||
return mArgNum;
|
return mArgNum;
|
||||||
}
|
}
|
||||||
Segment& arg()
|
const char* cmd() const
|
||||||
{
|
|
||||||
return mArg;
|
|
||||||
}
|
|
||||||
const Segment& arg() const
|
|
||||||
{
|
|
||||||
return mArg;
|
|
||||||
}
|
|
||||||
Segment& cmd()
|
|
||||||
{
|
|
||||||
return mCmd;
|
|
||||||
}
|
|
||||||
const Segment& cmd() const
|
|
||||||
{
|
{
|
||||||
return mCmd;
|
return mCmd;
|
||||||
}
|
}
|
||||||
@ -103,14 +106,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
void parseCmd();
|
void parseCmd();
|
||||||
bool isKey(bool split) const;
|
bool isKey(bool split) const;
|
||||||
|
bool isSplit(bool split) const;
|
||||||
private:
|
private:
|
||||||
Command::Type mType;
|
Command::Type mType;
|
||||||
const Command* mCommand;
|
const Command* mCommand;
|
||||||
// *2\r\n$3\r\nget\r\n$3\r\nkey\r\n
|
Segment mReq;
|
||||||
Segment mReq; // |------------------------------|
|
Segment mKey;
|
||||||
Segment mCmd; // |-|
|
char mCmd[Const::MaxCmdLen];
|
||||||
Segment mArg; // |-----------|
|
|
||||||
Segment mKey; // |-|
|
|
||||||
Status mStatus;
|
Status mStatus;
|
||||||
State mState;
|
State mState;
|
||||||
bool mInline;
|
bool mInline;
|
||||||
|
|||||||
@ -12,41 +12,42 @@ struct GenericResponse
|
|||||||
Response::GenericCode code;
|
Response::GenericCode code;
|
||||||
Reply::Type type;
|
Reply::Type type;
|
||||||
const char* content;
|
const char* content;
|
||||||
const Response* res;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static GenericResponse GenericResponses[] = {
|
static const GenericResponse GenericResponseDefs[] = {
|
||||||
{Response::Pong, Reply::Status, "+PONG\r\n", nullptr},
|
{Response::Pong, Reply::Status, "+PONG\r\n"},
|
||||||
{Response::Ok, Reply::Status, "+OK\r\n", nullptr},
|
{Response::Ok, Reply::Status, "+OK\r\n"},
|
||||||
{Response::Cmd, Reply::Array, "*0\r\n"},
|
{Response::Cmd, Reply::Array, "*0\r\n"},
|
||||||
{Response::UnknownCmd, Reply::Error, "-ERR unknown command\r\n", nullptr},
|
{Response::UnknownCmd, Reply::Error, "-ERR unknown command\r\n"},
|
||||||
{Response::ArgWrong, Reply::Error, "-ERR argument wrong\r\n", nullptr},
|
{Response::ArgWrong, Reply::Error, "-ERR argument wrong\r\n"},
|
||||||
{Response::InvalidDb, Reply::Error, "-ERR invalid DB index\r\n", nullptr},
|
{Response::InvalidDb, Reply::Error, "-ERR invalid DB index\r\n"},
|
||||||
{Response::NoPasswordSet, Reply::Error, "-ERR Client sent AUTH, but no password is set\r\n", nullptr},
|
{Response::NoPasswordSet, Reply::Error, "-ERR Client sent AUTH, but no password is set\r\n"},
|
||||||
{Response::InvalidPassword, Reply::Error, "-ERR invalid password\r\n", nullptr},
|
{Response::InvalidPassword, Reply::Error, "-ERR invalid password\r\n"},
|
||||||
{Response::Unauth, Reply::Error, "-NOAUTH Authentication required.\r\n", nullptr},
|
{Response::Unauth, Reply::Error, "-NOAUTH Authentication required.\r\n"},
|
||||||
{Response::PermissionDeny, Reply::Error, "-ERR auth permission deny\r\n", nullptr},
|
{Response::PermissionDeny, Reply::Error, "-ERR auth permission deny\r\n"},
|
||||||
{Response::NoServer, Reply::Error, "-ERR no server avaliable\r\n", nullptr},
|
{Response::NoServer, Reply::Error, "-ERR no server avaliable\r\n"},
|
||||||
{Response::NoServerConnection, Reply::Error, "-ERR no server connection avaliable\r\n", nullptr},
|
{Response::NoServerConnection, Reply::Error, "-ERR no server connection avaliable\r\n"},
|
||||||
{Response::ServerConnectionClose, Reply::Error, "-ERR server connection close\r\n", nullptr},
|
{Response::ServerConnectionClose, Reply::Error, "-ERR server connection close\r\n"},
|
||||||
{Response::DeliverRequestFail, Reply::Error, "-ERR deliver request fail\r\n", nullptr},
|
{Response::DeliverRequestFail, Reply::Error, "-ERR deliver request fail\r\n"},
|
||||||
{Response::ForbidTransaction, Reply::Error, "-ERR forbid transaction in current server pool\r\n", nullptr},
|
{Response::ForbidTransaction, Reply::Error, "-ERR forbid transaction in current server pool\r\n"},
|
||||||
{Response::ConfigSubCmdUnknown, Reply::Error, "-ERR CONFIG subcommand must be one of GET, SET\r\n", nullptr},
|
{Response::ConfigSubCmdUnknown, Reply::Error, "-ERR CONFIG subcommand must be one of GET, SET\r\n"},
|
||||||
{Response::InvalidScanCursor, Reply::Error, "-ERR invalid cursor\r\n", nullptr},
|
{Response::InvalidScanCursor, Reply::Error, "-ERR invalid cursor\r\n"},
|
||||||
{Response::ScanEnd, Reply::Array, "*2\r\n$1\r\n0\r\n*0\r\n", nullptr}
|
{Response::ScanEnd, Reply::Array, "*2\r\n$1\r\n0\r\n*0\r\n"}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
thread_local static Response* GenericResponses[Response::CodeSentinel];
|
||||||
|
|
||||||
void Response::init()
|
void Response::init()
|
||||||
{
|
{
|
||||||
BufferPtr buf = BufferAlloc::create();
|
BufferPtr buf = BufferAlloc::create();
|
||||||
for (auto& r : GenericResponses) {
|
for (auto& r : GenericResponseDefs) {
|
||||||
Response* res = new Response();
|
Response* res = new Response();
|
||||||
res->mType = r.type;
|
res->mType = r.type;
|
||||||
if (buf->room() < (int)strlen(r.content)) {
|
if (buf->room() < (int)strlen(r.content)) {
|
||||||
buf = BufferAlloc::create();
|
buf = BufferAlloc::create();
|
||||||
}
|
}
|
||||||
buf = res->mRes.set(buf, r.content);
|
buf = res->mRes.set(buf, r.content);
|
||||||
r.res = res;
|
GenericResponses[r.code] = res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +61,7 @@ Response::Response(GenericCode code):
|
|||||||
mType(Reply::None),
|
mType(Reply::None),
|
||||||
mInteger(0)
|
mInteger(0)
|
||||||
{
|
{
|
||||||
auto r = GenericResponses[code].res;
|
auto r = GenericResponses[code];
|
||||||
mType = r->mType;
|
mType = r->mType;
|
||||||
mRes = r->mRes;
|
mRes = r->mRes;
|
||||||
}
|
}
|
||||||
@ -74,7 +75,6 @@ void Response::set(const ResponseParser& p)
|
|||||||
{
|
{
|
||||||
mType = p.type();
|
mType = p.type();
|
||||||
mInteger = p.integer();
|
mInteger = p.integer();
|
||||||
mHead.clear();
|
|
||||||
mRes = p.response();
|
mRes = p.response();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,14 +83,12 @@ void Response::set(int64_t num)
|
|||||||
{
|
{
|
||||||
mType = Reply::Integer;
|
mType = Reply::Integer;
|
||||||
mInteger = num;
|
mInteger = num;
|
||||||
mHead.clear();
|
|
||||||
mRes.fset(nullptr, ":%ld\r\n", num);
|
mRes.fset(nullptr, ":%ld\r\n", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Response::setStr(const char* str, int len)
|
void Response::setStr(const char* str, int len)
|
||||||
{
|
{
|
||||||
mType = Reply::String;
|
mType = Reply::String;
|
||||||
mHead.clear();
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
}
|
}
|
||||||
@ -100,7 +98,6 @@ void Response::setStr(const char* str, int len)
|
|||||||
void Response::setErr(const char* str, int len)
|
void Response::setErr(const char* str, int len)
|
||||||
{
|
{
|
||||||
mType = Reply::Error;
|
mType = Reply::Error;
|
||||||
mHead.clear();
|
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
len = strlen(str);
|
len = strlen(str);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,9 @@ public:
|
|||||||
ForbidTransaction,
|
ForbidTransaction,
|
||||||
ConfigSubCmdUnknown,
|
ConfigSubCmdUnknown,
|
||||||
InvalidScanCursor,
|
InvalidScanCursor,
|
||||||
ScanEnd
|
ScanEnd,
|
||||||
|
|
||||||
|
CodeSentinel
|
||||||
};
|
};
|
||||||
static void init();
|
static void init();
|
||||||
static Response* create(GenericCode code, Request* req = nullptr);
|
static Response* create(GenericCode code, Request* req = nullptr);
|
||||||
|
|||||||
@ -39,11 +39,11 @@ void SentinelServerPool::init(const SentinelServerPoolConf& conf)
|
|||||||
mSentinels[i++] = s;
|
mSentinels[i++] = s;
|
||||||
mServs[s->addr()] = s;
|
mServs[s->addr()] = s;
|
||||||
}
|
}
|
||||||
mGroups.resize(conf.groups.size());
|
mGroupPool.resize(conf.groups.size());
|
||||||
i = 0;
|
i = 0;
|
||||||
for (auto& gc : conf.groups) {
|
for (auto& gc : conf.groups) {
|
||||||
ServerGroup* g = new ServerGroup(this, gc.name);
|
ServerGroup* g = new ServerGroup(this, gc.name);
|
||||||
mGroups[i++] = g;
|
mGroupPool[i++] = g;
|
||||||
for (auto& sc : gc.servers) {
|
for (auto& sc : gc.servers) {
|
||||||
Server* s = new Server(this, sc.addr, true);
|
Server* s = new Server(this, sc.addr, true);
|
||||||
s->setPassword(sc.password.empty() ? conf.password : sc.password);
|
s->setPassword(sc.password.empty() ? conf.password : sc.password);
|
||||||
@ -55,7 +55,7 @@ void SentinelServerPool::init(const SentinelServerPoolConf& conf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Server* SentinelServerPool::getServer(Handler* h, Request* req) const
|
Server* SentinelServerPool::getServer(Handler* h, Request* req, const String& key) const
|
||||||
{
|
{
|
||||||
FuncCallTimer();
|
FuncCallTimer();
|
||||||
switch (req->type()) {
|
switch (req->type()) {
|
||||||
@ -76,22 +76,21 @@ Server* SentinelServerPool::getServer(Handler* h, Request* req) const
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (mGroups.size() == 1) {
|
if (mGroupPool.size() == 1) {
|
||||||
return mGroups[0]->getServer(h, req);
|
return mGroupPool[0]->getServer(h, req);
|
||||||
} else if (mGroups.size() > 1) {
|
} else if (mGroupPool.size() > 1) {
|
||||||
switch (mDist) {
|
switch (mDist) {
|
||||||
case Distribution::Modula:
|
case Distribution::Modula:
|
||||||
{
|
{
|
||||||
SegmentStr<Const::MaxKeyLen> key(req->key());
|
|
||||||
long idx = mHash.hash(key.data(), key.length(), mHashTag);
|
long idx = mHash.hash(key.data(), key.length(), mHashTag);
|
||||||
idx %= mGroups.size();
|
idx %= mGroupPool.size();
|
||||||
return mGroups[idx]->getServer(h, req);
|
return mGroupPool[idx]->getServer(h, req);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Distribution::Random:
|
case Distribution::Random:
|
||||||
{
|
{
|
||||||
int idx = h->rand() % mGroups.size();
|
int idx = h->rand() % mGroupPool.size();
|
||||||
return mGroups[idx]->getServer(h, req);
|
return mGroupPool[idx]->getServer(h, req);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -104,7 +103,7 @@ Server* SentinelServerPool::getServer(Handler* h, Request* req) const
|
|||||||
void SentinelServerPool::refreshRequest(Handler* h)
|
void SentinelServerPool::refreshRequest(Handler* h)
|
||||||
{
|
{
|
||||||
logDebug("h %d update sentinel server pool", h->id());
|
logDebug("h %d update sentinel server pool", h->id());
|
||||||
for (auto g : mGroups) {
|
for (auto g : mGroupPool) {
|
||||||
RequestPtr req = RequestAlloc::create();
|
RequestPtr req = RequestAlloc::create();
|
||||||
req->setSentinels(g->name());
|
req->setSentinels(g->name());
|
||||||
req->setData(g);
|
req->setData(g);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ public:
|
|||||||
SentinelServerPool(Proxy* p);
|
SentinelServerPool(Proxy* p);
|
||||||
~SentinelServerPool();
|
~SentinelServerPool();
|
||||||
void init(const SentinelServerPoolConf& conf);
|
void init(const SentinelServerPoolConf& conf);
|
||||||
Server* getServer(Handler* h, Request* req) const;
|
Server* getServer(Handler* h, Request* req, const String& key) const;
|
||||||
Server* iter(int& cursor) const
|
Server* iter(int& cursor) const
|
||||||
{
|
{
|
||||||
return ServerPool::iter(mServPool, cursor);
|
return ServerPool::iter(mServPool, cursor);
|
||||||
@ -34,7 +34,6 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::vector<Server*> mSentinels;
|
std::vector<Server*> mSentinels;
|
||||||
std::vector<Server*> mServPool;
|
std::vector<Server*> mServPool;
|
||||||
std::vector<ServerGroup*> mGroups;
|
|
||||||
Distribution mDist;
|
Distribution mDist;
|
||||||
Hash mHash;
|
Hash mHash;
|
||||||
char mHashTag[2];
|
char mHashTag[2];
|
||||||
|
|||||||
@ -56,6 +56,7 @@ Server* ServerGroup::getServer(Handler* h, Request* req) const
|
|||||||
}
|
}
|
||||||
if (s->role() == Server::Master) {
|
if (s->role() == Server::Master) {
|
||||||
serv = s;
|
serv = s;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (auto dataCenter = mPool->proxy()->dataCenter()) {
|
} else if (auto dataCenter = mPool->proxy()->dataCenter()) {
|
||||||
|
|||||||
@ -78,9 +78,9 @@ public:
|
|||||||
auto it = mServs.find(addr);
|
auto it = mServs.find(addr);
|
||||||
return it == mServs.end() ? nullptr : it->second;
|
return it == mServs.end() ? nullptr : it->second;
|
||||||
}
|
}
|
||||||
Server* getServer(Handler* h, Request* req) const
|
Server* getServer(Handler* h, Request* req, const String& key) const
|
||||||
{
|
{
|
||||||
return mGetServerFunc(this, h, req);
|
return mGetServerFunc(this, h, req, key);
|
||||||
}
|
}
|
||||||
Server* iter(int& cursor) const
|
Server* iter(int& cursor) const
|
||||||
{
|
{
|
||||||
@ -92,7 +92,7 @@ public:
|
|||||||
}
|
}
|
||||||
void handleResponse(Handler* h, ConnectConnection* s, Request* req, Response* res);
|
void handleResponse(Handler* h, ConnectConnection* s, Request* req, Response* res);
|
||||||
protected:
|
protected:
|
||||||
typedef Server* (*GetServerFunc)(const ServerPool* p, Handler* h, Request* req);
|
typedef Server* (*GetServerFunc)(const ServerPool* p, Handler* h, Request* req, const String& key);
|
||||||
typedef Server* (*IterFunc)(const ServerPool* p, int& cursor);
|
typedef Server* (*IterFunc)(const ServerPool* p, int& cursor);
|
||||||
typedef void (*RefreshRequestFunc)(ServerPool* p, Handler* h);
|
typedef void (*RefreshRequestFunc)(ServerPool* p, Handler* h);
|
||||||
typedef void (*HandleResponseFunc)(ServerPool* p, Handler* h, ConnectConnection* s, Request* req, Response* res);
|
typedef void (*HandleResponseFunc)(ServerPool* p, Handler* h, ConnectConnection* s, Request* req, Response* res);
|
||||||
@ -147,9 +147,9 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
static Server* getServer(const ServerPool* p, Handler* h, Request* req)
|
static Server* getServer(const ServerPool* p, Handler* h, Request* req, const String& key)
|
||||||
{
|
{
|
||||||
return static_cast<const T*>(p)->getServer(h, req);
|
return static_cast<const T*>(p)->getServer(h, req, key);
|
||||||
}
|
}
|
||||||
static Server* iter(const ServerPool* p, int& cursor)
|
static Server* iter(const ServerPool* p, int& cursor)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -48,12 +48,12 @@ void TimerPoint::report()
|
|||||||
std::sort(points, points + cnt,
|
std::sort(points, points + cnt,
|
||||||
[](TimerPoint* p1, TimerPoint* p2)
|
[](TimerPoint* p1, TimerPoint* p2)
|
||||||
{return p1->elapsed() > p2->elapsed();});
|
{return p1->elapsed() > p2->elapsed();});
|
||||||
printf("%16s %12s %8s %s\n","Total(us)", "Count", "Avg(us)", "Point" );
|
printf("%16s %12s %8s %s\n","Total(us)", "Count", "Avg(ns)", "Point" );
|
||||||
for (i = 0; i < cnt; ++i) {
|
for (i = 0; i < cnt; ++i) {
|
||||||
auto p = points[i];
|
auto p = points[i];
|
||||||
printf("%16ld %12ld %8ld %s\n",
|
printf("%16ld %12ld %9ld %s\n",
|
||||||
p->elapsed(), p->count(),
|
p->elapsed(), p->count(),
|
||||||
p->elapsed()/p->count(), p->key());
|
p->elapsed()*1000/p->count(), p->key());
|
||||||
}
|
}
|
||||||
if (points != points0) {
|
if (points != points0) {
|
||||||
delete[] points;
|
delete[] points;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user