mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-08 10:31:50 -05:00
sqlite: guard against dangling to-be-reverted db transactions
If the handler that initiated the database transaction is destroyed, the ongoing transaction cannot be left dangling when the db txn fails to abort. It must be forcefully reversed; otherwise, any subsequent db handler executing a write operation will dump the dangling, to-be-reverted transaction data to disk. This not only breaks the database isolation property but also results in the improper storage of incomplete information on disk, impacting the wallet consistency.
This commit is contained in:
parent
472d2ca981
commit
fc0e747192
1 changed files with 18 additions and 1 deletions
|
@ -405,12 +405,18 @@ SQLiteBatch::SQLiteBatch(SQLiteDatabase& database)
|
|||
|
||||
void SQLiteBatch::Close()
|
||||
{
|
||||
bool force_conn_refresh = false;
|
||||
|
||||
// If we began a transaction, and it wasn't committed, abort the transaction in progress
|
||||
if (m_database.HasActiveTxn()) {
|
||||
if (TxnAbort()) {
|
||||
LogPrintf("SQLiteBatch: Batch closed unexpectedly without the transaction being explicitly committed or aborted\n");
|
||||
} else {
|
||||
LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction\n");
|
||||
// If transaction cannot be aborted, it means there is a bug or there has been data corruption. Try to recover in this case
|
||||
// by closing and reopening the database. Closing the database should also ensure that any changes made since the transaction
|
||||
// was opened will be rolled back and future transactions can succeed without committing old data.
|
||||
force_conn_refresh = true;
|
||||
LogPrintf("SQLiteBatch: Batch closed and failed to abort transaction, resetting db connection..\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,6 +437,17 @@ void SQLiteBatch::Close()
|
|||
}
|
||||
*stmt_prepared = nullptr;
|
||||
}
|
||||
|
||||
if (force_conn_refresh) {
|
||||
m_database.Close();
|
||||
try {
|
||||
m_database.Open();
|
||||
} catch (const std::runtime_error&) {
|
||||
// If open fails, cleanup this object and rethrow the exception
|
||||
m_database.Close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SQLiteBatch::ReadKey(DataStream&& key, DataStream& value)
|
||||
|
|
Loading…
Add table
Reference in a new issue