add TransactionScope

This commit is contained in:
fusion32 2025-07-11 12:30:22 -03:00
parent 3ab6d1d312
commit ac41dc912d
3 changed files with 105 additions and 42 deletions

View File

@ -623,9 +623,11 @@ void ProcessInsertHousesQuery(TConnection *Connection, TReadBuffer *Buffer){
return;
}
// TODO(fusion): Have some TransactionGuard type that will either commit or
// rollback a transaction when we leave its scope, based on whether some
// `Commit` function was called.
TransactionScope Tx("UpdateHouses");
if(!Tx.Begin()){
SendQueryStatusFailed(Connection);
return;
}
if(!DeleteHouses(Connection->WorldID)){
SendQueryStatusFailed(Connection);
@ -654,6 +656,11 @@ void ProcessInsertHousesQuery(TConnection *Connection, TReadBuffer *Buffer){
}
}
if(!Tx.Commit()){
SendQueryStatusFailed(Connection);
return;
}
SendQueryStatusOk(Connection);
}
@ -680,9 +687,12 @@ void ProcessCreatePlayerlistQuery(TConnection *Connection, TReadBuffer *Buffer){
return;
}
// TODO(fusion): Have some TransactionGuard type that will either commit or
// rollback a transaction when we leave its scope, based on whether some
// `Commit` function was called.
TransactionScope Tx("OnlineList");
if(!Tx.Begin()){
SendQueryStatusFailed(Connection);
return;
}
if(!DeleteOnlineCharacters(Connection->WorldID)){
SendQueryStatusFailed(Connection);
@ -710,6 +720,11 @@ void ProcessCreatePlayerlistQuery(TConnection *Connection, TReadBuffer *Buffer){
}
}
if(!Tx.Commit()){
SendQueryStatusFailed(Connection);
return;
}
TWriteBuffer WriteBuffer = PrepareResponse(Connection, QUERY_STATUS_OK);
WriteBuffer.WriteFlag(NewRecord);
SendResponse(Connection, &WriteBuffer);

View File

@ -98,6 +98,49 @@ void ExitStatementCache(void){
}
}
// TransactionScope
//==============================================================================
TransactionScope::TransactionScope(const char *Context){
m_Context = (Context != NULL ? Context : "NOCONTEXT");
m_Running = false;
}
TransactionScope::~TransactionScope(void){
if(m_Running && !ExecInternal("ROLLBACK")){
LOG_ERR("Failed to rollback transaction (%s)", m_Context);
}
}
bool TransactionScope::Begin(void){
if(m_Running){
LOG_ERR("Transaction (%s) already running", m_Context);
return false;
}
if(!ExecInternal("BEGIN")){
LOG_ERR("Failed to begin transaction (%s)", m_Context);
return false;
}
m_Running = true;
return true;
}
bool TransactionScope::Commit(void){
if(!m_Running){
LOG_ERR("Transaction (%s) not running", m_Context);
return false;
}
if(!ExecInternal("COMMIT")){
LOG_ERR("Failed to commit transaction (%s)", m_Context);
return false;
}
m_Running = false;
return true;
}
// Queries
//==============================================================================
bool LoadWorldID(const char *WorldName, int *WorldID){
@ -467,7 +510,6 @@ bool ExecFile(const char *FileName){
return Result;
}
bool ExecInternal(const char *Format, ...) ATTR_PRINTF(1, 2);
bool ExecInternal(const char *Format, ...){
va_list ap;
va_start(ap, Format);
@ -510,38 +552,31 @@ bool GetPragmaInt(const char *Name, int *OutValue){
}
bool InitDatabaseSchema(void){
bool Result = true;
if(Result && !ExecInternal("BEGIN")){
LOG_ERR("Failed to start schema transaction");
Result = false;
TransactionScope Tx("SchemaInit");
if(!Tx.Begin()){
return false;
}
if(Result && !ExecFile("sql/schema.sql")){
if(!ExecFile("sql/schema.sql")){
LOG_ERR("Failed to execute \"sql/schema.sql\"");
Result = false;
return false;
}
if(Result && !ExecInternal("PRAGMA application_id = %d", g_ApplicationID)){
if(!ExecInternal("PRAGMA application_id = %d", g_ApplicationID)){
LOG_ERR("Failed to set application id");
Result = false;
return false;
}
if(Result && !ExecInternal("PRAGMA user_version = 1")){
if(!ExecInternal("PRAGMA user_version = 1")){
LOG_ERR("Failed to set user version");
Result = false;
return false;
}
if(Result && !ExecInternal("COMMIT")){
LOG_ERR("Failed to commit schema transaction");
Result = false;
if(!Tx.Commit()){
return false;
}
if(!Result && !ExecInternal("ROLLBACK")){
LOG_ERR("Failed to rollback schema transaction");
}
return Result;
return true;
}
bool UpgradeDatabaseSchema(int UserVersion){
@ -556,40 +591,34 @@ bool UpgradeDatabaseSchema(int UserVersion){
}
}
bool Result = true;
if(UserVersion != NewVersion){
LOG("Upgrading database schema to version %d", NewVersion);
if(Result && !ExecInternal("BEGIN")){
LOG_ERR("Failed to start upgrade transaction");
Result = false;
TransactionScope Tx("SchemaUpgrade");
if(!Tx.Begin()){
return false;
}
while(Result && UserVersion < NewVersion){
while(UserVersion < NewVersion){
snprintf(FileName, sizeof(FileName), "upgrade-%d.sql", UserVersion);
if(!ExecFile(FileName)){
LOG_ERR("Failed to execute \"%s\"", FileName);
Result = false;
return false;
}
UserVersion += 1;
}
if(Result && !ExecInternal("PRAGMA user_version = %d", UserVersion)){
if(!ExecInternal("PRAGMA user_version = %d", UserVersion)){
LOG_ERR("Failed to set user version");
Result = false;
return false;
}
if(Result && !ExecInternal("COMMIT")){
LOG_ERR("Failed to commit upgrade transaction");
Result = false;
}
if(!Result && !ExecInternal("ROLLBACK")){
LOG_ERR("Failed to rollback upgrade transaction");
if(!Tx.Commit()){
return false;
}
}
return Result;
return true;
}
bool CheckDatabaseSchema(void){

View File

@ -688,6 +688,18 @@ struct TWorldConfig{
int PremiumNewbieBuffer;
};
struct TransactionScope{
private:
const char *m_Context;
bool m_Running;
public:
TransactionScope(const char *Context);
~TransactionScope(void);
bool Begin(void);
bool Commit(void);
};
bool LoadWorldID(const char *WorldName, int *WorldID);
//bool DecrementIsOnline(int WorldID, int CharacterID);
bool LoadHouseOwners(int WorldID, DynamicArray<THouseOwner> *HouseOwners);
@ -701,6 +713,13 @@ bool LoadCharacterIndex(int WorldID, int MinimumCharacterID,
int MaxEntries, int *NumEntries, TCharacterIndexEntry *Entries);
bool LoadWorldConfig(int WorldID, TWorldConfig *WorldConfig);
bool FileExists(const char *FileName);
bool ExecFile(const char *FileName);
bool ExecInternal(const char *Format, ...) ATTR_PRINTF(1, 2);
bool GetPragmaInt(const char *Name, int *OutValue);
bool InitDatabaseSchema(void);
bool UpgradeDatabaseSchema(int UserVersion);
bool CheckDatabaseSchema(void);
bool InitDatabase(void);
void ExitDatabase(void);