#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 для подготовленного оператора.
В любом из сценариев один из потоков должен быть победителем в получении блокировки для этой таблицы.
Мой вопрос в том, как я могу найти, кто блокирует таблицу. Есть ли какой-либо способ получить эту информацию? почему это происходит при удалении, когда одновременное обновление и вставки выполняются должным образом?