[Libreoffice-commits] online.git: net/Socket.hpp wsd/DocumentBroker.cpp wsd/DocumentBroker.hpp wsd/LOOLWSD.cpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Wed Apr 19 05:04:44 UTC 2017
net/Socket.hpp | 3 +
wsd/DocumentBroker.cpp | 75 +++++++++++++++++++++++++++++++++----------------
wsd/DocumentBroker.hpp | 3 -
wsd/LOOLWSD.cpp | 25 +++++++++++++++-
4 files changed, 78 insertions(+), 28 deletions(-)
New commits:
commit 9b3a22aafee8d0163212ea0c1b499eb03cb632ba
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Wed Apr 19 00:54:42 2017 -0400
wsd: save document upon server shutdown
The server correctly saves all documents
and waits to upload them before exiting.
Change-Id: I04dc9ce588bc0fa39a9deb298d0a5efa61a03f1a
Reviewed-on: https://gerrit.libreoffice.org/36654
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 89844912..c0b4b97e 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -438,7 +438,8 @@ public:
void wakeup()
{
if (!isAlive())
- LOG_WRN("Waking up dead poll thread [" << _name << "]");
+ LOG_WRN("Waking up dead poll thread [" << _name << "], started: " <<
+ _threadStarted << ", finished: " << _threadFinished);
wakeup(_wakeup[1]);
}
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 8ad9571e..94a49a1d 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -12,6 +12,7 @@
#include "DocumentBroker.hpp"
#include <cassert>
+#include <chrono>
#include <ctime>
#include <fstream>
#include <sstream>
@@ -220,29 +221,66 @@ void DocumentBroker::pollThread()
auto last30SecCheckTime = std::chrono::steady_clock::now();
+ static const bool AutoSaveEnabled = !std::getenv("LOOL_NO_AUTOSAVE");
+
// Main polling loop goodness.
- while (!_stop && _poll->continuePolling() && !TerminationFlag && !ShutdownRequestFlag)
+ while (!_stop && _poll->continuePolling() && !TerminationFlag)
{
_poll->poll(SocketPoll::DefaultPollTimeoutMs);
- if (!std::getenv("LOOL_NO_AUTOSAVE") && !_stop &&
- std::chrono::duration_cast<std::chrono::seconds>
- (std::chrono::steady_clock::now() - last30SecCheckTime).count() >= 30)
+ const auto now = std::chrono::steady_clock::now();
+ if (_lastSaveTime < _lastSaveRequestTime &&
+ std::chrono::duration_cast<std::chrono::milliseconds>
+ (now - _lastSaveRequestTime).count() <= COMMAND_TIMEOUT_MS)
+ {
+ // We are saving, nothing more to do but wait.
+ continue;
+ }
+
+ if (ShutdownRequestFlag)
{
- LOG_TRC("Trigger an autosave ...");
+ // Shutting down the server: notify clients, save, and stop.
+ static const std::string msg("close: recycling");
+
+ // First copy into local container, since removeSession
+ // will erase from _sessions, but will leave the last.
+ std::vector<std::shared_ptr<ClientSession>> sessions;
+ for (const auto& pair : _sessions)
+ {
+ sessions.push_back(pair.second);
+ }
+
+ for (const std::shared_ptr<ClientSession>& session : sessions)
+ {
+ try
+ {
+ // Notify the client and disconnect.
+ session->sendMessage(msg);
+ session->shutdown(WebSocketHandler::StatusCodes::ENDPOINT_GOING_AWAY, "recycling");
+
+ // Remove session, save, and mark to destroy.
+ removeSession(session->getId(), true);
+ }
+ catch (const std::exception& exc)
+ {
+ LOG_WRN("Error while shutting down client [" <<
+ session->getName() << "]: " << exc.what());
+ }
+ }
+ }
+ else if (AutoSaveEnabled && !_stop &&
+ std::chrono::duration_cast<std::chrono::seconds>(now - last30SecCheckTime).count() >= 30)
+ {
+ LOG_TRC("Triggering an autosave.");
autoSave(false);
last30SecCheckTime = std::chrono::steady_clock::now();
}
- const bool notSaving = (std::chrono::duration_cast<std::chrono::milliseconds>
- (std::chrono::steady_clock::now() - _lastSaveRequestTime).count() > COMMAND_TIMEOUT_MS);
-
// Remove idle documents after 1 hour.
const bool idle = (getIdleTimeSecs() >= 3600);
// If all sessions have been removed, no reason to linger.
- if ((isLoaded() || _markToDestroy) && notSaving &&
- (_sessions.empty() || idle))
+ if ((isLoaded() || _markToDestroy) && (_sessions.empty() || idle))
{
LOG_INF("Terminating " << (idle ? "idle" : "dead") <<
" DocumentBroker for docKey [" << getDocKey() << "].");
@@ -251,17 +289,8 @@ void DocumentBroker::pollThread()
}
LOG_INF("Finished polling doc [" << _docKey << "]. stop: " << _stop << ", continuePolling: " <<
- _poll->continuePolling() << ", TerminationFlag: " << TerminationFlag <<
- ", ShutdownRequestFlag: " << ShutdownRequestFlag << ".");
-
- if (ShutdownRequestFlag)
- {
- static const std::string msg("close: recycling");
- for (const auto& pair : _sessions)
- {
- pair.second->sendMessage(msg);
- }
- }
+ _poll->continuePolling() << ", ShutdownRequestFlag: " << ShutdownRequestFlag <<
+ ", TerminationFlag: " << TerminationFlag << ".");
// Terminate properly while we can.
//TODO: pass some sensible reason.
@@ -309,7 +338,7 @@ DocumentBroker::~DocumentBroker()
Admin::instance().rmDoc(_docKey);
- LOG_INF("~DocumentBroker [" << _uriPublic.toString() <<
+ LOG_INF("~DocumentBroker [" << _docKey <<
"] destroyed with " << _sessions.size() << " sessions left.");
// Do this early - to avoid operating on _childProcess from two threads.
@@ -317,7 +346,7 @@ DocumentBroker::~DocumentBroker()
if (!_sessions.empty())
{
- LOG_WRN("DocumentBroker still has unremoved sessions.");
+ LOG_WRN("DocumentBroker [" << _docKey << "] still has unremoved sessions.");
}
// Need to first make sure the child exited, socket closed,
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 62cb6a95..5b64d7ed 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -48,8 +48,7 @@ public:
bool continuePolling() override
{
- return SocketPoll::continuePolling()
- && !TerminationFlag && !ShutdownRequestFlag;
+ return SocketPoll::continuePolling() && !TerminationFlag;
}
};
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index c432a862..d109e5d2 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -2466,8 +2466,29 @@ int LOOLWSD::innerMain()
// atexit handlers tend to free Admin before Documents
LOG_INF("Cleaning up lingering documents.");
- for (auto& docBrokerIt : DocBrokers)
- docBrokerIt.second->joinThread();
+ if (ShutdownRequestFlag || TerminationFlag)
+ {
+ // Don't stop the DocBroker, they will exit.
+ const size_t sleepMs = 300;
+ const size_t count = std::max<size_t>(COMMAND_TIMEOUT_MS, 2000) / sleepMs;
+ for (size_t i = 0; i < count; ++i)
+ {
+ std::unique_lock<std::mutex> docBrokersLock(DocBrokersMutex);
+ cleanupDocBrokers();
+ if (DocBrokers.empty())
+ break;
+ docBrokersLock.unlock();
+
+ // Give them time to save and cleanup.
+ std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
+ }
+ }
+ else
+ {
+ // Stop and join.
+ for (auto& docBrokerIt : DocBrokers)
+ docBrokerIt.second->joinThread();
+ }
// Disable thread checking - we'll now cleanup lots of things if we can
Socket::InhibitThreadChecks = true;
More information about the Libreoffice-commits
mailing list