2017-09-30 23:51:01 +02:00
|
|
|
#include "DbWorkerPool.h"
|
|
|
|
#include "DbConnection.h"
|
|
|
|
#include "PreparedStatement.h"
|
2018-03-06 22:22:19 +01:00
|
|
|
#include <MySqlConnector.h>
|
2017-09-30 23:51:01 +02:00
|
|
|
#include "StatementTask.h"
|
|
|
|
#include "Operation.h"
|
2018-09-09 23:56:22 +02:00
|
|
|
#include "ZoneDbConnection.h"
|
2018-03-09 10:36:07 +01:00
|
|
|
#include "Framework.h"
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-03-06 22:22:19 +01:00
|
|
|
#include "Logging/Logger.h"
|
2018-10-26 19:12:55 +02:00
|
|
|
#include <mysql.h>
|
2018-03-09 10:36:07 +01:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
class PingOperation :
|
2018-11-29 16:55:48 +01:00
|
|
|
public Sapphire::Db::Operation
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
bool execute() override
|
|
|
|
{
|
|
|
|
m_pConn->ping();
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-30 23:51:01 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
template< class T >
|
2018-12-23 03:53:08 +01:00
|
|
|
Sapphire::Db::DbWorkerPool< T >::DbWorkerPool() :
|
2018-11-29 16:55:48 +01:00
|
|
|
m_queue( new Sapphire::LockedWaitQueue< std::shared_ptr< Operation > >() ),
|
2018-08-29 21:40:59 +02:00
|
|
|
m_asyncThreads( 0 ),
|
|
|
|
m_synchThreads( 0 )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Db::DbWorkerPool< T >::~DbWorkerPool()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_queue->cancel();
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::setConnectionInfo( const ConnectionInfo& info,
|
2018-12-23 03:53:08 +01:00
|
|
|
uint8_t asyncThreads,
|
|
|
|
uint8_t synchThreads )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_connectionInfo = info;
|
|
|
|
m_asyncThreads = asyncThreads;
|
|
|
|
m_synchThreads = synchThreads;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
uint32_t Sapphire::Db::DbWorkerPool< T >::open()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "[DbPool] Opening DatabasePool {0} Asynchronous connections: {1} Synchronous connections: {2}",
|
|
|
|
getDatabaseName(), m_asyncThreads, m_synchThreads );
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
uint32_t error = openConnections( IDX_ASYNC, m_asyncThreads );
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( error )
|
|
|
|
return error;
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
error = openConnections( IDX_SYNCH, m_synchThreads );
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !error )
|
|
|
|
{
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "[DbPool] DatabasePool '{0}' opened successfully. {1} total connections running.",
|
|
|
|
getDatabaseName(), ( m_connections[ IDX_SYNCH ].size() + m_connections[ IDX_ASYNC ].size() ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
}
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return error;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::close()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "[DbPool] Closing down DatabasePool {0}", getDatabaseName() );
|
2018-08-29 21:40:59 +02:00
|
|
|
m_connections[ IDX_ASYNC ].clear();
|
|
|
|
m_connections[ IDX_SYNCH ].clear();
|
2019-01-04 21:46:37 +11:00
|
|
|
Logger::info( "[DbPool] All connections on DatabasePool {0} closed.", getDatabaseName() );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
bool Sapphire::Db::DbWorkerPool< T >::prepareStatements()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
for( auto& connections : m_connections )
|
|
|
|
for( auto& connection : connections )
|
|
|
|
{
|
|
|
|
connection->lockIfReady();
|
|
|
|
if( !connection->prepareStatements() )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
connection->unlock();
|
|
|
|
close();
|
|
|
|
return false;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
else
|
|
|
|
connection->unlock();
|
|
|
|
}
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return true;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-10-24 12:53:26 +02:00
|
|
|
std::shared_ptr< Mysql::ResultSet >
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Db::DbWorkerPool< T >::query( const std::string& sql, std::shared_ptr< T > connection )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !connection )
|
|
|
|
connection = getFreeConnection();
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-10-24 12:53:26 +02:00
|
|
|
std::shared_ptr< Mysql::ResultSet > result = connection->query( sql );
|
2018-08-29 21:40:59 +02:00
|
|
|
connection->unlock();
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return result;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-10-24 12:53:26 +02:00
|
|
|
std::shared_ptr< Mysql::PreparedResultSet >
|
2018-11-29 16:55:48 +01:00
|
|
|
Sapphire::Db::DbWorkerPool< T >::query( std::shared_ptr< PreparedStatement > stmt )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
auto connection = getFreeConnection();
|
2018-10-24 12:53:26 +02:00
|
|
|
auto ret = std::static_pointer_cast< Mysql::PreparedResultSet >( connection->query( stmt ) );
|
2018-08-29 21:40:59 +02:00
|
|
|
connection->unlock();
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return ret;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
std::shared_ptr< Sapphire::Db::PreparedStatement >
|
|
|
|
Sapphire::Db::DbWorkerPool< T >::getPreparedStatement( PreparedStatementIndex index )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-10-24 12:53:26 +02:00
|
|
|
return std::make_shared< PreparedStatement >( index );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::escapeString( std::string& str )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( str.empty() )
|
|
|
|
return;
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
char* buf = new char[str.size() * 2 + 1];
|
|
|
|
escapeString( buf, str.c_str(), str.size() );
|
|
|
|
str = buf;
|
|
|
|
delete[] buf;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::keepAlive()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
for( auto& connection : m_connections[ IDX_SYNCH ] )
|
|
|
|
{
|
|
|
|
if( connection->lockIfReady() )
|
|
|
|
{
|
|
|
|
connection->ping();
|
|
|
|
connection->unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto count = m_connections[ IDX_ASYNC ].size();
|
|
|
|
for( uint8_t i = 0; i < count; ++i )
|
2018-10-24 12:53:26 +02:00
|
|
|
enqueue( std::make_shared< PingOperation >() );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
uint32_t Sapphire::Db::DbWorkerPool< T >::openConnections( InternalIndex type, uint8_t numConnections )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
for( uint8_t i = 0; i < numConnections; ++i )
|
|
|
|
{
|
|
|
|
// Create the connection
|
|
|
|
auto connection = [ & ]
|
|
|
|
{
|
|
|
|
switch( type )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
case IDX_ASYNC:
|
2018-10-24 12:53:26 +02:00
|
|
|
return std::make_shared< T >( m_queue.get(), m_connectionInfo );
|
2018-08-29 21:40:59 +02:00
|
|
|
case IDX_SYNCH:
|
2018-10-24 12:53:26 +02:00
|
|
|
return std::make_shared< T >( m_connectionInfo );
|
2018-08-29 21:40:59 +02:00
|
|
|
default:
|
2018-10-24 12:53:26 +02:00
|
|
|
return std::shared_ptr< T >( nullptr );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
2018-08-29 21:40:59 +02:00
|
|
|
}();
|
|
|
|
|
|
|
|
if( uint32_t error = connection->open() )
|
|
|
|
{
|
|
|
|
// Failed to open a connection or invalid version, abort and cleanup
|
|
|
|
m_connections[ type ].clear();
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
m_connections[ type ].push_back( connection );
|
|
|
|
}
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return 0;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
unsigned long Sapphire::Db::DbWorkerPool< T >::escapeString( char* to, const char* from, unsigned long length )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
if( !to || !from || !length )
|
|
|
|
return 0;
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return mysql_real_escape_string(
|
|
|
|
m_connections[ IDX_SYNCH ].front()->getConnection()->getRawCon(), to, from, length );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::enqueue( std::shared_ptr< Operation > op )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
m_queue->push( op );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
std::shared_ptr< T > Sapphire::Db::DbWorkerPool< T >::getFreeConnection()
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
uint8_t i = 0;
|
|
|
|
const auto numCons = m_connections[ IDX_SYNCH ].size();
|
2018-10-24 12:53:26 +02:00
|
|
|
std::shared_ptr< T > connection = nullptr;
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
while( true )
|
|
|
|
{
|
|
|
|
connection = m_connections[ IDX_SYNCH ][ i++ % numCons ];
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
if( connection->lockIfReady() )
|
|
|
|
break;
|
|
|
|
}
|
2017-09-30 23:51:01 +02:00
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
return connection;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
const std::string& Sapphire::Db::DbWorkerPool< T >::getDatabaseName() const
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
return m_connectionInfo.database;
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::execute( const std::string& sql )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-10-24 12:53:26 +02:00
|
|
|
auto task = std::make_shared< StatementTask >( sql );
|
2018-08-29 21:40:59 +02:00
|
|
|
enqueue( task );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::execute( std::shared_ptr< PreparedStatement > stmt )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-10-24 12:53:26 +02:00
|
|
|
auto task = std::make_shared< PreparedStatementTask >( stmt );
|
2018-08-29 21:40:59 +02:00
|
|
|
enqueue( task );
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::directExecute( const std::string& sql )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
auto connection = getFreeConnection();
|
|
|
|
connection->execute( sql );
|
|
|
|
connection->unlock();
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
template< class T >
|
2018-11-29 16:55:48 +01:00
|
|
|
void Sapphire::Db::DbWorkerPool< T >::directExecute( std::shared_ptr< PreparedStatement > stmt )
|
2017-09-30 23:51:01 +02:00
|
|
|
{
|
2018-08-29 21:40:59 +02:00
|
|
|
auto connection = getFreeConnection();
|
|
|
|
connection->execute( stmt );
|
|
|
|
connection->unlock();
|
2017-09-30 23:51:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
template <class T>
|
|
|
|
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction& trans, const char* sql)
|
|
|
|
{
|
|
|
|
if (!trans)
|
|
|
|
Execute(sql);
|
|
|
|
else
|
|
|
|
trans->Append(sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
void DatabaseWorkerPool<T>::ExecuteOrAppend(SQLTransaction& trans, PreparedStatement* stmt)
|
|
|
|
{
|
|
|
|
if (!trans)
|
|
|
|
Execute(stmt);
|
|
|
|
else
|
|
|
|
trans->Append(stmt);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
2018-08-29 21:40:59 +02:00
|
|
|
template
|
2018-11-29 16:55:48 +01:00
|
|
|
class Sapphire::Db::DbWorkerPool< Sapphire::Db::ZoneDbConnection >;
|