#include "server_archive.h" #include "../Interface/Server.h" #include "../Interface/Database.h" #include "database.h" #include "../stringtools.h" #include "../urbackupcommon/os_functions.h" #include #include ICondition *ServerAutomaticArchive::cond=NULL; IMutex *ServerAutomaticArchive::mutex=NULL; volatile bool ServerAutomaticArchive::do_quit=false; void ServerAutomaticArchive::operator()(void) { Server->waitForStartupComplete(); db=Server->getDatabase(Server->getThreadID(), URBACKUPDB_SERVER); while(!do_quit) { archiveTimeout(); archiveBackups(); IScopedLock lock(mutex); cond->wait(&lock, 60*60*1000); } delete this; } void ServerAutomaticArchive::archiveTimeout(void) { IQuery *q_timeout=db->Prepare("SELECT id FROM backups WHERE archived=1 AND archive_timeout<>0 AND archive_timeoutBind(Server->getTimeSeconds()); db_results res_timeout=q_timeout->Read(); IQuery *q_unarchive=db->Prepare("UPDATE backups SET archived=0 WHERE id=?"); if(q_unarchive==NULL) return; for(size_t i=0;iBind(res_timeout[i][L"id"]); q_unarchive->Write(); q_unarchive->Reset(); } } void ServerAutomaticArchive::archiveBackups(void) { db_results res_clients=db->Read("SELECT id FROM clients"); for(size_t i=0;iPrepare("SELECT value FROM settings_db.settings WHERE clientid=? AND key=?"); q_get->Bind(clientid); q_get->Bind("overwrite"); db_results res=q_get->Read(); q_get->Reset(); if(res.empty() || res[0][L"value"]!=L"true") r_clientid=0; q_get->Bind(clientid); q_get->Bind("overwrite_archive_settings"); res=q_get->Read(); q_get->Reset(); if(res.empty() || res[0][L"value"]!=L"true") r_clientid=0; bool archive_settings_copied=false; q_get->Bind(clientid); q_get->Bind("archive_settings_copied"); res=q_get->Read(); if(!res.empty() && res[0][L"value"]==L"true") archive_settings_copied=true; if(r_clientid==0 && !archive_settings_copied) { copyArchiveSettings(clientid); } IQuery *q_get_archived=db->Prepare("SELECT id, next_archival, interval, length, backup_types, archive_window FROM settings_db.automatic_archival WHERE clientid=?"); q_get_archived->Bind(clientid); db_results res_archived=q_get_archived->Read(); for(size_t j=0;jgetTimeSeconds(); if(next_archivalLog("Archived file backup with id="+nconvert(backupid)+" for "+nconvert(length)+" seconds", LL_INFO); updateInterval(watoi(res_archived[j][L"id"]), watoi(res_archived[j][L"interval"])); } else { Server->Log("Did not find file backup suitable for archiving with backup_type="+nconvert(watoi(res_archived[j][L"backup_types"])), LL_INFO); } } } } } void ServerAutomaticArchive::updateInterval(int archiveid, int interval) { IQuery *q_update_interval=db->Prepare("UPDATE settings_db.automatic_archival SET next_archival=? WHERE id=?"); if(interval>0) { interval-=60; } q_update_interval->Bind(Server->getTimeSeconds()+interval); q_update_interval->Bind(archiveid); q_update_interval->Write(); } int ServerAutomaticArchive::getNonArchivedFileBackup(int backup_types, int clientid) { std::string incremental; if(backup_types & backup_type_full_file && backup_types & backup_type_incr_file) incremental=""; else if( backup_types & backup_type_full_file ) incremental=" AND incremental<>0"; else if( backup_types & backup_type_incr_file) incremental=" AND incremental=0"; IQuery *q_get_backups=db->Prepare("SELECT id FROM backups WHERE complete=1 AND archived=0 AND clientid=?"+incremental+" ORDER BY backuptime DESC LIMIT 1"); q_get_backups->Bind(clientid); db_results res=q_get_backups->Read(); if(!res.empty()) return watoi(res[0][L"id"]); else return 0; } void ServerAutomaticArchive::archiveFileBackup(int backupid, int length) { IQuery *q_archive=db->Prepare("UPDATE backups SET archived=1, archive_timeout=? WHERE id=?"); if(length!=-1) { q_archive->Bind(Server->getTimeSeconds()+length); } else { q_archive->Bind(-1); } q_archive->Bind(backupid); q_archive->Write(); } int ServerAutomaticArchive::getBackupTypes(const std::wstring &backup_type_name) { int type=0; if(backup_type_name==L"incr_file") type|=backup_type_incr_file; else if(backup_type_name==L"full_file") type|=backup_type_full_file; else if(backup_type_name==L"file") type|=backup_type_incr_file|backup_type_full_file; return type; } std::wstring ServerAutomaticArchive::getBackupType(int backup_types) { if( backup_types & backup_type_full_file && backup_types & backup_type_incr_file ) return L"file"; else if( backup_types & backup_type_full_file ) return L"full_file"; else if( backup_types & backup_type_incr_file) return L"incr_file"; return L""; } void ServerAutomaticArchive::copyArchiveSettings(int clientid) { db_results res_all=db->Read("SELECT id, next_archival, interval, interval_unit, length, length_unit, backup_types, archive_window FROM settings_db.automatic_archival WHERE clientid=0"); std::vector next_archivals; for(size_t i=0;iPrepare("SELECT next_archival FROM settings_db.automatic_archival WHERE clientid=? AND interval=? AND length=? AND backup_types=? AND archive_window=?"); IQuery *q_num=db->Prepare("SELECT count(*) AS num FROM settings_db.automatic_archival WHERE clientid=0 AND interval=? AND length=? AND backup_types=? AND archive_window=? AND idBind(interval); q_num->Bind(length); q_num->Bind(backup_types); q_num->Bind(archive_window); q_num->Bind(id); db_results res_num=q_num->Read(); int num=watoi(res_num[0][L"num"]); q_next->Bind(clientid); q_next->Bind(interval); q_next->Bind(length); q_next->Bind(backup_types); q_next->Bind(archive_window); db_results res_next=q_next->Read(); if((size_t)numgetTimeSeconds()); } } next_archivals.push_back(next_archival); } IQuery *q_del_all=db->Prepare("DELETE FROM settings_db.automatic_archival WHERE clientid=?"); IQuery *q_insert_all=db->Prepare("INSERT INTO settings_db.automatic_archival (next_archival, interval, interval_unit, length, length_unit, backup_types, clientid, archive_window)" "VALUES (?,?,?,?,?,?,?,?)"); q_del_all->Bind(clientid); q_del_all->Write(); for(size_t i=0;iBind(next_archivals[i]); q_insert_all->Bind(interval); q_insert_all->Bind(res_all[i][L"interval_unit"]); q_insert_all->Bind(length); q_insert_all->Bind(res_all[i][L"length_unit"]); q_insert_all->Bind(backup_types); q_insert_all->Bind(clientid); q_insert_all->Bind(archive_window); q_insert_all->Write(); q_insert_all->Reset(); } IQuery *q_insert_copied=db->Prepare("INSERT INTO settings_db.settings (key, value, clientid) VALUES ('archive_settings_copied','true',?)"); q_insert_copied->Bind(clientid); q_insert_copied->Write(); } bool ServerAutomaticArchive::isInArchiveWindow(const std::wstring &window_def) { std::vector toks; Tokenize(window_def, toks, L";"); bool matched_dom=false; for(size_t i=0;i stoks; Tokenize(toks[i], stoks, L","); std::vector nums; for(size_t j=0;jnotify_all(); } void ServerAutomaticArchive::initMutex(void) { mutex=Server->createMutex(); cond=Server->createCondition(); } void ServerAutomaticArchive::destroyMutex(void) { Server->destroy(mutex); Server->destroy(cond); }