Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
VideoLAN
medialibrary
Commits
1ce85038
Commit
1ce85038
authored
Oct 08, 2015
by
Hugo Beauzée-Luyssen
Browse files
SqliteConnection: Attempt to use the big lock of death approach
parent
b220566b
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/database/SqliteConnection.cpp
View file @
1ce85038
...
...
@@ -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
::
executeRequest
Locked
(
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
};
}
src/database/SqliteConnection.h
View file @
1ce85038
...
...
@@ -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
src/database/SqliteTools.h
View file @
1ce85038
...
...
@@ -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
,
">
\n
Invalid 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
,
">
\n
Invalid 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
;
};
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment