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() ...@@ -26,7 +26,7 @@ sqlite3 *SqliteConnection::getConn()
LOG_WARN( "Failed to enable sqlite busy timeout" ); LOG_WARN( "Failed to enable sqlite busy timeout" );
m_conns.emplace(std::this_thread::get_id(), ConnPtr( dbConnection, &sqlite3_close ) ); m_conns.emplace(std::this_thread::get_id(), ConnPtr( dbConnection, &sqlite3_close ) );
lock.unlock(); 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" ); throw std::runtime_error( "Failed to enable foreign keys" );
return dbConnection; return dbConnection;
} }
...@@ -38,3 +38,8 @@ void SqliteConnection::release() ...@@ -38,3 +38,8 @@ void SqliteConnection::release()
std::unique_lock<std::mutex> lock( m_connMutex ); std::unique_lock<std::mutex> lock( m_connMutex );
m_conns.erase( std::this_thread::get_id() ); m_conns.erase( std::this_thread::get_id() );
} }
SqliteConnection::RequestContext SqliteConnection::acquireContext()
{
return RequestContext{ m_contextMutex };
}
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
class SqliteConnection class SqliteConnection
{ {
private:
using RequestContext = std::unique_lock<std::mutex>;
public: public:
SqliteConnection( const std::string& dbPath ); SqliteConnection( const std::string& dbPath );
// Returns the current thread's connection // Returns the current thread's connection
...@@ -17,12 +19,14 @@ public: ...@@ -17,12 +19,14 @@ public:
sqlite3* getConn(); sqlite3* getConn();
// Release the current thread's connection // Release the current thread's connection
void release(); void release();
RequestContext acquireContext();
private: private:
using ConnPtr = std::unique_ptr<sqlite3, int(*)(sqlite3*)>; using ConnPtr = std::unique_ptr<sqlite3, int(*)(sqlite3*)>;
const std::string m_dbPath; const std::string m_dbPath;
std::mutex m_connMutex; std::mutex m_connMutex;
std::unordered_map<std::thread::id, ConnPtr> m_conns; std::unordered_map<std::thread::id, ConnPtr> m_conns;
std::mutex m_contextMutex;
}; };
#endif // SQLITECONNECTION_H #endif // SQLITECONNECTION_H
...@@ -106,6 +106,8 @@ class Tools ...@@ -106,6 +106,8 @@ class Tools
template <typename IMPL, typename INTF, typename... Args> template <typename IMPL, typename INTF, typename... Args>
static std::vector<std::shared_ptr<INTF> > fetchAll( DBConnection dbConnection, const std::string& req, Args&&... 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; std::vector<std::shared_ptr<INTF>> results;
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )...); auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )...);
if ( stmt == nullptr ) if ( stmt == nullptr )
...@@ -123,6 +125,8 @@ class Tools ...@@ -123,6 +125,8 @@ class Tools
template <typename T, typename... Args> template <typename T, typename... Args>
static std::shared_ptr<T> fetchOne( DBConnection dbConnection, const std::string& req, Args&&... 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 )... ); auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )... );
if ( stmt == nullptr ) if ( stmt == nullptr )
return nullptr; return nullptr;
...@@ -135,32 +139,15 @@ class Tools ...@@ -135,32 +139,15 @@ class Tools
template <typename... Args> template <typename... Args>
static bool executeRequest( DBConnection dbConnection, const std::string& req, Args&&... args ) static bool executeRequest( DBConnection dbConnection, const std::string& req, Args&&... args )
{ {
auto stmt = prepareRequest( dbConnection, req, std::forward<Args>( args )... ); auto ctx = dbConnection->acquireContext();
if ( stmt == nullptr ) return executeRequestLocked( dbConnection, req, std::forward<Args>( args )... );
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> template <typename... Args>
static bool executeDelete( DBConnection dbConnection, const std::string& req, Args&&... 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 false;
return sqlite3_changes( dbConnection->getConn() ) > 0; return sqlite3_changes( dbConnection->getConn() ) > 0;
} }
...@@ -179,12 +166,38 @@ class Tools ...@@ -179,12 +166,38 @@ class Tools
template <typename... Args> template <typename... Args>
static unsigned int insert( DBConnection dbConnection, const std::string& req, Args&&... 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 0;
return sqlite3_last_insert_rowid( dbConnection->getConn() ); return sqlite3_last_insert_rowid( dbConnection->getConn() );
} }
private: 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> template <typename... Args>
static StmtPtr prepareRequest( DBConnection dbConnection, const std::string& req, Args&&... args ) static StmtPtr prepareRequest( DBConnection dbConnection, const std::string& req, Args&&... args )
{ {
...@@ -211,6 +224,8 @@ class Tools ...@@ -211,6 +224,8 @@ class Tools
Traits<T>::Bind( stmt.get(), COLIDX, std::forward<T>( arg ) ); Traits<T>::Bind( stmt.get(), COLIDX, std::forward<T>( arg ) );
return stmt; 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