mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 05:37:17 +02:00
Add recovery mode and full backup information to DS
This commit is contained in:
parent
dd0b8a0c2f
commit
2942a53a1d
3 changed files with 96 additions and 37 deletions
|
@ -147,7 +147,24 @@ bool DomainContentBackupManager::process() {
|
||||||
|
|
||||||
if (sinceLastSave > intervalToCheck) {
|
if (sinceLastSave > intervalToCheck) {
|
||||||
_lastCheck = now;
|
_lastCheck = now;
|
||||||
backup();
|
if (_isRecovering) {
|
||||||
|
bool anyHandlerIsRecovering { false };
|
||||||
|
for (auto& handler : _backupHandlers) {
|
||||||
|
bool handlerIsRecovering { false };
|
||||||
|
float progress { 0.0f };
|
||||||
|
//std::tie<handlerIsRecovering, progress> = handler->getRecoveryStatus();
|
||||||
|
if (handlerIsRecovering) {
|
||||||
|
anyHandlerIsRecovering = true;
|
||||||
|
emit recoveryCompleted();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isRecovering = anyHandlerIsRecovering;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isRecovering) {
|
||||||
|
backup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +230,13 @@ void DomainContentBackupManager::deleteBackup(MiniPromise::Promise promise, cons
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_isRecovering && backupName == _recoveryFilename) {
|
||||||
|
promise->resolve({
|
||||||
|
{ "success", false }
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QDir backupDir { _backupDirectory };
|
QDir backupDir { _backupDirectory };
|
||||||
QFile backupFile { backupDir.filePath(backupName) };
|
QFile backupFile { backupDir.filePath(backupName) };
|
||||||
auto success = backupFile.remove();
|
auto success = backupFile.remove();
|
||||||
|
@ -222,6 +246,13 @@ void DomainContentBackupManager::deleteBackup(MiniPromise::Promise promise, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, const QString& backupName) {
|
void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise, const QString& backupName) {
|
||||||
|
if (_isRecovering) {
|
||||||
|
promise->resolve({
|
||||||
|
{ "success", false }
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if (QThread::currentThread() != thread()) {
|
if (QThread::currentThread() != thread()) {
|
||||||
QMetaObject::invokeMethod(this, "recoverFromBackup", Q_ARG(MiniPromise::Promise, promise),
|
QMetaObject::invokeMethod(this, "recoverFromBackup", Q_ARG(MiniPromise::Promise, promise),
|
||||||
Q_ARG(const QString&, backupName));
|
Q_ARG(const QString&, backupName));
|
||||||
|
@ -239,11 +270,12 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
|
||||||
qWarning() << "Failed to unzip file: " << backupName;
|
qWarning() << "Failed to unzip file: " << backupName;
|
||||||
success = false;
|
success = false;
|
||||||
} else {
|
} else {
|
||||||
|
_isRecovering = true;
|
||||||
for (auto& handler : _backupHandlers) {
|
for (auto& handler : _backupHandlers) {
|
||||||
handler->recoverBackup(zip);
|
handler->recoverBackup(zip);
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Successfully recovered from " << backupName;
|
qDebug() << "Successfully started recovering from " << backupName;
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
backupFile.close();
|
backupFile.close();
|
||||||
|
@ -257,8 +289,11 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BackupItemInfo> DomainContentBackupManager::getAllBackups() {
|
void DomainContentBackupManager::getAllBackupInformation(MiniPromise::Promise promise) {
|
||||||
std::vector<BackupItemInfo> backups;
|
if (QThread::currentThread() != thread()) {
|
||||||
|
QMetaObject::invokeMethod(this, "getAllBackupInformation", Q_ARG(MiniPromise::Promise, promise));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QDir backupDir { _backupDirectory };
|
QDir backupDir { _backupDirectory };
|
||||||
auto matchingFiles =
|
auto matchingFiles =
|
||||||
|
@ -269,6 +304,8 @@ std::vector<BackupItemInfo> DomainContentBackupManager::getAllBackups() {
|
||||||
QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")";
|
QString dateTimeFormat = "(" + DATETIME_FORMAT_RE + ")";
|
||||||
QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" };
|
QRegExp backupNameFormat { prefixFormat + nameFormat + "-" + dateTimeFormat + "\\.zip" };
|
||||||
|
|
||||||
|
QVariantList backups;
|
||||||
|
|
||||||
for (const auto& fileInfo : matchingFiles) {
|
for (const auto& fileInfo : matchingFiles) {
|
||||||
auto fileName = fileInfo.fileName();
|
auto fileName = fileInfo.fileName();
|
||||||
if (backupNameFormat.exactMatch(fileName)) {
|
if (backupNameFormat.exactMatch(fileName)) {
|
||||||
|
@ -280,12 +317,50 @@ std::vector<BackupItemInfo> DomainContentBackupManager::getAllBackups() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
BackupItemInfo backup { fileInfo.fileName(), name, fileInfo.absoluteFilePath(), createdAt, type == MANUAL_BACKUP_PREFIX };
|
bool isAvailable { true };
|
||||||
backups.push_back(backup);
|
float availabilityProgress { 0.0f };
|
||||||
|
for (auto& handler : _backupHandlers) {
|
||||||
|
bool handlerIsAvailable { false };
|
||||||
|
float progress { 0.0f };
|
||||||
|
//std::tie<handlerIsAvailable, progress> = handler->isAvailable();
|
||||||
|
//isAvailable = isAvailable && !handlerIsAvailable);
|
||||||
|
//availabilityProgress += progress / _backupHandlers.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
backups.push_back(QVariantMap({
|
||||||
|
{ "id", fileInfo.fileName() },
|
||||||
|
{ "name", name },
|
||||||
|
{ "createdAtMillis", createdAt.toMSecsSinceEpoch() },
|
||||||
|
{ "isAvailable", isAvailable },
|
||||||
|
{ "availabilityProgress", availabilityProgress },
|
||||||
|
{ "isManualBackup", type == MANUAL_BACKUP_PREFIX }
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return backups;
|
float recoveryProgress = 0.0f;
|
||||||
|
bool isRecovering = _isRecovering.load();
|
||||||
|
if (_isRecovering) {
|
||||||
|
for (auto& handler : _backupHandlers) {
|
||||||
|
bool handlerIsRecovering { false };
|
||||||
|
float progress { 0.0f };
|
||||||
|
//std::tie<handlerIsRecovering, progress> = handler->getRecoveryStatus();
|
||||||
|
recoveryProgress += progress / _backupHandlers.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariantMap status {
|
||||||
|
{ "isRecovering", isRecovering },
|
||||||
|
{ "recoveringBackupId", _recoveryFilename },
|
||||||
|
{ "recoveryProgress", recoveryProgress }
|
||||||
|
};
|
||||||
|
|
||||||
|
QVariantMap info {
|
||||||
|
{ "backups", backups },
|
||||||
|
{ "status", status }
|
||||||
|
};
|
||||||
|
|
||||||
|
promise->resolve(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainContentBackupManager::removeOldBackupVersions(const BackupRule& rule) {
|
void DomainContentBackupManager::removeOldBackupVersions(const BackupRule& rule) {
|
||||||
|
@ -433,6 +508,8 @@ void DomainContentBackupManager::consolidateBackup(MiniPromise::Promise promise,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "copyFilePath" << copyFilePath;
|
||||||
|
|
||||||
promise->resolve({
|
promise->resolve({
|
||||||
{ "success", true },
|
{ "success", true },
|
||||||
{ "backupFilePath", copyFilePath }
|
{ "backupFilePath", copyFilePath }
|
||||||
|
|
|
@ -24,14 +24,6 @@
|
||||||
|
|
||||||
#include <shared/MiniPromises.h>
|
#include <shared/MiniPromises.h>
|
||||||
|
|
||||||
struct BackupItemInfo {
|
|
||||||
QString id;
|
|
||||||
QString name;
|
|
||||||
QString absolutePath;
|
|
||||||
QDateTime createdAt;
|
|
||||||
bool isManualBackup;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DomainContentBackupManager : public GenericThread {
|
class DomainContentBackupManager : public GenericThread {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -52,13 +44,13 @@ public:
|
||||||
bool debugTimestampNow = false);
|
bool debugTimestampNow = false);
|
||||||
|
|
||||||
void addBackupHandler(BackupHandlerPointer handler);
|
void addBackupHandler(BackupHandlerPointer handler);
|
||||||
std::vector<BackupItemInfo> getAllBackups();
|
|
||||||
|
|
||||||
void aboutToFinish(); /// call this to inform the persist thread that the owner is about to finish to support final persist
|
void aboutToFinish(); /// call this to inform the persist thread that the owner is about to finish to support final persist
|
||||||
|
|
||||||
void replaceData(QByteArray data);
|
void replaceData(QByteArray data);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
void getAllBackupInformation(MiniPromise::Promise promise);
|
||||||
void createManualBackup(MiniPromise::Promise promise, const QString& name);
|
void createManualBackup(MiniPromise::Promise promise, const QString& name);
|
||||||
void recoverFromBackup(MiniPromise::Promise promise, const QString& backupName);
|
void recoverFromBackup(MiniPromise::Promise promise, const QString& backupName);
|
||||||
void deleteBackup(MiniPromise::Promise promise, const QString& backupName);
|
void deleteBackup(MiniPromise::Promise promise, const QString& backupName);
|
||||||
|
@ -66,6 +58,7 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loadCompleted();
|
void loadCompleted();
|
||||||
|
void recoveryCompleted();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Implements generic processing behavior for this thread.
|
/// Implements generic processing behavior for this thread.
|
||||||
|
@ -86,6 +79,9 @@ private:
|
||||||
std::vector<BackupHandlerPointer> _backupHandlers;
|
std::vector<BackupHandlerPointer> _backupHandlers;
|
||||||
int _persistInterval { 0 };
|
int _persistInterval { 0 };
|
||||||
|
|
||||||
|
std::atomic<bool> _isRecovering { false };
|
||||||
|
QString _recoveryFilename { };
|
||||||
|
|
||||||
int64_t _lastCheck { 0 };
|
int64_t _lastCheck { 0 };
|
||||||
std::vector<BackupRule> _backupRules;
|
std::vector<BackupRule> _backupRules;
|
||||||
};
|
};
|
||||||
|
|
|
@ -307,10 +307,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
|
||||||
_contentManager->initialize(true);
|
_contentManager->initialize(true);
|
||||||
|
|
||||||
qDebug() << "Existing backups:";
|
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
|
||||||
for (auto& backup : _contentManager->getAllBackups()) {
|
|
||||||
qDebug() << " Backup: " << backup.name << backup.createdAt;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::parseCommandLine() {
|
void DomainServer::parseCommandLine() {
|
||||||
|
@ -2131,24 +2128,13 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (url.path() == URI_API_BACKUPS) {
|
} else if (url.path() == URI_API_BACKUPS) {
|
||||||
QJsonObject rootJSON;
|
auto deferred = makePromise("getAllBackupInformation");
|
||||||
QJsonArray backupsJSON;
|
deferred->then([connection, JSON_MIME_TYPE](QString error, QVariantMap result) {
|
||||||
|
QJsonDocument docJSON(QJsonObject::fromVariantMap(result));
|
||||||
|
|
||||||
auto backups = _contentManager->getAllBackups();
|
connection->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8());
|
||||||
|
});
|
||||||
for (const auto& backup : backups) {
|
_contentManager->getAllBackupInformation(deferred);
|
||||||
QJsonObject obj;
|
|
||||||
obj["id"] = backup.id;
|
|
||||||
obj["name"] = backup.name;
|
|
||||||
obj["createdAtMillis"] = backup.createdAt.toMSecsSinceEpoch();
|
|
||||||
obj["isManualBackup"] = backup.isManualBackup;
|
|
||||||
backupsJSON.push_back(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
rootJSON["backups"] = backupsJSON;
|
|
||||||
QJsonDocument docJSON(rootJSON);
|
|
||||||
|
|
||||||
connection->respond(HTTPConnection::StatusCode200, docJSON.toJson(), JSON_MIME_TYPE.toUtf8());
|
|
||||||
return true;
|
return true;
|
||||||
} else if (url.path().startsWith(URI_API_BACKUPS_ID)) {
|
} else if (url.path().startsWith(URI_API_BACKUPS_ID)) {
|
||||||
auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length());
|
auto id = url.path().mid(QString(URI_API_BACKUPS_ID).length());
|
||||||
|
|
Loading…
Reference in a new issue