[tracker/wip/carlosg/bus-statements] libtracker-data: Fix race condition



commit ed204139a1af9a2b539b0b07429bb7df6096eab7
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Mar 2 14:17:50 2020 +0100

    libtracker-data: Fix race condition
    
    For some reason ever unseen (by me?) till CI happened to trip on this
    branch. The underlying TrackerDBStatements have a brief window between
    them being looked up in the stmt LRU and them being used for query
    execution that they might end up in use by two threads at the same time.
    
    Add a new TrackerDBStatement flag to indicate that the statement is owned,
    set it early when fetching the TrackerDBStatement and make the LRU checks
    check for it before considering using a temporary stmt. The lifetime of
    this flag matches the time the TrackerDBStatement is in use by a given
    user.
    
    The flag is released altogether on _release(), as it works for indicating
    the statement is being made available to other users.

 src/libtracker-data/tracker-db-interface-sqlite.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
---
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c 
b/src/libtracker-data/tracker-db-interface-sqlite.c
index 074bf40f1..3dbfcc233 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -131,7 +131,8 @@ struct TrackerDBStatement {
        GInitiallyUnowned parent_instance;
        TrackerDBInterface *db_interface;
        sqlite3_stmt *stmt;
-       gboolean stmt_is_used;
+       guint stmt_is_used : 1;
+       guint stmt_is_owned : 1;
        TrackerDBStatement *next;
        TrackerDBStatement *prev;
 };
@@ -2572,9 +2573,9 @@ tracker_db_interface_lru_lookup (TrackerDBInterface          *db_interface,
 
        /* a) Cached */
 
-       if (stmt && stmt->stmt_is_used) {
+       if (stmt && stmt->stmt_is_owned) {
                /* c) Forced non-cached
-                * prepared statement is still in use, create new uncached one
+                * prepared statement is owned somewhere else, create new uncached one
                 */
                stmt = NULL;
                /* Make sure to set cache_type here, to avoid replacing
@@ -2741,6 +2742,7 @@ tracker_db_interface_create_statement (TrackerDBInterface           *db_interfac
                                                 stmt);
        }
 
+       stmt->stmt_is_owned = TRUE;
        g_free (full_query);
 
        tracker_db_interface_unlock (db_interface);
@@ -2929,6 +2931,7 @@ static TrackerDBStatement *
 tracker_db_statement_sqlite_grab (TrackerDBStatement *stmt)
 {
        g_assert (!stmt->stmt_is_used);
+       g_assert (stmt->stmt_is_owned);
        stmt->stmt_is_used = TRUE;
        g_object_ref (stmt->db_interface);
        return g_object_ref (stmt);
@@ -2939,8 +2942,9 @@ tracker_db_statement_sqlite_release (TrackerDBStatement *stmt)
 {
        TrackerDBInterface *iface = stmt->db_interface;
 
-       g_assert (stmt->stmt_is_used);
+       g_assert (stmt->stmt_is_owned);
        stmt->stmt_is_used = FALSE;
+       stmt->stmt_is_owned = FALSE;
        tracker_db_statement_sqlite_reset (stmt);
        g_object_unref (stmt);
        g_object_unref (iface);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]