aboutsummaryrefslogtreecommitdiff
path: root/src/database
diff options
context:
space:
mode:
authorJude Melton-Houghton <jwmhjwmh@gmail.com>2022-09-26 17:03:43 -0400
committerGitHub <noreply@github.com>2022-09-26 17:03:43 -0400
commitf4a01f3a5dc0d8fe2f4f6d804d790da91d1bc30c (patch)
tree089ddc309e22ae8549ec3b86765ee272f57a33df /src/database
parent03428d9825cfdf2cfaed6ac9410dafccac0d4f3a (diff)
downloadminetest-f4a01f3a5dc0d8fe2f4f6d804d790da91d1bc30c.tar.xz
Avoid duplication of mod metadata in memory (#12562)
Co-authored-by: sfan5 <sfan5@live.de>
Diffstat (limited to 'src/database')
-rw-r--r--src/database/database-dummy.cpp36
-rw-r--r--src/database/database-dummy.h4
-rw-r--r--src/database/database-files.cpp31
-rw-r--r--src/database/database-files.h4
-rw-r--r--src/database/database-sqlite3.cpp75
-rw-r--r--src/database/database-sqlite3.h7
-rw-r--r--src/database/database.h4
7 files changed, 153 insertions, 8 deletions
diff --git a/src/database/database-dummy.cpp b/src/database/database-dummy.cpp
index a44762d8a..ee88c6684 100644
--- a/src/database/database-dummy.cpp
+++ b/src/database/database-dummy.cpp
@@ -92,6 +92,32 @@ bool Database_Dummy::getModEntries(const std::string &modname, StringMap *storag
return true;
}
+bool Database_Dummy::getModEntry(const std::string &modname,
+ const std::string &key, std::string *value)
+{
+ auto mod_pair = m_mod_meta_database.find(modname);
+ if (mod_pair == m_mod_meta_database.end())
+ return false;
+ const StringMap &meta = mod_pair->second;
+
+ auto pair = meta.find(key);
+ if (pair != meta.end()) {
+ *value = pair->second;
+ return true;
+ }
+ return false;
+}
+
+bool Database_Dummy::hasModEntry(const std::string &modname, const std::string &key)
+{
+ auto mod_pair = m_mod_meta_database.find(modname);
+ if (mod_pair == m_mod_meta_database.end())
+ return false;
+ const StringMap &meta = mod_pair->second;
+
+ return meta.find(key) != meta.cend();
+}
+
bool Database_Dummy::setModEntry(const std::string &modname,
const std::string &key, const std::string &value)
{
@@ -112,6 +138,16 @@ bool Database_Dummy::removeModEntry(const std::string &modname, const std::strin
return false;
}
+bool Database_Dummy::removeModEntries(const std::string &modname)
+{
+ auto mod_pair = m_mod_meta_database.find(modname);
+ if (mod_pair != m_mod_meta_database.end() && !mod_pair->second.empty()) {
+ mod_pair->second.clear();
+ return true;
+ }
+ return false;
+}
+
void Database_Dummy::listMods(std::vector<std::string> *res)
{
for (const auto &pair : m_mod_meta_database) {
diff --git a/src/database/database-dummy.h b/src/database/database-dummy.h
index 44b9e8d68..86c680ef1 100644
--- a/src/database/database-dummy.h
+++ b/src/database/database-dummy.h
@@ -38,9 +38,13 @@ public:
void listPlayers(std::vector<std::string> &res);
bool getModEntries(const std::string &modname, StringMap *storage);
+ bool getModEntry(const std::string &modname,
+ const std::string &key, std::string *value);
+ bool hasModEntry(const std::string &modname, const std::string &key);
bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value);
bool removeModEntry(const std::string &modname, const std::string &key);
+ bool removeModEntries(const std::string &modname);
void listMods(std::vector<std::string> *res);
void beginSave() {}
diff --git a/src/database/database-files.cpp b/src/database/database-files.cpp
index 00bc6d765..eff08de12 100644
--- a/src/database/database-files.cpp
+++ b/src/database/database-files.cpp
@@ -396,6 +396,26 @@ bool ModMetadataDatabaseFiles::getModEntries(const std::string &modname, StringM
return true;
}
+bool ModMetadataDatabaseFiles::getModEntry(const std::string &modname,
+ const std::string &key, std::string *value)
+{
+ Json::Value *meta = getOrCreateJson(modname);
+ if (!meta)
+ return false;
+
+ if (meta->isMember(key)) {
+ *value = (*meta)[key].asString();
+ return true;
+ }
+ return false;
+}
+
+bool ModMetadataDatabaseFiles::hasModEntry(const std::string &modname, const std::string &key)
+{
+ Json::Value *meta = getOrCreateJson(modname);
+ return meta && meta->isMember(key);
+}
+
bool ModMetadataDatabaseFiles::setModEntry(const std::string &modname,
const std::string &key, const std::string &value)
{
@@ -424,6 +444,17 @@ bool ModMetadataDatabaseFiles::removeModEntry(const std::string &modname,
return false;
}
+bool ModMetadataDatabaseFiles::removeModEntries(const std::string &modname)
+{
+ Json::Value *meta = getOrCreateJson(modname);
+ if (!meta || meta->empty())
+ return false;
+
+ meta->clear();
+ m_modified.insert(modname);
+ return true;
+}
+
void ModMetadataDatabaseFiles::beginSave()
{
}
diff --git a/src/database/database-files.h b/src/database/database-files.h
index 962e4d7bb..089e071fe 100644
--- a/src/database/database-files.h
+++ b/src/database/database-files.h
@@ -79,9 +79,13 @@ public:
virtual ~ModMetadataDatabaseFiles() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage);
+ virtual bool getModEntry(const std::string &modname,
+ const std::string &key, std::string *value);
+ virtual bool hasModEntry(const std::string &modname, const std::string &key);
virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value);
virtual bool removeModEntry(const std::string &modname, const std::string &key);
+ virtual bool removeModEntries(const std::string &modname);
virtual void listMods(std::vector<std::string> *res);
virtual void beginSave();
diff --git a/src/database/database-sqlite3.cpp b/src/database/database-sqlite3.cpp
index 5e565be55..0406fadc8 100644
--- a/src/database/database-sqlite3.cpp
+++ b/src/database/database-sqlite3.cpp
@@ -770,9 +770,12 @@ ModMetadataDatabaseSQLite3::ModMetadataDatabaseSQLite3(const std::string &savedi
ModMetadataDatabaseSQLite3::~ModMetadataDatabaseSQLite3()
{
+ FINALIZE_STATEMENT(m_stmt_remove_all)
FINALIZE_STATEMENT(m_stmt_remove)
FINALIZE_STATEMENT(m_stmt_set)
+ FINALIZE_STATEMENT(m_stmt_has)
FINALIZE_STATEMENT(m_stmt_get)
+ FINALIZE_STATEMENT(m_stmt_get_all)
}
void ModMetadataDatabaseSQLite3::createDatabase()
@@ -792,31 +795,74 @@ void ModMetadataDatabaseSQLite3::createDatabase()
void ModMetadataDatabaseSQLite3::initStatements()
{
- PREPARE_STATEMENT(get, "SELECT `key`, `value` FROM `entries` WHERE `modname` = ?");
+ PREPARE_STATEMENT(get_all, "SELECT `key`, `value` FROM `entries` WHERE `modname` = ?");
+ PREPARE_STATEMENT(get,
+ "SELECT `value` FROM `entries` WHERE `modname` = ? AND `key` = ? LIMIT 1");
+ PREPARE_STATEMENT(has,
+ "SELECT 1 FROM `entries` WHERE `modname` = ? AND `key` = ? LIMIT 1");
PREPARE_STATEMENT(set,
"REPLACE INTO `entries` (`modname`, `key`, `value`) VALUES (?, ?, ?)");
PREPARE_STATEMENT(remove, "DELETE FROM `entries` WHERE `modname` = ? AND `key` = ?");
+ PREPARE_STATEMENT(remove_all, "DELETE FROM `entries` WHERE `modname` = ?");
}
bool ModMetadataDatabaseSQLite3::getModEntries(const std::string &modname, StringMap *storage)
{
verifyDatabase();
- str_to_sqlite(m_stmt_get, 1, modname);
- while (sqlite3_step(m_stmt_get) == SQLITE_ROW) {
- const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get, 0);
- size_t key_len = sqlite3_column_bytes(m_stmt_get, 0);
- const char *value_data = (const char *) sqlite3_column_blob(m_stmt_get, 1);
- size_t value_len = sqlite3_column_bytes(m_stmt_get, 1);
+ str_to_sqlite(m_stmt_get_all, 1, modname);
+ while (sqlite3_step(m_stmt_get_all) == SQLITE_ROW) {
+ const char *key_data = (const char *) sqlite3_column_blob(m_stmt_get_all, 0);
+ size_t key_len = sqlite3_column_bytes(m_stmt_get_all, 0);
+ const char *value_data = (const char *) sqlite3_column_blob(m_stmt_get_all, 1);
+ size_t value_len = sqlite3_column_bytes(m_stmt_get_all, 1);
(*storage)[std::string(key_data, key_len)] = std::string(value_data, value_len);
}
sqlite3_vrfy(sqlite3_errcode(m_database), SQLITE_DONE);
- sqlite3_reset(m_stmt_get);
+ sqlite3_reset(m_stmt_get_all);
return true;
}
+bool ModMetadataDatabaseSQLite3::getModEntry(const std::string &modname,
+ const std::string &key, std::string *value)
+{
+ verifyDatabase();
+
+ str_to_sqlite(m_stmt_get, 1, modname);
+ SQLOK(sqlite3_bind_blob(m_stmt_get, 2, key.data(), key.size(), NULL),
+ "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
+ bool found = sqlite3_step(m_stmt_get) == SQLITE_ROW;
+ if (found) {
+ const char *value_data = (const char *) sqlite3_column_blob(m_stmt_get, 0);
+ size_t value_len = sqlite3_column_bytes(m_stmt_get, 0);
+ value->assign(value_data, value_len);
+ sqlite3_step(m_stmt_get);
+ }
+
+ sqlite3_reset(m_stmt_get);
+
+ return found;
+}
+
+bool ModMetadataDatabaseSQLite3::hasModEntry(const std::string &modname,
+ const std::string &key)
+{
+ verifyDatabase();
+
+ str_to_sqlite(m_stmt_has, 1, modname);
+ SQLOK(sqlite3_bind_blob(m_stmt_has, 2, key.data(), key.size(), NULL),
+ "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__));
+ bool found = sqlite3_step(m_stmt_has) == SQLITE_ROW;
+ if (found)
+ sqlite3_step(m_stmt_has);
+
+ sqlite3_reset(m_stmt_has);
+
+ return found;
+}
+
bool ModMetadataDatabaseSQLite3::setModEntry(const std::string &modname,
const std::string &key, const std::string &value)
{
@@ -850,6 +896,19 @@ bool ModMetadataDatabaseSQLite3::removeModEntry(const std::string &modname,
return changes > 0;
}
+bool ModMetadataDatabaseSQLite3::removeModEntries(const std::string &modname)
+{
+ verifyDatabase();
+
+ str_to_sqlite(m_stmt_remove_all, 1, modname);
+ sqlite3_vrfy(sqlite3_step(m_stmt_remove_all), SQLITE_DONE);
+ int changes = sqlite3_changes(m_database);
+
+ sqlite3_reset(m_stmt_remove_all);
+
+ return changes > 0;
+}
+
void ModMetadataDatabaseSQLite3::listMods(std::vector<std::string> *res)
{
verifyDatabase();
diff --git a/src/database/database-sqlite3.h b/src/database/database-sqlite3.h
index 5e3d7c96c..566f6cebb 100644
--- a/src/database/database-sqlite3.h
+++ b/src/database/database-sqlite3.h
@@ -240,9 +240,13 @@ public:
virtual ~ModMetadataDatabaseSQLite3();
virtual bool getModEntries(const std::string &modname, StringMap *storage);
+ virtual bool getModEntry(const std::string &modname,
+ const std::string &key, std::string *value);
+ virtual bool hasModEntry(const std::string &modname, const std::string &key);
virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value);
virtual bool removeModEntry(const std::string &modname, const std::string &key);
+ virtual bool removeModEntries(const std::string &modname);
virtual void listMods(std::vector<std::string> *res);
virtual void beginSave() { Database_SQLite3::beginSave(); }
@@ -253,7 +257,10 @@ protected:
virtual void initStatements();
private:
+ sqlite3_stmt *m_stmt_get_all = nullptr;
sqlite3_stmt *m_stmt_get = nullptr;
+ sqlite3_stmt *m_stmt_has = nullptr;
sqlite3_stmt *m_stmt_set = nullptr;
sqlite3_stmt *m_stmt_remove = nullptr;
+ sqlite3_stmt *m_stmt_remove_all = nullptr;
};
diff --git a/src/database/database.h b/src/database/database.h
index fbb5befea..0f22deebc 100644
--- a/src/database/database.h
+++ b/src/database/database.h
@@ -92,8 +92,12 @@ public:
virtual ~ModMetadataDatabase() = default;
virtual bool getModEntries(const std::string &modname, StringMap *storage) = 0;
+ virtual bool hasModEntry(const std::string &modname, const std::string &key) = 0;
+ virtual bool getModEntry(const std::string &modname,
+ const std::string &key, std::string *value) = 0;
virtual bool setModEntry(const std::string &modname,
const std::string &key, const std::string &value) = 0;
virtual bool removeModEntry(const std::string &modname, const std::string &key) = 0;
+ virtual bool removeModEntries(const std::string &modname) = 0;
virtual void listMods(std::vector<std::string> *res) = 0;
};