2
0
Эх сурвалжийг харах

Create periodic backup copies of controller.db in network controller from the main process itself to facilitate easier and safer backups of controller.db.

Adam Ierymenko 10 жил өмнө
parent
commit
7903f24a8f

+ 55 - 0
controller/SqliteNetworkController.cpp

@@ -71,6 +71,9 @@
 // than this (ms).
 #define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
 
+// Delay between backups in milliseconds
+#define ZT_NETCONF_BACKUP_PERIOD 60000
+
 namespace ZeroTier {
 
 namespace {
@@ -122,6 +125,7 @@ struct NetworkRecord {
 
 SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath) :
 	_node(node),
+	_backupThreadRun(true),
 	_dbPath(dbPath),
 	_circuitTestPath(circuitTestPath),
 	_db((sqlite3 *)0)
@@ -247,10 +251,15 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
 			throw std::runtime_error("SqliteNetworkController unable to read instanceId (it's NULL)");
 		_instanceId = iid;
 	}
+
+	_backupThread = Thread::start(this);
 }
 
 SqliteNetworkController::~SqliteNetworkController()
 {
+	_backupThreadRun = false;
+	Thread::join(_backupThread);
+
 	Mutex::Lock _l(_lock);
 	if (_db) {
 		sqlite3_finalize(_sGetNetworkById);
@@ -991,6 +1000,52 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
 	return 404;
 }
 
+void SqliteNetworkController::threadMain()
+	throw()
+{
+	uint64_t lastBackupTime = 0;
+	while (_backupThreadRun) {
+		if ((OSUtils::now() - lastBackupTime) >= ZT_NETCONF_BACKUP_PERIOD) {
+			lastBackupTime = OSUtils::now();
+
+			char backupPath[4096],backupPath2[4096];
+			Utils::snprintf(backupPath,sizeof(backupPath),"%s.backupInProgress",_dbPath.c_str());
+			Utils::snprintf(backupPath2,sizeof(backupPath),"%s.backup",_dbPath.c_str());
+			OSUtils::rm(backupPath); // delete any unfinished backups
+
+			sqlite3 *bakdb = (sqlite3 *)0;
+			sqlite3_backup *bak = (sqlite3_backup *)0;
+			if (sqlite3_open_v2(backupPath,&bakdb,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK) {
+				fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_open_v2()"ZT_EOL_S);
+				continue;
+			}
+			bak = sqlite3_backup_init(bakdb,"main",_db,"main");
+			if (!bak) {
+				sqlite3_close(bakdb);
+				OSUtils::rm(backupPath); // delete any unfinished backups
+				fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_backup_init()"ZT_EOL_S);
+				continue;
+			}
+
+			int rc = SQLITE_OK;
+			for(;;) {
+				rc = sqlite3_backup_step(bak,1);
+				if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY))
+					Thread::sleep(100);
+				else break;
+			}
+
+			sqlite3_backup_finish(bak);
+			sqlite3_close(bakdb);
+
+			OSUtils::rm(backupPath2);
+			::rename(backupPath,backupPath2);
+		}
+
+		Thread::sleep(500);
+	}
+}
+
 unsigned int SqliteNetworkController::_doCPGet(
 	const std::vector<std::string> &path,
 	const std::map<std::string,std::string> &urlArgs,

+ 7 - 0
controller/SqliteNetworkController.hpp

@@ -39,6 +39,7 @@
 #include "../node/Constants.hpp"
 #include "../node/NetworkController.hpp"
 #include "../node/Mutex.hpp"
+#include "../osdep/Thread.hpp"
 
 // Number of in-memory last log entries to maintain per user
 #define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32
@@ -86,6 +87,10 @@ public:
 		std::string &responseBody,
 		std::string &responseContentType);
 
+	// threadMain() for backup thread -- do not call directly
+	void threadMain()
+		throw();
+
 private:
 	enum IpAssignmentType {
 		// IP assignment is a static IP address
@@ -112,6 +117,8 @@ private:
 	static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
 
 	Node *_node;
+	Thread _backupThread;
+	volatile bool _backupThreadRun;
 	std::string _dbPath;
 	std::string _circuitTestPath;
 	std::string _instanceId;

+ 0 - 1
osdep/OSUtils.hpp

@@ -95,7 +95,6 @@ public:
 	static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); }
 
 	static inline bool mkdir(const char *path)
-		throw()
 	{
 #ifdef __WINDOWS__
 		if (::PathIsDirectoryA(path))