From cd4b2677324981374c2d63b1d8d485a59eebff08 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 14 Nov 2014 11:11:32 -0800 Subject: [PATCH] implement persist backup --- assignment-client/src/octree/OctreeServer.cpp | 25 ++++++- assignment-client/src/octree/OctreeServer.h | 5 ++ libraries/octree/src/OctreePersistThread.cpp | 74 +++++++++++++++---- libraries/octree/src/OctreePersistThread.h | 16 +++- 4 files changed, 101 insertions(+), 19 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 34378effd3..f78a9a2b30 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1020,7 +1020,7 @@ void OctreeServer::readConfiguration() { bool noPersist; readOptionBool(QString("NoPersist"), settingsSectionObject, noPersist); _wantPersist = !noPersist; - qDebug("wantPersist=%s", debug::valueOf(_wantPersist)); + qDebug() << "wantPersist=" << _wantPersist; if (_wantPersist) { QString persistFilename; @@ -1029,6 +1029,26 @@ void OctreeServer::readConfiguration() { } strcpy(_persistFilename, qPrintable(persistFilename)); qDebug("persistFilename=%s", _persistFilename); + + _persistInterval = OctreePersistThread::DEFAULT_PERSIST_INTERVAL; + readOptionInt(QString("persistInterval"), settingsSectionObject, _persistInterval); + qDebug() << "persistInterval=" << _persistInterval; + + bool noBackup; + readOptionBool(QString("NoBackup"), settingsSectionObject, noBackup); + _wantBackup = !noBackup; + qDebug() << "wantBackup=" << _wantBackup; + + if (_wantBackup) { + _backupExtensionFormat = OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT; + readOptionString(QString("backupExtensionFormat"), settingsSectionObject, _backupExtensionFormat); + qDebug() << "backupExtensionFormat=" << _backupExtensionFormat; + + _backupInterval = OctreePersistThread::DEFAULT_BACKUP_INTERVAL; + readOptionInt(QString("backupInterval"), settingsSectionObject, _backupInterval); + qDebug() << "backupInterval=" << _backupInterval; + } + } else { qDebug("persistFilename= DISABLED"); } @@ -1112,7 +1132,8 @@ void OctreeServer::run() { if (_wantPersist) { // now set up PersistThread - _persistThread = new OctreePersistThread(_tree, _persistFilename); + _persistThread = new OctreePersistThread(_tree, _persistFilename, _persistInterval, + _wantBackup, _backupInterval, _backupExtensionFormat); if (_persistThread) { _persistThread->initialize(true); } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index b05896596c..8a91b94da0 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -167,6 +167,11 @@ protected: JurisdictionSender* _jurisdictionSender; OctreeInboundPacketProcessor* _octreeInboundPacketProcessor; OctreePersistThread* _persistThread; + + int _persistInterval; + bool _wantBackup; + QString _backupExtensionFormat; + int _backupInterval; static OctreeServer* _instance; diff --git a/libraries/octree/src/OctreePersistThread.cpp b/libraries/octree/src/OctreePersistThread.cpp index dd81b3ff4d..f8afb52b85 100644 --- a/libraries/octree/src/OctreePersistThread.cpp +++ b/libraries/octree/src/OctreePersistThread.cpp @@ -15,12 +15,23 @@ #include "OctreePersistThread.h" -OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval) : +const int OctreePersistThread::DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds +const int OctreePersistThread::DEFAULT_BACKUP_INTERVAL = 1000 * 60 * 1; // every 1 minutes +const QString OctreePersistThread::DEFAULT_BACKUP_EXTENSION_FORMAT(".backup.%Y-%m-%d.%H:%M:%S.%z"); + + +OctreePersistThread::OctreePersistThread(Octree* tree, const QString& filename, int persistInterval, + bool wantBackup, int backupInterval, const QString& backupExtensionFormat) : _tree(tree), _filename(filename), + _backupExtensionFormat(backupExtensionFormat), _persistInterval(persistInterval), + _backupInterval(backupInterval), _initialLoadComplete(false), - _loadTimeUSecs(0) + _loadTimeUSecs(0), + _lastCheck(0), + _lastBackup(0), + _wantBackup(wantBackup) { } @@ -51,16 +62,22 @@ bool OctreePersistThread::process() { unsigned long leafNodeCount = OctreeElement::getLeafNodeCount(); qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves", nodeCount, internalNodeCount, leafNodeCount); - double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() / (double)OctreeElement::getGetChildAtIndexCalls(); - qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls() - << " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet; + bool wantDebug = false; + if (wantDebug) { + double usecPerGet = (double)OctreeElement::getGetChildAtIndexTime() + / (double)OctreeElement::getGetChildAtIndexCalls(); + qDebug() << "getChildAtIndexCalls=" << OctreeElement::getGetChildAtIndexCalls() + << " getChildAtIndexTime=" << OctreeElement::getGetChildAtIndexTime() << " perGet=" << usecPerGet; - double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() / (double)OctreeElement::getSetChildAtIndexCalls(); - qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls() - << " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perset=" << usecPerSet; + double usecPerSet = (double)OctreeElement::getSetChildAtIndexTime() + / (double)OctreeElement::getSetChildAtIndexCalls(); + qDebug() << "setChildAtIndexCalls=" << OctreeElement::getSetChildAtIndexCalls() + << " setChildAtIndexTime=" << OctreeElement::getSetChildAtIndexTime() << " perSet=" << usecPerSet; + } _initialLoadComplete = true; - _lastCheck = usecTimestampNow(); // we just loaded, no need to save again + _lastBackup = _lastCheck = usecTimestampNow(); // we just loaded, no need to save again + time(&_lastPersistTime); emit loadCompleted(); } @@ -79,7 +96,7 @@ bool OctreePersistThread::process() { if (sinceLastSave > intervalToCheck) { _lastCheck = now; - persistOperation(); + persist(); } } return isStillRunning(); // keep running till they terminate us @@ -88,11 +105,11 @@ bool OctreePersistThread::process() { void OctreePersistThread::aboutToFinish() { qDebug() << "Persist thread about to finish..."; - persistOperation(); + persist(); qDebug() << "Persist thread done with about to finish..."; } -void OctreePersistThread::persistOperation() { +void OctreePersistThread::persist() { if (_tree->isDirty()) { _tree->lockForWrite(); { @@ -102,9 +119,38 @@ void OctreePersistThread::persistOperation() { } _tree->unlock(); + backup(); // handle backup if requested + qDebug() << "saving Octree to file " << _filename << "..."; - _tree->writeToSVOFile(_filename.toLocal8Bit().constData()); + _tree->writeToSVOFile(qPrintable(_filename)); + time(&_lastPersistTime); _tree->clearDirtyBit(); // tree is clean after saving - qDebug("DONE saving Octree to file..."); + qDebug() << "DONE saving Octree to file..."; + } +} + +void OctreePersistThread::backup() { + if (_wantBackup) { + quint64 now = usecTimestampNow(); + quint64 sinceLastBackup = now - _lastBackup; + quint64 MSECS_TO_USECS = 1000; + quint64 intervalToBackup = _backupInterval * MSECS_TO_USECS; + + if (sinceLastBackup > intervalToBackup) { + struct tm* localTime = localtime(&_lastPersistTime); + + char backupExtension[256]; + strftime(backupExtension, sizeof(backupExtension), qPrintable(_backupExtensionFormat), localTime); + + QString backupFileName = _filename + backupExtension; + + qDebug() << "backing up persist file " << _filename << "to" << backupFileName << "..."; + int result = rename(qPrintable(_filename), qPrintable(backupFileName)); + if (result == 0) { + qDebug() << "DONE backing up persist file..."; + } else { + qDebug() << "ERROR in backing up persist file..."; + } + } } } diff --git a/libraries/octree/src/OctreePersistThread.h b/libraries/octree/src/OctreePersistThread.h index c4bccd55b9..c02e416e25 100644 --- a/libraries/octree/src/OctreePersistThread.h +++ b/libraries/octree/src/OctreePersistThread.h @@ -22,9 +22,13 @@ class OctreePersistThread : public GenericThread { Q_OBJECT public: - static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds + static const int DEFAULT_PERSIST_INTERVAL; + static const int DEFAULT_BACKUP_INTERVAL; + static const QString DEFAULT_BACKUP_EXTENSION_FORMAT; - OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL); + OctreePersistThread(Octree* tree, const QString& filename, int persistInterval = DEFAULT_PERSIST_INTERVAL, + bool wantBackup = true, int backupInterval = DEFAULT_BACKUP_INTERVAL, + const QString& backupExtensionFormat = DEFAULT_BACKUP_EXTENSION_FORMAT); bool isInitialLoadComplete() const { return _initialLoadComplete; } quint64 getLoadElapsedTime() const { return _loadTimeUSecs; } @@ -38,15 +42,21 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process(); - void persistOperation(); + void persist(); + void backup(); private: Octree* _tree; QString _filename; + QString _backupExtensionFormat; int _persistInterval; + int _backupInterval; bool _initialLoadComplete; quint64 _loadTimeUSecs; quint64 _lastCheck; + quint64 _lastBackup; + bool _wantBackup; + time_t _lastPersistTime; }; #endif // hifi_OctreePersistThread_h