improve performance

fix scan for sentinel groups
This commit is contained in:
joyield 2017-07-30 15:00:51 +08:00
parent 9d86d04374
commit ecc63e5586
28 changed files with 377 additions and 225 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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);
} }

View File

@ -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;

View File

@ -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>

View File

@ -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;

View File

@ -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];

View File

@ -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

View File

@ -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;

View File

@ -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;
}; };

View File

@ -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;

View File

@ -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};

View File

@ -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;

View File

@ -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);
} }

View File

@ -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;

View File

@ -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);

View File

@ -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());

View File

@ -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) {

View File

@ -43,7 +43,9 @@ public:
DelHead, DelHead,
UnlinkHead, UnlinkHead,
PsubscribeHead, PsubscribeHead,
SubscribeHead SubscribeHead,
CodeSentinel
}; };
static void init(); static void init();
public: public:

View File

@ -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:

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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()) {

View File

@ -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)
{ {

View File

@ -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;