mirror of
https://github.com/anope/anope.git
synced 2026-06-27 19:46:38 +02:00
Make db_flatfile import-only.
This commit is contained in:
@@ -11,31 +11,6 @@
|
||||
|
||||
#include "module.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
class SaveData final
|
||||
: public Serialize::Data
|
||||
{
|
||||
public:
|
||||
Anope::string last;
|
||||
std::fstream *fs = nullptr;
|
||||
|
||||
std::iostream &operator[](const Anope::string &key) override
|
||||
{
|
||||
if (key != last)
|
||||
{
|
||||
*fs << "\nDATA " << key << " ";
|
||||
last = key;
|
||||
}
|
||||
|
||||
return *fs;
|
||||
}
|
||||
};
|
||||
|
||||
class LoadData final
|
||||
: public Serialize::Data
|
||||
{
|
||||
@@ -97,133 +72,14 @@ public:
|
||||
|
||||
class DBFlatFile final
|
||||
: public Module
|
||||
, public Pipe
|
||||
{
|
||||
/* Day the last backup was on */
|
||||
int last_day = 0;
|
||||
private:
|
||||
bool loaded = false;
|
||||
|
||||
int child_pid = -1;
|
||||
|
||||
void BackupDatabase()
|
||||
{
|
||||
tm *tm = localtime(&Anope::CurTime);
|
||||
|
||||
if (tm->tm_mday != last_day)
|
||||
{
|
||||
last_day = tm->tm_mday;
|
||||
|
||||
std::set<Anope::string> dbs;
|
||||
dbs.insert(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
|
||||
|
||||
for (const auto &type_order : Serialize::Type::GetTypeOrder())
|
||||
{
|
||||
Serialize::Type *stype = Serialize::Type::Find(type_order);
|
||||
|
||||
if (stype && stype->GetOwner())
|
||||
dbs.insert("module_" + stype->GetOwner()->name + ".db");
|
||||
}
|
||||
|
||||
const auto backupdir = Anope::ExpandData("backups");
|
||||
for (const auto &db : dbs)
|
||||
{
|
||||
const auto oldname = Anope::ExpandData(db);
|
||||
const auto basename = Anope::Expand(backupdir, db + "-");
|
||||
const auto newname = Anope::printf("%s%04i-%02i-%02i", basename.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
|
||||
/* Backup already exists or no database to backup */
|
||||
if (Anope::IsFile(newname) || !Anope::IsFile(oldname))
|
||||
continue;
|
||||
|
||||
Log(LOG_DEBUG) << "db_flatfile: Attempting to rename " << db << " to " << newname;
|
||||
if (rename(oldname.c_str(), newname.c_str()))
|
||||
{
|
||||
Anope::string err = Anope::LastError();
|
||||
Log(this) << "Unable to back up database " << db << " (" << err << ")!";
|
||||
|
||||
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
|
||||
{
|
||||
Anope::Quitting = true;
|
||||
Anope::QuitReason = "Unable to back up database " + db + " (" + err + ")";
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto keepbackups = Config->GetModule(this).Get<unsigned>("keepbackups", "7");
|
||||
if (!keepbackups)
|
||||
continue;
|
||||
|
||||
std::error_code ec;
|
||||
std::set<Anope::string> old_backups;
|
||||
for (const auto &entry : std::filesystem::directory_iterator(backupdir.str(), ec))
|
||||
{
|
||||
Anope::string entryname = entry.path().string();
|
||||
if (entryname.compare(0, basename.length(), basename) != 0)
|
||||
continue;
|
||||
|
||||
old_backups.insert(entryname);
|
||||
if (old_backups.size() <= keepbackups)
|
||||
continue;
|
||||
|
||||
Log(LOG_DEBUG) << "Deleting expired backup " << *old_backups.begin();
|
||||
if (!std::filesystem::remove(old_backups.begin()->str(), ec))
|
||||
{
|
||||
Log(this) << "Failed to delete expired backup " << *old_backups.begin() << ": " << ec.message();
|
||||
continue;
|
||||
}
|
||||
old_backups.erase(old_backups.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DBFlatFile(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR)
|
||||
DBFlatFile(const Anope::string &modname, const Anope::string &creator)
|
||||
: Module(modname, creator, DATABASE | VENDOR)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void OnRestart() override
|
||||
{
|
||||
OnShutdown();
|
||||
}
|
||||
|
||||
void OnShutdown() override
|
||||
{
|
||||
if (child_pid > -1)
|
||||
{
|
||||
Log(this) << "Waiting for child to exit...";
|
||||
|
||||
int status;
|
||||
waitpid(child_pid, &status, 0);
|
||||
|
||||
Log(this) << "Done";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OnNotify() override
|
||||
{
|
||||
char buf[512];
|
||||
int i = this->Read(buf, sizeof(buf) - 1);
|
||||
if (i <= 0)
|
||||
return;
|
||||
buf[i] = 0;
|
||||
|
||||
child_pid = -1;
|
||||
|
||||
if (!*buf)
|
||||
{
|
||||
Log(this) << "Finished saving databases";
|
||||
return;
|
||||
}
|
||||
|
||||
Log(this) << "Error saving databases: " << buf;
|
||||
|
||||
if (!Config->GetModule(this).Get<bool>("nobackupokay"))
|
||||
Anope::Quitting = true;
|
||||
}
|
||||
|
||||
EventReturn OnLoadDatabase() override
|
||||
@@ -270,110 +126,6 @@ public:
|
||||
return EVENT_STOP;
|
||||
}
|
||||
|
||||
|
||||
void OnSaveDatabase() override
|
||||
{
|
||||
if (child_pid > -1)
|
||||
{
|
||||
Log(this) << "Database save is already in progress!";
|
||||
return;
|
||||
}
|
||||
|
||||
BackupDatabase();
|
||||
|
||||
int i = -1;
|
||||
#ifndef _WIN32
|
||||
if (!Anope::Quitting && Config->GetModule(this).Get<bool>("fork"))
|
||||
{
|
||||
i = fork();
|
||||
if (i > 0)
|
||||
{
|
||||
child_pid = i;
|
||||
return;
|
||||
}
|
||||
else if (i < 0)
|
||||
Log(this) << "Unable to fork for database save";
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
std::map<Module *, std::fstream *> databases;
|
||||
|
||||
/* First open the databases of all of the registered types. This way, if we have a type with 0 objects, that database will be properly cleared */
|
||||
for (const auto &[_, s_type] : Serialize::Type::GetTypes())
|
||||
{
|
||||
if (databases[s_type->GetOwner()])
|
||||
continue;
|
||||
|
||||
Anope::string db_name;
|
||||
if (s_type->GetOwner())
|
||||
db_name = Anope::ExpandData("module_" + s_type->GetOwner()->name + ".db");
|
||||
else
|
||||
db_name = Anope::ExpandData(Config->GetModule(this).Get<const Anope::string>("database", "anope.db"));
|
||||
|
||||
std::fstream *fs = databases[s_type->GetOwner()] = new std::fstream((db_name + ".tmp").c_str(), std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
|
||||
|
||||
if (!fs->is_open())
|
||||
Log(this) << "Unable to open " << db_name << " for writing";
|
||||
}
|
||||
|
||||
SaveData data;
|
||||
const std::list<Serializable *> &items = Serializable::GetItems();
|
||||
for (auto *base : items)
|
||||
{
|
||||
Serialize::Type *s_type = base->GetSerializableType();
|
||||
if (!s_type)
|
||||
continue;
|
||||
|
||||
data.fs = databases[s_type->GetOwner()];
|
||||
if (!data.fs || !data.fs->is_open())
|
||||
continue;
|
||||
|
||||
*data.fs << "OBJECT " << s_type->GetName();
|
||||
if (base->id)
|
||||
*data.fs << "\nID " << base->id;
|
||||
s_type->Serialize(base, data);
|
||||
*data.fs << "\nEND\n";
|
||||
}
|
||||
|
||||
for (auto &[mod, f] : databases)
|
||||
{
|
||||
const auto db_name = Anope::ExpandData((mod ? (mod->name + ".db") : Config->GetModule(this).Get<const Anope::string>("database", "anope.db")));
|
||||
|
||||
if (!f->is_open() || !f->good())
|
||||
{
|
||||
this->Write("Unable to write database " + db_name);
|
||||
|
||||
f->close();
|
||||
}
|
||||
else
|
||||
{
|
||||
f->close();
|
||||
#ifdef _WIN32
|
||||
/* Windows rename() fails if the file already exists. */
|
||||
remove(db_name.c_str());
|
||||
#endif
|
||||
rename((db_name + ".tmp").c_str(), db_name.c_str());
|
||||
}
|
||||
|
||||
delete f;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (i)
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!i)
|
||||
{
|
||||
this->Notify();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load just one type. Done if a module is reloaded during runtime */
|
||||
void OnSerializeTypeCreate(Serialize::Type *stype) override
|
||||
{
|
||||
if (!loaded)
|
||||
|
||||
Reference in New Issue
Block a user