[Sync] Project Sync plus Revision changes

The main revision system changes are based on FoeReapers work in:
b37de3b83e
This commit is contained in:
Antz 2016-03-24 17:58:53 +00:00 committed by Antz
parent f5e2d53ccc
commit bf4b6fafc5
39 changed files with 684 additions and 416 deletions

View file

@ -25,6 +25,7 @@
#include "DatabaseEnv.h"
#include "Config/Config.h"
#include "Database/SqlOperations.h"
#include "revision.h"
#include <ctime>
#include <iostream>
@ -34,6 +35,21 @@
#define MIN_CONNECTION_POOL_SIZE 1
#define MAX_CONNECTION_POOL_SIZE 16
struct DBVersion
{
std::string dbname;
uint32 expected_version;
uint32 expected_structure;
uint32 expected_content;
std::string description;
};
const DBVersion databaseVersions[COUNT_DATABASES] = {
{ "World", WORLD_DB_VERSION_NR, WORLD_DB_STRUCTURE_NR, WORLD_DB_CONTENT_NR, WORLD_DB_UPDATE_DESCRIPTION }, // DATABASE_WORLD
{ "Realmd", REALMD_DB_VERSION_NR, REALMD_DB_STRUCTURE_NR, REALMD_DB_CONTENT_NR, REALMD_DB_UPDATE_DESCRIPTION }, // DATABASE_REALMD
{ "Character", CHAR_DB_VERSION_NR, CHAR_DB_STRUCTURE_NR, CHAR_DB_CONTENT_NR, CHAR_DB_UPDATE_DESCRIPTION }, // DATABASE_CHARACTER
};
//////////////////////////////////////////////////////////////////////////
SqlPreparedStatement* SqlConnection::CreateStatement(const std::string& fmt)
{
@ -178,6 +194,7 @@ void Database::InitDelayThread()
// New delay thread for delay execute
m_threadBody = CreateDelayThread(); // will deleted at m_delayThread delete
m_TransStorage = new ACE_TSS<Database::TransHelper>();
m_delayThread = new ACE_Based::Thread(m_threadBody);
}
@ -187,9 +204,11 @@ void Database::HaltDelayThread()
m_threadBody->Stop(); // Stop event
m_delayThread->wait(); // Wait for flush to DB
delete m_TransStorage;
delete m_delayThread; // This also deletes m_threadBody
m_delayThread = NULL;
m_threadBody = NULL;
m_TransStorage=NULL;
}
void Database::ThreadStart()
@ -333,7 +352,7 @@ bool Database::Execute(const char* sql)
if (!m_pAsyncConn)
{ return false; }
SqlTransaction* pTrans = m_TransStorage->get();
SqlTransaction* pTrans = (*m_TransStorage)->get();
if (pTrans)
{
// add SQL request to trans queue
@ -399,7 +418,7 @@ bool Database::BeginTransaction()
// initiate transaction on current thread
// currently we do not support queued transactions
m_TransStorage->init();
(*m_TransStorage)->init();
return true;
}
@ -409,7 +428,7 @@ bool Database::CommitTransaction()
{ return false; }
// check if we have pending transaction
if (!m_TransStorage->get())
if (!(*m_TransStorage)->get())
{ return false; }
// if async execution is not available
@ -417,7 +436,7 @@ bool Database::CommitTransaction()
{ return CommitTransactionDirect(); }
// add SqlTransaction to the async queue
m_threadBody->Delay(m_TransStorage->detach());
m_threadBody->Delay((*m_TransStorage)->detach());
return true;
}
@ -427,11 +446,11 @@ bool Database::CommitTransactionDirect()
{ return false; }
// check if we have pending transaction
if (!m_TransStorage->get())
if (!(*m_TransStorage)->get())
{ return false; }
// directly execute SqlTransaction
SqlTransaction* pTrans = m_TransStorage->detach();
SqlTransaction* pTrans = (*m_TransStorage)->detach();
pTrans->Execute(m_pAsyncConn);
delete pTrans;
@ -443,101 +462,93 @@ bool Database::RollbackTransaction()
if (!m_pAsyncConn)
{ return false; }
if (!m_TransStorage->get())
if (!(*m_TransStorage)->get())
{ return false; }
// remove scheduled transaction
m_TransStorage->reset();
(*m_TransStorage)->reset();
return true;
}
bool Database::CheckRequiredField(char const* table_name, char const* required_name)
bool Database::CheckDatabaseVersion(DatabaseTypes database)
{
// check required field
QueryResult* result = PQuery("SELECT %s FROM %s LIMIT 1", required_name, table_name);
if (result)
{
delete result;
return true;
}
const DBVersion& dbversion = databaseVersions[database];
// check fail, prepare readabale error message
// Fetch the database version table information
QueryResult* result = Query("SELECT version, structure, content, description FROM db_version ORDER BY version DESC, structure DESC, content DESC LIMIT 1");
// search current required_* field in DB
const char* db_name;
if (!strcmp(table_name, "db_version"))
{ db_name = "WORLD"; }
else if (!strcmp(table_name, "character_db_version"))
{ db_name = "CHARACTER"; }
else if (!strcmp(table_name, "realmd_db_version"))
{ db_name = "REALMD"; }
else
{ db_name = "UNKNOWN"; }
char const* req_sql_update_name = required_name + strlen("required_");
QueryNamedResult* result2 = PQueryNamed("SELECT * FROM %s LIMIT 1", table_name);
if (result2)
{
QueryFieldNames const& namesMap = result2->GetFieldNames();
std::string reqName;
for (QueryFieldNames::const_iterator itr = namesMap.begin(); itr != namesMap.end(); ++itr)
{
if (itr->substr(0, 9) == "required_")
{
reqName = *itr;
break;
}
}
delete result2;
std::string cur_sql_update_name = reqName.substr(strlen("required_"), reqName.npos);
if (!reqName.empty())
{
sLog.outErrorDb("The table `%s` in your [%s] database indicates that this database is out of date!", table_name, db_name);
sLog.outErrorDb();
sLog.outErrorDb(" [A] You have: --> `%s.sql`", cur_sql_update_name.c_str());
sLog.outErrorDb();
sLog.outErrorDb(" [B] You need: --> `%s.sql`", req_sql_update_name);
sLog.outErrorDb();
sLog.outErrorDb("You must apply all updates after [A] to [B] to use mangos with this database.");
sLog.outErrorDb("These updates are included in the sql/updates folder.");
sLog.outErrorDb("Please read the included [README] in sql/updates for instructions on updating.");
}
else
{
sLog.outErrorDb("The table `%s` in your [%s] database is missing its version info.", table_name, db_name);
sLog.outErrorDb("MaNGOS can not find the version info needed to check that the db is up to date.");
sLog.outErrorDb();
sLog.outErrorDb("This revision of MaNGOS requires a database updated to:");
sLog.outErrorDb("`%s.sql`", req_sql_update_name);
sLog.outErrorDb();
if (!strcmp(db_name, "WORLD"))
{ sLog.outErrorDb("Post this error to your database provider forum or find a solution there."); }
else
{ sLog.outErrorDb("Reinstall your [%s] database with the included sql file in the sql folder.", db_name); }
}
}
else
{
sLog.outErrorDb("The table `%s` in your [%s] database is missing or corrupt.", table_name, db_name);
sLog.outErrorDb("MaNGOS can not find the version info needed to check that the db is up to date.");
// db_version table does not exist or is empty
if (!result)
{
sLog.outErrorDb("The table `db_version` in your [%s] database is missing or corrupt.", dbversion.dbname.c_str());
sLog.outErrorDb();
sLog.outErrorDb("This revision of mangos requires a database updated to:");
sLog.outErrorDb("`%s.sql`", req_sql_update_name);
sLog.outErrorDb(" [A] You have database Version: MaNGOS can not verify your database version or its existence!");
sLog.outErrorDb();
if (!strcmp(db_name, "WORLD"))
{ sLog.outErrorDb("Post this error to your database provider forum or find a solution there."); }
else
{ sLog.outErrorDb("Reinstall your [%s] database with the included sql file in the sql folder.", db_name); }
sLog.outErrorDb(" [B] You need database Version: %u", dbversion.expected_version);
sLog.outErrorDb(" Structure: %u", dbversion.expected_structure);
sLog.outErrorDb(" Content: %u", dbversion.expected_content);
sLog.outErrorDb(" Description: %s", dbversion.description.c_str());
sLog.outErrorDb();
sLog.outErrorDb("Please verify your database location or your database integrity.");
return false;
}
return false;
Field* fields = result->Fetch();
uint32 version = fields[0].GetUInt32();
uint32 structure = fields[1].GetUInt32();
uint32 content = fields[2].GetUInt32();
std::string description = fields[3].GetCppString();
delete result;
// Structure does not match the required version
if (version != dbversion.expected_version || structure != dbversion.expected_structure)
{
sLog.outErrorDb("The table `db_version` indicates that your [%s] database does not match the expected structure!", dbversion.dbname.c_str());
sLog.outErrorDb();
sLog.outErrorDb(" [A] You have database Version: %u", version);
sLog.outErrorDb(" Structure: %u", structure);
sLog.outErrorDb(" Content: %u", content);
sLog.outErrorDb(" Description: %s", description.c_str());
sLog.outErrorDb();
sLog.outErrorDb(" [B] You need database Version: %u", dbversion.expected_version);
sLog.outErrorDb(" Structure: %u", dbversion.expected_structure);
sLog.outErrorDb(" Content: %u", dbversion.expected_content);
sLog.outErrorDb(" Description: %s", dbversion.description.c_str());
sLog.outErrorDb();
sLog.outErrorDb("You must apply all updates after [A] to [B] to use MaNGOS with this database.");
sLog.outErrorDb("These updates are included in the database/%s/Updates folder.", dbversion.dbname.c_str());
return false;
}
// DB is not up to date, but structure is correct. Send warning but start core
if (content > dbversion.expected_content)
{
sLog.outErrorDb("You have not updated the core for few DB [%s] updates!", dbversion.dbname.c_str());
sLog.outErrorDb("Current DB content is %u, core expects %u", content, dbversion.expected_content);
sLog.outErrorDb("This is ok for now but should not last long.");
}
else if (content != dbversion.expected_content)
{
sLog.outErrorDb("The table `db_version` indicates that your [%s] database does not match the expected version!", dbversion.dbname.c_str());
sLog.outErrorDb();
sLog.outErrorDb(" [A] You have database Version: %u", version);
sLog.outErrorDb(" Structure: %u", structure);
sLog.outErrorDb(" Content: %u", content);
sLog.outErrorDb(" Description: %s", description.c_str());
sLog.outErrorDb();
sLog.outErrorDb(" [B] You need database Version: %u", dbversion.expected_version);
sLog.outErrorDb(" Structure: %u", dbversion.expected_structure);
sLog.outErrorDb(" Content: %u", dbversion.expected_content);
sLog.outErrorDb(" Description: %s", dbversion.description.c_str());
sLog.outErrorDb();
sLog.outErrorDb("You are missing content updates or you have content updates beyond the expected core version.");
sLog.outErrorDb("It is recommended to run ALL database updates up to the required core version.");
sLog.outErrorDb("These updates are included in the database/%s/Updates folder.", dbversion.dbname.c_str());
};
return true;
}
bool Database::ExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params)
@ -545,7 +556,7 @@ bool Database::ExecuteStmt(const SqlStatementID& id, SqlStmtParameters* params)
if (!m_pAsyncConn)
{ return false; }
SqlTransaction* pTrans = m_TransStorage->get();
SqlTransaction* pTrans = (*m_TransStorage)->get();
if (pTrans)
{
// add SQL request to trans queue

View file

@ -43,6 +43,14 @@ class Database;
#define MAX_QUERY_LEN (32*1024)
enum DatabaseTypes
{
DATABASE_WORLD,
DATABASE_REALMD,
DATABASE_CHARACTER,
COUNT_DATABASES,
};
/**
* @brief
*
@ -613,13 +621,12 @@ class Database
void ProcessResultQueue();
/**
* @brief
*
* @param table_name
* @param required_name
* @return bool
*/
bool CheckRequiredField(char const* table_name, char const* required_name);
* @brief Function to check that the database version matches expected core version
*
* @param DatabaseTypes
* @return bool
*/
bool CheckDatabaseVersion(DatabaseTypes database);
/**
* @brief
*
@ -651,7 +658,7 @@ class Database
Database() :
m_nQueryConnPoolSize(1), m_pAsyncConn(NULL), m_pResultQueue(NULL),
m_threadBody(NULL), m_delayThread(NULL), m_bAllowAsyncTransactions(false),
m_iStmtIndex(-1), m_logSQL(false), m_pingIntervallms(0)
m_iStmtIndex(-1), m_logSQL(false), m_pingIntervallms(0), m_TransStorage(NULL)
{
m_nQueryCounter = -1;
}
@ -679,7 +686,7 @@ class Database
* @brief
*
*/
class TransHelper
class TransHelper
{
public:
/**
@ -730,7 +737,7 @@ class Database
*
*/
typedef ACE_TSS<Database::TransHelper> DBTransHelperTSS;
Database::DBTransHelperTSS m_TransStorage; /**< TODO */
Database::DBTransHelperTSS *m_TransStorage; /**< TODO */
///< DB connections
/**
@ -781,7 +788,7 @@ class Database
SqlResultQueue* m_pResultQueue; /**< Transaction queues from diff. threads */
SqlDelayThread* m_threadBody; /**< Pointer to delay sql executer (owned by m_delayThread) */
ACE_Based::Thread* m_delayThread; /**< Pointer to executer thread */
ACE_Based::Thread* m_delayThread; /**< Pointer to executer thread */
bool m_bAllowAsyncTransactions; /**< flag which specifies if async transactions are enabled */

View file

@ -114,7 +114,7 @@ class Field
*
* @return int8
*/
int8 GetInt8() const { return mValue ? static_cast<int8>(atol(mValue)) : int8(0); }
int8 GetInt8() const { return mValue ? static_cast<int8>(atol(mValue)) : int8(0); }
/**
* @brief
*
@ -154,29 +154,29 @@ class Field
{
uint64 value = 0;
if (!mValue || sscanf(mValue, UI64FMTD, &value) == -1)
return 0;
{ return 0; }
return value;
}
}
/**
* @brief
*
* @return int64
*/
uint64 GetInt64() const
{
int64 value = 0;
if (!mValue || sscanf(mValue, SI64FMTD, &value) == -1)
return 0;
uint64 GetInt64() const
{
int64 value = 0;
if (!mValue || sscanf(mValue, SI64FMTD, &value) == -1)
return 0;
return value;
}
return value;
}
/**
* @brief
*
* @param type
*/
/**
* @brief
*
* @param type
*/
void SetType(enum DataTypes type) { mType = type; }
/**

View file

@ -162,7 +162,7 @@ void SQLStorage::prepareToLoad(uint32 maxRecordId, uint32 recordCount, uint32 re
// Set index array
m_Index = new char*[maxRecordId];
memset(m_Index, NULL, maxRecordId * sizeof(char*));
memset(m_Index, 0, maxRecordId * sizeof(char*));
SQLStorageBase::prepareToLoad(maxRecordId, recordCount, recordSize);
}