urbackup_backend/urbackupclient/PersistentOpenFiles.cpp
2021-06-20 20:58:50 +02:00

294 lines
6.3 KiB
C++

#include "PersistentOpenFiles.h"
#include "../urbackupcommon/os_functions.h"
#include "../stringtools.h"
#include "file_permissions.h"
const char* persistent_open_files_fn = "urbackup\\open_files.dat";
const char* persistent_open_files_new_fn = "urbackup\\open_files.dat.new";
bool PersistentOpenFiles::cycle()
{
Server->destroy(persistf);
persistf = Server->openFile(persistent_open_files_new_fn, MODE_WRITE);
#ifndef _DEBUG
change_file_permissions_admin_only(persistent_open_files_new_fn);
#endif
if(!persistf) return false;
bytes_deleted = 0;
bytes_written = 0;
for(std::map<std::string, unsigned int>::iterator it=open_files.begin();it!=open_files.end();++it)
{
addf(it->first, it->second);
}
flushf_int(false);
Server->destroy(persistf);
if(!os_rename_file(persistent_open_files_new_fn, persistent_open_files_fn))
{
return false;
}
persistf = Server->openFile(persistent_open_files_fn, MODE_RW);
if(!persistf) return false;
return true;
}
bool PersistentOpenFiles::flushf_int(bool allow_cycle)
{
if(!persistf) return false;
if(wdata.getDataSize()==0) return true;
if(bytes_deleted>bytes_written*2 && allow_cycle)
{
wdata.clear();
return cycle();
}
_u32 w = persistf->Write(wdata.getDataPtr(), wdata.getDataSize());
if(w!=wdata.getDataSize())
{
Server->Log("Error persisting open files to disk", LL_ERROR);
wdata.clear();
return false;
}
wdata.clear();
if(persistf->Size()>20*1024*1024 && allow_cycle
&& bytes_deleted>5*1024*1024)
{
return cycle();
}
return true;
}
bool PersistentOpenFiles::flushf()
{
return flushf_int(true);
}
void PersistentOpenFiles::removef( unsigned int id, size_t fn_size )
{
wdata.addChar(PERSIST_REMOVE);
wdata.addInt64(Server->getTimeMS());
wdata.addUInt(id);
bytes_deleted+=1+sizeof(int64)+sizeof(id);
bytes_deleted+=1+sizeof(int64)+sizeof(_u32)+fn_size+sizeof(id);
}
void PersistentOpenFiles::addf( const std::string& fn, unsigned int id )
{
if(!persistf) return;
wdata.addChar(PERSIST_ADD);
wdata.addInt64(Server->getTimeMS());
wdata.addString((fn));
wdata.addUInt(id);
bytes_written+=1+sizeof(int64)+sizeof(_u32)+fn.size()+sizeof(id);
}
bool PersistentOpenFiles::load()
{
if(!persistf)
{
Server->Log("No persisted open files list", LL_INFO);
return false;
}
bytes_written=0;
bytes_deleted=0;
std::vector<char> data;
data.resize(persistf->Size());
size_t read=0;
while(read<data.size())
{
read+=persistf->Read(data.data()+read, static_cast<_u32>(data.size()-read));
}
CRData pdata(data.data(), data.size());
std::map<std::string, unsigned int> new_open_files;
int64 max_time=0;
int64 ctime = Server->getTimeMS();
char id;
while(pdata.getChar(&id))
{
if(id==PERSIST_ADD)
{
int64 rec_time;
if(!pdata.getInt64(&rec_time))
{
Server->Log("Error reading rec_time from persisted open files", LL_ERROR);
return false;
}
std::string fn;
if(!pdata.getStr(&fn))
{
Server->Log("Error reading fn from persisted open files", LL_ERROR);
return false;
}
unsigned int id;
if(!pdata.getUInt(&id))
{
Server->Log("Error reading id from persisted open files", LL_ERROR);
return false;
}
new_open_files[(fn)]=id;
curr_id=(std::max)(curr_id, id);
max_time=(std::max)(max_time, rec_time);
if(max_time>ctime)
{
Server->Log("Persisted open files list is obsolete (restart occurred) (1)", LL_INFO);
return false;
}
bytes_written+=1+sizeof(int64)+sizeof(_u32)+fn.size()+sizeof(id);
}
else if(id==PERSIST_REMOVE)
{
int64 rec_time;
if(!pdata.getInt64(&rec_time))
{
Server->Log("Error reading rec_time from persisted open files (remove)", LL_ERROR);
return false;
}
unsigned int id;
if(!pdata.getUInt(&id))
{
Server->Log("Error reading id from persisted open files (remove)", LL_ERROR);
return false;
}
bool found=false;
for(std::map<std::string, unsigned int>::iterator it=new_open_files.begin();it!=new_open_files.end();++it)
{
if(it->second==id)
{
bytes_deleted+=1+sizeof(int64)+sizeof(id);
bytes_deleted+=1+sizeof(int64)+sizeof(_u32)+it->first.size()+sizeof(id);
found=true;
new_open_files.erase(it);
break;
}
}
if(!found) return false;
max_time=(std::max)(max_time, rec_time);
if(max_time>ctime)
{
Server->Log("Persisted open files list is obsolete (restart occurred) (2)", LL_INFO);
return false;
}
}
else
{
Server->Log("Unknown id while reading persisted open files", LL_ERROR);
return false;
}
}
if(max_time>Server->getTimeMS())
{
Server->Log("Persisted open files list is obsolete (restart occurred)", LL_INFO);
return false;
}
open_files = new_open_files;
return true;
}
std::vector<std::string> PersistentOpenFiles::get()
{
std::vector<std::string> ret;
for(std::map<std::string, unsigned int>::iterator it=open_files.begin();it!=open_files.end();++it)
{
ret.push_back(it->first);
}
return ret;
}
void PersistentOpenFiles::remove( const std::string& fn )
{
std::map<std::string, unsigned int>::iterator it=open_files.find(fn);
if(it!=open_files.end())
{
removef(it->second, it->first.size());
open_files.erase(it);
}
}
void PersistentOpenFiles::add( const std::string& fn )
{
if(open_files.find(fn)==open_files.end())
{
++curr_id;
open_files[fn]=curr_id;
addf(fn, curr_id);
}
}
bool PersistentOpenFiles::is_present( const std::string& fn )
{
return (open_files.find(fn)!=open_files.end());
}
PersistentOpenFiles::PersistentOpenFiles() : curr_id(0), bytes_written(0), bytes_deleted(0)
{
persistf = Server->openFile(persistent_open_files_fn, MODE_RW_CREATE);
#ifndef _DEBUG
change_file_permissions_admin_only(persistent_open_files_fn);
#endif
if(!load())
{
Server->destroy(persistf);
persistf = Server->openFile(persistent_open_files_fn, MODE_WRITE);
#ifndef _DEBUG
change_file_permissions_admin_only(persistent_open_files_fn);
#endif
if(persistf==nullptr)
{
Server->Log(std::string("Error opening open write file at ")+persistent_open_files_fn, LL_ERROR);
}
}
}
PersistentOpenFiles::~PersistentOpenFiles()
{
Server->destroy(persistf);
}