wsd: terminate DocBrokers asynchronously

Remove locks and replace with isCorrectThread
assertions instead.

Crash recovery still needs some work, but
otherwise tests are clean (91/94 pass).

Change-Id: I9ac3e21854447d19a8e6106487dfd8be00fcf5ef
This commit is contained in:
Ashod Nakashian 2017-03-29 22:50:29 -04:00
parent 00f8232652
commit 7d3f5c0d2b
4 changed files with 26 additions and 31 deletions

View file

@ -611,8 +611,7 @@ bool ClientSession::handleKitToClientMessage(const char* buffer, const int lengt
docBroker->removeSession(getId());
// Now terminate.
auto lock = docBroker->getLock();
docBroker->terminateChild(lock, "", true);
docBroker->stop();
}
return true;
@ -731,6 +730,7 @@ void ClientSession::onDisconnect()
const auto docBroker = getDocumentBroker();
LOG_CHECK_RET(docBroker && "Null DocumentBroker instance", );
assert(docBroker->isCorrectThread());
const auto docKey = docBroker->getDocKey();
try

View file

@ -259,6 +259,10 @@ void DocumentBroker::pollThread()
}
}
// Terminate properly while we can.
//TODO: pass some sensible reason.
terminateChild("", false);
// Flush socket data.
const int flushTimeoutMs = POLL_TIMEOUT_MS * 2; // ~1000ms
const auto flushStartTime = std::chrono::steady_clock::now();
@ -272,9 +276,6 @@ void DocumentBroker::pollThread()
_poll->poll(std::min(flushTimeoutMs - elapsedMs, POLL_TIMEOUT_MS / 5));
}
// Terminate properly while we can.
auto lock = getLock();
terminateChild(lock, "", false);
LOG_INF("Finished docBroker polling thread for docKey [" << _docKey << "].");
}
@ -501,6 +502,8 @@ bool DocumentBroker::load(const std::shared_ptr<ClientSession>& session, const s
bool DocumentBroker::saveToStorage(const std::string& sessionId,
bool success, const std::string& result)
{
assert(isCorrectThread());
const bool res = saveToStorageInternal(sessionId, success, result);
// If marked to destroy, then this was the last session.
@ -537,8 +540,6 @@ bool DocumentBroker::saveToStorageInternal(const std::string& sessionId,
return true;
}
std::unique_lock<std::mutex> lock(_mutex);
const auto it = _sessions.find(sessionId);
if (it == _sessions.end())
{
@ -805,7 +806,7 @@ size_t DocumentBroker::addSession(const std::shared_ptr<ClientSession>& session)
size_t DocumentBroker::removeSession(const std::string& id, bool destroyIfLast)
{
auto guard = getLock();
assert(isCorrectThread());
if (destroyIfLast)
destroyIfLastEditor(id);
@ -828,6 +829,7 @@ size_t DocumentBroker::removeSession(const std::string& id, bool destroyIfLast)
size_t DocumentBroker::removeSessionInternal(const std::string& id)
{
assert(isCorrectThread());
try
{
Admin::instance().rmDoc(_docKey, id);
@ -1139,7 +1141,7 @@ void DocumentBroker::handleTileCombinedResponse(const std::vector<char>& payload
void DocumentBroker::destroyIfLastEditor(const std::string& id)
{
Util::assertIsLocked(_mutex);
assert(isCorrectThread());
const auto currentSession = _sessions.find(id);
if (currentSession == _sessions.end())
@ -1275,10 +1277,9 @@ void DocumentBroker::childSocketTerminated()
}
}
void DocumentBroker::terminateChild(std::unique_lock<std::mutex>& lock, const std::string& closeReason, const bool rude)
void DocumentBroker::terminateChild(const std::string& closeReason, const bool rude)
{
Util::assertIsLocked(_mutex);
Util::assertIsLocked(lock);
assert(isCorrectThread());
LOG_INF("Terminating doc [" << _docKey << "].");
@ -1309,26 +1310,20 @@ void DocumentBroker::terminateChild(std::unique_lock<std::mutex>& lock, const st
_childProcess->stop();
}
// Release the lock and wait for the thread to finish.
lock.unlock();
_childProcess->close(rude);
}
// Stop the polling thread.
_poll->stop();
_stop = true;
// Trigger cleanup.
LOOLWSD::triggerChildAndDocHousekeeping();
}
void DocumentBroker::closeDocument(const std::string& reason)
{
auto lock = getLock();
assert(isCorrectThread());
LOG_DBG("Closing DocumentBroker for docKey [" << _docKey << "] with reason: " << reason);
terminateChild(lock, reason, true);
terminateChild(reason, true);
}
void DocumentBroker::updateLastActivityTime()

View file

@ -224,6 +224,10 @@ public:
/// Start processing events
void startThread();
/// Flag for termination.
//TODO: Take reason to broadcast to clients.
void stop() { _stop = true; }
/// Loads a document from the public URI into the jail.
bool load(const std::shared_ptr<ClientSession>& session, const std::string& jailId);
bool isLoaded() const { return _isLoaded; }
@ -319,13 +323,6 @@ public:
/// or upon failing to process an incoming message.
void childSocketTerminated();
/// This gracefully terminates the connection
/// with the child and cleans up ChildProcess etc.
/// We must be called under lock and it must be
/// passed to us so we unlock before waiting on
/// the ChildProcess thread, which can take our lock.
void terminateChild(std::unique_lock<std::mutex>& lock, const std::string& closeReason, const bool rude);
/// Get the PID of the associated child process
Poco::Process::PID getPid() const { return _childProcess->getPid(); }
@ -341,6 +338,10 @@ public:
}
private:
/// This gracefully terminates the connection
/// with the child and cleans up ChildProcess etc.
void terminateChild(const std::string& closeReason, const bool rude);
/// Sends the .uno:Save command to LoKit.
bool sendUnoSave(const bool dontSaveIfUnmodified);

View file

@ -248,7 +248,7 @@ bool cleanupDocBrokers()
{
LOG_INF("Terminating " << (idle ? "idle" : "dead") <<
" DocumentBroker for docKey [" << it->first << "].");
docBroker->terminateChild(lock, idle ? "idle" : "", true);
docBroker->stop();
// Remove only when not alive.
if (!docBroker->isAlive())
@ -1351,8 +1351,7 @@ public:
if (docBroker)
{
// FIXME: No need to notify if asked to stop.
auto lock = docBroker->getLock();
docBroker->terminateChild(lock, "Service unavailable", true);
docBroker->stop();
}
}
@ -1379,7 +1378,7 @@ private:
{
auto lock = docBroker->getLock();
assert(docBroker->isCorrectThread());
docBroker->terminateChild(lock, "Service unavailable", false);
docBroker->stop();
}
}