Commit 1ce85038 authored by Hugo Beauzée-Luyssen's avatar Hugo Beauzée-Luyssen

SqliteConnection: Attempt to use the big lock of death approach

parent b220566b
......@@ -26,7 +26,7 @@ sqlite3 *SqliteConnection::getConn()
LOG_WARN( "Failed to enable sqlite busy timeout" );
m_conns.emplace(std::this_thread::get_id(), ConnPtr( dbConnection, &sqlite3_close ) );
lock.unlock();
if ( sqlite::Tools::executeRequest( this, "PRAGMA foreign_keys = ON" ) == false )
if ( sqlite::Tools::executeRequestLocked( this, "PRAGMA foreign_keys = ON" ) == false )
throw std::runtime_error( "Failed to enable foreign keys" );
return dbConnection;
}
......@@ -38,3 +38,8 @@ void SqliteConnection::release()
std::unique_lock<std::mutex> lock( m_connMutex );
m_conns.erase( std::this_thread::get_id() );
}
SqliteConnection::RequestContext SqliteConnection::acquireContext()
{
return RequestContext{ m_contextMutex };
}
......@@ -10,6 +10,8 @@
class SqliteConnection
{
private:
using RequestContext = std::unique_lock<std::mutex>;
public:
SqliteConnection( const std::string& dbPath );
// Returns the current thread's connection
......@@ -17,12 +19,14 @@ public:
sqlite3* getConn();
// Release the current thread's connection
void release();
RequestContext acquireContext();
private:
using ConnPtr = std::unique_ptr<sqlite3, int(*)(sqlite3*)>;
const std::string m_dbPath;
std::mutex m_connMutex;
std::unordered_map<std::thread::id, ConnPtr> m_conns;
std::mutex m_contextMutex;
};
#endif // SQLITECONNECTION_H
......@@ -106,6 +106,8 @@ class Tools
template <typename IMPL, typename INTF, typename... Args>
static std::vector<std::shared_ptr<INTF> > fetchAll( DBConnection dbConnection, const std::string& req, Args&&... args )
{
auto ctx = dbConnection->acquireContext();
std::vector<std::shared_ptr<INTF>> results;
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )...);
if ( stmt == nullptr )
......@@ -123,6 +125,8 @@ class Tools
template <typename T, typename... Args>
static std::shared_ptr<T> fetchOne( DBConnection dbConnection, const std::string& req, Args&&... args )
{
auto ctx = dbConnection->acquireContext();
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )... );
if ( stmt == nullptr )
return nullptr;
......@@ -135,32 +139,15 @@ class Tools
template <typename... Args>
static bool executeRequest( DBConnection dbConnection, const std::string& req, Args&&... args )
{
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )... );
if ( stmt == nullptr )
return false;
int res;
do
{
res = sqlite3_step( stmt.get() );
} while ( res == SQLITE_ROW );
if ( res != SQLITE_DONE )
{
#if SQLITE_VERSION_NUMBER >= 3007015
auto err = sqlite3_errstr( res );
#else
auto err = res;
#endif
LOG_ERROR( "Failed to execute <", req, ">\nInvalid result: ", err,
": ", sqlite3_errmsg( dbConnection->getConn() ) );
return false;
}
return true;
auto ctx = dbConnection->acquireContext();
return executeRequestLocked( dbConnection, req, std::forward<Args>( args )... );
}
template <typename... Args>
static bool executeDelete( DBConnection dbConnection, const std::string& req, Args&&... args )
{
if ( executeRequest( dbConnection, req, std::forward<Args>( args )... ) == false )
auto ctx = dbConnection->acquireContext();
if ( executeRequestLocked( dbConnection, req, std::forward<Args>( args )... ) == false )
return false;
return sqlite3_changes( dbConnection->getConn() ) > 0;
}
......@@ -179,12 +166,38 @@ class Tools
template <typename... Args>
static unsigned int insert( DBConnection dbConnection, const std::string& req, Args&&... args )
{
if ( executeRequest( dbConnection, req, std::forward<Args>( args )... ) == false )
auto ctx = dbConnection->acquireContext();
if ( executeRequestLocked( dbConnection, req, std::forward<Args>( args )... ) == false )
return 0;
return sqlite3_last_insert_rowid( dbConnection->getConn() );
}
private:
template <typename... Args>
static bool executeRequestLocked( DBConnection dbConnection, const std::string& req, Args&&... args )
{
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )... );
if ( stmt == nullptr )
return false;
int res;
do
{
res = sqlite3_step( stmt.get() );
} while ( res == SQLITE_ROW );
if ( res != SQLITE_DONE )
{
#if SQLITE_VERSION_NUMBER >= 3007015
auto err = sqlite3_errstr( res );
#else
auto err = res;
#endif
LOG_ERROR( "Failed to execute <", req, ">\nInvalid result: ", err,
": ", sqlite3_errmsg( dbConnection->getConn() ) );
return false;
}
return true;
}
template <typename... Args>
static StmtPtr prepareRequest( DBConnection dbConnection, const std::string& req, Args&&... args )
{
......@@ -211,6 +224,8 @@ class Tools
Traits<T>::Bind( stmt.get(), COLIDX, std::forward<T>( arg ) );
return stmt;
}
friend SqliteConnection;
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment