1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-18 20:40:43 +01:00

Run a database backup on startup after the integrity check.

Update issue #2743
Database backup now run on startup, still needs a way to restore.
This commit is contained in:
John Maguire 2012-03-16 14:50:20 +01:00
parent 56b9546744
commit 9ed8ab63aa
2 changed files with 126 additions and 2 deletions

View File

@ -23,6 +23,8 @@
#include "core/logging.h"
#include "core/taskmanager.h"
#include <boost/scope_exit.hpp>
#include <QCoreApplication>
#include <QDir>
#include <QLibrary>
@ -95,6 +97,16 @@ const uchar* (*Database::_sqlite3_value_text) (sqlite3_value*) = NULL;
void (*Database::_sqlite3_result_int64) (sqlite3_context*, sqlite_int64) = NULL;
void* (*Database::_sqlite3_user_data) (sqlite3_context*) = NULL;
int (*Database::_sqlite3_open) (const char*, sqlite3**) = NULL;
const char* (*Database::_sqlite3_errmsg) (sqlite3*) = NULL;
int (*Database::_sqlite3_close) (sqlite3*) = NULL;
sqlite3_backup* (*Database::_sqlite3_backup_init) (
sqlite3*, const char*, sqlite3*, const char*) = NULL;
int (*Database::_sqlite3_backup_step) (sqlite3_backup*, int) = NULL;
int (*Database::_sqlite3_backup_finish) (sqlite3_backup*) = NULL;
int (*Database::_sqlite3_backup_pagecount) (sqlite3_backup*) = NULL;
int (*Database::_sqlite3_backup_remaining) (sqlite3_backup*) = NULL;
bool Database::sStaticInitDone = false;
bool Database::sLoadedSqliteSymbols = false;
@ -233,6 +245,16 @@ void Database::StaticInit() {
_sqlite3_value_text = sqlite3_value_text;
_sqlite3_result_int64 = sqlite3_result_int64;
_sqlite3_user_data = sqlite3_user_data;
_sqlite3_open = sqlite3_open;
_sqlite3_errmsg = sqlite3_errmsg;
_sqlite3_close = sqlite3_close;
_sqlite3_backup_init = sqlite3_backup_init;
_sqlite3_backup_step = sqlite3_backup_step;
_sqlite3_backup_finish = sqlite3_backup_finish;
_sqlite3_backup_pagecount = sqlite3_backup_pagecount;
_sqlite3_backup_remaining = sqlite3_backup_remaining;
sLoadedSqliteSymbols = true;
return;
#else // HAVE_STATIC_SQLITE
@ -258,12 +280,38 @@ void Database::StaticInit() {
_sqlite3_user_data = reinterpret_cast<void* (*) (sqlite3_context*)>(
library.resolve("sqlite3_user_data"));
_sqlite3_open = reinterpret_cast<int (*) (const char*, sqlite3*)>(
library.resolve("sqlite3_open"));
_sqlite3_errmsg = reinterpret_cast<const char* (*) (sqlite3*)>(
library.resolve("sqlite3_errmsg"));
_sqlite3_close = reinterpret_cast<int (*) (sqlite3*)>(
library.resolve("sqlite3_close"));
_sqlite3_backup_init = reinterpret_cast<
sqlite3_backup* (*) (sqlite3*, const char*, sqlite3*, const char*)>(
library.resolve("sqlite3_backup_init"));
_sqlite3_backup_step = reinterpret_cast<int (*) (sqlite3_backup*, int)>(
library.resolve("sqlite3_backup_step"));
_sqlite3_backup_finish = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_finish"));
_sqlite3_backup_pagecount = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_pagecount"));
_sqlite3_backup_remaining = reinterpret_cast<int (*) (sqlite3_backup*)>(
library.resolve("sqlite3_backup_remaining"));
if (!_sqlite3_create_function ||
!_sqlite3_value_type ||
!_sqlite3_value_int64 ||
!_sqlite3_value_text ||
!_sqlite3_result_int64 ||
!_sqlite3_user_data) {
!_sqlite3_user_data ||
!_sqlite3_open ||
!_sqlite3_errmsg ||
!_sqlite3_close ||
!_sqlite3_backup_init ||
!_sqlite3_backup_step ||
!_sqlite3_backup_finish ||
!_sqlite3_backup_pagecount ||
!_sqlite3_backup_remaining) {
qLog(Error) << "Couldn't resolve sqlite symbols";
sLoadedSqliteSymbols = false;
} else {
@ -673,6 +721,69 @@ void Database::DoBackup() {
const bool ok = IntegrityCheck(db);
if (ok) {
// TODO: Run database backup...
BackupFile(db.databaseName());
}
}
bool Database::OpenDatabase(const QString& filename, sqlite3** connection) const {
int ret = _sqlite3_open(filename.toUtf8(), connection);
if (ret != 0) {
if (*connection) {
const char* error_message = _sqlite3_errmsg(*connection);
qLog(Error) << "Failed to open source database for backup:"
<< error_message;
} else {
qLog(Error) << "Failed to open source database for backup";
}
return false;
}
return true;
}
void Database::BackupFile(const QString& filename) {
QString dest_filename = QString("%1.bak").arg(filename);
const int task_id = app_->task_manager()->StartTask(tr("Backing up database"));
sqlite3* source_connection = NULL;
sqlite3* dest_connection = NULL;
BOOST_SCOPE_EXIT((source_connection)(dest_connection)(task_id)(app_)) {
// Harmless to call sqlite3_close() with a NULL pointer.
_sqlite3_close(source_connection);
_sqlite3_close(dest_connection);
app_->task_manager()->SetTaskFinished(task_id);
} BOOST_SCOPE_EXIT_END
bool success = OpenDatabase(filename, &source_connection);
if (!success) {
return;
}
success = OpenDatabase(dest_filename, &dest_connection);
if (!success) {
return;
}
sqlite3_backup* backup = _sqlite3_backup_init(
dest_connection, "main",
source_connection, "main");
if (!backup) {
const char* error_message = _sqlite3_errmsg(dest_connection);
qLog(Error) << "Failed to start database backup:" << error_message;
return;
}
int ret = SQLITE_OK;
do {
ret = _sqlite3_backup_step(backup, 16);
const int page_count = _sqlite3_backup_pagecount(backup);
app_->task_manager()->SetTaskProgress(
task_id, page_count - _sqlite3_backup_remaining(backup), page_count);
} while (ret == SQLITE_OK);
if (ret != SQLITE_DONE) {
qLog(Error) << "Database backup failed";
}
_sqlite3_backup_finish(backup);
}

View File

@ -74,6 +74,8 @@ class Database : public QObject {
void UrlEncodeFilenameColumn(const QString& table, QSqlDatabase& db);
QStringList SongsTables(QSqlDatabase& db, int schema_version) const;
bool IntegrityCheck(QSqlDatabase db);
void BackupFile(const QString& filename);
bool OpenDatabase(const QString& filename, sqlite3** connection) const;
struct AttachedDatabase {
AttachedDatabase() {}
@ -143,6 +145,17 @@ class Database : public QObject {
static void (*_sqlite3_result_int64) (sqlite3_context*, sqlite_int64);
static void* (*_sqlite3_user_data) (sqlite3_context*);
// These are necessary for SQLite backups.
static int (*_sqlite3_open) (const char*, sqlite3**);
static const char* (*_sqlite3_errmsg) (sqlite3*);
static int (*_sqlite3_close) (sqlite3*);
static sqlite3_backup* (*_sqlite3_backup_init) (
sqlite3*, const char*, sqlite3*, const char*);
static int (*_sqlite3_backup_step) (sqlite3_backup*, int);
static int (*_sqlite3_backup_finish) (sqlite3_backup*);
static int (*_sqlite3_backup_pagecount) (sqlite3_backup*);
static int (*_sqlite3_backup_remaining) (sqlite3_backup*);
static bool sStaticInitDone;
static bool sLoadedSqliteSymbols;