Sqlite C API в многопроцессорном режиме - PullRequest
0 голосов
/ 24 апреля 2020

Я тестирую 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, так что, возможно, в моем коде лежит очевидная ошибка. Любая помощь приветствуется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...