1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-11-23 17:30:17 +01:00

A bit more checkpoint thread cleanup

Just some additional error checking and moves the close of the db
to the main thread where it was opened.  Not required, but...
This commit is contained in:
Leland Lucius
2021-04-08 15:18:32 -05:00
parent 40d3a36296
commit b67c71688b
2 changed files with 159 additions and 145 deletions

View File

@@ -47,6 +47,7 @@ DBConnection::DBConnection(
, mCallback{ std::move(callback) }
{
mDB = nullptr;
mCheckpointDB = nullptr;
mBypass = false;
}
@@ -133,46 +134,77 @@ int DBConnection::Open(const FilePath fileName)
wxASSERT(mDB == nullptr);
int rc;
rc = sqlite3_open(fileName.ToUTF8(), &mDB);
if (rc != SQLITE_OK)
{
wxLogMessage("Failed to open %s: %d, %s\n",
fileName,
rc,
sqlite3_errstr(rc));
sqlite3_close(mDB);
mDB = nullptr;
return rc;
}
// Set default mode
// (See comments in ProjectFileIO::SaveProject() about threading
SafeMode();
// Kick off the checkpoint thread
// Initalize checkpoint controls
mCheckpointStop = false;
mCheckpointPending = false;
mCheckpointActive = false;
// Open another connection to the DB to prevent blocking the main thread.
//
// If it fails, then we won't checkpoint until the main thread closes
// the associated DB.
sqlite3 *db = nullptr;
const auto name = sqlite3_db_filename(mDB, nullptr);
if (sqlite3_open(name, &db) == SQLITE_OK &&
// Configure it to be safe
ModeConfig(db, "main", SafeConfig) ) {
mCheckpointThread = std::thread([this, db]{ CheckpointThread(db); });
}
else
sqlite3_close(db);
const char *name = fileName.ToUTF8();
bool success = false;
rc = sqlite3_open(name, &mDB);
if (rc == SQLITE_OK)
{
// Set default mode
// (See comments in ProjectFileIO::SaveProject() about threading
if (SafeMode())
{
rc = sqlite3_open(name, &mCheckpointDB);
if (rc == SQLITE_OK)
{
// Set default mode
// (See comments in ProjectFileIO::SaveProject() about threading
if (SafeMode())
{
auto db = mCheckpointDB;
mCheckpointThread = std::thread([this, db, name]{ CheckpointThread(db, name); });
// Install our checkpoint hook
sqlite3_wal_hook(mDB, CheckpointHook, this);
success = true;
}
else
{
SetDBError(XO("Failed to set safe mode on checkpoint connection to %s").Format(fileName));
}
}
else
{
wxLogMessage("Failed to open checkpoint connection to %s: %d, %s\n",
fileName,
rc,
sqlite3_errstr(rc));
}
}
else
{
SetDBError(XO("Failed to set safe mode on primary connection to %s").Format(fileName));
}
}
else
{
wxLogMessage("Failed to open primary connection to %s: %d, %s\n",
fileName,
rc,
sqlite3_errstr(rc));
}
if (!success)
{
if (mCheckpointDB)
{
sqlite3_close(mCheckpointDB);
mCheckpointDB = nullptr;
}
if (mDB)
{
sqlite3_close(mDB);
mDB = nullptr;
}
}
return rc;
}
@@ -227,7 +259,9 @@ bool DBConnection::Close()
// And wait for it to do so
if (mCheckpointThread.joinable())
{
mCheckpointThread.join();
}
// We're done with the prepared statements
{
@@ -249,23 +283,28 @@ bool DBConnection::Close()
mStatements.clear();
}
// Close the DB
// Not much we can do if the closes fail, so just report the error
// Close the checkpoint connection
rc = sqlite3_close(mCheckpointDB);
if (rc != SQLITE_OK)
{
wxLogMessage("Failed to close checkpoint connection for %s\n"
"\tError: %s\n",
sqlite3_db_filename(mCheckpointDB, nullptr),
sqlite3_errmsg(mCheckpointDB));
}
mCheckpointDB = nullptr;
// Close the primary connection
rc = sqlite3_close(mDB);
if (rc != SQLITE_OK)
{
// I guess we could try to recover by repreparing statements and reinstalling
// the hook, but who knows if that would work either.
//
// Should we throw an error???
//
// LLL: Probably not worthwhile since the DB will just be recovered when
// next opened, but log it for diagnosis.
wxLogMessage("Failed to close %s\n"
"\tError: %s\n",
sqlite3_db_filename(mDB, nullptr),
sqlite3_errmsg(mDB));
}
mDB = nullptr;
return true;
@@ -387,14 +426,11 @@ sqlite3_stmt *DBConnection::Prepare(enum StatementID id, const char *sql)
return stmt;
}
void DBConnection::CheckpointThread(sqlite3 *db)
void DBConnection::CheckpointThread(sqlite3 *db, const char *name)
{
int rc = SQLITE_OK;
bool giveUp = false;
const char *name = nullptr;
if (db)
{
name = sqlite3_db_filename(db, nullptr);
while (true)
{
{
@@ -478,29 +514,6 @@ void DBConnection::CheckpointThread(sqlite3 *db)
);
}
}
}
else
{
wxLogMessage("Checkpoint thread failed to open %s\n"
"\tErrCode: %d\n"
"\tErrMsg: %s",
name,
rc,
sqlite3_errstr(rc));
}
// All done (always close)
if (db)
rc = sqlite3_close(db);
if (rc != SQLITE_OK && name)
{
wxLogMessage("Checkpoint thread failed to close %s\n"
"\tErrCode: %d\n"
"\tErrMsg: %s",
name,
rc,
sqlite3_errstr(rc));
}
return;
}

View File

@@ -98,12 +98,13 @@ public:
private:
bool ModeConfig(sqlite3 *db, const char *schema, const char *config);
void CheckpointThread(sqlite3 *db);
void CheckpointThread(sqlite3 *db, const char *name);
static int CheckpointHook(void *data, sqlite3 *db, const char *schema, int pages);
private:
std::weak_ptr<AudacityProject> mpProject;
sqlite3 *mDB;
sqlite3 *mCheckpointDB;
std::thread mCheckpointThread;
std::condition_variable mCheckpointCondition;