diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-10-10 15:14:02 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-10-10 15:22:27 -0300 |
| commit | 46c653293381dcc1188013d3e2c3f7587a199dc4 (patch) | |
| tree | 0b9776f73d6e2afcd9104cf400dc5e345fcdcbea | |
| parent | cc4873e33866ba86561774a7e55449d59367661e (diff) | |
| download | querymanager-46c653293381dcc1188013d3e2c3f7587a199dc4.tar.gz querymanager-46c653293381dcc1188013d3e2c3f7587a199dc4.zip | |
organize database configs and schema files + compilation guards
| -rw-r--r-- | Makefile | 16 | ||||
| -rw-r--r-- | config.cfg | 51 | ||||
| -rw-r--r-- | sqlite/README.txt (renamed from sql/README.txt) | 0 | ||||
| -rw-r--r-- | sqlite/init.sql (renamed from sql/init.sql) | 2 | ||||
| -rw-r--r-- | sqlite/schema.sql (renamed from sql/schema.sql) | 0 | ||||
| -rw-r--r-- | src/connections.cc | 2 | ||||
| -rw-r--r-- | src/database_mysql.cc | 6 | ||||
| -rw-r--r-- | src/database_postgres.cc | 6 | ||||
| -rw-r--r-- | src/database_pq.cc | 4 | ||||
| -rw-r--r-- | src/database_sqlite.cc | 19 | ||||
| -rw-r--r-- | src/querymanager.cc | 148 | ||||
| -rw-r--r-- | src/querymanager.hh | 40 |
12 files changed, 203 insertions, 91 deletions
@@ -23,11 +23,17 @@ endif DATABASE ?= sqlite ifeq ($(DATABASE), sqlite) DATABASEOBJ = $(BUILDDIR)/database_sqlite.obj $(BUILDDIR)/sqlite3.obj + CFLAGS += -DDATABASE_SQLITE=1 else ifeq ($(DATABASE), postgres) - DATABASEOBJ = $(BUILDDIR)/database_pq.obj + DATABASEOBJ = $(BUILDDIR)/database_postgres.obj + CFLAGS += -DDATABASE_POSTGRESQL=1 LFLAGS += -lpq +else ifeq ($(DATABASE), mariadb) + DATABASEOBJ = $(BUILDDIR)/database_mysql.obj + CFLAGS += -DDATABASE_MYSQL=1 -DDATABASE_MARIADB=1 + LFLAGS += -lmariadb else - $(error Unsupported DATABASE: `$(DATABASE)`. Valid options are `sqlite` or `postgres`) + $(error Unsupported DATABASE: `$(DATABASE)`. Valid options are `sqlite`, `postgres`, or `mariadb`) endif $(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/connections.obj $(BUILDDIR)/hostcache.obj $(BUILDDIR)/query.obj $(BUILDDIR)/querymanager.obj $(BUILDDIR)/sha256.obj $(DATABASEOBJ) @@ -58,7 +64,11 @@ $(BUILDDIR)/database_sqlite.obj: $(SRCDIR)/database_sqlite.cc $(SRCDIR)/queryman @mkdir -p $(@D) $(CXX) -c $(CXXFLAGS) -o $@ $< -$(BUILDDIR)/database_pq.obj: $(SRCDIR)/database_pq.cc $(SRCDIR)/querymanager.hh +$(BUILDDIR)/database_postgres.obj: $(SRCDIR)/database_postgres.cc $(SRCDIR)/querymanager.hh + @mkdir -p $(@D) + $(CXX) -c $(CXXFLAGS) -o $@ $< + +$(BUILDDIR)/database_mysql.obj: $(SRCDIR)/database_mysql.cc $(SRCDIR)/querymanager.hh @mkdir -p $(@D) $(CXX) -c $(CXXFLAGS) -o $@ $< @@ -1,23 +1,36 @@ # HostCache Config -MaxCachedHostNames = 100 -HostNameExpireTime = 30m +MaxCachedHostNames = 100 +HostNameExpireTime = 30m -# Database Config -MaxCachedStatements = 100 -DatabaseFile = "tibia.db" -# TODO(fusion): This is not great. Probably switch to database specific options? -#DatabaseHost = "localhost" -#DatabasePort = 5432 -#DatabaseUser = "postgres" -#DatabasePassword = "" -#DatabaseName = "tibia" -#DatabaseTLS = true +# SQLite Config +SQLite.File = "tibia.db" +SQLite.MaxCachedStatements = 100 + +# PostgreSQL Config +#PostgreSQL.UnixSocket = "" +#PostgreSQL.Host = "localhost" +#PostgreSQL.Port = 5432 +#PostgreSQL.User = "postgres" +#PostgreSQL.Password = "" +#PostgreSQL.Database = "tibia" +#PostgreSQL.TLS = true +#PostgreSQL.MaxCachedStatements = 100 + +# MySQL/MariaDB Config +#MySQL.UnixSocket = "" +#MySQL.Host = "localhost" +#MySQL.Port = 3306 +#MySQL.User = "mysql" +#MySQL.Password = "" +#MySQL.Database = "tibia" +#MySQL.TLS = true +#MySQL.MaxCachedStatements = 100 # Connection Config -QueryManagerPort = 7173 -QueryManagerPassword = "a6glaf0c" -QueryWorkerThreads = 1 -QueryBufferSize = 1M -QueryMaxAttempts = 3 -MaxConnections = 25 -MaxConnectionIdleTime = 5m +QueryManagerPort = 7173 +QueryManagerPassword = "a6glaf0c" +QueryWorkerThreads = 1 +QueryBufferSize = 1M +QueryMaxAttempts = 3 +MaxConnections = 25 +MaxConnectionIdleTime = 5m diff --git a/sql/README.txt b/sqlite/README.txt index 26f782a..26f782a 100644 --- a/sql/README.txt +++ b/sqlite/README.txt diff --git a/sql/init.sql b/sqlite/init.sql index 589c4e3..dc30adf 100644 --- a/sql/init.sql +++ b/sqlite/init.sql @@ -1,7 +1,7 @@ -- NOTE(fusion): The query manager WON'T automatically run this but the game -- server still requires at least the world config to be able to boot up. It -- is probably a good idea to keep this separated from `schema.sql` and then --- running it with `sqlite3 -echo tibia.db < sql/init.sql`, although it is +-- running it with `sqlite3 -echo tibia.db < sqlite/init.sql`, although it is -- not mandatory. -- Because this isn't automatically managed, all queries are wrapped in a -- transaction to avoid partial writes in case of errors. diff --git a/sql/schema.sql b/sqlite/schema.sql index 677d778..677d778 100644 --- a/sql/schema.sql +++ b/sqlite/schema.sql diff --git a/src/connections.cc b/src/connections.cc index b08b52a..0760514 100644 --- a/src/connections.cc +++ b/src/connections.cc @@ -612,7 +612,7 @@ void ProcessConnections(void){ ASSERT(NumFds > 0); int NumEvents = poll(Fds, NumFds, -1); if(NumEvents == -1){ - if(errno != ETIMEDOUT){ + if(errno != ETIMEDOUT && errno != EINTR){ LOG_ERR("Failed to poll connections: (%d) %s", errno, strerrordesc_np(errno)); } diff --git a/src/database_mysql.cc b/src/database_mysql.cc new file mode 100644 index 0000000..583bb7d --- /dev/null +++ b/src/database_mysql.cc @@ -0,0 +1,6 @@ +#if DATABASE_MYSQL +#include "querymanager.hh" + +// TODO + +#endif //DATABASE_MYSQL diff --git a/src/database_postgres.cc b/src/database_postgres.cc new file mode 100644 index 0000000..3b24967 --- /dev/null +++ b/src/database_postgres.cc @@ -0,0 +1,6 @@ +#if DATABASE_POSTGRESQL +#include "querymanager.hh" + +// TODO + +#endif //DATABASE_POSTGRESQL diff --git a/src/database_pq.cc b/src/database_pq.cc deleted file mode 100644 index 69cc45e..0000000 --- a/src/database_pq.cc +++ /dev/null @@ -1,4 +0,0 @@ -#include "querymanager.hh" - -// TODO(fusion): - diff --git a/src/database_sqlite.cc b/src/database_sqlite.cc index 8a5e526..37a62e0 100644 --- a/src/database_sqlite.cc +++ b/src/database_sqlite.cc @@ -1,3 +1,4 @@ +#if DATABASE_SQLITE #include "querymanager.hh" #include "sqlite3.h" @@ -43,8 +44,8 @@ public: static void EnsureStatementCache(TDatabase *Database){ if(Database->CachedStatements == NULL){ - ASSERT(g_Config.MaxCachedStatements > 0); - Database->MaxCachedStatements = g_Config.MaxCachedStatements; + ASSERT(g_Config.SQLite.MaxCachedStatements > 0); + Database->MaxCachedStatements = g_Config.SQLite.MaxCachedStatements; Database->CachedStatements = (TCachedStatement*)calloc( Database->MaxCachedStatements, sizeof(TCachedStatement)); } @@ -233,8 +234,8 @@ static bool InitDatabaseSchema(TDatabase *Database){ return false; } - if(!ExecFile(Database, "sql/schema.sql")){ - LOG_ERR("Failed to execute \"sql/schema.sql\""); + if(!ExecFile(Database, "sqlite/schema.sql")){ + LOG_ERR("Failed to execute \"sqlite/schema.sql\""); return false; } @@ -255,7 +256,7 @@ static bool UpgradeDatabaseSchema(TDatabase *Database, int UserVersion){ char FileName[256]; int NewVersion = UserVersion; while(true){ - snprintf(FileName, sizeof(FileName), "sql/upgrade-%d.sql", NewVersion); + snprintf(FileName, sizeof(FileName), "sqlite/upgrade-%d.sql", NewVersion); if(FileExists(FileName)){ NewVersion += 1; }else{ @@ -346,9 +347,9 @@ void DatabaseClose(TDatabase *Database){ TDatabase *DatabaseOpen(void){ TDatabase *Database = (TDatabase*)calloc(1, sizeof(TDatabase)); int Flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX; - if(sqlite3_open_v2(g_Config.DatabaseFile, &Database->Handle, Flags, NULL) != SQLITE_OK){ + if(sqlite3_open_v2(g_Config.SQLite.File, &Database->Handle, Flags, NULL) != SQLITE_OK){ LOG_ERR("Failed to open database at \"%s\": %s\n", - g_Config.DatabaseFile, sqlite3_errmsg(Database->Handle)); + g_Config.SQLite.File, sqlite3_errmsg(Database->Handle)); DatabaseClose(Database); return NULL; } @@ -357,7 +358,7 @@ TDatabase *DatabaseOpen(void){ LOG_ERR("Failed to open database file \"%s\" with WRITE PERMISSIONS." " Make sure it has the appropriate permissions and is owned" " by the same user running the query manager.", - g_Config.DatabaseFile); + g_Config.SQLite.File); DatabaseClose(Database); return NULL; } @@ -2482,3 +2483,5 @@ bool CheckOnlineRecord(TDatabase *Database, int WorldID, int NumCharacters, bool *NewRecord = sqlite3_changes(Database->Handle) > 0; return true; } + +#endif //DATABASE_SQLITE diff --git a/src/querymanager.cc b/src/querymanager.cc index 6c1fffe..004bc35 100644 --- a/src/querymanager.cc +++ b/src/querymanager.cc @@ -67,6 +67,9 @@ int64 GetClockMonotonicMS(void){ QueryPerformanceFrequency(&Frequency); return (int64)((Counter.QuadPart * 1000) / Frequency.QuadPart); #else + // NOTE(fusion): The coarse monotonic clock has a larger resolution but is + // supposed to be faster, even avoiding system calls in some cases. It should + // be fine for millisecond precision which is what we're using. struct timespec Time; clock_gettime(CLOCK_MONOTONIC_COARSE, &Time); return ((int64)Time.tv_sec * 1000) @@ -374,22 +377,46 @@ bool ReadConfig(const char *FileName, TConfig *Config){ ReadIntegerConfig(&Config->MaxCachedHostNames, Val); }else if(StringEqCI(Key, "HostNameExpireTime")){ ReadDurationConfig(&Config->HostNameExpireTime, Val); - }else if(StringEqCI(Key, "MaxCachedStatements")){ - ReadIntegerConfig(&Config->MaxCachedStatements, Val); - }else if(StringEqCI(Key, "DatabaseFile")){ - ReadStringBufConfig(Config->DatabaseFile, Val); - }else if(StringEqCI(Key, "DatabaseHost")){ - ReadStringBufConfig(Config->DatabaseHost, Val); - }else if(StringEqCI(Key, "DatabasePort")){ - ReadIntegerConfig(&Config->DatabasePort, Val); - }else if(StringEqCI(Key, "DatabaseUser")){ - ReadStringBufConfig(Config->DatabaseUser, Val); - }else if(StringEqCI(Key, "DatabasePassword")){ - ReadStringBufConfig(Config->DatabasePassword, Val); - }else if(StringEqCI(Key, "DatabaseName")){ - ReadStringBufConfig(Config->DatabaseName, Val); - }else if(StringEqCI(Key, "DatabaseTLS")){ - ReadBooleanConfig(&Config->DatabaseTLS, Val); +#if DATABASE_SQLITE + }else if(StringEqCI(Key, "SQLite.File")){ + ReadStringBufConfig(Config->SQLite.File, Val); + }else if(StringEqCI(Key, "SQLite.MaxCachedStatements")){ + ReadIntegerConfig(&Config->SQLite.MaxCachedStatements, Val); +#elif DATABASE_POSTGRESQL + }else if(StringEqCI(Key, "PostgreSQL.UnixSocket")){ + ReadStringBufConfig(Config->PostgreSQL.UnixSocket, Val); + }else if(StringEqCI(Key, "PostgreSQL.Host")){ + ReadStringBufConfig(Config->PostgreSQL.Host, Val); + }else if(StringEqCI(Key, "PostgreSQL.Port")){ + ReadIntegerConfig(&Config->PostgreSQL.Port, Val); + }else if(StringEqCI(Key, "PostgreSQL.User")){ + ReadStringBufConfig(Config->PostgreSQL.User, Val); + }else if(StringEqCI(Key, "PostgreSQL.Password")){ + ReadStringBufConfig(Config->PostgreSQL.Password, Val); + }else if(StringEqCI(Key, "PostgreSQL.Database")){ + ReadStringBufConfig(Config->PostgreSQL.Database, Val); + }else if(StringEqCI(Key, "PostgreSQL.TLS")){ + ReadBooleanConfig(&Config->PostgreSQL.TLS, Val); + }else if(StringEqCI(Key, "PostgreSQL.MaxCachedStatements")){ + ReadIntegerConfig(&Config->PostgreSQL.MaxCachedStatements, Val); +#elif DATABASE_MYSQL + }else if(StringEqCI(Key, "MySQL.UnixSocket")){ + ReadStringBufConfig(Config->MySQL.UnixSocket, Val); + }else if(StringEqCI(Key, "MySQL.Host")){ + ReadStringBufConfig(Config->MySQL.Host, Val); + }else if(StringEqCI(Key, "MySQL.Port")){ + ReadIntegerConfig(&Config->MySQL.Port, Val); + }else if(StringEqCI(Key, "MySQL.User")){ + ReadStringBufConfig(Config->MySQL.User, Val); + }else if(StringEqCI(Key, "MySQL.Password")){ + ReadStringBufConfig(Config->MySQL.Password, Val); + }else if(StringEqCI(Key, "MySQL.Database")){ + ReadStringBufConfig(Config->MySQL.Database, Val); + }else if(StringEqCI(Key, "MySQL.TLS")){ + ReadBooleanConfig(&Config->MySQL.TLS, Val); + }else if(StringEqCI(Key, "MySQL.MaxCachedStatements")){ + ReadIntegerConfig(&Config->MySQL.MaxCachedStatements, Val); +#endif }else if(StringEqCI(Key, "QueryManagerPort")){ ReadIntegerConfig(&Config->QueryManagerPort, Val); }else if(StringEqCI(Key, "QueryManagerPassword")){ @@ -445,27 +472,41 @@ int main(int argc, const char **argv){ g_StartTimeMS = GetClockMonotonicMS(); // HostCache Config - g_Config.MaxCachedHostNames = 100; - g_Config.HostNameExpireTime = 30 * 60 * 1000; // milliseconds + g_Config.MaxCachedHostNames = 100; + g_Config.HostNameExpireTime = 30 * 60 * 1000; // milliseconds // Database Config - g_Config.MaxCachedStatements = 100; - StringBufCopy(g_Config.DatabaseFile, "tibia.db"); - StringBufCopy(g_Config.DatabaseHost, "localhost"); - g_Config.DatabasePort = 5432; - StringBufCopy(g_Config.DatabaseUser, "tibia"); - StringBufCopy(g_Config.DatabasePassword, ""); - StringBufCopy(g_Config.DatabaseName, ""); - g_Config.DatabaseTLS = true; +#if DATABASE_SQLITE + StringBufCopy(g_Config.SQLite.File, "tibia.db"); + g_Config.SQLite.MaxCachedStatements = 100; +#elif DATABASE_POSTGRESQL + StringBufCopy(g_Config.PostgreSQL.UnixSocket, ""); + StringBufCopy(g_Config.PostgreSQL.Host, "localhost"); + g_Config.PostgreSQL.Port = 5432; + StringBufCopy(g_Config.PostgreSQL.User, "postgres"); + StringBufCopy(g_Config.PostgreSQL.Password, ""); + StringBufCopy(g_Config.PostgreSQL.Database, "tibia"); + g_Config.PostgreSQL.TLS = true; + g_Config.PostgreSQL.MaxCachedStatements = 100; +#elif DATABASE_MYSQL + StringBufCopy(g_Config.MySQL.UnixSocket, ""); + StringBufCopy(g_Config.MySQL.Host, "localhost"); + g_Config.MySQL.Port = 5432; + StringBufCopy(g_Config.MySQL.User, "postgres"); + StringBufCopy(g_Config.MySQL.Password, ""); + StringBufCopy(g_Config.MySQL.Database, "tibia"); + g_Config.MySQL.TLS = true; + g_Config.MySQL.MaxCachedStatements = 100; +#endif // Connection Config - g_Config.QueryManagerPort = 7174; + g_Config.QueryManagerPort = 7174; StringBufCopy(g_Config.QueryManagerPassword, ""); - g_Config.QueryWorkerThreads = 1; - g_Config.QueryBufferSize = (int)MB(1); - g_Config.QueryMaxAttempts = 2; - g_Config.MaxConnections = 50; - g_Config.MaxConnectionIdleTime = 60 * 1000; // milliseconds + g_Config.QueryWorkerThreads = 1; + g_Config.QueryBufferSize = (int)MB(1); + g_Config.QueryMaxAttempts = 3; + g_Config.MaxConnections = 25; + g_Config.MaxConnectionIdleTime = 60 * 1000; // milliseconds LOG("Tibia Query Manager v0.2"); if(!ReadConfig("config.cfg", &g_Config)){ @@ -473,21 +514,34 @@ int main(int argc, const char **argv){ } // NOTE(fusion): Print config values for debugging purposes. - LOG("Max cached host names: %d", g_Config.MaxCachedHostNames); - LOG("Host name expire time: %dms", g_Config.HostNameExpireTime); - LOG("Max cached statements: %d", g_Config.MaxCachedStatements); - LOG("Database file: \"%s\"", g_Config.DatabaseFile); - LOG("Database host: \"%s\"", g_Config.DatabaseHost); - LOG("Database port: %d", g_Config.DatabasePort); - LOG("Database user: \"%s\"", g_Config.DatabaseUser); - LOG("Database name: \"%s\"", g_Config.DatabaseName); - LOG("Database TLS: %s", g_Config.DatabaseTLS ? "true" : "false"); - LOG("Query manager port: %d", g_Config.QueryManagerPort); - LOG("Query worker threads: %d", g_Config.QueryWorkerThreads); - LOG("Query buffer size: %d", g_Config.QueryBufferSize); - LOG("Query max attempts: %d", g_Config.QueryMaxAttempts); - LOG("Max connections: %d", g_Config.MaxConnections); - LOG("Max connection idle time: %dms", g_Config.MaxConnectionIdleTime); + LOG("Max cached host names: %d", g_Config.MaxCachedHostNames); + LOG("Host name expire time: %dms", g_Config.HostNameExpireTime); +#if DATABASE_SQLITE + LOG("SQLite file: \"%s\"", g_Config.SQLite.File); + LOG("SQLite max cached statements: %d", g_Config.SQLite.MaxCachedStatements); +#elif DATABASE_POSTGRESQL + LOG("PostgreSQL unix socket: \"%s\"", g_Config.PostgreSQL.UnixSocket); + LOG("PostgreSQL host: \"%s\"", g_Config.PostgreSQL.Host); + LOG("PostgreSQL port: %d", g_Config.PostgreSQL.Port); + LOG("PostgreSQL user: \"%s\"", g_Config.PostgreSQL.User); + LOG("PostgreSQL database: \"%s\"", g_Config.PostgreSQL.Database); + LOG("PostgreSQL TLS: %s", g_Config.PostgreSQL.TLS ? "true" : "false"); + LOG("PostgreSQL max cached statements: %d", g_Config.PostgreSQL.MaxCachedStatements); +#elif DATABASE_MYSQL + LOG("MySQL unix socket: \"%s\"", g_Config.MySQL.UnixSocket); + LOG("MySQL host: \"%s\"", g_Config.MySQL.Host); + LOG("MySQL port: %d", g_Config.MySQL.Port); + LOG("MySQL user: \"%s\"", g_Config.MySQL.User); + LOG("MySQL database: \"%s\"", g_Config.MySQL.Database); + LOG("MySQL TLS: %s", g_Config.MySQL.TLS ? "true" : "false"); + LOG("MySQL max cached statements: %d", g_Config.MySQL.MaxCachedStatements); +#endif + LOG("Query manager port: %d", g_Config.QueryManagerPort); + LOG("Query worker threads: %d", g_Config.QueryWorkerThreads); + LOG("Query buffer size: %d", g_Config.QueryBufferSize); + LOG("Query max attempts: %d", g_Config.QueryMaxAttempts); + LOG("Max connections: %d", g_Config.MaxConnections); + LOG("Max connection idle time: %dms", g_Config.MaxConnectionIdleTime); if(!CheckSHA256()){ return EXIT_FAILURE; diff --git a/src/querymanager.hh b/src/querymanager.hh index 15234e9..2ae12b1 100644 --- a/src/querymanager.hh +++ b/src/querymanager.hh @@ -75,20 +75,44 @@ typedef size_t usize; TRAP(); \ }while(0) +#if !DATABASE_SQLITE && !DATABASE_POSTGRESQL && !DATABASE_MYSQL +# error "No database system defined." +#endif + struct TConfig{ // HostCache Config int MaxCachedHostNames; int HostNameExpireTime; // Database Config - int MaxCachedStatements; - char DatabaseFile[100]; - char DatabaseHost[100]; - int DatabasePort; - char DatabaseUser[30]; - char DatabasePassword[30]; - char DatabaseName[30]; - bool DatabaseTLS; +#if DATABASE_SQLITE + struct{ + char File[100]; + int MaxCachedStatements; + } SQLite; +#elif DATABASE_POSTGRESQL + struct{ + char UnixSocket[100]; + char Host[100]; + int Port; + char User[30]; + char Password[30]; + char Database[30]; + bool TLS; + int MaxCachedStatements; + } PostgreSQL; +#elif DATABASE_MYSQL + struct{ + char UnixSocket[100]; + char Host[100]; + int Port; + char User[30]; + char Password[30]; + char Database[30]; + bool TLS; + int MaxCachedStatements; + } MySQL; +#endif // Connection Config int QueryManagerPort; |
