server: rework cleanup of connection, channel, and operation

This commit is contained in:
Michael Davidsaver
2023-02-21 11:57:25 -08:00
parent 9c546f0ed4
commit fedbec649b
5 changed files with 104 additions and 95 deletions
+27 -44
View File
@@ -36,6 +36,30 @@ ServerChan::~ServerChan() {
assert(!onClose);
}
/* reached from:
* 1. connection close
* 2. DESTROY_CHANNEL
* 3. local user calls ServerChannelControl::close()
*/
void ServerChan::cleanup()
{
if(state==ServerChan::Destroy)
return;
state = ServerChan::Destroy;
{
auto ops(std::move(opByIOID));
for(auto& op : ops) {
// removes from conn->opByIOID
op.second->cleanup();
}
}
auto fn(std::move(onClose));
if(fn)
fn("");
}
ServerChannelControl::ServerChannelControl(const std::shared_ptr<ServerConn> &conn, const std::shared_ptr<ServerChan>& channel)
:server::ChannelControl(channel->name, conn->cred, None)
,server(conn->iface->server->internal_self)
@@ -104,45 +128,6 @@ void ServerChannelControl::onClose(std::function<void(const std::string&)>&& fn)
});
}
static
void ServerChannel_shutdown(const std::shared_ptr<ServerChan>& chan)
{
if(chan->state==ServerChan::Destroy)
return;
chan->state = ServerChan::Destroy;
if(auto conn = chan->conn.lock()) {
conn->chanBySID.erase(chan->sid);
for(auto& pair : chan->opByIOID) {
auto op = pair.second;
if(op->state==ServerOp::Dead)
continue;
if(op->state==ServerOp::Executing && op->onCancel)
op->onCancel();
op->state = ServerOp::Dead;
if(op->onClose) {
auto fn(std::move(op->onClose));
fn("");
}
conn->opByIOID.erase(op->ioid);
}
}
chan->opByIOID.clear();
if(chan->onClose) {
auto fn(std::move(chan->onClose));
fn("");
}
}
void ServerChannelControl::close()
{
// fail soft if server stopped, or channel/connection already closed
@@ -167,7 +152,8 @@ void ServerChannelControl::close()
conn->statTx += 16u;
ch->statTx += 16u;
}
ServerChannel_shutdown(ch);
ch->cleanup();
});
}
@@ -407,10 +393,7 @@ void ServerConn::handle_DESTROY_CHANNEL()
unsigned(sid), unsigned(chan->cid), unsigned(cid), chan->name.c_str());
}
ServerChannel_shutdown(chan);
assert(chan.use_count()==1); // we only take transient refs on this thread
// ServerChannel is delete'd
chan->cleanup();
{
auto tx = bufferevent_get_output(bev.get());