client Channel search bypass
Bypass the broadcast search phase and directly connect to a specific server and issue CMD_CREATE_CHANNEL. Note, due to pvAccessCPP buggyness, this can only be relied upon to connect with the unadvertised magic 'server' PV.
This commit is contained in:
+54
-22
@@ -127,7 +127,6 @@ void Channel::disconnect(const std::shared_ptr<Channel>& self)
|
||||
{
|
||||
self->state = Channel::Searching;
|
||||
self->sid = 0xdeadbeef; // spoil
|
||||
context->searchBuckets[context->currentBucket].push_back(self);
|
||||
|
||||
auto conns(connectors); // copy list
|
||||
|
||||
@@ -137,10 +136,25 @@ void Channel::disconnect(const std::shared_ptr<Channel>& self)
|
||||
conn->_onDis();
|
||||
}
|
||||
|
||||
log_debug_printf(io, "Server %s detach channel '%s' to re-search\n",
|
||||
conn ? conn->peerName.c_str() : "<disconnected>",
|
||||
self->name.c_str());
|
||||
if(forcedServer.family()==AF_UNSPEC) {
|
||||
|
||||
context->searchBuckets[context->currentBucket].push_back(self);
|
||||
|
||||
log_debug_printf(io, "Server %s detach channel '%s' to re-search\n",
|
||||
conn ? conn->peerName.c_str() : "<disconnected>",
|
||||
self->name.c_str());
|
||||
|
||||
} else { // reconnect to specific server
|
||||
// TODO: holdoff to prevent fast reconnect loop
|
||||
|
||||
self->conn = Connection::build(context, self->forcedServer);
|
||||
|
||||
self->conn->pending.push_back(self);
|
||||
self->state = Connecting;
|
||||
|
||||
self->conn->createChannels();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Connect::~Connect() {}
|
||||
@@ -186,7 +200,7 @@ std::shared_ptr<Connect> ConnectBuilder::exec()
|
||||
context->tcp_loop.dispatch([op, context]() {
|
||||
// on worker
|
||||
|
||||
op->chan = Channel::build(context, op->_name);
|
||||
op->chan = Channel::build(context, op->_name, std::string());
|
||||
|
||||
bool cur = op->_connected = op->chan->state==Channel::Active;
|
||||
if(cur && op->_onConn)
|
||||
@@ -258,12 +272,20 @@ RequestInfo::RequestInfo(uint32_t sid, uint32_t ioid, std::shared_ptr<OperationB
|
||||
,handle(handle)
|
||||
{}
|
||||
|
||||
std::shared_ptr<Channel> Channel::build(const std::shared_ptr<ContextImpl>& context, const std::string& name)
|
||||
std::shared_ptr<Channel> Channel::build(const std::shared_ptr<ContextImpl>& context,
|
||||
const std::string& name,
|
||||
const std::string& server)
|
||||
{
|
||||
SockAddr forceServer;
|
||||
decltype (context->chanByName)::key_type namekey(name, server);
|
||||
|
||||
if(!server.empty()) {
|
||||
forceServer.setAddress(server.c_str(), context->effective.tcp_port);
|
||||
}
|
||||
|
||||
std::shared_ptr<Channel> chan;
|
||||
|
||||
auto it = context->chanByName.find(name);
|
||||
auto it = context->chanByName.find(namekey);
|
||||
if(it!=context->chanByName.end()) {
|
||||
chan = it->second;
|
||||
chan->garbage = false;
|
||||
@@ -274,12 +296,25 @@ std::shared_ptr<Channel> Channel::build(const std::shared_ptr<ContextImpl>& cont
|
||||
context->nextCID++;
|
||||
|
||||
chan = std::make_shared<Channel>(context, name, context->nextCID);
|
||||
|
||||
context->chanByCID[chan->cid] = chan;
|
||||
context->chanByName[chan->name] = chan;
|
||||
context->chanByName[namekey] = chan;
|
||||
|
||||
context->searchBuckets[context->currentBucket].push_back(chan);
|
||||
if(server.empty()) {
|
||||
context->searchBuckets[context->currentBucket].push_back(chan);
|
||||
|
||||
context->poke(true);
|
||||
context->poke(true);
|
||||
|
||||
} else { // bypass search and connect so a specific server
|
||||
chan->forcedServer = forceServer;
|
||||
chan->conn = Connection::build(context, forceServer);
|
||||
|
||||
chan->conn->pending.push_back(chan);
|
||||
chan->state = Connecting;
|
||||
|
||||
chan->conn->createChannels();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return chan;
|
||||
@@ -481,7 +516,7 @@ void ContextImpl::startNS()
|
||||
// start connections to name servers
|
||||
for(auto& ns : nameServers) {
|
||||
const auto& serv = ns.first;
|
||||
connByAddr[serv] = ns.second = std::make_shared<Connection>(shared_from_this(), serv);
|
||||
ns.second = Connection::build(shared_from_this(), serv);
|
||||
ns.second->nameserver = true;
|
||||
log_debug_printf(io, "Connecting to nameserver %s\n", ns.second->peerName.c_str());
|
||||
}
|
||||
@@ -631,10 +666,7 @@ void procSearchReply(ContextImpl& self, const SockAddr& src, Buffer& M, bool ist
|
||||
chan->guid = guid;
|
||||
chan->replyAddr = serv;
|
||||
|
||||
auto it = self.connByAddr.find(serv);
|
||||
if(it==self.connByAddr.end() || !(chan->conn = it->second.lock())) {
|
||||
self.connByAddr[serv] = chan->conn = std::make_shared<Connection>(self.shared_from_this(), serv);
|
||||
}
|
||||
chan->conn = Connection::build(self.shared_from_this(), serv);
|
||||
|
||||
chan->conn->pending.push_back(chan);
|
||||
chan->state = Channel::Connecting;
|
||||
@@ -963,7 +995,7 @@ void ContextImpl::onNSCheck()
|
||||
if(ns.second && ns.second->bev) // connecting or connected
|
||||
continue;
|
||||
|
||||
connByAddr[ns.first] = ns.second = std::make_shared<Connection>(shared_from_this(), ns.first);
|
||||
ns.second = Connection::build(shared_from_this(), ns.first);
|
||||
ns.second->nameserver = true;
|
||||
log_debug_printf(io, "Reconnecting nameserver %s\n", ns.second->peerName.c_str());
|
||||
}
|
||||
@@ -980,16 +1012,16 @@ void ContextImpl::onNSCheckS(evutil_socket_t fd, short evt, void *raw)
|
||||
|
||||
void ContextImpl::cacheClean(const std::string& name)
|
||||
{
|
||||
std::set<std::string> trash;
|
||||
std::set<decltype (chanByName)::key_type> trash;
|
||||
|
||||
for(auto& pair : chanByName) {
|
||||
if(!name.empty() && pair.first!=name)
|
||||
if(!name.empty() && pair.first.first!=name)
|
||||
continue; // skip
|
||||
|
||||
if(pair.second.use_count()<=1) {
|
||||
if(!pair.second->garbage) {
|
||||
// mark for next sweep
|
||||
log_debug_printf(setup, "Chan GC mark '%s'\n", pair.first.c_str());
|
||||
log_debug_printf(setup, "Chan GC mark '%s':'%s'\n", pair.first.first.c_str(), pair.first.second.c_str());
|
||||
pair.second->garbage = true;
|
||||
|
||||
} else {
|
||||
@@ -1000,9 +1032,9 @@ void ContextImpl::cacheClean(const std::string& name)
|
||||
}
|
||||
|
||||
// explicitly break ref. loop of channel cache
|
||||
for(auto& name : trash) {
|
||||
chanByName.erase(name);
|
||||
log_debug_printf(setup, "Chan GC sweep '%s'\n", name.c_str());
|
||||
for(auto& key : trash) {
|
||||
chanByName.erase(key);
|
||||
log_debug_printf(setup, "Chan GC sweep '%s':'%s'\n", key.first.c_str(), key.second.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,16 @@ Connection::~Connection()
|
||||
cleanup();
|
||||
}
|
||||
|
||||
std::shared_ptr<Connection> Connection::build(const std::shared_ptr<ContextImpl>& context,
|
||||
const SockAddr& serv)
|
||||
{
|
||||
std::shared_ptr<Connection> ret;
|
||||
auto it = context->connByAddr.find(serv);
|
||||
if(it==context->connByAddr.end() || !(ret = it->second.lock())) {
|
||||
context->connByAddr[serv] = ret = std::make_shared<Connection>(context, serv);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Connection::createChannels()
|
||||
{
|
||||
|
||||
+6
-5
@@ -570,6 +570,7 @@ void Connection::handle_RPC() { handle_GPR(CMD_RPC); }
|
||||
static
|
||||
std::shared_ptr<Operation> gpr_setup(const std::shared_ptr<ContextImpl>& context,
|
||||
std::string name, // need to capture by value
|
||||
std::string server,
|
||||
std::shared_ptr<GPROp>&& op,
|
||||
bool syncCancel)
|
||||
{
|
||||
@@ -591,10 +592,10 @@ std::shared_ptr<Operation> gpr_setup(const std::shared_ptr<ContextImpl>& context
|
||||
}, std::move(temp)));
|
||||
});
|
||||
|
||||
context->tcp_loop.dispatch([internal, context, name]() {
|
||||
context->tcp_loop.dispatch([internal, context, name, server]() {
|
||||
// on worker
|
||||
|
||||
internal->chan = Channel::build(context, name);
|
||||
internal->chan = Channel::build(context, name, server);
|
||||
|
||||
internal->chan->pending.push_back(internal);
|
||||
internal->chan->createOperations();
|
||||
@@ -616,7 +617,7 @@ std::shared_ptr<Operation> GetBuilder::_exec_get()
|
||||
op->autoExec = _autoexec;
|
||||
op->pvRequest = _buildReq();
|
||||
|
||||
return gpr_setup(context, _name, std::move(op), _syncCancel);
|
||||
return gpr_setup(context, _name, _server, std::move(op), _syncCancel);
|
||||
}
|
||||
|
||||
std::shared_ptr<Operation> PutBuilder::exec()
|
||||
@@ -646,7 +647,7 @@ std::shared_ptr<Operation> PutBuilder::exec()
|
||||
op->autoExec = _autoexec;
|
||||
op->pvRequest = _buildReq();
|
||||
|
||||
return gpr_setup(context, _name, std::move(op), _syncCancel);
|
||||
return gpr_setup(context, _name, _server, std::move(op), _syncCancel);
|
||||
}
|
||||
|
||||
std::shared_ptr<Operation> RPCBuilder::exec()
|
||||
@@ -671,7 +672,7 @@ std::shared_ptr<Operation> RPCBuilder::exec()
|
||||
op->autoExec = _autoexec;
|
||||
op->pvRequest = _buildReq();
|
||||
|
||||
return gpr_setup(context, _name, std::move(op), _syncCancel);
|
||||
return gpr_setup(context, _name, _server, std::move(op), _syncCancel);
|
||||
}
|
||||
|
||||
} // namespace client
|
||||
|
||||
+12
-2
@@ -96,6 +96,10 @@ struct Connection : public ConnBase, public std::enable_shared_from_this<Connect
|
||||
Connection(const std::shared_ptr<ContextImpl>& context, const SockAddr &peerAddr);
|
||||
virtual ~Connection();
|
||||
|
||||
static
|
||||
std::shared_ptr<Connection> build(const std::shared_ptr<ContextImpl>& context,
|
||||
const SockAddr& serv);
|
||||
|
||||
void createChannels();
|
||||
|
||||
void sendDestroyRequest(uint32_t sid, uint32_t ioid);
|
||||
@@ -166,6 +170,9 @@ struct Channel {
|
||||
std::shared_ptr<Connection> conn;
|
||||
uint32_t sid = 0u;
|
||||
|
||||
// channel created with .server() to bypass normal search process
|
||||
SockAddr forcedServer;
|
||||
|
||||
// when state==Searching, number of repeatitions
|
||||
size_t nSearch = 0u;
|
||||
|
||||
@@ -191,7 +198,9 @@ struct Channel {
|
||||
void disconnect(const std::shared_ptr<Channel>& self);
|
||||
|
||||
static
|
||||
std::shared_ptr<Channel> build(const std::shared_ptr<ContextImpl>& context, const std::string &name);
|
||||
std::shared_ptr<Channel> build(const std::shared_ptr<ContextImpl>& context,
|
||||
const std::string& name,
|
||||
const std::string& server);
|
||||
};
|
||||
|
||||
struct ContextImpl : public std::enable_shared_from_this<ContextImpl>
|
||||
@@ -233,7 +242,8 @@ struct ContextImpl : public std::enable_shared_from_this<ContextImpl>
|
||||
std::map<uint32_t, std::weak_ptr<Channel>> chanByCID;
|
||||
// strong ref. loop through Channel::context
|
||||
// explicitly broken by Context::close(), Context::cacheClear, or ContextImpl::cacheClean()
|
||||
std::map<std::string, std::shared_ptr<Channel>> chanByName;
|
||||
// chanByName key'd by (pv, forceServer)
|
||||
std::map<std::pair<std::string, std::string>, std::shared_ptr<Channel>> chanByName;
|
||||
|
||||
std::map<SockAddr, std::weak_ptr<Connection>> connByAddr;
|
||||
|
||||
|
||||
@@ -213,10 +213,11 @@ std::shared_ptr<Operation> GetBuilder::_exec_info()
|
||||
});
|
||||
|
||||
auto name(std::move(_name));
|
||||
context->tcp_loop.dispatch([op, context, name]() {
|
||||
auto server(std::move(_server));
|
||||
context->tcp_loop.dispatch([op, context, name, server]() {
|
||||
// on worker
|
||||
|
||||
op->chan = Channel::build(context, name);
|
||||
op->chan = Channel::build(context, name, server);
|
||||
|
||||
op->chan->pending.push_back(op);
|
||||
op->chan->createOperations();
|
||||
|
||||
+3
-2
@@ -642,10 +642,11 @@ std::shared_ptr<Subscription> MonitorBuilder::exec()
|
||||
});
|
||||
|
||||
auto name(std::move(_name));
|
||||
context->tcp_loop.dispatch([op, context, name]() {
|
||||
auto server(std::move(_server));
|
||||
context->tcp_loop.dispatch([op, context, name, server]() {
|
||||
// on worker
|
||||
|
||||
op->chan = Channel::build(context, name);
|
||||
op->chan = Channel::build(context, name, server);
|
||||
|
||||
op->chan->pending.push_back(op);
|
||||
op->chan->createOperations();
|
||||
|
||||
Reference in New Issue
Block a user