#include <cstdarg>
#include <memory>
+
+namespace {
+const int MAX_RETRY = 10;
+}
+
namespace CKM {
namespace DB {
namespace // anonymous
// Notify all after potentially synchronized database connection access
ScopedNotifyAll notifyAll(connection->m_synchronizationObject.get());
- for (;;) {
+ for (int i = 0; i < MAX_RETRY; i++) {
int ret = sqlcipher3_prepare_v2(connection->m_connection,
buffer, strlen(buffer),
&m_stmt, NULL);
if (ret == SQLCIPHER_OK) {
- LogPedantic("Data command prepared successfuly");
- break;
+ LogPedantic("Prepared data command: " << buffer);
+
+ // Increment stored data command count
+ ++m_masterConnection->m_dataCommandsCount;
+ return;
} else if (ret == SQLCIPHER_BUSY) {
LogPedantic("Collision occurred while preparing SQL command");
ThrowMsg(Exception::SyntaxError, error);
}
- LogPedantic("Prepared data command: " << buffer);
-
- // Increment stored data command count
- ++m_masterConnection->m_dataCommandsCount;
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
SqlConnection::DataCommand::~DataCommand()
ScopedNotifyAll notifyAll(
m_masterConnection->m_synchronizationObject.get());
- for (;;) {
+ for (int i = 0; i < MAX_RETRY; i++) {
int ret = sqlcipher3_step(m_stmt);
if (ret == SQLCIPHER_ROW) {
continue;
}
-
// No synchronization object defined. Fail.
}
ThrowMsg(Exception::InternalError, error);
}
+
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
void SqlConnection::DataCommand::Reset()
// Notify all after potentially synchronized database connection access
ScopedNotifyAll notifyAll(m_synchronizationObject.get());
- for (;;) {
+ for (int i = 0; i < MAX_RETRY; i++) {
char *errorBuffer;
int ret = sqlcipher3_exec(m_connection,
LogError("Failed to execute SQL command. Error: " << errorMsg);
ThrowMsg(Exception::SyntaxError, errorMsg);
}
+
+ LogError("sqlite in the state of possible infinite loop");
+ ThrowMsg(Exception::InternalError, "sqlite permanently busy");
}
SqlConnection::DataCommandUniquePtr SqlConnection::PrepareDataCommand(
m_db->m_connection->ExecCommand("BEGIN EXCLUSIVE");
m_db->m_inUserTransaction = true;
m_inTransaction = true;
+ } Catch (DB::SqlConnection::Exception::InternalError) {
+ LogError("sqlite got into infinite busy state");
+ ReThrow(DBCrypto::Exception::TransactionError);
} Catch (DB::SqlConnection::Exception::Base) {
LogError("Couldn't begin transaction");
ReThrow(DBCrypto::Exception::TransactionError);
m_db->m_connection->CommitTransaction();
m_db->m_inUserTransaction = false;
m_inTransaction = false;
+ } Catch (DB::SqlConnection::Exception::InternalError) {
+ LogError("sqlite got into infinite busy state");
+ ReThrow(DBCrypto::Exception::TransactionError);
} Catch (DB::SqlConnection::Exception::Base) {
LogError("Couldn't commit transaction");
ReThrow(DBCrypto::Exception::TransactionError);
m_db->m_connection->RollbackTransaction();
m_db->m_inUserTransaction = false;
m_inTransaction = false;
+ } Catch (DB::SqlConnection::Exception::InternalError) {
+ LogError("sqlite got into infinite busy state");
+ ReThrow(DBCrypto::Exception::TransactionError);
} Catch (DB::SqlConnection::Exception::Base) {
LogError("Couldn't rollback transaction");
ReThrow(DBCrypto::Exception::TransactionError);
m_db->m_inUserTransaction = false;
m_db->m_connection->RollbackTransaction();
}
+ } Catch (DB::SqlConnection::Exception::InternalError) {
+ LogError("sqlite got into infinite busy state");
+ ReThrow(DBCrypto::Exception::TransactionError);
} Catch (DB::SqlConnection::Exception::Base) {
LogError("Transaction rollback failed!");
}