All pastes #614048 Raw Edit

Untitled

public text v1 · immutable
·published 2007-07-11 09:51 UTC
rendered paste body
Index: 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