From f44513ebe7df295587867a0ab9f7bf0ac31b247f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 15 Nov 2014 22:55:12 -0800 Subject: [PATCH] added support for rolling version numbers in backups --- assignment-client/src/octree/OctreeServer.cpp | 6 +- assignment-client/src/octree/OctreeServer.h | 1 + .../resources/describe-settings.json | 14 ++++- libraries/octree/src/OctreePersistThread.cpp | 58 +++++++++++++++++-- libraries/octree/src/OctreePersistThread.h | 6 +- 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f78a9a2b30..35b706d5f2 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1047,6 +1047,10 @@ void OctreeServer::readConfiguration() { _backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL; readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval); qDebug() << "backupInterval=" << _backupInterval; + + _maxBackupVersions = OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS; + readOptionInt(QString("maxBackupVersions"), settingsSectionObject, _maxBackupVersions); + qDebug() << "maxBackupVersions=" << _maxBackupVersions; } } else { @@ -1133,7 +1137,7 @@ void OctreeServer::run() { // now set up PersistThread _persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval, - _wantBackup, _backupInterval, _backupExtensionFormat); + _wantBackup, _backupInterval, _backupExtensionFormat, _maxBackupVersions); if (_persistThread) { _persistThread->initialize(true); } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 8a91b94da0..b2a452ae52 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -172,6 +172,7 @@ protected: bool _wantBackup; QString _backupExtensionFormat; int _backupInterval; + int _maxBackupVersions; static OctreeServer* _instance; diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 04c48e460e..d698fc3454 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -302,9 +302,9 @@ { "name": "backupExtensionFormat", "label": "Backup File Extension Format:", - "help": "Format used to create the extension for the backup of your persisted entities.", - "placeholder": ".backup.%Y-%m-%d.%H:%M:%S.%z", - "default": ".backup.%Y-%m-%d.%H:%M:%S.%z", + "help": "Format used to create the extension for the backup of your persisted entities. Use a format with %N to get rolling. Or use date formatting like %Y-%m-%d.%H:%M:%S.%z", + "placeholder": ".backup.%N", + "default": ".backup.%N", "advanced": true }, { @@ -315,6 +315,14 @@ "default": "1800000", "advanced": true }, + { + "name": "maxBackupVersions", + "label": "Max Rolled Backup Versions", + "help": "If your backup extension format uses 'rolling', how many versions do you want us to keep?", + "placeholder": "5", + "default": "5", + "advanced": true + }, { "name": "NoBackup", "type": "checkbox", diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index f74ddfa5f0..53de80660c 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -12,21 +12,26 @@ #include #include +#include + #include #include #include "OctreePersistThread.h" const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds -const int OctreePersistThread::DEFAULT_BACKUP_INTERVAL = 1000 * 60 * 30; // every 30 minutes -const QString OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT(".backup.%Y-%m-%d.%H:%M:%S.%z"); +const int OctreePersistThread::DEFAULT_BACKUP_INTERVAL = 1000 * 60 * 1; // 30; // every 30 minutes +const QString OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT(".backup.%N"); +const int OctreePersistThread::DEFAULT_MAX_BACKUP_VERSIONS = 5; OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval, - bool wantBackup, int backupInterval, const QString& backupExtensionFormat) : + bool wantBackup, int backupInterval, const QString& backupExtensionFormat, + int maxBackupVersions) : _tree(tree), _filename(filename), _backupExtensionFormat(backupExtensionFormat), + _maxBackupVersions(maxBackupVersions), _persistInterval(persistInterval), _backupInterval(backupInterval), _initialLoadComplete(false), @@ -131,6 +136,37 @@ void OctreePersistThread::persist() { } } +void OctreePersistThread::rollOldBackupVersions() { + if (!_backupExtensionFormat.contains("%N")) { + return; // this backup extension format doesn't support rolling + } + + qDebug() << "Rolling old backup versions..."; + for(int n = _maxBackupVersions - 1; n > 0; n--) { + QString backupExtensionN = _backupExtensionFormat; + QString backupExtensionNplusOne = _backupExtensionFormat; + backupExtensionN.replace(QString("%N"), QString::number(n)); + backupExtensionNplusOne.replace(QString("%N"), QString::number(n+1)); + + QString backupFilenameN = _filename + backupExtensionN; + QString backupFilenameNplusOne = _filename + backupExtensionNplusOne; + + QFile backupFileN(backupFilenameN); + + if (backupFileN.exists()) { + qDebug() << "rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + int result = rename(qPrintable(backupFilenameN), qPrintable(backupFilenameNplusOne)); + if (result == 0) { + qDebug() << "DONE rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + } else { + qDebug() << "ERROR in rolling backup file " << backupFilenameN << "to" << backupFilenameNplusOne << "..."; + } + } + } + qDebug() << "Done rolling old backup versions..."; +} + + void OctreePersistThread::backup() { if (_wantBackup) { quint64 now = usecTimestampNow(); @@ -141,10 +177,20 @@ void OctreePersistThread::backup() { if (sinceLastBackup > intervalToBackup) { struct tm* localTime = localtime(&_lastPersistTime); - char backupExtension[256]; - strftime(backupExtension, sizeof(backupExtension), qPrintable(_backupExtensionFormat), localTime); + QString backupFileName; + + // check to see if they asked for version rolling format + if (_backupExtensionFormat.contains("%N")) { + rollOldBackupVersions(); // rename all the old backup files accordingly + QString backupExtension = _backupExtensionFormat; + backupExtension.replace(QString("%N"), QString("1")); + backupFileName = _filename + backupExtension; + } else { + char backupExtension[256]; + strftime(backupExtension, sizeof(backupExtension), qPrintable(_backupExtensionFormat), localTime); + backupFileName = _filename + backupExtension; + } - QString backupFileName = _filename + backupExtension; qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "..."; int result = rename(qPrintable(_filename), qPrintable(backupFileName)); diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index 06b97b2dcb..5aac67844f 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -25,10 +25,12 @@ public: static const int DEFAULT_PERSIST_INTERVAL; static const int DEFAULT_BACKUP_INTERVAL; static const QString DEFAULT_BACKUP_EXTENSION_FORMAT; + static const int DEFAULT_MAX_BACKUP_VERSIONS; OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, bool wantBackup = false, int backupInterval = DEFAULT_BACKUP_INTERVAL, - const QString& backupExtensionFormat = DEFAULT_BACKUP_EXTENSION_FORMAT); + const QString& backupExtensionFormat = DEFAULT_BACKUP_EXTENSION_FORMAT, + int maxBackupVersions = DEFAULT_MAX_BACKUP_VERSIONS); bool isInitialLoadComplete() const { return _initialLoadComplete; } quint64 getLoadElapsedTime() const { return _loadTimeUSecs; } @@ -44,10 +46,12 @@ protected: void persist(); void backup(); + void rollOldBackupVersions(); private: Octree* _tree; QString _filename; QString _backupExtensionFormat; + int _maxBackupVersions; int _persistInterval; int _backupInterval; bool _initialLoadComplete;