mirror of
https://github.com/overte-org/overte.git
synced 2025-07-22 23:14:08 +02:00
CR
This commit is contained in:
parent
b18d5db062
commit
dbfbee5406
9 changed files with 53 additions and 70 deletions
|
@ -1041,8 +1041,6 @@ void OctreeServer::readConfiguration() {
|
||||||
_persistFilePath = getMyDefaultPersistFilename();
|
_persistFilePath = getMyDefaultPersistFilename();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If persist filename does not exist, let's see if there is one beside the application binary
|
|
||||||
// If there is, let's copy it over to our target persist directory
|
|
||||||
QDir persistPath { _persistFilePath };
|
QDir persistPath { _persistFilePath };
|
||||||
|
|
||||||
if (persistPath.isRelative()) {
|
if (persistPath.isRelative()) {
|
||||||
|
|
|
@ -38,8 +38,7 @@
|
||||||
|
|
||||||
#include "DomainServer.h"
|
#include "DomainServer.h"
|
||||||
|
|
||||||
const int DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
const std::chrono::milliseconds DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL { 30 * 1000 }; // every 30 seconds
|
||||||
|
|
||||||
// Backup format looks like: daily_backup-TIMESTAMP.zip
|
// Backup format looks like: daily_backup-TIMESTAMP.zip
|
||||||
static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" };
|
static const QString DATETIME_FORMAT { "yyyy-MM-dd_HH-mm-ss" };
|
||||||
static const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" };
|
static const QString DATETIME_FORMAT_RE { "\\d{4}-\\d{2}-\\d{2}_\\d{2}-\\d{2}-\\d{2}" };
|
||||||
|
@ -53,12 +52,11 @@ void DomainContentBackupManager::addBackupHandler(BackupHandlerPointer handler)
|
||||||
|
|
||||||
DomainContentBackupManager::DomainContentBackupManager(const QString& backupDirectory,
|
DomainContentBackupManager::DomainContentBackupManager(const QString& backupDirectory,
|
||||||
const QVariantList& backupRules,
|
const QVariantList& backupRules,
|
||||||
int persistInterval,
|
std::chrono::milliseconds persistInterval,
|
||||||
bool debugTimestampNow)
|
bool debugTimestampNow) :
|
||||||
: _backupDirectory(backupDirectory),
|
_backupDirectory(backupDirectory), _persistInterval(persistInterval), _lastCheck(p_high_resolution_clock::now())
|
||||||
_persistInterval(persistInterval),
|
|
||||||
_lastCheck(usecTimestampNow())
|
|
||||||
{
|
{
|
||||||
|
|
||||||
setObjectName("DomainContentBackupManager");
|
setObjectName("DomainContentBackupManager");
|
||||||
|
|
||||||
// Make sure the backup directory exists.
|
// Make sure the backup directory exists.
|
||||||
|
@ -121,7 +119,32 @@ int64_t DomainContentBackupManager::getMostRecentBackupTimeInSecs(const QString&
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainContentBackupManager::setup() {
|
void DomainContentBackupManager::setup() {
|
||||||
load();
|
auto backups = getAllBackups();
|
||||||
|
for (auto& backup : backups) {
|
||||||
|
QFile backupFile { backup.absolutePath };
|
||||||
|
if (!backupFile.open(QIODevice::ReadOnly)) {
|
||||||
|
qCritical() << "Could not open file:" << backup.absolutePath;
|
||||||
|
qCritical() << " ERROR:" << backupFile.errorString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QuaZip zip { &backupFile };
|
||||||
|
if (!zip.open(QuaZip::mdUnzip)) {
|
||||||
|
qCritical() << "Could not open backup archive:" << backup.absolutePath;
|
||||||
|
qCritical() << " ERROR:" << zip.getZipError();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& handler : _backupHandlers) {
|
||||||
|
handler->loadBackup(backup.id, zip);
|
||||||
|
}
|
||||||
|
|
||||||
|
zip.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& handler : _backupHandlers) {
|
||||||
|
handler->loadingComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DomainContentBackupManager::process() {
|
bool DomainContentBackupManager::process() {
|
||||||
|
@ -130,10 +153,6 @@ bool DomainContentBackupManager::process() {
|
||||||
constexpr int64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms
|
constexpr int64_t USECS_TO_SLEEP = 10 * MSECS_TO_USECS; // every 10ms
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP));
|
std::this_thread::sleep_for(std::chrono::microseconds(USECS_TO_SLEEP));
|
||||||
|
|
||||||
int64_t now = usecTimestampNow();
|
|
||||||
int64_t sinceLastSave = now - _lastCheck;
|
|
||||||
int64_t intervalToCheck = _persistInterval * MSECS_TO_USECS;
|
|
||||||
|
|
||||||
if (_isRecovering) {
|
if (_isRecovering) {
|
||||||
bool isStillRecovering = any_of(begin(_backupHandlers), end(_backupHandlers), [](const BackupHandlerPointer& handler) {
|
bool isStillRecovering = any_of(begin(_backupHandlers), end(_backupHandlers), [](const BackupHandlerPointer& handler) {
|
||||||
return handler->getRecoveryStatus().first;
|
return handler->getRecoveryStatus().first;
|
||||||
|
@ -146,7 +165,9 @@ bool DomainContentBackupManager::process() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sinceLastSave > intervalToCheck) {
|
auto now = p_high_resolution_clock::now();
|
||||||
|
auto sinceLastSave = now - _lastCheck;
|
||||||
|
if (sinceLastSave > _persistInterval) {
|
||||||
_lastCheck = now;
|
_lastCheck = now;
|
||||||
|
|
||||||
if (!_isRecovering) {
|
if (!_isRecovering) {
|
||||||
|
@ -279,7 +300,8 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
|
||||||
|
|
||||||
bool success { false };
|
bool success { false };
|
||||||
QDir backupDir { _backupDirectory };
|
QDir backupDir { _backupDirectory };
|
||||||
QFile backupFile { backupDir.filePath(backupName) };
|
auto backupFilePath { backupDir.filePath(backupName) };
|
||||||
|
QFile backupFile { backupFilePath };
|
||||||
if (backupFile.open(QIODevice::ReadOnly)) {
|
if (backupFile.open(QIODevice::ReadOnly)) {
|
||||||
QuaZip zip { &backupFile };
|
QuaZip zip { &backupFile };
|
||||||
|
|
||||||
|
@ -288,7 +310,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
|
||||||
backupFile.close();
|
backupFile.close();
|
||||||
} else {
|
} else {
|
||||||
success = false;
|
success = false;
|
||||||
qWarning() << "Invalid id: " << backupName;
|
qWarning() << "Failed to open backup file for reading: " << backupFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
promise->resolve({
|
promise->resolve({
|
||||||
|
@ -339,19 +361,10 @@ std::vector<BackupItemInfo> DomainContentBackupManager::getAllBackups() {
|
||||||
auto dateTime = backupNameFormat.cap(3);
|
auto dateTime = backupNameFormat.cap(3);
|
||||||
auto createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT);
|
auto createdAt = QDateTime::fromString(dateTime, DATETIME_FORMAT);
|
||||||
if (!createdAt.isValid()) {
|
if (!createdAt.isValid()) {
|
||||||
|
qDebug().nospace() << "Skipping backup (" << fileName << ") with invalid timestamp: " << dateTime;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAvailable { true };
|
|
||||||
float availabilityProgress { 0.0f };
|
|
||||||
for (auto& handler : _backupHandlers) {
|
|
||||||
bool handlerIsAvailable { true };
|
|
||||||
float progress { 0.0f };
|
|
||||||
std::tie(handlerIsAvailable, progress) = handler->isAvailable(fileName);
|
|
||||||
isAvailable &= handlerIsAvailable;
|
|
||||||
availabilityProgress += progress / _backupHandlers.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
backups.emplace_back(fileInfo.fileName(), name, fileInfo.absoluteFilePath(), createdAt,
|
backups.emplace_back(fileInfo.fileName(), name, fileInfo.absoluteFilePath(), createdAt,
|
||||||
type == MANUAL_BACKUP_PREFIX);
|
type == MANUAL_BACKUP_PREFIX);
|
||||||
}
|
}
|
||||||
|
@ -448,35 +461,6 @@ void DomainContentBackupManager::removeOldBackupVersions(const BackupRule& rule)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainContentBackupManager::load() {
|
|
||||||
auto backups = getAllBackups();
|
|
||||||
for (auto& backup : backups) {
|
|
||||||
QFile backupFile { backup.absolutePath };
|
|
||||||
if (!backupFile.open(QIODevice::ReadOnly)) {
|
|
||||||
qCritical() << "Could not open file:" << backup.absolutePath;
|
|
||||||
qCritical() << " ERROR:" << backupFile.errorString();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QuaZip zip { &backupFile };
|
|
||||||
if (!zip.open(QuaZip::mdUnzip)) {
|
|
||||||
qCritical() << "Could not open backup archive:" << backup.absolutePath;
|
|
||||||
qCritical() << " ERROR:" << zip.getZipError();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& handler : _backupHandlers) {
|
|
||||||
handler->loadBackup(backup.id, zip);
|
|
||||||
}
|
|
||||||
|
|
||||||
zip.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& handler : _backupHandlers) {
|
|
||||||
handler->loadingComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DomainContentBackupManager::backup() {
|
void DomainContentBackupManager::backup() {
|
||||||
auto nowDateTime = QDateTime::currentDateTime();
|
auto nowDateTime = QDateTime::currentDateTime();
|
||||||
auto nowSeconds = nowDateTime.toSecsSinceEpoch();
|
auto nowSeconds = nowDateTime.toSecsSinceEpoch();
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include <shared/MiniPromises.h>
|
#include <shared/MiniPromises.h>
|
||||||
|
|
||||||
|
#include <PortableHighResolutionClock.h>
|
||||||
|
|
||||||
struct BackupItemInfo {
|
struct BackupItemInfo {
|
||||||
BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) :
|
BackupItemInfo(QString pId, QString pName, QString pAbsolutePath, QDateTime pCreatedAt, bool pIsManualBackup) :
|
||||||
id(pId), name(pName), absolutePath(pAbsolutePath), createdAt(pCreatedAt), isManualBackup(pIsManualBackup) { };
|
id(pId), name(pName), absolutePath(pAbsolutePath), createdAt(pCreatedAt), isManualBackup(pIsManualBackup) { };
|
||||||
|
@ -48,11 +50,11 @@ public:
|
||||||
qint64 lastBackupSeconds;
|
qint64 lastBackupSeconds;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int DEFAULT_PERSIST_INTERVAL;
|
static const std::chrono::milliseconds DEFAULT_PERSIST_INTERVAL;
|
||||||
|
|
||||||
DomainContentBackupManager(const QString& rootBackupDirectory,
|
DomainContentBackupManager(const QString& rootBackupDirectory,
|
||||||
const QVariantList& settings,
|
const QVariantList& settings,
|
||||||
int persistInterval = DEFAULT_PERSIST_INTERVAL,
|
std::chrono::milliseconds persistInterval = DEFAULT_PERSIST_INTERVAL,
|
||||||
bool debugTimestampNow = false);
|
bool debugTimestampNow = false);
|
||||||
|
|
||||||
std::vector<BackupItemInfo> getAllBackups();
|
std::vector<BackupItemInfo> getAllBackups();
|
||||||
|
@ -78,7 +80,6 @@ protected:
|
||||||
virtual bool process() override;
|
virtual bool process() override;
|
||||||
virtual void shutdown() override;
|
virtual void shutdown() override;
|
||||||
|
|
||||||
void load();
|
|
||||||
void backup();
|
void backup();
|
||||||
void removeOldBackupVersions(const BackupRule& rule);
|
void removeOldBackupVersions(const BackupRule& rule);
|
||||||
void refreshBackupRules();
|
void refreshBackupRules();
|
||||||
|
@ -93,12 +94,12 @@ protected:
|
||||||
private:
|
private:
|
||||||
const QString _backupDirectory;
|
const QString _backupDirectory;
|
||||||
std::vector<BackupHandlerPointer> _backupHandlers;
|
std::vector<BackupHandlerPointer> _backupHandlers;
|
||||||
int _persistInterval { 0 };
|
std::chrono::milliseconds _persistInterval { 0 };
|
||||||
|
|
||||||
std::atomic<bool> _isRecovering { false };
|
std::atomic<bool> _isRecovering { false };
|
||||||
QString _recoveryFilename { };
|
QString _recoveryFilename { };
|
||||||
|
|
||||||
int64_t _lastCheck { 0 };
|
std::chrono::time_point<std::chrono::high_resolution_clock> _lastCheck;
|
||||||
std::vector<BackupRule> _backupRules;
|
std::vector<BackupRule> _backupRules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3354,8 +3354,7 @@ void DomainServer::maybeHandleReplacementEntityFile() {
|
||||||
if (!replacementFile.remove()) {
|
if (!replacementFile.remove()) {
|
||||||
// If we can't remove the replacement file, we are at risk of getting into a state where
|
// If we can't remove the replacement file, we are at risk of getting into a state where
|
||||||
// we continually replace the primary entity file with the replacement entity file.
|
// we continually replace the primary entity file with the replacement entity file.
|
||||||
qCWarning(domain_server)
|
qCWarning(domain_server) << "Unable to remove replacement file, bailing";
|
||||||
<< "Unable to remove replacement file, bailing";
|
|
||||||
} else {
|
} else {
|
||||||
data.resetIdAndVersion();
|
data.resetIdAndVersion();
|
||||||
auto gzippedData = data.toGzippedByteArray();
|
auto gzippedData = data.toGzippedByteArray();
|
||||||
|
|
|
@ -31,7 +31,10 @@ void EntitiesBackupHandler::createBackup(const QString& backupName, QuaZip& zip)
|
||||||
|
|
||||||
if (entitiesFile.open(QIODevice::ReadOnly)) {
|
if (entitiesFile.open(QIODevice::ReadOnly)) {
|
||||||
QuaZipFile zipFile { &zip };
|
QuaZipFile zipFile { &zip };
|
||||||
zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ENTITIES_BACKUP_FILENAME, _entitiesFilePath));
|
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ENTITIES_BACKUP_FILENAME, _entitiesFilePath))) {
|
||||||
|
qCritical().nospace() << "Failed to open " << ENTITIES_BACKUP_FILENAME << " for writing in zip";
|
||||||
|
return;
|
||||||
|
}
|
||||||
zipFile.write(entitiesFile.readAll());
|
zipFile.write(entitiesFile.readAll());
|
||||||
zipFile.close();
|
zipFile.close();
|
||||||
if (zipFile.getZipError() != UNZ_OK) {
|
if (zipFile.getZipError() != UNZ_OK) {
|
||||||
|
|
|
@ -1816,8 +1816,6 @@ bool Octree::toGzippedJSON(QByteArray* data, const OctreeElementPointer& element
|
||||||
if (!gzip(jsonData, *data, -1)) {
|
if (!gzip(jsonData, *data, -1)) {
|
||||||
qCritical("Unable to gzip data while saving to json.");
|
qCritical("Unable to gzip data while saving to json.");
|
||||||
return false;
|
return false;
|
||||||
} else {
|
|
||||||
qDebug() <<"Did gzip!";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory,
|
OctreePersistThread(OctreePointer tree, const QString& filename, const QString& backupDirectory,
|
||||||
int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false,
|
int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false,
|
||||||
const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false,
|
const QJsonObject& settings = QJsonObject(), bool debugTimestampNow = false,
|
||||||
QString persistAsFileType="json.gz", const QByteArray& replacementData = QByteArray());
|
QString persistAsFileType = "json.gz", const QByteArray& replacementData = QByteArray());
|
||||||
|
|
||||||
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
||||||
quint64 getLoadElapsedTime() const { return _loadTimeUSecs; }
|
quint64 getLoadElapsedTime() const { return _loadTimeUSecs; }
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <AABox.h>
|
#include <AABox.h>
|
||||||
#include <Gzip.h>
|
#include <Gzip.h>
|
||||||
|
#include <udt/PacketHeaders.h>
|
||||||
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
@ -140,10 +141,11 @@ bool OctreeUtils::readOctreeDataInfoFromFile(QString path, OctreeUtils::RawOctre
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray OctreeUtils::RawOctreeData::toByteArray() {
|
QByteArray OctreeUtils::RawOctreeData::toByteArray() {
|
||||||
|
const auto protocolVersion = (int)versionForPacketType(PacketType::EntityData);
|
||||||
QJsonObject obj {
|
QJsonObject obj {
|
||||||
{ "DataVersion", QJsonValue((qint64)version) },
|
{ "DataVersion", QJsonValue((qint64)version) },
|
||||||
{ "Id", QJsonValue(id.toString()) },
|
{ "Id", QJsonValue(id.toString()) },
|
||||||
{ "Version", QJsonValue(5) },
|
{ "Version", protocolVersion },
|
||||||
{ "Entities", octreeData }
|
{ "Entities", octreeData }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,6 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) {
|
||||||
// match the thread name to our object name
|
// match the thread name to our object name
|
||||||
_thread->setObjectName(objectName());
|
_thread->setObjectName(objectName());
|
||||||
|
|
||||||
// when the worker thread is started, call our engine's run..
|
|
||||||
|
|
||||||
connect(_thread, &QThread::started, this, &GenericThread::started);
|
connect(_thread, &QThread::started, this, &GenericThread::started);
|
||||||
connect(_thread, &QThread::started, this, &GenericThread::threadRoutine);
|
connect(_thread, &QThread::started, this, &GenericThread::threadRoutine);
|
||||||
connect(_thread, &QThread::finished, this, &GenericThread::finished);
|
connect(_thread, &QThread::finished, this, &GenericThread::finished);
|
||||||
|
|
Loading…
Reference in a new issue