rendered paste bodyIndex: src/shared/Database/Database.cpp
===================================================================
--- src/shared/Database/Database.cpp (revision 4065)
+++ src/shared/Database/Database.cpp (working copy)
@@ -23,6 +23,12 @@
#include <iostream>
#include <fstream>
+Database::~Database()
+{
+ /*Delete objects*/
+ delete m_delayThread; //This also delate m_threadBody
+}
+
bool Database::Initialize(const char *)
{
// Enable logging of SQL commands (usally only GM commands)
Index: src/shared/Database/Database.h
===================================================================
--- src/shared/Database/Database.h (revision 4065)
+++ src/shared/Database/Database.h (working copy)
@@ -19,14 +19,29 @@
#if !defined(DATABASE_H)
#define DATABASE_H
+#include "zthread/Thread.h"
+#include "Utilities/HashMap.h"
+#include "Database/SqlDelayThread.h"
+
+#include <queue>
+
+class SqlTransaction;
+typedef HM_NAMESPACE::hash_map<ZThread::ThreadImpl*, SqlTransaction*> TransactionMap;
+
+#define MAX_QUERY_LEN 1024
+
class Database
{
protected:
- Database() {}
+ Database() {};
+
+ TransactionMap m_tranQueues; ///< Transaction queue from diff. threads
+ SqlDelayThread* m_threadBody; ///< Pointer to delay sql executer
+ ZThread::Thread* m_delayThread; ///< Pointer to executer thread
public:
- virtual ~Database() {}
+ virtual ~Database();
virtual bool Initialize(const char *infoString);
@@ -35,6 +50,7 @@
virtual bool Execute(const char *sql) = 0;
virtual bool PExecute(const char *format,...) = 0;
+ virtual bool DirectExecute(const char* sql) = 0;
// Writes SQL commands to a LOG file (see mangosd.conf "LogSQL")
bool PExecuteLog(const char *format,...);
@@ -65,4 +81,5 @@
// 0 - do not log, 1 - log sql commands
uint32 m_logSQL;
};
+
#endif
Index: src/shared/Database/DatabaseMysql.cpp
===================================================================
--- src/shared/Database/DatabaseMysql.cpp (revision 4065)
+++ src/shared/Database/DatabaseMysql.cpp (working copy)
@@ -21,6 +21,8 @@
#include "Policies/SingletonImp.h"
#include "Platform/Define.h"
#include "../src/zthread/ThreadImpl.h"
+#include "Database/MySQLDelayThread.h"
+#include "SqlStatements.h"
using namespace std;
@@ -50,10 +52,15 @@
exit(1);
}
}
+ //New delay thread for delay execute
+ m_delayThread = new ZThread::Thread(m_threadBody = new MySQLDelayThread(this));
}
DatabaseMysql::~DatabaseMysql()
{
+ m_threadBody->Stop(); //Stop event
+ m_delayThread->wait(); //Wait for flush to DB
+
if (mMysql)
mysql_close(mMysql);
@@ -150,9 +157,9 @@
if(!format) return NULL;
va_list ap;
- char szQuery [1024];
+ char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
- int res = vsnprintf( szQuery, 1024, format, ap );
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
@@ -175,7 +182,7 @@
{
// guarded block for thread-safe mySQL request
- ZThread::Guard<ZThread::FastMutex> query_connection_guard((ZThread::ThreadImpl::current()==tranThread?tranMutex:mMutex));
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
if(mysql_query(mMysql, sql))
{
@@ -215,22 +222,18 @@
{
if (!mMysql)
return false;
-
+
+ tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionMap::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ // Statement for transaction
+ i->second->DelayExecute(sql);
+ }
+ else
{
- // guarded block for thread-safe mySQL request
- ZThread::Guard<ZThread::FastMutex> query_connection_guard((ZThread::ThreadImpl::current()==tranThread?tranMutex:mMutex));
-
- if(mysql_query(mMysql, sql))
- {
- sLog.outErrorDb("SQL: %s", sql);
- sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql));
- return false;
- }
- else
- {
- DEBUG_LOG("SQL: %s", sql);
- }
- // end guarded block
+ // Simple sql statement
+ m_threadBody->Delay(new SqlStatement(sql));
}
return true;
@@ -242,9 +245,9 @@
return false;
va_list ap;
- char szQuery [1024];
+ char szQuery [MAX_QUERY_LEN];
va_start(ap, format);
- int res = vsnprintf( szQuery, 1024, format, ap );
+ int res = vsnprintf( szQuery, MAX_QUERY_LEN, format, ap );
va_end(ap);
if(res==-1)
@@ -256,6 +259,31 @@
return Execute(szQuery);
}
+bool DatabaseMysql::DirectExecute(const char* sql)
+{
+ if (!mMysql)
+ return false;
+
+ {
+ // guarded block for thread-safe mySQL request
+ ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex);
+
+ if(mysql_query(mMysql, sql))
+ {
+ sLog.outErrorDb("SQL: %s", sql);
+ sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql));
+ return false;
+ }
+ else
+ {
+ DEBUG_LOG("SQL: %s", sql);
+ }
+ // end guarded block
+ }
+
+ return true;
+}
+
bool DatabaseMysql::_TransactionCmd(const char *sql)
{
if (mysql_query(mMysql, sql))
@@ -275,16 +303,11 @@
{
if (!mMysql)
return false;
- if (tranThread==ZThread::ThreadImpl::current())
- return false; // huh? this thread already started transaction
- mMutex.acquire();
- if (!_TransactionCmd("START TRANSACTION"))
- {
- mMutex.release(); // can't start transaction
- return false;
- }
- // transaction started
tranThread = ZThread::ThreadImpl::current(); // owner of this transaction
+ TransactionMap::iterator i = m_tranQueues.find(tranThread);
+ if (i == m_tranQueues.end())
+ // If for thread not existing queue create one
+ m_tranQueues[tranThread] = new SqlTransaction();
return true;
}
@@ -292,24 +315,32 @@
{
if (!mMysql)
return false;
- if (tranThread!=ZThread::ThreadImpl::current())
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionMap::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ // We not need locking the transaction queue it is only one
+ // for every thread (no concurency there)
+ m_threadBody->Delay(i->second);
+ i->second = NULL;
+ return true;
+ }
+ else
return false;
- bool _res = _TransactionCmd("COMMIT");
- tranThread = NULL;
- mMutex.release();
- return _res;
}
bool DatabaseMysql::RollbackTransaction()
{
if (!mMysql)
return false;
- if (tranThread!=ZThread::ThreadImpl::current())
- return false;
- bool _res = _TransactionCmd("ROLLBACK");
- tranThread = NULL;
- mMutex.release();
- return _res;
+ tranThread = ZThread::ThreadImpl::current();
+ TransactionMap::iterator i = m_tranQueues.find(tranThread);
+ if (i != m_tranQueues.end() && i->second != NULL)
+ {
+ delete i->second;
+ i->second = NULL;
+ }
+ return true;
}
unsigned long DatabaseMysql::escape_string(char *to, const char *from, unsigned long length)
Index: src/shared/Database/DatabaseMysql.h
===================================================================
--- src/shared/Database/DatabaseMysql.h (revision 4065)
+++ src/shared/Database/DatabaseMysql.h (working copy)
@@ -45,6 +45,7 @@
QueryResult* Query(const char *sql);
bool Execute(const char *sql);
bool PExecute(const char *format,...);
+ bool DirectExecute(const char* sql);
bool BeginTransaction();
bool CommitTransaction();
bool RollbackTransaction();
Index: src/shared/Database/SQLStatements.cpp
===================================================================
--- src/shared/Database/SQLStatements.cpp (revision 0)
+++ src/shared/Database/SQLStatements.cpp (revision 0)
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "DatabaseEnv.h"
+#include "SQLStatements.h"
+
+void SqlStatement::Execute(Database *db)
+{
+ db->DirectExecute(m_sql);
+}
+
+void SqlTransaction::Execute(Database *db)
+{
+ if(m_queue.empty()) return;
+ db->DirectExecute("START TRANSACTION");
+ while(!m_queue.empty())
+ {
+ const char *sql = (const char*)m_queue.front();
+ m_queue.pop();
+ db->DirectExecute(sql);
+ delete [] sql;
+ }
+ db->DirectExecute("COMMIT");
+}
+
+void SqlQuery::Execute(Database *db)
+{
+ m_result = db->PQuery(m_sql);
+ Callback();
+}
+
+/*class Obj
+{
+public:
+ void SomeMethod(QueryResult *q)
+ {
+ Player *ply;
+ ply->
+ }
+
+} *obj;*/
+
+class ObjInterface1;
+class ObjInterface2;
+class ObjFullInterface;
+class Obj2Interface1;
+class Obj2Interface2;
+class Obj2FullInterface;
+
+class BaseObj
+{
+
+};
+
+class Obj : public BaseObj
+{
+ public:
+ ObjInterface1* GetInterface1() { return (ObjInterface1*)this; }
+ ObjInterface2* GetInterface2() { return (ObjInterface2*)this; }
+ ObjFullInterface* GetFullInterface() { return (ObjFullInterface*)this; }
+};
+
+class ObjInterface1 : public BaseObj
+{
+ public:
+ void I1_AFunc() {}
+};
+
+class ObjInterface2 : public BaseObj
+{
+ public:
+ void I2_AFunc() {}
+};
+
+class ObjFullInterface : public ObjInterface1, public ObjInterface2
+{
+
+};
+
+class BaseObj2 : public BaseObj
+{
+
+};
+
+class Obj2 : public BaseObj2
+{
+ public:
+ Obj2Interface1* GetInterface1() { return (Obj2Interface1*)this; }
+ Obj2Interface2* GetInterface2() { return (Obj2Interface2*)this; }
+ Obj2FullInterface* GetFullInterface() { return (Obj2FullInterface*)this; }
+};
+
+class Obj2Interface1 : public BaseObj2, public ObjInterface1
+{
+ public:
+ void I1_BFunc() {}
+};
+
+class Obj2Interface2 : public BaseObj2, public ObjInterface2
+{
+ public:
+ void I2_BFunc() {}
+};
+
+class Obj2FullInterface : public Obj2Interface1, public Obj2Interface2
+{
+
+};
+
+void Test()
+{
+ Obj *obj = (Obj*)new ObjFullInterface;
+ obj->GetInterface1()->I1_AFunc();
+ Obj2 *obj2 = (Obj2*)new Obj2FullInterface;
+ obj2->GetInterface1()->I1_BFunc();
+}
+
+void SqlQueryQueue::Update()
+{
+ while(!empty())
+ {
+ SqlQuery * query =next();
+ query->Callback();
+ }
+ //_SqlQuery<Obj> *query = new _SqlQuery<Obj>("select ...", obj, &Obj::SomeMethod);
+}
\ No newline at end of file
Index: src/shared/Database/SQLStatements.h
===================================================================
--- src/shared/Database/SQLStatements.h (revision 0)
+++ src/shared/Database/SQLStatements.h (revision 0)
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2005,2006,2007 MaNGOS <http://www.mangosproject.org/>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SQLSTATEMENTS_H
+#define __SQLSTATEMENTS_H
+
+#include <queue>
+using namespace std;
+
+// ---- BASE ---
+
+class Database;
+
+class SqlOperation
+{
+ public:
+ SqlOperation() {}
+ virtual void Execute(Database *db) = 0;
+};
+
+// ---- ASYNC STATEMENTS / TRANSACTIONS ----
+
+class SqlStatement : public SqlOperation
+{
+ private:
+ const char *m_sql;
+ public:
+ SqlStatement(const char *sql) : m_sql(strdup(sql)), SqlOperation() {}
+ ~SqlStatement() { delete[] m_sql; }
+ void Execute(Database *db);
+};
+
+class SqlTransaction : public SqlOperation
+{
+ private:
+ queue<const char *> m_queue;
+ public:
+ SqlTransaction() : SqlOperation() {}
+ void DelayExecute(const char *sql) { m_queue.push(strdup(sql)); }
+ void Execute(Database *db);
+};
+
+// ---- ASYNC QUERIES ----
+
+class SqlQueryQueue;
+class SqlQuery;
+class QueryResult;
+
+class SqlQueryQueue : public ZThread::LockedQueue<SqlQuery*, ZThread::FastMutex>
+{
+ public:
+ SqlQueryQueue() : ZThread::LockedQueue<SqlQuery*, ZThread::FastMutex>() {}
+ void Update();
+};
+
+class SqlQuery : public SqlOperation
+{
+ private:
+ QueryResult *m_result;
+ const char *m_sql;
+ public:
+ SqlQuery(const char *sql)
+ : m_sql(strdup(sql)), m_result(NULL), SqlOperation() {}
+ QueryResult *GetResult() { return m_result; }
+ void Execute(Database *db);
+ virtual void Callback() = 0;
+};
+
+template<class Class>
+class _SqlQuery : public SqlQuery
+{
+ private:
+ typedef void (Class::*Method)(QueryResult*);
+ Class *m_object;
+ Method m_method;
+ public:
+ _SqlQuery(const char *sql, Class *object, Method method)
+ : m_object(object), m_method(method), SqlQuery(sql) {}
+ void Callback() { (m_object->*m_method)(GetResult()); }
+};
+
+#endif
\ No newline at end of file