Я тестирую Sqlite C API для многопроцессорного параллелизма и сталкиваюсь с ошибкой, которую не понимаю.
Тест прост: 1 база данных, 1 таблица из 1000 строк с 2 колонны. Столбец 1 - это UUID, а столбец 2 - это состояние, установленное на 0. Я запускаю 2 рабочих, которые одновременно выбирают 2 UUID в статусе 0 и обновляют их до 1, пока не останется ни одного UUID для обновления.
Здесь код в основном l oop рабочего:
std::vector<std::string> uuids;
res = sqlite3_exec(database,
"BEGIN IMMEDIATE TRANSACTION;", nullptr, nullptr, nullptr);
if (res != SQLITE_OK)
{
Log("Worker: Failed to begin transaction, wait for other worker to finish");
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}
Log("Worker: Begin Transaction");
// SELECT UUIDS
std::string selectString = "SELECT " + m_uuidStr + " FROM " + m_tableStr + " WHERE " + m_statusStr + "=" + std::to_string(0) + " LIMIT " + std::to_string(2);
// Log("Worker: SelectString = " + selectString);
auto selectStatement = selectString.c_str();
res = sqlite3_exec(database,
selectStatement,
fill_uuids,
&uuids, nullptr);
if (res != SQLITE_OK)
{
Log("Worker: Failed to select uuids");
return 3;
}
if (uuids.empty())
{
sqlite3_exec(database, "ROLLBACK;", nullptr, nullptr, nullptr);
Log("Worker: nothing more to update");
break;
}
// UPDATE UUIDS
std::stringstream ss;
ss << '\"' << uuids[0] << '\"';
for (int i = 1; i < uuids.size(); ++i)
ss << ", \"" << uuids[i] << '\"';
Log("Worker: UUIDs selected = " + ss.str());
std::string updateString = "UPDATE " + m_tableStr
+ " SET " + m_statusStr + "=" + std::to_string(1)
+ " WHERE (" + m_uuidStr + " in (" + ss.str() + ")) AND (" + m_statusStr + "=" + std::to_string(0) + ");";
auto updateStatement = updateString.c_str();
// BIG CRASH HERE WITH IMMEDIATE TRANSACTION ///
res = sqlite3_exec(database,
updateStatement,
nullptr, nullptr, nullptr);
if (res != SQLITE_OK)
{
Log("Worker: Failed to update uuids, err = " + std::string(err));
return 4;
}
// COMMIT CHANGES
res = sqlite3_exec(database,
"COMMIT;", nullptr, nullptr, nullptr);
if (res != SQLITE_OK)
{
Log("Worker: Failed to commit, err = " + std::string(err));
return 5;
}
Log("Worker: Transaction ended");
При использовании немедленных транзакций один из рабочих аварийно завершает работу с отрицательным кодом ошибки (-1073741819, но я сомневаюсь, что это помогает) при выполнении ОБНОВЛЕНИЯ заявление. При использовании эксклюзивных транзакций у меня нет cra sh. Версия с немедленными транзакциями работает с уникальным работником. База данных открыта с использованием флагов SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX
, Sqlite скомпилирован с опцией SQLITE_THREADSAFE=1
.
Нет других процессов, обращающихся к базе данных, пока рабочие работают. В этом отношении я не понимаю, почему немедленные транзакции вызывают cra sh, а исключительные транзакции - нет, так как поведение должно быть схожим (поскольку ни один поток / процесс не создает оператор чтения во время рабочего выполнения).
Я очень плохо знаком с Sqlite, так что, возможно, в моем коде лежит очевидная ошибка. Любая помощь приветствуется.