[tracker/checkpoint: 9/17] libtracker-data: Implement backup/restore with disabled journal



commit 19e19151a4f53c84ecc817478e8c2ffa0bdec615
Author: Philip Van Hoof <philip codeminded be>
Date:   Thu Jun 23 17:56:41 2011 +0200

    libtracker-data: Implement backup/restore with disabled journal

 src/libtracker-data/Makefile.am           |    2 +
 src/libtracker-data/tracker-data-backup.c |   75 +++++++-
 src/libtracker-data/tracker-db-backup.c   |  313 +++++++++++++++++++++++++++++
 src/libtracker-data/tracker-db-backup.h   |   53 +++++
 4 files changed, 436 insertions(+), 7 deletions(-)
---
diff --git a/src/libtracker-data/Makefile.am b/src/libtracker-data/Makefile.am
index cf7ba92..08b648b 100644
--- a/src/libtracker-data/Makefile.am
+++ b/src/libtracker-data/Makefile.am
@@ -39,6 +39,7 @@ libtracker_data_la_SOURCES =                           \
 	tracker-db-interface-sqlite.c                  \
 	tracker-db-manager.c                           \
 	tracker-db-journal.c                           \
+	tracker-db-backup.c                            \
 	tracker-namespace.c                            \
 	tracker-ontology.c                             \
 	tracker-ontologies.c                           \
@@ -71,6 +72,7 @@ noinst_HEADERS =                                       \
 	tracker-db-interface-sqlite.h                  \
 	tracker-db-manager.h                           \
 	tracker-db-journal.h                           \
+	tracker-db-backup.h                            \
 	tracker-namespace.h                            \
 	tracker-ontology.h                             \
 	tracker-ontologies.h                           \
diff --git a/src/libtracker-data/tracker-data-backup.c b/src/libtracker-data/tracker-data-backup.c
index e7f6503..9f38bd9 100644
--- a/src/libtracker-data/tracker-data-backup.c
+++ b/src/libtracker-data/tracker-data-backup.c
@@ -31,6 +31,7 @@
 #include "tracker-data-manager.h"
 #include "tracker-db-manager.h"
 #include "tracker-db-journal.h"
+#include "tracker-db-backup.h"
 
 typedef struct {
 	GFile *destination, *journal;
@@ -40,6 +41,8 @@ typedef struct {
 	GError *error;
 } BackupSaveInfo;
 
+#ifndef DISABLE_JOURNAL
+
 typedef struct {
 	GPid pid;
 	guint stdout_watch_id;
@@ -51,11 +54,7 @@ typedef struct {
 	GString *lines;
 } ProcessContext;
 
-GQuark
-tracker_data_backup_error_quark (void)
-{
-	return g_quark_from_static_string (TRACKER_DATA_BACKUP_ERROR_DOMAIN);
-}
+#endif /* DISABLE_JOURNAL */
 
 static void
 free_backup_save_info (BackupSaveInfo *info)
@@ -77,6 +76,15 @@ free_backup_save_info (BackupSaveInfo *info)
 	g_free (info);
 }
 
+
+GQuark
+tracker_data_backup_error_quark (void)
+{
+	return g_quark_from_static_string (TRACKER_DATA_BACKUP_ERROR_DOMAIN);
+}
+
+#ifndef DISABLE_JOURNAL
+
 static void
 on_journal_copied (BackupSaveInfo *info, GError *error)
 {
@@ -209,6 +217,25 @@ process_context_child_watch_cb (GPid     pid,
 
 	process_context_destroy (context, error);
 }
+#endif /* DISABLE_JOURNAL */
+
+
+
+#ifdef DISABLE_JOURNAL
+static void
+on_backup_finished (GError *error,
+                    gpointer user_data)
+{
+	BackupSaveInfo *info = user_data;
+
+	if (info->callback) {
+		info->callback (error, info->user_data);
+	}
+
+	free_backup_save_info (info);
+}
+
+#endif /* DISABLE_JOURNAL */
 
 /* delete all regular files from the directory */
 static void
@@ -385,6 +412,7 @@ tracker_data_backup_save (GFile *destination,
                           gpointer user_data,
                           GDestroyNotify destroy)
 {
+#ifndef DISABLE_JOURNAL
 	BackupSaveInfo *info;
 	ProcessContext *context;
 	gchar **argv;
@@ -480,6 +508,20 @@ tracker_data_backup_save (GFile *destination,
 	         pid, argv[0], argv[1], argv[2]);
 
 	g_strfreev (argv);
+#else
+	BackupSaveInfo *info;
+
+	info = g_new0 (BackupSaveInfo, 1);
+	info->destination = g_object_ref (destination);
+	info->callback = callback;
+	info->user_data = user_data;
+	info->destroy = destroy;
+
+	tracker_db_backup_save (destination,
+	                        on_backup_finished, 
+	                        info,
+	                        NULL);
+#endif /* DISABLE_JOURNAL */
 }
 
 void
@@ -493,19 +535,26 @@ tracker_data_backup_restore (GFile                *journal,
 	GError *internal_error = NULL;
 
 	info = g_new0 (BackupSaveInfo, 1);
+#ifndef DISABLE_JOURNAL
 	info->destination = g_file_new_for_path (tracker_db_journal_get_filename ());
+#else
+	info->destination = g_file_new_for_path (tracker_db_manager_get_file (TRACKER_DB_METADATA));
+#endif /* DISABLE_JOURNAL */
+
 	info->journal = g_object_ref (journal);
 
 	if (g_file_query_exists (info->journal, NULL)) {
 		TrackerDBManagerFlags flags;
+		guint select_cache_size, update_cache_size;
 		gboolean is_first;
+#ifndef DISABLE_JOURNAL
+		GError *n_error = NULL;
 		GFile *parent = g_file_get_parent (info->destination);
 		gchar *tmp_stdout = NULL;
 		gchar *tmp_stderr = NULL;
 		gchar **argv;
 		gint exit_status;
-		guint select_cache_size, update_cache_size;
-		GError *n_error = NULL;
+#endif /* DISABLE_JOURNAL */
 
 		flags = tracker_db_manager_get_flags (&select_cache_size, &update_cache_size);
 
@@ -513,6 +562,7 @@ tracker_data_backup_restore (GFile                *journal,
 
 		move_to_temp ();
 
+#ifndef DISABLE_JOURNAL
 		argv = g_new0 (char*, 6);
 
 		argv[0] = g_strdup ("tar");
@@ -549,8 +599,16 @@ tracker_data_backup_restore (GFile                *journal,
 		g_free (tmp_stderr);
 		g_free (tmp_stdout);
 		g_strfreev (argv);
+#else
+		g_file_copy (info->journal, info->destination,
+		             G_FILE_COPY_OVERWRITE, 
+		             NULL, NULL, NULL,
+		             &info->error);
+#endif /* DISABLE_JOURNAL */
 
 		tracker_db_manager_init_locations ();
+
+#ifndef DISABLE_JOURNAL
 		tracker_db_journal_init (NULL, FALSE, &n_error);
 
 		if (n_error) {
@@ -563,6 +621,7 @@ tracker_data_backup_restore (GFile                *journal,
 			}
 			n_error = NULL;
 		}
+#endif /* DISABLE_JOURNAL */
 
 		if (info->error) {
 			restore_from_temp ();
@@ -570,6 +629,7 @@ tracker_data_backup_restore (GFile                *journal,
 			remove_temp ();
 		}
 
+#ifndef DISABLE_JOURNAL
 		tracker_db_journal_shutdown (&n_error);
 
 		if (n_error) {
@@ -577,6 +637,7 @@ tracker_data_backup_restore (GFile                *journal,
 			           n_error->message ? n_error->message : "No error given");
 			g_error_free (n_error);
 		}
+#endif /* DISABLE_JOURNAL */
 
 		tracker_data_manager_init (flags, test_schemas, &is_first, TRUE,
 		                           select_cache_size, update_cache_size,
diff --git a/src/libtracker-data/tracker-db-backup.c b/src/libtracker-data/tracker-db-backup.c
new file mode 100644
index 0000000..212f313
--- /dev/null
+++ b/src/libtracker-data/tracker-db-backup.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2009, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <sqlite3.h>
+
+#include <libtracker-data/tracker-ontology.h>
+#include <libtracker-data/tracker-db-manager.h>
+#include <libtracker-data/tracker-db-interface-sqlite.h>
+
+#if HAVE_TRACKER_FTS
+#include <libtracker-fts/tracker-fts.h>
+#endif /* HAVE_TRACKER_FTS */
+
+#include "tracker-db-backup.h"
+
+#define TRACKER_DB_BACKUP_META_FILENAME_T	"meta-backup.db.tmp"
+
+typedef struct {
+	TrackerDBBackupFinished callback;
+	GDestroyNotify destroy;
+	gpointer user_data;
+	GError *error;
+	sqlite3_stmt *stmt;
+	sqlite3 *db, *backup_temp;
+	sqlite3_backup *backup_db;
+	gchar *backup_fname;
+	int result;
+	GFile *destination, *temp;
+} BackupInfo;
+
+GQuark
+tracker_db_backup_error_quark (void)
+{
+	return g_quark_from_static_string ("tracker-db-backup-error-quark");
+}
+
+static gboolean
+perform_callback (gpointer user_data)
+{
+	BackupInfo *info = user_data;
+
+	if (info->callback) {
+		info->callback (info->error, info->user_data);
+	}
+
+	return FALSE;
+}
+
+static void
+backup_info_free (gpointer user_data)
+{
+	BackupInfo *info = user_data;
+
+	if (info->destination) {
+		g_object_unref (info->destination);
+	}
+
+	if (info->temp) {
+		g_object_unref (info->temp);
+	}
+
+	if (info->destroy) {
+		info->destroy (info->user_data);
+	}
+
+	g_clear_error (&info->error);
+
+	if (info->stmt) {
+		sqlite3_finalize (info->stmt);
+	}
+
+	if (info->backup_db) {
+		sqlite3_backup_finish (info->backup_db);
+		info->backup_db = NULL;
+	}
+
+	if (info->backup_temp) {
+		sqlite3_close (info->backup_temp);
+	}
+
+	if (info->db) {
+		sqlite3_close (info->db);
+	}
+
+	if (info->backup_fname) {
+		g_free (info->backup_fname);
+	}
+
+	g_free (info);
+}
+
+
+static gboolean
+backup_file_step (gpointer user_data)
+{
+	BackupInfo *info = user_data;
+	guint cnt = 0;
+	gboolean cont = TRUE;
+
+	while (cont && info->result == SQLITE_OK) {
+
+		info->result = sqlite3_backup_step (info->backup_db, 5);
+
+		switch (info->result) {
+			case SQLITE_OK:
+			break;
+
+			case SQLITE_ERROR:
+			default:
+			cont = FALSE;
+			break;
+		}
+
+		if (cnt > 100) {
+			break;
+		}
+
+		cnt++;
+	}
+
+	return cont;
+}
+
+static void
+on_backup_temp_finished (gpointer user_data)
+{
+	BackupInfo *info = user_data;
+
+	if (info->backup_db) {
+		sqlite3_backup_finish (info->backup_db);
+		info->backup_db = NULL;
+	}
+
+	if (info->db) {
+		sqlite3_close (info->db);
+		info->db = NULL;
+	}
+
+
+	if (!info->error && info->result != SQLITE_DONE) {
+		g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, 
+		             TRACKER_DB_BACKUP_ERROR_UNKNOWN,
+		             "%s", sqlite3_errmsg (info->backup_temp));
+	}
+
+	if (!info->error) {
+		g_file_move (info->temp, info->destination,
+		             G_FILE_COPY_OVERWRITE,
+		             NULL, NULL, NULL,
+		             &info->error);
+	}
+
+	perform_callback (info);
+
+	backup_info_free (info);
+
+	return;
+}
+
+void
+tracker_db_backup_save (GFile                   *destination,
+                        TrackerDBBackupFinished  callback,
+                        gpointer                 user_data,
+                        GDestroyNotify           destroy)
+{
+	const gchar *db_file = tracker_db_manager_get_file (TRACKER_DB_METADATA);
+	BackupInfo *info = g_new0 (BackupInfo, 1);
+	GFile *parent;
+
+	info->callback = callback;
+	info->user_data = user_data;
+	info->destroy = destroy;
+
+	parent = g_file_get_parent (destination);
+	info->temp = g_file_get_child (parent, TRACKER_DB_BACKUP_META_FILENAME_T);
+	info->destination = g_object_ref (destination);
+	info->backup_fname = g_file_get_path (info->temp);
+	g_object_unref (parent);
+
+	if (sqlite3_open_v2 (db_file, &info->db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
+		g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
+		             "Could not open sqlite3 database:'%s'", db_file);
+
+		g_idle_add_full (G_PRIORITY_DEFAULT, perform_callback, info, 
+		                 backup_info_free);
+
+		return;
+	}
+
+	if (sqlite3_open (info->backup_fname, &info->backup_temp) != SQLITE_OK) {
+		g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
+		             "Could not open sqlite3 database:'%s'", info->backup_fname);
+
+		g_idle_add_full (G_PRIORITY_DEFAULT, perform_callback, info, 
+		                 backup_info_free);
+
+		return;
+	}
+
+	info->backup_db = sqlite3_backup_init (info->backup_temp, "main", 
+	                                       info->db, "main");
+
+	if (!info->backup_db) {
+		g_set_error (&info->error, TRACKER_DB_BACKUP_ERROR, TRACKER_DB_BACKUP_ERROR_UNKNOWN,
+		             "Unknown error creating backup db: '%s'", info->backup_fname);
+
+		g_idle_add_full (G_PRIORITY_DEFAULT, perform_callback, info, 
+		                 backup_info_free);
+
+		return;
+	}
+
+	g_idle_add_full (G_PRIORITY_DEFAULT, backup_file_step, info, 
+	                 on_backup_temp_finished);
+}
+
+#if HAVE_TRACKER_FTS
+
+void
+tracker_db_backup_sync_fts (void)
+{
+	TrackerProperty   **properties, **property;
+	TrackerDBInterface *iface;
+	TrackerDBStatement *stmt;
+	TrackerDBCursor    *cursor;
+	TrackerClass       *prop_class;
+	gchar              *query;
+
+	iface = tracker_db_manager_get_db_interface ();
+
+	query = tracker_fts_get_drop_fts_table_query ();
+	tracker_db_interface_execute_query (iface, NULL, "%s", query);
+	g_free (query);
+
+	query = tracker_fts_get_create_fts_table_query ();
+	tracker_db_interface_execute_query (iface, NULL, "%s", query);
+	g_free (query);
+
+	properties = tracker_ontology_get_properties ();
+	for (property = properties; *property; property++) {
+		if (tracker_property_get_data_type (*property) == TRACKER_PROPERTY_TYPE_STRING &&
+		    tracker_property_get_fulltext_indexed (*property)) {
+
+			prop_class  = tracker_property_get_domain (*property);
+
+			if (tracker_property_get_multiple_values (*property)) {
+				query = g_strdup_printf ("SELECT ID, \"%s\" FROM \"%s_%s\"", 
+				                         tracker_property_get_name (*property), 
+				                         tracker_class_get_name (prop_class),
+				                         tracker_property_get_name (*property));
+			} else {
+				query = g_strdup_printf ("SELECT ID, \"%s\" FROM \"%s\" WHERE \"%s\" IS NOT NULL", 
+				                         tracker_property_get_name (*property), 
+				                         tracker_class_get_name (prop_class),
+				                         tracker_property_get_name (*property));
+			}
+
+			stmt = tracker_db_interface_create_statement (iface, "%s", query);
+			cursor = tracker_db_statement_start_cursor (stmt, NULL);
+			g_object_unref (stmt);
+
+			if (cursor) {
+				while (tracker_db_cursor_iter_next (cursor)) {
+					guint32 id;
+					const gchar *text;
+
+					id = tracker_db_cursor_get_int (cursor, 0);
+					text = tracker_db_cursor_get_string (cursor, 1);
+
+					// TODO we need to retrieve all existing (FTS indexed) property values for
+					// this resource to properly support incremental FTS updates
+					// (like calling deleteTerms and then calling insertTerms)
+
+					tracker_fts_update_init (id);
+					tracker_fts_update_text (id, 0,  text);
+				}
+
+				g_object_unref (cursor);
+			}
+
+			g_free (query);
+		}
+	}
+	g_free (properties);
+
+	tracker_fts_update_commit ();
+}
+
+#endif /* HAVE_TRACKER_FTS */
diff --git a/src/libtracker-data/tracker-db-backup.h b/src/libtracker-data/tracker-db-backup.h
new file mode 100644
index 0000000..b5c3572
--- /dev/null
+++ b/src/libtracker-data/tracker-db-backup.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2009, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKER_DB_BACKUP_H__
+#define __TRACKER_DB_BACKUP_H__
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#define TRACKER_DB_BACKUP_META_FILENAME		"meta-backup.db"
+
+G_BEGIN_DECLS
+
+#define TRACKER_DB_BACKUP_ERROR	    (tracker_db_backup_error_quark ())
+
+typedef enum {
+	TRACKER_DB_BACKUP_ERROR_UNKNOWN,
+} TrackerDBBackupError;
+
+typedef void (*TrackerDBBackupFinished)   (GError *error, gpointer user_data);
+
+GQuark    tracker_db_backup_error_quark (void);
+
+void      tracker_db_backup_save        (GFile                   *destination,
+                                         TrackerDBBackupFinished  callback,
+                                         gpointer                 user_data,
+                                         GDestroyNotify           destroy);
+
+#if HAVE_TRACKER_FTS
+void      tracker_db_backup_sync_fts    (void);
+#endif
+
+G_END_DECLS
+
+#endif /* __TRACKER_DB_BACKUP_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]