bgsave: detect crashed bgsave process, and/or early termination.

Warn, flag save as failed, and disable bgsave in these cases,
perhaps we will not crash  main kit process next time around.

Signed-off-by: Michael Meeks <michael.meeks@collabora.com>
Change-Id: Ia4f3d079a5503739efc11e408ed431c3b652860b
pull/9102/head
Michael Meeks 2024-05-18 17:10:07 +01:00 committed by Caolán McNamara
parent 766b919c55
commit 24e0196471
2 changed files with 34 additions and 10 deletions

View File

@ -27,6 +27,7 @@
#include "Kit.hpp"
#include "KitQueue.hpp"
#include "ChildSession.hpp"
#include "KitWebSocket.hpp"
using Poco::Exception;
@ -226,24 +227,31 @@ BgSaveChildWebSocketHandler::~BgSaveChildWebSocketHandler()
// Kit handler for messages from transient background save Kit
void BgSaveParentWebSocketHandler::terminateSave(const std::string &session, const std::string &reason)
void BgSaveParentWebSocketHandler::terminateSave(const std::string &reason)
{
LOG_WRN("terminating bgsave: " << reason);
// next time we get a non-background save.
_document->disableBgSave("on unexpected jsdialog");
LOG_TRC("terminating bgsave: " << reason);
// Hard terminate the bgsave child
sendMessage("exit");
shutdown(true, "unexpected jsdialog");
reportFailedSave(reason);
}
void BgSaveParentWebSocketHandler::reportFailedSave(const std::string &reason)
{
// next time we get a non-background save.
_document->disableBgSave(reason);
// Synthesize a failed save result
// FIXME: could this allow another new manual save to race against the ongoing bgsave ?
// either way - that's better than hanging and blocking if we get interactive dialogs on save.
std::string saveFailed = session + " unocommandresult: { \"commandName\": \".uno:Save\", \"success\": false }";
std::string saveFailed = "client-" + _session->getId() +
" unocommandresult: { \"commandName\": \".uno:Save\", \"success\": false }";
_document->sendFrame(saveFailed.c_str(), saveFailed.size(), WSOpCode::Text);
_document->updateModifiedOnFailedBgSave();
_saveCompleted = true;
}
void BgSaveParentWebSocketHandler::handleMessage(const std::vector<char>& data)
@ -266,7 +274,7 @@ void BgSaveParentWebSocketHandler::handleMessage(const std::vector<char>& data)
if (tokens[1] == "jsdialog:")
{
terminateSave(tokens[0], "Unexpected jsdialog message: " +
terminateSave("Unexpected jsdialog message: " +
COOLProtocol::getAbbreviatedMessage(data));
return;
}
@ -294,6 +302,7 @@ void BgSaveParentWebSocketHandler::handleMessage(const std::vector<char>& data)
LOG_DBG("Failed to save, not synthesizing modified state");
_document->disableBgSave("on failed save");
}
_saveCompleted = true;
}
}
}
@ -301,12 +310,22 @@ void BgSaveParentWebSocketHandler::handleMessage(const std::vector<char>& data)
void BgSaveParentWebSocketHandler::onDisconnect()
{
LOG_TRC("Disconnected background web socket to child " << _childPid);
// reap and de-zombify children.
int status = -1;
if (waitpid(_childPid, &status, WUNTRACED | WNOHANG) > 0)
{
LOG_TRC("Child " << _childPid << " terminated with status " << status);
if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGSEGV ||
WTERMSIG(status) == SIGBUS ||
WTERMSIG(status) == SIGABRT))
reportFailedSave("crashed with status " + std::to_string(WTERMSIG(status)));
}
else
LOG_TRC("Child disconnected but not terminated");
LOG_WRN("Background save process disconnected but not terminated " << _childPid);
if (!_saveCompleted)
reportFailedSave("terminated without saving");
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@ -83,6 +83,7 @@ protected:
class BgSaveParentWebSocketHandler final : public WebSocketHandler
{
pid_t _childPid;
bool _saveCompleted;
std::string _socketName;
std::shared_ptr<Document> _document;
std::shared_ptr<ChildSession> _session;
@ -94,6 +95,7 @@ public:
const std::shared_ptr<ChildSession> &session)
: WebSocketHandler(/* isClient = */ false, /* isMasking */ false)
, _childPid(childPid)
, _saveCompleted(false)
, _socketName(socketName)
, _document(std::move(document))
, _session(session)
@ -109,6 +111,9 @@ protected:
virtual void handleMessage(const std::vector<char>& data) override;
virtual void onDisconnect() override;
// something weird happened, cleanup & notify of failure
void terminateSave(const std::string &session, const std::string &reason);
// something weird happened, cleanup & report save failure
void terminateSave(const std::string &reason);
// let WSD know something went wrong during the save
void reportFailedSave(const std::string &reason);
};