mirror of
https://github.com/overte-org/overte.git
synced 2025-04-19 15:43:50 +02:00
Merge pull request #12413 from Atlante45/feat/backups-integration
Asset Server deplays queries until fully setup
This commit is contained in:
commit
e0e04b8bb2
11 changed files with 322 additions and 239 deletions
|
@ -257,12 +257,10 @@ AssetServer::AssetServer(ReceivedMessage& message) :
|
|||
_transferTaskPool.setMaxThreadCount(TASK_POOL_THREAD_COUNT);
|
||||
_bakingTaskPool.setMaxThreadCount(1);
|
||||
|
||||
// Queue all requests until the Asset Server is fully setup
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet");
|
||||
packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo");
|
||||
packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload");
|
||||
packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation");
|
||||
|
||||
packetReceiver.registerListenerForTypes({ PacketType::AssetGet, PacketType::AssetGetInfo, PacketType::AssetUpload, PacketType::AssetMappingOperation }, this, "queueRequests");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
updateConsumedCores();
|
||||
QTimer* timer = new QTimer(this);
|
||||
|
@ -417,6 +415,43 @@ void AssetServer::completeSetup() {
|
|||
|
||||
PathUtils::removeTemporaryApplicationDirs();
|
||||
PathUtils::removeTemporaryApplicationDirs("Oven");
|
||||
|
||||
// We're fully setup, remove the request queueing and replay all requests
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
packetReceiver.unregisterListener(this);
|
||||
packetReceiver.registerListener(PacketType::AssetGet, this, "handleAssetGet");
|
||||
packetReceiver.registerListener(PacketType::AssetGetInfo, this, "handleAssetGetInfo");
|
||||
packetReceiver.registerListener(PacketType::AssetUpload, this, "handleAssetUpload");
|
||||
packetReceiver.registerListener(PacketType::AssetMappingOperation, this, "handleAssetMappingOperation");
|
||||
|
||||
replayRequests();
|
||||
}
|
||||
|
||||
void AssetServer::queueRequests(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode) {
|
||||
_queuedRequests.push_back({ packet, senderNode });
|
||||
}
|
||||
|
||||
void AssetServer::replayRequests() {
|
||||
for (const auto& request : _queuedRequests) {
|
||||
switch (request.first->getType()) {
|
||||
case PacketType::AssetGet:
|
||||
handleAssetGet(request.first, request.second);
|
||||
break;
|
||||
case PacketType::AssetGetInfo:
|
||||
handleAssetGetInfo(request.first, request.second);
|
||||
break;
|
||||
case PacketType::AssetUpload:
|
||||
handleAssetUpload(request.first, request.second);
|
||||
break;
|
||||
case PacketType::AssetMappingOperation:
|
||||
handleAssetMappingOperation(request.first, request.second);
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown queued request type:" << request.first->getType();
|
||||
break;
|
||||
}
|
||||
}
|
||||
_queuedRequests.clear();
|
||||
}
|
||||
|
||||
void AssetServer::cleanupUnmappedFiles() {
|
||||
|
|
|
@ -49,6 +49,7 @@ public slots:
|
|||
private slots:
|
||||
void completeSetup();
|
||||
|
||||
void queueRequests(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
|
||||
void handleAssetGetInfo(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
|
||||
void handleAssetGet(QSharedPointer<ReceivedMessage> packet, SharedNodePointer senderNode);
|
||||
void handleAssetUpload(QSharedPointer<ReceivedMessage> packetList, SharedNodePointer senderNode);
|
||||
|
@ -57,6 +58,8 @@ private slots:
|
|||
void sendStatsPacket() override;
|
||||
|
||||
private:
|
||||
void replayRequests();
|
||||
|
||||
void handleGetMappingOperation(ReceivedMessage& message, NLPacketList& replyPacket);
|
||||
void handleGetAllMappingOperation(NLPacketList& replyPacket);
|
||||
void handleSetMappingOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket);
|
||||
|
@ -120,6 +123,8 @@ private:
|
|||
QHash<AssetUtils::AssetHash, std::shared_ptr<BakeAssetTask>> _pendingBakes;
|
||||
QThreadPool _bakingTaskPool;
|
||||
|
||||
QVector<QPair<QSharedPointer<ReceivedMessage>, SharedNodePointer>> _queuedRequests;
|
||||
|
||||
bool _wasColorTextureCompressionEnabled { false };
|
||||
bool _wasGrayscaleTextureCompressionEnabled { false };
|
||||
bool _wasNormalTextureCompressionEnabled { false };
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// BackupSupervisor.cpp
|
||||
// AssetsBackupHandler.cpp
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Clement Brisset on 1/12/18.
|
||||
|
@ -9,13 +9,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "BackupSupervisor.h"
|
||||
#include "AssetsBackupHandler.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QDate>
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <quazip5/quazipfile.h>
|
||||
#include <quazip5/quazipdir.h>
|
||||
|
||||
#include <AssetClient.h>
|
||||
#include <AssetRequest.h>
|
||||
|
@ -23,15 +24,16 @@
|
|||
#include <MappingRequest.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
const QString ASSETS_DIR = "/assets/";
|
||||
const QString MAPPINGS_FILE = "mappings.json";
|
||||
static const QString ASSETS_DIR = "/assets/";
|
||||
static const QString MAPPINGS_FILE = "mappings.json";
|
||||
static const QString ZIP_ASSETS_FOLDER = "files";
|
||||
|
||||
using namespace std;
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(backup_supervisor)
|
||||
Q_LOGGING_CATEGORY(backup_supervisor, "hifi.backup-supervisor");
|
||||
Q_DECLARE_LOGGING_CATEGORY(asset_backup)
|
||||
Q_LOGGING_CATEGORY(asset_backup, "hifi.asset-backup");
|
||||
|
||||
BackupSupervisor::BackupSupervisor(const QString& backupDirectory) :
|
||||
AssetsBackupHandler::AssetsBackupHandler(const QString& backupDirectory) :
|
||||
_assetsDirectory(backupDirectory + ASSETS_DIR)
|
||||
{
|
||||
// Make sure the asset directory exists.
|
||||
|
@ -39,22 +41,29 @@ BackupSupervisor::BackupSupervisor(const QString& backupDirectory) :
|
|||
|
||||
refreshAssetsOnDisk();
|
||||
|
||||
setupRefreshTimer();
|
||||
}
|
||||
|
||||
void AssetsBackupHandler::setupRefreshTimer() {
|
||||
_mappingsRefreshTimer.setTimerType(Qt::CoarseTimer);
|
||||
_mappingsRefreshTimer.setSingleShot(true);
|
||||
QObject::connect(&_mappingsRefreshTimer, &QTimer::timeout, this, &BackupSupervisor::refreshMappings);
|
||||
QObject::connect(&_mappingsRefreshTimer, &QTimer::timeout, this, &AssetsBackupHandler::refreshMappings);
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
QObject::connect(nodeList.data(), &LimitedNodeList::nodeAdded, this, [this](SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::AssetServer) {
|
||||
// Give the Asset Server some time to bootup.
|
||||
static constexpr int ASSET_SERVER_BOOTUP_MARGIN = 1 * 1000;
|
||||
_mappingsRefreshTimer.start(ASSET_SERVER_BOOTUP_MARGIN);
|
||||
// run immediately for the first time.
|
||||
_mappingsRefreshTimer.start(0);
|
||||
}
|
||||
});
|
||||
QObject::connect(nodeList.data(), &LimitedNodeList::nodeKilled, this, [this](SharedNodePointer node) {
|
||||
if (node->getType() == NodeType::AssetServer) {
|
||||
_mappingsRefreshTimer.stop();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void BackupSupervisor::refreshAssetsOnDisk() {
|
||||
void AssetsBackupHandler::refreshAssetsOnDisk() {
|
||||
QDir assetsDir { _assetsDirectory };
|
||||
auto assetNames = assetsDir.entryList(QDir::Files);
|
||||
|
||||
|
@ -65,7 +74,7 @@ void BackupSupervisor::refreshAssetsOnDisk() {
|
|||
|
||||
}
|
||||
|
||||
void BackupSupervisor::refreshAssetsInBackups() {
|
||||
void AssetsBackupHandler::refreshAssetsInBackups() {
|
||||
_assetsInBackups.clear();
|
||||
for (const auto& backup : _backups) {
|
||||
for (const auto& mapping : backup.mappings) {
|
||||
|
@ -74,41 +83,43 @@ void BackupSupervisor::refreshAssetsInBackups() {
|
|||
}
|
||||
}
|
||||
|
||||
void BackupSupervisor::checkForMissingAssets() {
|
||||
void AssetsBackupHandler::checkForMissingAssets() {
|
||||
vector<AssetUtils::AssetHash> missingAssets;
|
||||
set_difference(begin(_assetsInBackups), end(_assetsInBackups),
|
||||
begin(_assetsOnDisk), end(_assetsOnDisk),
|
||||
back_inserter(missingAssets));
|
||||
if (missingAssets.size() > 0) {
|
||||
qCWarning(backup_supervisor) << "Found" << missingAssets.size() << "assets missing.";
|
||||
qCWarning(asset_backup) << "Found" << missingAssets.size() << "backup assets missing from disk.";
|
||||
}
|
||||
}
|
||||
|
||||
void BackupSupervisor::checkForAssetsToDelete() {
|
||||
void AssetsBackupHandler::checkForAssetsToDelete() {
|
||||
vector<AssetUtils::AssetHash> deprecatedAssets;
|
||||
set_difference(begin(_assetsOnDisk), end(_assetsOnDisk),
|
||||
begin(_assetsInBackups), end(_assetsInBackups),
|
||||
back_inserter(deprecatedAssets));
|
||||
|
||||
if (deprecatedAssets.size() > 0) {
|
||||
qCDebug(backup_supervisor) << "Found" << deprecatedAssets.size() << "assets to delete.";
|
||||
qCDebug(asset_backup) << "Found" << deprecatedAssets.size() << "backup assets to delete from disk.";
|
||||
if (_allBackupsLoadedSuccessfully) {
|
||||
for (const auto& hash : deprecatedAssets) {
|
||||
QFile::remove(_assetsDirectory + hash);
|
||||
}
|
||||
} else {
|
||||
qCWarning(backup_supervisor) << "Some backups did not load properly, aborting deleting for safety.";
|
||||
qCWarning(asset_backup) << "Some backups did not load properly, aborting delete operation for safety.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BackupSupervisor::loadBackup(QuaZip& zip) {
|
||||
void AssetsBackupHandler::loadBackup(QuaZip& zip) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
_backups.push_back({ zip.getZipName(), {}, false });
|
||||
auto& backup = _backups.back();
|
||||
|
||||
if (!zip.setCurrentFile(MAPPINGS_FILE)) {
|
||||
qCCritical(backup_supervisor) << "Failed to find" << MAPPINGS_FILE << "while recovering backup";
|
||||
qCCritical(backup_supervisor) << " Error:" << zip.getZipError();
|
||||
qCCritical(asset_backup) << "Failed to find" << MAPPINGS_FILE << "while loading backup";
|
||||
qCCritical(asset_backup) << " Error:" << zip.getZipError();
|
||||
backup.corruptedBackup = true;
|
||||
_allBackupsLoadedSuccessfully = false;
|
||||
return;
|
||||
|
@ -116,8 +127,8 @@ void BackupSupervisor::loadBackup(QuaZip& zip) {
|
|||
|
||||
QuaZipFile zipFile { &zip };
|
||||
if (!zipFile.open(QFile::ReadOnly)) {
|
||||
qCCritical(backup_supervisor) << "Could not open backup file:" << zip.getZipName();
|
||||
qCCritical(backup_supervisor) << " Error:" << zip.getZipError();
|
||||
qCCritical(asset_backup) << "Could not unzip backup file for load:" << zip.getZipName();
|
||||
qCCritical(asset_backup) << " Error:" << zip.getZipError();
|
||||
backup.corruptedBackup = true;
|
||||
_allBackupsLoadedSuccessfully = false;
|
||||
return;
|
||||
|
@ -126,8 +137,8 @@ void BackupSupervisor::loadBackup(QuaZip& zip) {
|
|||
QJsonParseError error;
|
||||
auto document = QJsonDocument::fromJson(zipFile.readAll(), &error);
|
||||
if (document.isNull() || !document.isObject()) {
|
||||
qCCritical(backup_supervisor) << "Could not parse backup file to JSON object:" << zip.getZipName();
|
||||
qCCritical(backup_supervisor) << " Error:" << error.errorString();
|
||||
qCCritical(asset_backup) << "Could not parse backup file to JSON object for load:" << zip.getZipName();
|
||||
qCCritical(asset_backup) << " Error:" << error.errorString();
|
||||
backup.corruptedBackup = true;
|
||||
_allBackupsLoadedSuccessfully = false;
|
||||
return;
|
||||
|
@ -139,33 +150,37 @@ void BackupSupervisor::loadBackup(QuaZip& zip) {
|
|||
const auto& assetHash = it.value().toString();
|
||||
|
||||
if (!AssetUtils::isValidHash(assetHash)) {
|
||||
qCCritical(backup_supervisor) << "Corrupted mapping in backup file" << zip.getZipName() << ":" << it.key();
|
||||
qCCritical(asset_backup) << "Corrupted mapping in loading backup file" << zip.getZipName() << ":" << it.key();
|
||||
backup.corruptedBackup = true;
|
||||
_allBackupsLoadedSuccessfully = false;
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
backup.mappings[assetPath] = assetHash;
|
||||
_assetsInBackups.insert(assetHash);
|
||||
}
|
||||
|
||||
checkForMissingAssets();
|
||||
checkForAssetsToDelete();
|
||||
return;
|
||||
}
|
||||
|
||||
void BackupSupervisor::createBackup(QuaZip& zip) {
|
||||
void AssetsBackupHandler::createBackup(QuaZip& zip) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (operationInProgress()) {
|
||||
qCWarning(backup_supervisor) << "There is already an operation in progress.";
|
||||
qCWarning(asset_backup) << "There is already an operation in progress.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lastMappingsRefresh == 0) {
|
||||
qCWarning(backup_supervisor) << "Current mappings not yet loaded.";
|
||||
qCWarning(asset_backup) << "Current mappings not yet loaded.";
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr quint64 MAX_REFRESH_TIME = 15 * 60 * 1000 * 1000;
|
||||
if (usecTimestampNow() - _lastMappingsRefresh > MAX_REFRESH_TIME) {
|
||||
qCWarning(backup_supervisor) << "Backing up asset mappings that might be stale.";
|
||||
qCWarning(asset_backup) << "Backing up asset mappings that might be stale.";
|
||||
}
|
||||
|
||||
AssetServerBackup backup;
|
||||
|
@ -181,43 +196,65 @@ void BackupSupervisor::createBackup(QuaZip& zip) {
|
|||
|
||||
QuaZipFile zipFile { &zip };
|
||||
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(MAPPINGS_FILE))) {
|
||||
qCDebug(backup_supervisor) << "Could not open zip file:" << zipFile.getZipError();
|
||||
qCDebug(asset_backup) << "Could not open zip file:" << zipFile.getZipError();
|
||||
return;
|
||||
}
|
||||
zipFile.write(document.toJson());
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCDebug(backup_supervisor) << "Could not close zip file: " << zipFile.getZipError();
|
||||
qCDebug(asset_backup) << "Could not close zip file: " << zipFile.getZipError();
|
||||
return;
|
||||
}
|
||||
_backups.push_back(backup);
|
||||
}
|
||||
|
||||
void BackupSupervisor::recoverBackup(QuaZip& zip) {
|
||||
void AssetsBackupHandler::recoverBackup(QuaZip& zip) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (operationInProgress()) {
|
||||
qCWarning(backup_supervisor) << "There is already a backup/restore in progress.";
|
||||
qCWarning(asset_backup) << "There is already a backup/restore in progress.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_lastMappingsRefresh == 0) {
|
||||
qCWarning(backup_supervisor) << "Current mappings not yet loaded.";
|
||||
qCWarning(asset_backup) << "Current mappings not yet loaded.";
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr quint64 MAX_REFRESH_TIME = 15 * 60 * 1000 * 1000;
|
||||
if (usecTimestampNow() - _lastMappingsRefresh > MAX_REFRESH_TIME) {
|
||||
qCWarning(backup_supervisor) << "Current asset mappings that might be stale.";
|
||||
qCWarning(asset_backup) << "Current asset mappings that might be stale.";
|
||||
}
|
||||
|
||||
startOperation();
|
||||
|
||||
auto it = find_if(begin(_backups), end(_backups), [&](const std::vector<AssetServerBackup>::value_type& value) {
|
||||
return value.filePath == zip.getZipName();
|
||||
});
|
||||
if (it == end(_backups)) {
|
||||
qCDebug(backup_supervisor) << "Could not find backup" << zip.getZipName() << "to restore.";
|
||||
stopOperation();
|
||||
return;
|
||||
qCDebug(asset_backup) << "Could not find backup" << zip.getZipName() << "to restore.";
|
||||
|
||||
loadBackup(zip);
|
||||
|
||||
QuaZipDir zipDir { &zip, ZIP_ASSETS_FOLDER };
|
||||
|
||||
auto assetNames = zipDir.entryList(QDir::Files);
|
||||
for (const auto& asset : assetNames) {
|
||||
if (AssetUtils::isValidHash(asset)) {
|
||||
if (!zip.setCurrentFile(zipDir.filePath(asset))) {
|
||||
qCCritical(asset_backup) << "Failed to find" << asset << "while recovering backup";
|
||||
qCCritical(asset_backup) << " Error:" << zip.getZipError();
|
||||
continue;
|
||||
}
|
||||
|
||||
QuaZipFile zipFile { &zip };
|
||||
if (!zipFile.open(QFile::ReadOnly)) {
|
||||
qCCritical(asset_backup) << "Could not unzip asset file:" << asset;
|
||||
qCCritical(asset_backup) << " Error:" << zip.getZipError();
|
||||
continue;
|
||||
}
|
||||
|
||||
writeAssetFile(asset, zipFile.readAll());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto& newMappings = it->mappings;
|
||||
|
@ -226,9 +263,11 @@ void BackupSupervisor::recoverBackup(QuaZip& zip) {
|
|||
restoreAllAssets();
|
||||
}
|
||||
|
||||
void BackupSupervisor::deleteBackup(QuaZip& zip) {
|
||||
void AssetsBackupHandler::deleteBackup(QuaZip& zip) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (operationInProgress()) {
|
||||
qCWarning(backup_supervisor) << "There is a backup/restore in progress.";
|
||||
qCWarning(asset_backup) << "There is a backup/restore in progress.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -236,7 +275,7 @@ void BackupSupervisor::deleteBackup(QuaZip& zip) {
|
|||
return value.filePath == zip.getZipName();
|
||||
});
|
||||
if (it == end(_backups)) {
|
||||
qCDebug(backup_supervisor) << "Could not find backup" << zip.getZipName() << "to delete.";
|
||||
qCDebug(asset_backup) << "Could not find backup" << zip.getZipName() << "to delete.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -244,9 +283,11 @@ void BackupSupervisor::deleteBackup(QuaZip& zip) {
|
|||
checkForAssetsToDelete();
|
||||
}
|
||||
|
||||
void BackupSupervisor::consolidateBackup(QuaZip& zip) {
|
||||
void AssetsBackupHandler::consolidateBackup(QuaZip& zip) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
|
||||
if (operationInProgress()) {
|
||||
qCWarning(backup_supervisor) << "There is a backup/restore in progress.";
|
||||
qCWarning(asset_backup) << "There is a backup/restore in progress.";
|
||||
return;
|
||||
}
|
||||
QFileInfo zipInfo(zip.getZipName());
|
||||
|
@ -256,7 +297,7 @@ void BackupSupervisor::consolidateBackup(QuaZip& zip) {
|
|||
return info.fileName() == zipInfo.fileName();
|
||||
});
|
||||
if (it == end(_backups)) {
|
||||
qCDebug(backup_supervisor) << "Could not find backup" << zip.getZipName() << "to consolidate.";
|
||||
qCDebug(asset_backup) << "Could not find backup" << zip.getZipName() << "to consolidate.";
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -266,27 +307,26 @@ void BackupSupervisor::consolidateBackup(QuaZip& zip) {
|
|||
QDir assetsDir { _assetsDirectory };
|
||||
QFile file { assetsDir.filePath(hash) };
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
qCCritical(backup_supervisor) << "Could not open asset file" << file.fileName();
|
||||
qCCritical(asset_backup) << "Could not open asset file" << file.fileName();
|
||||
continue;
|
||||
}
|
||||
|
||||
QuaZipFile zipFile { &zip };
|
||||
static const QString ZIP_ASSETS_FOLDER = "files/";
|
||||
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ZIP_ASSETS_FOLDER + hash))) {
|
||||
qCDebug(backup_supervisor) << "Could not open zip file:" << zipFile.getZipError();
|
||||
if (!zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo(ZIP_ASSETS_FOLDER + "/" + hash))) {
|
||||
qCDebug(asset_backup) << "Could not open zip file:" << zipFile.getZipError();
|
||||
continue;
|
||||
}
|
||||
zipFile.write(file.readAll());
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCDebug(backup_supervisor) << "Could not close zip file: " << zipFile.getZipError();
|
||||
qCDebug(asset_backup) << "Could not close zip file: " << zipFile.getZipError();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void BackupSupervisor::refreshMappings() {
|
||||
void AssetsBackupHandler::refreshMappings() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
auto request = assetClient->createGetAllMappingsRequest();
|
||||
|
||||
|
@ -301,8 +341,8 @@ void BackupSupervisor::refreshMappings() {
|
|||
|
||||
downloadMissingFiles(_currentMappings);
|
||||
} else {
|
||||
qCCritical(backup_supervisor) << "Could not refresh asset server mappings.";
|
||||
qCCritical(backup_supervisor) << " Error:" << request->getErrorString();
|
||||
qCCritical(asset_backup) << "Could not refresh asset server mappings.";
|
||||
qCCritical(asset_backup) << " Error:" << request->getErrorString();
|
||||
}
|
||||
|
||||
request->deleteLater();
|
||||
|
@ -315,7 +355,7 @@ void BackupSupervisor::refreshMappings() {
|
|||
request->start();
|
||||
}
|
||||
|
||||
void BackupSupervisor::downloadMissingFiles(const AssetUtils::Mappings& mappings) {
|
||||
void AssetsBackupHandler::downloadMissingFiles(const AssetUtils::Mappings& mappings) {
|
||||
auto wasEmpty = _assetsLeftToRequest.empty();
|
||||
|
||||
for (const auto& mapping : mappings) {
|
||||
|
@ -331,7 +371,7 @@ void BackupSupervisor::downloadMissingFiles(const AssetUtils::Mappings& mappings
|
|||
}
|
||||
}
|
||||
|
||||
void BackupSupervisor::downloadNextMissingFile() {
|
||||
void AssetsBackupHandler::downloadNextMissingFile() {
|
||||
if (_assetsLeftToRequest.empty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -342,14 +382,14 @@ void BackupSupervisor::downloadNextMissingFile() {
|
|||
|
||||
QObject::connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) {
|
||||
if (request->getError() == AssetRequest::NoError) {
|
||||
qCDebug(backup_supervisor) << "Backing up asset" << request->getHash();
|
||||
qCDebug(asset_backup) << "Backing up asset" << request->getHash();
|
||||
|
||||
bool success = writeAssetFile(request->getHash(), request->getData());
|
||||
if (!success) {
|
||||
qCCritical(backup_supervisor) << "Failed to write asset file" << request->getHash();
|
||||
qCCritical(asset_backup) << "Failed to write asset file" << request->getHash();
|
||||
}
|
||||
} else {
|
||||
qCCritical(backup_supervisor) << "Failed to backup asset" << request->getHash();
|
||||
qCCritical(asset_backup) << "Failed to backup asset" << request->getHash();
|
||||
}
|
||||
|
||||
_assetsLeftToRequest.erase(request->getHash());
|
||||
|
@ -361,17 +401,17 @@ void BackupSupervisor::downloadNextMissingFile() {
|
|||
assetRequest->start();
|
||||
}
|
||||
|
||||
bool BackupSupervisor::writeAssetFile(const AssetUtils::AssetHash& hash, const QByteArray& data) {
|
||||
bool AssetsBackupHandler::writeAssetFile(const AssetUtils::AssetHash& hash, const QByteArray& data) {
|
||||
QDir assetsDir { _assetsDirectory };
|
||||
QFile file { assetsDir.filePath(hash) };
|
||||
if (!file.open(QFile::WriteOnly)) {
|
||||
qCCritical(backup_supervisor) << "Could not open backup file" << file.fileName();
|
||||
qCCritical(asset_backup) << "Could not open asset file for write:" << file.fileName();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto bytesWritten = file.write(data);
|
||||
if (bytesWritten != data.size()) {
|
||||
qCCritical(backup_supervisor) << "Could not write data to file" << file.fileName();
|
||||
qCCritical(asset_backup) << "Could not write data to file" << file.fileName();
|
||||
file.remove();
|
||||
return false;
|
||||
}
|
||||
|
@ -381,7 +421,7 @@ bool BackupSupervisor::writeAssetFile(const AssetUtils::AssetHash& hash, const Q
|
|||
return true;
|
||||
}
|
||||
|
||||
void BackupSupervisor::computeServerStateDifference(const AssetUtils::Mappings& currentMappings,
|
||||
void AssetsBackupHandler::computeServerStateDifference(const AssetUtils::Mappings& currentMappings,
|
||||
const AssetUtils::Mappings& newMappings) {
|
||||
_mappingsLeftToSet.reserve((int)newMappings.size());
|
||||
_assetsLeftToUpload.reserve((int)newMappings.size());
|
||||
|
@ -411,16 +451,18 @@ void BackupSupervisor::computeServerStateDifference(const AssetUtils::Mappings&
|
|||
}
|
||||
}
|
||||
|
||||
qCDebug(backup_supervisor) << "Mappings to set:" << _mappingsLeftToSet.size();
|
||||
qCDebug(backup_supervisor) << "Mappings to del:" << _mappingsLeftToDelete.size();
|
||||
qCDebug(backup_supervisor) << "Assets to upload:" << _assetsLeftToUpload.size();
|
||||
qCDebug(asset_backup) << "Mappings to set:" << _mappingsLeftToSet.size();
|
||||
qCDebug(asset_backup) << "Mappings to del:" << _mappingsLeftToDelete.size();
|
||||
qCDebug(asset_backup) << "Assets to upload:" << _assetsLeftToUpload.size();
|
||||
}
|
||||
|
||||
void BackupSupervisor::restoreAllAssets() {
|
||||
void AssetsBackupHandler::restoreAllAssets() {
|
||||
restoreNextAsset();
|
||||
}
|
||||
|
||||
void BackupSupervisor::restoreNextAsset() {
|
||||
void AssetsBackupHandler::restoreNextAsset() {
|
||||
startOperation();
|
||||
|
||||
if (_assetsLeftToUpload.empty()) {
|
||||
updateMappings();
|
||||
return;
|
||||
|
@ -436,8 +478,8 @@ void BackupSupervisor::restoreNextAsset() {
|
|||
|
||||
QObject::connect(request, &AssetUpload::finished, this, [this](AssetUpload* request) {
|
||||
if (request->getError() != AssetUpload::NoError) {
|
||||
qCCritical(backup_supervisor) << "Failed to restore asset:" << request->getFilename();
|
||||
qCCritical(backup_supervisor) << " Error:" << request->getErrorString();
|
||||
qCCritical(asset_backup) << "Failed to restore asset:" << request->getFilename();
|
||||
qCCritical(asset_backup) << " Error:" << request->getErrorString();
|
||||
}
|
||||
|
||||
restoreNextAsset();
|
||||
|
@ -448,14 +490,14 @@ void BackupSupervisor::restoreNextAsset() {
|
|||
request->start();
|
||||
}
|
||||
|
||||
void BackupSupervisor::updateMappings() {
|
||||
void AssetsBackupHandler::updateMappings() {
|
||||
auto assetClient = DependencyManager::get<AssetClient>();
|
||||
for (const auto& mapping : _mappingsLeftToSet) {
|
||||
auto request = assetClient->createSetMappingRequest(mapping.first, mapping.second);
|
||||
QObject::connect(request, &SetMappingRequest::finished, this, [this](SetMappingRequest* request) {
|
||||
if (request->getError() != MappingRequest::NoError) {
|
||||
qCCritical(backup_supervisor) << "Failed to set mapping:" << request->getPath();
|
||||
qCCritical(backup_supervisor) << " Error:" << request->getErrorString();
|
||||
qCCritical(asset_backup) << "Failed to set mapping:" << request->getPath();
|
||||
qCCritical(asset_backup) << " Error:" << request->getErrorString();
|
||||
}
|
||||
|
||||
if (--_mappingRequestsInFlight == 0) {
|
||||
|
@ -473,8 +515,8 @@ void BackupSupervisor::updateMappings() {
|
|||
auto request = assetClient->createDeleteMappingsRequest(_mappingsLeftToDelete);
|
||||
QObject::connect(request, &DeleteMappingsRequest::finished, this, [this](DeleteMappingsRequest* request) {
|
||||
if (request->getError() != MappingRequest::NoError) {
|
||||
qCCritical(backup_supervisor) << "Failed to delete mappings";
|
||||
qCCritical(backup_supervisor) << " Error:" << request->getErrorString();
|
||||
qCCritical(asset_backup) << "Failed to delete mappings";
|
||||
qCCritical(asset_backup) << " Error:" << request->getErrorString();
|
||||
}
|
||||
|
||||
if (--_mappingRequestsInFlight == 0) {
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// BackupSupervisor.h
|
||||
// AssetsBackupHandler.h
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Clement Brisset on 1/12/18.
|
||||
|
@ -9,8 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_BackupSupervisor_h
|
||||
#define hifi_BackupSupervisor_h
|
||||
#ifndef hifi_AssetsBackupHandler_h
|
||||
#define hifi_AssetsBackupHandler_h
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
@ -21,22 +21,15 @@
|
|||
#include <QJsonObject>
|
||||
|
||||
#include <AssetUtils.h>
|
||||
|
||||
#include <ReceivedMessage.h>
|
||||
|
||||
class QuaZip;
|
||||
#include "BackupHandler.h"
|
||||
|
||||
struct AssetServerBackup {
|
||||
QString filePath;
|
||||
AssetUtils::Mappings mappings;
|
||||
bool corruptedBackup;
|
||||
};
|
||||
|
||||
class BackupSupervisor : public QObject {
|
||||
class AssetsBackupHandler : public QObject, public BackupHandlerInterface {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BackupSupervisor(const QString& backupDirectory);
|
||||
AssetsBackupHandler(const QString& backupDirectory);
|
||||
|
||||
void loadBackup(QuaZip& zip);
|
||||
void createBackup(QuaZip& zip);
|
||||
|
@ -47,6 +40,7 @@ public:
|
|||
bool operationInProgress() const { return _operationInProgress; }
|
||||
|
||||
private:
|
||||
void setupRefreshTimer();
|
||||
void refreshMappings();
|
||||
|
||||
void refreshAssetsInBackups();
|
||||
|
@ -73,6 +67,12 @@ private:
|
|||
quint64 _lastMappingsRefresh { 0 };
|
||||
AssetUtils::Mappings _currentMappings;
|
||||
|
||||
struct AssetServerBackup {
|
||||
QString filePath;
|
||||
AssetUtils::Mappings mappings;
|
||||
bool corruptedBackup;
|
||||
};
|
||||
|
||||
bool _operationInProgress { false };
|
||||
|
||||
// Internal storage for backups on disk
|
||||
|
@ -91,4 +91,4 @@ private:
|
|||
int _mappingRequestsInFlight { 0 };
|
||||
};
|
||||
|
||||
#endif /* hifi_BackupSupervisor_h */
|
||||
#endif /* hifi_AssetsBackupHandler_h */
|
|
@ -14,140 +14,19 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
#include <QDebug>
|
||||
class QuaZip;
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
|
||||
class BackupHandler {
|
||||
class BackupHandlerInterface {
|
||||
public:
|
||||
template <typename T>
|
||||
BackupHandler(T* x) : _self(new Model<T>(x)) {}
|
||||
virtual ~BackupHandlerInterface() = default;
|
||||
|
||||
void loadBackup(QuaZip& zip) {
|
||||
_self->loadBackup(zip);
|
||||
}
|
||||
void createBackup(QuaZip& zip) {
|
||||
_self->createBackup(zip);
|
||||
}
|
||||
void recoverBackup(QuaZip& zip) {
|
||||
_self->recoverBackup(zip);
|
||||
}
|
||||
void deleteBackup(QuaZip& zip) {
|
||||
_self->deleteBackup(zip);
|
||||
}
|
||||
void consolidateBackup(QuaZip& zip) {
|
||||
_self->consolidateBackup(zip);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Concept {
|
||||
virtual ~Concept() = default;
|
||||
|
||||
virtual void loadBackup(QuaZip& zip) = 0;
|
||||
virtual void createBackup(QuaZip& zip) = 0;
|
||||
virtual void recoverBackup(QuaZip& zip) = 0;
|
||||
virtual void deleteBackup(QuaZip& zip) = 0;
|
||||
virtual void consolidateBackup(QuaZip& zip) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Model : Concept {
|
||||
Model(T* x) : data(x) {}
|
||||
|
||||
void loadBackup(QuaZip& zip) override {
|
||||
data->loadBackup(zip);
|
||||
}
|
||||
void createBackup(QuaZip& zip) override {
|
||||
data->createBackup(zip);
|
||||
}
|
||||
void recoverBackup(QuaZip& zip) override {
|
||||
data->recoverBackup(zip);
|
||||
}
|
||||
void deleteBackup(QuaZip& zip) override {
|
||||
data->deleteBackup(zip);
|
||||
}
|
||||
void consolidateBackup(QuaZip& zip) override {
|
||||
data->consolidateBackup(zip);
|
||||
}
|
||||
|
||||
std::unique_ptr<T> data;
|
||||
};
|
||||
|
||||
std::unique_ptr<Concept> _self;
|
||||
virtual void loadBackup(QuaZip& zip) = 0;
|
||||
virtual void createBackup(QuaZip& zip) = 0;
|
||||
virtual void recoverBackup(QuaZip& zip) = 0;
|
||||
virtual void deleteBackup(QuaZip& zip) = 0;
|
||||
virtual void consolidateBackup(QuaZip& zip) = 0;
|
||||
};
|
||||
|
||||
#include <quazip5/quazipfile.h>
|
||||
#include <OctreeUtils.h>
|
||||
|
||||
class EntitiesBackupHandler {
|
||||
public:
|
||||
EntitiesBackupHandler(QString entitiesFilePath, QString entitiesReplacementFilePath) :
|
||||
_entitiesFilePath(entitiesFilePath),
|
||||
_entitiesReplacementFilePath(entitiesReplacementFilePath) {}
|
||||
|
||||
void loadBackup(QuaZip& zip) {}
|
||||
|
||||
// Create a skeleton backup
|
||||
void createBackup(QuaZip& zip) {
|
||||
QFile entitiesFile { _entitiesFilePath };
|
||||
|
||||
if (entitiesFile.open(QIODevice::ReadOnly)) {
|
||||
QuaZipFile zipFile { &zip };
|
||||
zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("models.json.gz", _entitiesFilePath));
|
||||
zipFile.write(entitiesFile.readAll());
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCritical() << "Failed to zip models.json.gz: " << zipFile.getZipError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recover from a full backup
|
||||
void recoverBackup(QuaZip& zip) {
|
||||
if (!zip.setCurrentFile("models.json.gz")) {
|
||||
qWarning() << "Failed to find models.json.gz while recovering backup";
|
||||
return;
|
||||
}
|
||||
QuaZipFile zipFile { &zip };
|
||||
if (!zipFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "Failed to open models.json.gz in backup";
|
||||
return;
|
||||
}
|
||||
auto rawData = zipFile.readAll();
|
||||
|
||||
zipFile.close();
|
||||
|
||||
OctreeUtils::RawOctreeData data;
|
||||
if (!OctreeUtils::readOctreeDataInfoFromData(rawData, &data)) {
|
||||
qCritical() << "Unable to parse octree data during backup recovery";
|
||||
return;
|
||||
}
|
||||
|
||||
data.resetIdAndVersion();
|
||||
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCritical() << "Failed to unzip models.json.gz: " << zipFile.getZipError();
|
||||
return;
|
||||
}
|
||||
|
||||
QFile entitiesFile { _entitiesReplacementFilePath };
|
||||
|
||||
if (entitiesFile.open(QIODevice::WriteOnly)) {
|
||||
entitiesFile.write(data.toGzippedByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
// Delete a skeleton backup
|
||||
void deleteBackup(QuaZip& zip) {
|
||||
}
|
||||
|
||||
// Create a full backup
|
||||
void consolidateBackup(QuaZip& zip) {
|
||||
}
|
||||
|
||||
private:
|
||||
QString _entitiesFilePath;
|
||||
QString _entitiesReplacementFilePath;
|
||||
};
|
||||
using BackupHandlerPointer = std::unique_ptr<BackupHandlerInterface>;
|
||||
|
||||
#endif /* hifi_BackupHandler_h */
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "DomainContentBackupManager.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
|
@ -25,13 +27,15 @@
|
|||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <PerfStat.h>
|
||||
#include <PathUtils.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
|
||||
#include "DomainServer.h"
|
||||
#include "DomainContentBackupManager.h"
|
||||
|
||||
const int DomainContentBackupManager::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
||||
|
||||
// Backup format looks like: daily_backup-TIMESTAMP.zip
|
||||
|
@ -39,7 +43,8 @@ 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 AUTOMATIC_BACKUP_PREFIX { "autobackup-" };
|
||||
static const QString MANUAL_BACKUP_PREFIX { "backup-" };
|
||||
void DomainContentBackupManager::addBackupHandler(BackupHandler handler) {
|
||||
|
||||
void DomainContentBackupManager::addBackupHandler(BackupHandlerPointer handler) {
|
||||
_backupHandlers.push_back(std::move(handler));
|
||||
}
|
||||
|
||||
|
@ -238,7 +243,7 @@ void DomainContentBackupManager::recoverFromBackup(MiniPromise::Promise promise,
|
|||
success = false;
|
||||
} else {
|
||||
for (auto& handler : _backupHandlers) {
|
||||
handler.recoverBackup(zip);
|
||||
handler->recoverBackup(zip);
|
||||
}
|
||||
|
||||
qDebug() << "Successfully recovered from " << backupName;
|
||||
|
@ -339,7 +344,7 @@ void DomainContentBackupManager::load() {
|
|||
}
|
||||
|
||||
for (auto& handler : _backupHandlers) {
|
||||
handler.loadBackup(zip);
|
||||
handler->loadBackup(zip);
|
||||
}
|
||||
|
||||
zip.close();
|
||||
|
@ -402,7 +407,7 @@ void DomainContentBackupManager::consolidate(QString fileName) {
|
|||
}
|
||||
|
||||
for (auto& handler : _backupHandlers) {
|
||||
handler.consolidateBackup(zip);
|
||||
handler->consolidateBackup(zip);
|
||||
}
|
||||
|
||||
zip.close();
|
||||
|
@ -437,7 +442,7 @@ std::pair<bool, QString> DomainContentBackupManager::createBackup(const QString&
|
|||
}
|
||||
|
||||
for (auto& handler : _backupHandlers) {
|
||||
handler.createBackup(zip);
|
||||
handler->createBackup(zip);
|
||||
}
|
||||
|
||||
zip.close();
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QDateTime>
|
||||
|
||||
#include <GenericThread.h>
|
||||
|
||||
|
@ -50,7 +51,7 @@ public:
|
|||
int persistInterval = DEFAULT_PERSIST_INTERVAL,
|
||||
bool debugTimestampNow = false);
|
||||
|
||||
void addBackupHandler(BackupHandler 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
|
||||
|
@ -82,7 +83,7 @@ protected:
|
|||
|
||||
private:
|
||||
const QString _backupDirectory;
|
||||
std::vector<BackupHandler> _backupHandlers;
|
||||
std::vector<BackupHandlerPointer> _backupHandlers;
|
||||
int _persistInterval { 0 };
|
||||
|
||||
int64_t _lastCheck { 0 };
|
||||
|
|
|
@ -45,8 +45,9 @@
|
|||
#include <Trace.h>
|
||||
#include <StatTracker.h>
|
||||
|
||||
#include "BackupSupervisor.h"
|
||||
#include "AssetsBackupHandler.h"
|
||||
#include "DomainServerNodeData.h"
|
||||
#include "EntitiesBackupHandler.h"
|
||||
#include "NodeConnectionData.h"
|
||||
|
||||
#include <Gzip.h>
|
||||
|
@ -296,8 +297,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
maybeHandleReplacementEntityFile();
|
||||
|
||||
_contentManager.reset(new DomainContentBackupManager(getContentBackupDir(), _settingsManager.settingsResponseObjectForType("6")["entity_server_settings"].toObject()));
|
||||
_contentManager->addBackupHandler(new EntitiesBackupHandler(getEntitiesFilePath(), getEntitiesReplacementFilePath()));
|
||||
_contentManager->addBackupHandler(new BackupSupervisor(getContentBackupDir()));
|
||||
_contentManager->addBackupHandler(BackupHandlerPointer(new EntitiesBackupHandler(getEntitiesFilePath(), getEntitiesReplacementFilePath())));
|
||||
_contentManager->addBackupHandler(BackupHandlerPointer(new AssetsBackupHandler(getContentBackupDir())));
|
||||
_contentManager->initialize(true);
|
||||
|
||||
qDebug() << "Existing backups:";
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <HTTPSConnection.h>
|
||||
#include <LimitedNodeList.h>
|
||||
|
||||
#include "BackupSupervisor.h"
|
||||
#include "AssetsBackupHandler.h"
|
||||
#include "DomainGatekeeper.h"
|
||||
#include "DomainMetadata.h"
|
||||
#include "DomainServerSettingsManager.h"
|
||||
|
|
73
domain-server/src/EntitiesBackupHandler.cpp
Normal file
73
domain-server/src/EntitiesBackupHandler.cpp
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// EntitiesBackupHandler.cpp
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Clement Brisset on 2/14/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "EntitiesBackupHandler.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <quazip5/quazip.h>
|
||||
#include <quazip5/quazipfile.h>
|
||||
|
||||
#include <OctreeUtils.h>
|
||||
|
||||
EntitiesBackupHandler::EntitiesBackupHandler(QString entitiesFilePath, QString entitiesReplacementFilePath) :
|
||||
_entitiesFilePath(entitiesFilePath),
|
||||
_entitiesReplacementFilePath(entitiesReplacementFilePath)
|
||||
{
|
||||
}
|
||||
|
||||
void EntitiesBackupHandler::createBackup(QuaZip& zip) {
|
||||
QFile entitiesFile { _entitiesFilePath };
|
||||
|
||||
if (entitiesFile.open(QIODevice::ReadOnly)) {
|
||||
QuaZipFile zipFile { &zip };
|
||||
zipFile.open(QIODevice::WriteOnly, QuaZipNewInfo("models.json.gz", _entitiesFilePath));
|
||||
zipFile.write(entitiesFile.readAll());
|
||||
zipFile.close();
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCritical() << "Failed to zip models.json.gz: " << zipFile.getZipError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EntitiesBackupHandler::recoverBackup(QuaZip& zip) {
|
||||
if (!zip.setCurrentFile("models.json.gz")) {
|
||||
qWarning() << "Failed to find models.json.gz while recovering backup";
|
||||
return;
|
||||
}
|
||||
QuaZipFile zipFile { &zip };
|
||||
if (!zipFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "Failed to open models.json.gz in backup";
|
||||
return;
|
||||
}
|
||||
auto rawData = zipFile.readAll();
|
||||
|
||||
zipFile.close();
|
||||
|
||||
OctreeUtils::RawOctreeData data;
|
||||
if (!OctreeUtils::readOctreeDataInfoFromData(rawData, &data)) {
|
||||
qCritical() << "Unable to parse octree data during backup recovery";
|
||||
return;
|
||||
}
|
||||
|
||||
data.resetIdAndVersion();
|
||||
|
||||
if (zipFile.getZipError() != UNZ_OK) {
|
||||
qCritical() << "Failed to unzip models.json.gz: " << zipFile.getZipError();
|
||||
return;
|
||||
}
|
||||
|
||||
QFile entitiesFile { _entitiesReplacementFilePath };
|
||||
|
||||
if (entitiesFile.open(QIODevice::WriteOnly)) {
|
||||
entitiesFile.write(data.toGzippedByteArray());
|
||||
}
|
||||
}
|
42
domain-server/src/EntitiesBackupHandler.h
Normal file
42
domain-server/src/EntitiesBackupHandler.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// EntitiesBackupHandler.h
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Clement Brisset on 2/14/18.
|
||||
// Copyright 2018 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_EntitiesBackupHandler_h
|
||||
#define hifi_EntitiesBackupHandler_h
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "BackupHandler.h"
|
||||
|
||||
class EntitiesBackupHandler : public BackupHandlerInterface {
|
||||
public:
|
||||
EntitiesBackupHandler(QString entitiesFilePath, QString entitiesReplacementFilePath);
|
||||
|
||||
void loadBackup(QuaZip& zip) {}
|
||||
|
||||
// Create a skeleton backup
|
||||
void createBackup(QuaZip& zip);
|
||||
|
||||
// Recover from a full backup
|
||||
void recoverBackup(QuaZip& zip);
|
||||
|
||||
// Delete a skeleton backup
|
||||
void deleteBackup(QuaZip& zip) {}
|
||||
|
||||
// Create a full backup
|
||||
void consolidateBackup(QuaZip& zip) {}
|
||||
|
||||
private:
|
||||
QString _entitiesFilePath;
|
||||
QString _entitiesReplacementFilePath;
|
||||
};
|
||||
|
||||
#endif /* hifi_EntitiesBackupHandler_h */
|
Loading…
Reference in a new issue