Sqlite в состоянии мертвой блокировки при удалении записей из одной и той же таблицы из разных потоков

#c #database #multithreading #sqlite

#c #База данных #многопоточность #sqlite

Вопрос:

Мы используем код sqlite 3.7.14.1 в нашем приложении. В последнее время мы наблюдаем состояние мертвой блокировки при удалении записей из таблицы. Удаление выполняется из двух разных потоков и воздействует на одну и ту же таблицу.

Sqlite настроен в режиме WAL. Все потоки открывают свое собственное совместное подключение к базе данных. Приложение соответствует SQLITE_THREADSAFE=1 и SQLITE_ENABLE_MEMORY_MANAGEMENT.

 m_init = sqlite3_open_v2(
            m_dbfilename.toUtf8().data(),                                                                   /* Database filename (UTF-8) */
            amp;m_dbHandler,                                                                                   /* OUT: SQLite db handle */
            SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX | SQLITE_OPEN_SHAREDCACHE,    /* Flags */
            NULL                                                                                             /* Name of VFS module to use */
            );
  

Все обновления, вставки и удаления записей в нескольких потоках происходят в транзакциях. Оператор update / insert работает абсолютно нормально без какой-либо мертвой блокировки. Но когда два или более потоков пытаются удалить запись в одной и той же таблице, они переходят в состояние мертвой блокировки, в котором sqlite3_step продолжает возвращать SQLITE_LOCKED. Когда мы выполняли отладку кода

 10:00.234 Thread 1 BEGIN
10:00.235 Thread 1 select * from <table1>
10:00.234 Thread 1 select * from <table x>
10:00.456 Thread 1 delete from <table1>

10:00.456 Thread 2 BEGIN
10:00.456 Thread 2 select * from <table1>
10:00.906 Thread 2 select * from <table x>
10:01.156 Thread 2 delete from  <table1>

Thread 1 SQLITE_LOCKED(6) Error <Table1> is locked
Thread 2 SQLITE_LOCKED(6) Error database table is locked
  

Поток 1, который является первым, который вводит BEGIN и вносит изменения в таблицу, и он должен был получить блокировку записи в таблицу. Даже если мы считаем, что поток 2 выполнял выбор в одной и той же таблице в одно и то же время, то поток 2 должен был заблокировать таблицу в своем вызове удаления. В этом случае ни один из потоков не получает блокировку таблицы и ожидает вечно. В каждом потоке мы ожидаем случайного количества времени повторного выполнения (sqlite3_step) того же подготовленного оператора после вызова reset для подготовленного оператора.

В любом из сценариев один из потоков должен быть победителем в получении блокировки для этой таблицы.

Мой вопрос в том, как я могу найти, кто блокирует таблицу. Есть ли какой-либо способ получить эту информацию? почему это происходит при удалении, когда одновременное обновление и вставки выполняются должным образом?