[tracker/gdbus-store: 7/8] tracker-store: Port to GDBus/Vala
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/gdbus-store: 7/8] tracker-store: Port to GDBus/Vala
- Date: Wed, 12 Jan 2011 12:01:58 +0000 (UTC)
commit 5333b0ffcced39f6a34dca3a4bcf337acc469091
Author: Jürg Billeter <j bitron ch>
Date: Wed Jan 12 11:48:35 2011 +0100
tracker-store: Port to GDBus/Vala
configure.ac | 2 -
src/tracker-store/.gitignore | 8 +
src/tracker-store/Makefile.am | 90 +--
src/tracker-store/tracker-backup.c | 215 -----
src/tracker-store/tracker-backup.h | 64 --
src/tracker-store/tracker-backup.vala | 110 +++
src/tracker-store/tracker-config.vapi | 27 +
src/tracker-store/tracker-dbus.c | 382 ---------
src/tracker-store/tracker-dbus.vala | 252 ++++++
src/tracker-store/tracker-events.vapi | 36 +
src/tracker-store/tracker-locale-change.c | 16 +-
src/tracker-store/tracker-locale-change.vapi | 25 +
src/tracker-store/tracker-main.c | 15 +-
src/tracker-store/tracker-marshal.list | 12 -
src/tracker-store/tracker-resources.c | 767 -----------------
src/tracker-store/tracker-resources.h | 95 ---
src/tracker-store/tracker-resources.vala | 337 ++++++++
src/tracker-store/tracker-statistics.c | 98 ---
src/tracker-store/tracker-statistics.h | 58 --
.../{tracker-dbus.h => tracker-statistics.vala} | 37 +-
src/tracker-store/tracker-status.c | 231 -----
src/tracker-store/tracker-status.h | 77 --
src/tracker-store/tracker-status.vala | 122 +++
src/tracker-store/tracker-steroids.c | 886 --------------------
src/tracker-store/tracker-steroids.h | 57 --
src/tracker-store/tracker-steroids.vala | 212 +++++
src/tracker-store/tracker-store.c | 685 ---------------
src/tracker-store/tracker-store.h | 92 --
src/tracker-store/tracker-store.vala | 431 ++++++++++
src/tracker-store/tracker-writeback.vapi | 34 +
30 files changed, 1668 insertions(+), 3805 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1ff2fb1..1abcfa4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -311,8 +311,6 @@ TRACKER_STORE_REQUIRED="glib-2.0 >= $GLIB_REQUIRED
gio-unix-2.0 >= $GLIB_REQUIRED
gthread-2.0 >= $GLIB_REQUIRED
gmodule-2.0 >= $GLIB_REQUIRED
- dbus-1 >= $DBUS_REQUIRED
- dbus-glib-1 >= $DBUS_GLIB_REQUIRED
sqlite3 >= $SQLITE_REQUIRED"
PKG_CHECK_MODULES(TRACKER_STORE, [$TRACKER_STORE_REQUIRED])
diff --git a/src/tracker-store/.gitignore b/src/tracker-store/.gitignore
index 5b17e28..b57c9e6 100644
--- a/src/tracker-store/.gitignore
+++ b/src/tracker-store/.gitignore
@@ -1 +1,9 @@
tracker-store
+tracker-backup.c
+tracker-dbus.c
+tracker-resources.c
+tracker-statistics.c
+tracker-status.c
+tracker-steroids.c
+tracker-store.c
+tracker-store.h
diff --git a/src/tracker-store/Makefile.am b/src/tracker-store/Makefile.am
index b113296..d7e2552 100644
--- a/src/tracker-store/Makefile.am
+++ b/src/tracker-store/Makefile.am
@@ -8,7 +8,9 @@ AM_CPPFLAGS = \
-DPUSH_MODULES_DIR=\""$(libdir)/tracker-$(TRACKER_API_VERSION)/push-modules/daemon"\" \
-I$(top_srcdir)/src \
-I$(top_builddir)/src \
- $(TRACKER_STORE_CFLAGS)
+ $(TRACKER_STORE_CFLAGS) \
+ -DNO_LIBDBUS
+ -DGETTEXT_PACKAGE=\"NULL\"
#
# Daemon sources
@@ -16,31 +18,39 @@ AM_CPPFLAGS = \
libexec_PROGRAMS = tracker-store
tracker_store_SOURCES = \
- $(marshal_sources) \
- $(dbus_sources) \
- tracker-backup.c \
- tracker-backup.h \
+ tracker-backup.vala \
tracker-config.c \
- tracker-config.h \
- tracker-dbus.c \
- tracker-dbus.h \
+ tracker-dbus.vala \
tracker-events.c \
- tracker-events.h \
- tracker-writeback.c \
- tracker-writeback.h \
+ tracker-locale-change.c \
tracker-main.c \
- tracker-resources.c \
- tracker-resources.h \
- tracker-statistics.c \
- tracker-statistics.h \
- tracker-store.c \
- tracker-store.h \
- tracker-status.c \
- tracker-status.h \
- tracker-steroids.c \
- tracker-steroids.h \
+ tracker-resources.vala \
+ tracker-statistics.vala \
+ tracker-status.vala \
+ tracker-steroids.vala \
+ tracker-store.vala \
+ tracker-writeback.c
+
+noinst_HEADERS = \
+ tracker-config.h \
+ tracker-events.h \
tracker-locale-change.h \
- tracker-locale-change.c
+ tracker-writeback.h
+
+tracker_store_VALAFLAGS = \
+ --pkg gio-2.0 \
+ --pkg gio-unix-2.0 \
+ --pkg posix \
+ $(BUILD_VALAFLAGS) \
+ $(top_srcdir)/src/libtracker-common/libtracker-common.vapi \
+ $(top_srcdir)/src/libtracker-sparql/tracker-sparql-$(TRACKER_API_VERSION).vapi \
+ $(top_srcdir)/src/libtracker-data/tracker-sparql-query.vapi \
+ $(top_srcdir)/src/libtracker-data/libtracker-data.vapi \
+ $(top_srcdir)/src/tracker-store/tracker-config.vapi \
+ $(top_srcdir)/src/tracker-store/tracker-events.vapi \
+ $(top_srcdir)/src/tracker-store/tracker-locale-change.vapi \
+ $(top_srcdir)/src/tracker-store/tracker-writeback.vapi \
+ -H tracker-store.h
tracker_store_LDADD = \
$(top_builddir)/src/libtracker-data/libtracker-data.la \
@@ -49,34 +59,8 @@ tracker_store_LDADD = \
$(BUILD_LIBS) \
$(TRACKER_STORE_LIBS)
-marshal_sources = \
- tracker-marshal.h \
- tracker-marshal.c
-
-dbus_sources = \
- tracker-backup-glue.h \
- tracker-resources-glue.h \
- tracker-statistics-glue.h \
- tracker-status-glue.h
-
-tracker-marshal.h: tracker-marshal.list
- $(AM_V_GEN)$(GLIB_GENMARSHAL) $< --prefix=tracker_marshal --header > $@
-
-tracker-marshal.c: tracker-marshal.list
- $(AM_V_GEN)echo "#include \"tracker-marshal.h\"" > $@ && \
- $(GLIB_GENMARSHAL) $< --prefix=tracker_marshal --body >> $@
-
-%-glue.h: $(top_srcdir)/data/dbus/%.xml
- $(AM_V_GEN)$(DBUSBINDINGTOOL) --mode=glib-server --output=$@ --prefix=$(subst -,_,$*) $^
-
-%-client.h: $(top_srcdir)/data/dbus/%.xml
- $(AM_V_GEN)$(DBUSBINDINGTOOL) --mode=glib-client --output=$@ --prefix=$(subst -,_,$*) $^
-
-BUILT_SOURCES = \
- $(marshal_sources) \
- $(dbus_sources)
-
-CLEANFILES = $(BUILT_SOURCES)
-
-EXTRA_DIST = tracker-marshal.list
-
+EXTRA_DIST = \
+ tracker-config.vapi \
+ tracker-events.vapi \
+ tracker-locale-change.vapi \
+ tracker-writeback.vapi
diff --git a/src/tracker-store/tracker-backup.vala b/src/tracker-store/tracker-backup.vala
new file mode 100644
index 0000000..a9a1bff
--- /dev/null
+++ b/src/tracker-store/tracker-backup.vala
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2006, Jamie McCracken <jamiemcc gnome org>
+ * Copyright (C) 2008, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+[DBus (name = "org.freedesktop.Tracker1.Backup")]
+class Tracker.Backup : Object {
+ public const string PATH = "/org/freedesktop/Tracker1/Backup";
+
+ public async void save (BusName sender, string destination_uri) throws Error {
+ var request = DBusRequest.begin (sender, "D-Bus request to save backup into '%s'", destination_uri);
+ try {
+ var destination = File.new_for_uri (destination_uri);
+
+ NotifyClassGetter getter = null;
+
+ var resources = (Resources) Tracker.DBus.get_object (typeof (Resources));
+ if (resources != null) {
+ resources.disable_signals ();
+ getter = Tracker.Events.get_class_getter ();
+ Tracker.Events.shutdown ();
+ }
+
+ yield Tracker.Store.pause ();
+
+ Error backup_error = null;
+ Data.backup_save (destination, error => {
+ backup_error = error;
+ save.callback ();
+ });
+ yield;
+
+ if (resources != null) {
+ Tracker.Events.init (getter);
+ resources.enable_signals ();
+ }
+
+ if (backup_error != null) {
+ throw backup_error;
+ }
+
+ Tracker.Store.resume ();
+
+ request.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ public async void restore (BusName sender, string journal_uri) throws Error {
+ var request = DBusRequest.begin (sender, "D-Bus request to restore backup from '%s'", journal_uri);
+ try {
+ NotifyClassGetter getter = null;
+
+ var resources = (Resources) Tracker.DBus.get_object (typeof (Resources));
+ if (resources != null) {
+ resources.disable_signals ();
+ getter = Tracker.Events.get_class_getter ();
+ Tracker.Events.shutdown ();
+ }
+
+ yield Tracker.Store.pause ();
+
+ var journal = File.new_for_uri (journal_uri);
+
+ var notifier = (Status) (Tracker.DBus.get_object (typeof (Status)));
+
+ var busy_callback = notifier.get_callback ();
+
+ Error restore_error = null;
+ Data.backup_restore (journal, error => {
+ restore_error = error;
+ restore.callback ();
+ }, null, busy_callback);
+ yield;
+
+ if (resources != null) {
+ Tracker.Events.init (getter);
+ resources.enable_signals ();
+ }
+
+ if (restore_error != null) {
+ throw restore_error;
+ }
+
+ Tracker.Store.resume ();
+
+ request.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+}
diff --git a/src/tracker-store/tracker-config.vapi b/src/tracker-store/tracker-config.vapi
new file mode 100644
index 0000000..72888da
--- /dev/null
+++ b/src/tracker-store/tracker-config.vapi
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+namespace Tracker {
+ [CCode (cheader_filename = "tracker-store/tracker-config.h")]
+ public class Config : ConfigFile {
+ public Config ();
+ public bool save ();
+ public int verbosity { get; set; }
+ }
+}
diff --git a/src/tracker-store/tracker-dbus.vala b/src/tracker-store/tracker-dbus.vala
new file mode 100644
index 0000000..75b54a0
--- /dev/null
+++ b/src/tracker-store/tracker-dbus.vala
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2006, Jamie McCracken <jamiemcc gnome org>
+ * Copyright (C) 2008, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+public class Tracker.DBus {
+ static DBusConnection connection;
+
+ const string SERVICE = "org.freedesktop.Tracker1";
+
+ static uint name_owner_changed_id;
+ static Tracker.Statistics statistics;
+ static uint statistics_id;
+ static Tracker.Resources resources;
+ static uint resources_id;
+ static Tracker.Steroids steroids;
+ static uint steroids_id;
+ static Tracker.Status notifier;
+ static uint notifier_id;
+ static Tracker.Backup backup;
+ static uint backup_id;
+
+ static bool dbus_register_service (string name) {
+ message ("Registering D-Bus service...\n Name:'%s'", name);
+
+ try {
+ Variant reply = connection.call_sync ("org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ "org.freedesktop.DBus", "RequestName",
+ new Variant ("(su)", name, 1 << 2 /* DBUS_NAME_FLAG_DO_NOT_QUEUE */),
+ (VariantType) "(u)",
+ 0, -1);
+
+ uint result;
+ reply.get ("(u)", out result);
+ if (result != 1 /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */) {
+ critical ("D-Bus service name:'%s' is already taken, " +
+ "perhaps the daemon is already running?",
+ name);
+ return false;
+ }
+
+ return true;
+ } catch (Error e) {
+ critical ("Could not aquire name:'%s', %s", name, e.message);
+ return false;
+ }
+ }
+
+ static uint register_object<T> (DBusConnection lconnection, T object, string path) {
+ message ("Registering D-Bus object...");
+ message (" Path:'%s'", path);
+ message (" Type:'%s'", typeof (T).name ());
+
+ return lconnection.register_object (path, object);
+ }
+
+ public static bool register_names () {
+ /* Register the service name for org.freedesktop.Tracker */
+ if (!dbus_register_service (SERVICE)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public static bool init () {
+ /* Don't reinitialize */
+ if (connection != null) {
+ return true;
+ }
+
+ try {
+ connection = Bus.get_sync (BusType.SESSION);
+ } catch (Error e) {
+ critical ("Could not connect to the D-Bus session bus, %s", e.message);
+ return false;
+ }
+
+ return true;
+ }
+
+ static void name_owner_changed_cb (DBusConnection connection, string sender_name, string object_path, string interface_name, string signal_name, Variant parameters) {
+
+ unowned string name, old_owner, new_owner;
+ parameters.get ("(&s&s&s)", out name, out old_owner, out new_owner);
+
+ if (old_owner != "" && new_owner == "") {
+ /* This means that old_owner got removed */
+ resources.unreg_batches (old_owner);
+ }
+ }
+
+ static void set_available (bool available) {
+ if (available) {
+ if (resources_id == 0) {
+ register_objects ();
+ }
+ } else {
+ if (resources_id != 0) {
+ connection.signal_unsubscribe (name_owner_changed_id);
+ name_owner_changed_id = 0;
+
+ connection.unregister_object (resources_id);
+ resources = null;
+ resources_id = 0;
+
+ connection.unregister_object (steroids_id);
+ steroids = null;
+ steroids_id = 0;
+ }
+ }
+ }
+
+ public static void shutdown () {
+ set_available (false);
+
+ if (backup != null) {
+ connection.unregister_object (backup_id);
+ backup = null;
+ backup_id = 0;
+ }
+
+ if (notifier != null) {
+ connection.unregister_object (notifier_id);
+ notifier = null;
+ notifier_id = 0;
+ }
+
+ connection = null;
+ }
+
+ public static Tracker.Status? register_notifier () {
+ if (connection == null) {
+ critical ("D-Bus support must be initialized before registering objects!");
+ return null;
+ }
+
+ /* Add org.freedesktop.Tracker */
+ notifier = new Tracker.Status ();
+ if (notifier == null) {
+ critical ("Could not create TrackerStatus object to register");
+ return null;
+ }
+
+ notifier_id = register_object (connection, notifier, Tracker.Status.PATH);
+
+ return notifier;
+ }
+
+ public static bool register_objects () {
+ //gpointer object, resources;
+
+ if (connection == null) {
+ critical ("D-Bus support must be initialized before registering objects!");
+ return false;
+ }
+
+ /* Add org.freedesktop.Tracker.Statistics */
+ statistics = new Tracker.Statistics ();
+ if (statistics == null) {
+ critical ("Could not create TrackerStatistics object to register");
+ return false;
+ }
+
+ statistics_id = register_object (connection, statistics, Tracker.Statistics.PATH);
+
+ /* Add org.freedesktop.Tracker1.Resources */
+ resources = new Tracker.Resources (connection);
+ if (resources == null) {
+ critical ("Could not create TrackerResources object to register");
+ return false;
+ }
+
+ name_owner_changed_id = connection.signal_subscribe ("org.freedesktop.DBus",
+ "org.freedesktop.DBus", "NameOwnerChanged",
+ "/org/freedesktop/DBus",
+ null,
+ 0,
+ name_owner_changed_cb);
+
+ resources_id = register_object (connection, resources, Tracker.Resources.PATH);
+
+ /* Add org.freedesktop.Tracker1.Steroids */
+ steroids = new Tracker.Steroids ();
+ if (steroids == null) {
+ critical ("Could not create TrackerSteroids object to register");
+ return false;
+ }
+
+ steroids_id = register_object (connection, steroids, Tracker.Steroids.PATH);
+
+ if (backup == null) {
+ /* Add org.freedesktop.Tracker1.Backup */
+ backup = new Tracker.Backup ();
+ if (backup == null) {
+ critical ("Could not create TrackerBackup object to register");
+ return false;
+ }
+
+ backup_id = register_object (connection, backup, Tracker.Backup.PATH);
+ }
+
+ return true;
+ }
+
+ public static bool register_prepare_class_signal () {
+ if (resources == null) {
+ message ("Error during initialization, Resources DBus object not available");
+ return false;
+ }
+
+ resources.enable_signals ();
+
+ return true;
+ }
+
+ public static Object? get_object (Type type) {
+ if (type == typeof (Resources)) {
+ return resources;
+ }
+
+ if (type == typeof (Steroids)) {
+ return steroids;
+ }
+
+ if (type == typeof (Status)) {
+ return notifier;
+ }
+
+ if (type == typeof (Backup)) {
+ return backup;
+ }
+
+ return null;
+ }
+}
diff --git a/src/tracker-store/tracker-events.vapi b/src/tracker-store/tracker-events.vapi
new file mode 100644
index 0000000..23bd415
--- /dev/null
+++ b/src/tracker-store/tracker-events.vapi
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+namespace Tracker {
+ [CCode (has_array_length = false, array_null_terminated = true, has_target = false, cheader_filename = "tracker-store/tracker-events.h")]
+ public delegate string[] NotifyClassGetter ();
+
+ [CCode (cheader_filename = "tracker-store/tracker-events.h")]
+ namespace Events {
+ public void init (NotifyClassGetter callback);
+ public NotifyClassGetter get_class_getter ();
+ public void shutdown ();
+ public void add_insert (int graph_id, int subject_id, string subject, int pred_id, int object_id, string object, GLib.PtrArray rdf_types);
+ public void add_delete (int graph_id, int subject_id, string subject, int pred_id, int object_id, string object, GLib.PtrArray rdf_types);
+ public GLib.HashTableIter<Tracker.Class, bool> classes_iter ();
+ public uint get_total (bool and_reset);
+ public void reset_pending ();
+ public void freeze ();
+ }
+}
diff --git a/src/tracker-store/tracker-locale-change.c b/src/tracker-store/tracker-locale-change.c
index 5a7495c..7c43f98 100644
--- a/src/tracker-store/tracker-locale-change.c
+++ b/src/tracker-store/tracker-locale-change.c
@@ -32,8 +32,6 @@
#include <libtracker-data/tracker-db-dbus.h>
#include "tracker-store.h"
-#include "tracker-dbus.h"
-#include "tracker-resources.h"
#include "tracker-events.h"
#include "tracker-locale-change.h"
@@ -47,17 +45,21 @@ static gpointer locale_notification_id;
static gboolean locale_change_notified;
static void
-locale_change_process_cb (gpointer user_data)
+locale_change_process_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
{
TrackerStatus *notifier;
TrackerBusyCallback busy_callback;
gpointer busy_user_data;
+ GDestroyNotify busy_destroy_notify;
TrackerLocaleChangeContext *ctxt = user_data;
notifier = TRACKER_STATUS (tracker_dbus_get_object (TRACKER_TYPE_STATUS));
busy_callback = tracker_status_get_callback (notifier,
- &busy_user_data);
+ &busy_user_data,
+ &busy_destroy_notify);
g_message ("Processing locale change...");
/* Reload! This will regenerate indexes with the new locale */
@@ -65,6 +67,8 @@ locale_change_process_cb (gpointer user_data)
busy_user_data,
"Changing locale");
+ busy_destroy_notify (busy_user_data);
+
if (ctxt->resources) {
tracker_events_init (ctxt->getter);
tracker_resources_enable_signals (ctxt->resources);
@@ -72,7 +76,7 @@ locale_change_process_cb (gpointer user_data)
}
g_free (ctxt);
- tracker_store_set_active (TRUE, FALSE, NULL);
+ tracker_store_resume ();
locale_change_notified = FALSE;
}
@@ -94,7 +98,7 @@ locale_change_process_idle_cb (gpointer data)
/* Note: Right now, the passed callback may be called instantly and not
* in an idle. */
g_message ("Setting tracker-store as inactive...");
- tracker_store_set_active (FALSE, locale_change_process_cb, ctxt);
+ tracker_store_pause (locale_change_process_cb, ctxt);
return FALSE;
}
diff --git a/src/tracker-store/tracker-locale-change.vapi b/src/tracker-store/tracker-locale-change.vapi
new file mode 100644
index 0000000..afc2153
--- /dev/null
+++ b/src/tracker-store/tracker-locale-change.vapi
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+namespace Tracker {
+ [CCode (cheader_filename = "tracker-store/tracker-locale-change.h")]
+ public void locale_change_initialize_subscription ();
+ [CCode (cheader_filename = "tracker-store/tracker-locale-change.h")]
+ public void locale_change_shutdown_subscription ();
+}
diff --git a/src/tracker-store/tracker-main.c b/src/tracker-store/tracker-main.c
index d21136b..5e10240 100644
--- a/src/tracker-store/tracker-main.c
+++ b/src/tracker-store/tracker-main.c
@@ -50,14 +50,11 @@
#include <libtracker-data/tracker-db-dbus.h>
#include <libtracker-data/tracker-db-manager.h>
-#include "tracker-dbus.h"
#include "tracker-config.h"
#include "tracker-events.h"
-#include "tracker-writeback.h"
-#include "tracker-backup.h"
-#include "tracker-store.h"
-#include "tracker-statistics.h"
#include "tracker-locale-change.h"
+#include "tracker-store.h"
+#include "tracker-writeback.h"
#define ABOUT \
"Tracker " PACKAGE_VERSION "\n"
@@ -296,6 +293,7 @@ main (gint argc, gchar *argv[])
TrackerStatus *notifier;
gpointer busy_user_data;
TrackerBusyCallback busy_callback;
+ GDestroyNotify busy_destroy_notify;
gint chunk_size_mb;
gsize chunk_size;
const gchar *rotate_to;
@@ -316,8 +314,6 @@ main (gint argc, gchar *argv[])
private,
private_free);
- dbus_g_thread_init ();
-
setlocale (LC_ALL, "");
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
@@ -398,7 +394,8 @@ main (gint argc, gchar *argv[])
notifier = tracker_dbus_register_notifier ();
busy_callback = tracker_status_get_callback (notifier,
- &busy_user_data);
+ &busy_user_data,
+ &busy_destroy_notify);
tracker_store_init ();
@@ -474,7 +471,7 @@ main (gint argc, gchar *argv[])
tracker_events_init (get_notifiable_classes);
tracker_writeback_init (get_writeback_predicates);
- tracker_store_set_active (TRUE, NULL, NULL);
+ tracker_store_resume ();
g_message ("Waiting for D-Bus requests...");
diff --git a/src/tracker-store/tracker-resources.vala b/src/tracker-store/tracker-resources.vala
new file mode 100644
index 0000000..fb8a900
--- /dev/null
+++ b/src/tracker-store/tracker-resources.vala
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2006, Jamie McCracken <jamiemcc gnome org>
+ * Copyright (C) 2008, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+[DBus (name = "org.freedesktop.Tracker1.Resources")]
+public class Tracker.Resources : Object {
+ public const string PATH = "/org/freedesktop/Tracker1/Resources";
+
+ const int GRAPH_UPDATED_IMMEDIATE_EMIT_AT = 1000;
+ const int SIGNALS_SECONDS_PER_EMIT = 1;
+
+ /* I *know* that this is some arbitrary number that doesn't seem to
+ * resemble anything. In fact it's what I experimentally measured to
+ * be a good value on a default Debian testing which has
+ * max_message_size set to 1 000 000 000 in session.conf. I didn't have
+ * the feeling that this value was very much respected, as the size
+ * of the DBusMessage when libdbus decided to exit() the process was
+ * around 160 MB, and not ~ 1000 MB. So if you take 160 MB and you
+ * devide it by 1000000 you have an average string size of ~ 160
+ * bytes plus DBusMessage's overhead. If that makes this number less
+ * arbitrary for you, then fine.
+ *
+ * I really hope that the libdbus people get to their senses and
+ * either stop doing their exit() nonsense in a library, and instead
+ * return a clean DBusError or something, or create crystal clear
+ * clarity about the maximum size of a message. And make it both so
+ * that I can get this length at runtime (without having to parse
+ * libdbus's own configuration files) and my DBusMessage's current
+ * total length. As far as I know are both not possible. So that for
+ * me means that libdbus's exit() is unacceptable.
+ *
+ * Note for the debugger of the future, the "Disconnected" signal gets
+ * sent to us by the bus, which in turn makes libdbus-glib perform exit(). */
+
+ const int DBUS_ARBITRARY_MAX_MSG_SIZE = 1000000;
+
+ DBusConnection connection;
+ uint signal_timeout;
+
+ public signal void writeback ([DBus (signature = "a{iai}")] Variant subjects);
+ public signal void graph_updated (string classname, [DBus (signature = "a(iiii)")] Variant deletes, [DBus (signature = "a(iiii)")] Variant inserts);
+
+ public Resources (DBusConnection connection) {
+ this.connection = connection;
+ }
+
+ public async void load (BusName sender, string uri) throws Error {
+ var request = DBusRequest.begin (sender, "Resources.Load (uri: '%s')", uri);
+ try {
+ var file = File.new_for_uri (uri);
+
+ yield Tracker.Store.queue_turtle_import (file, sender);
+
+ request.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ [DBus (signature = "aas")]
+ public async Variant sparql_query (BusName sender, string query) throws Error {
+ var request = DBusRequest.begin (sender, "Resources.SparqlQuery");
+ request.debug ("query: %s", query);
+ try {
+ var builder = new VariantBuilder ((VariantType) "aas");
+
+ yield Tracker.Store.sparql_query (query, Tracker.Store.Priority.HIGH, cursor => {
+ while (cursor.next ()) {
+ builder.open ((VariantType) "as");
+
+ for (int i = 0; i < cursor.n_columns; i++) {
+ unowned string str = cursor.get_string (i);
+
+ if (str == null) {
+ str = "";
+ }
+
+ builder.add ("s", str);
+ }
+
+ builder.close ();
+ }
+ }, sender);
+
+ request.end ();
+
+ var result = builder.end ();
+ if (result.get_size () > DBUS_ARBITRARY_MAX_MSG_SIZE) {
+ throw new DBusError.FAILED ("result set of the query is too large");
+ } else {
+ return result;
+ }
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ public async void sparql_update (BusName sender, string update) throws Error {
+ var request = DBusRequest.begin (sender, "Resources.SparqlUpdate");
+ request.debug ("query: %s", update);
+ try {
+ yield Tracker.Store.sparql_update (update, Tracker.Store.Priority.HIGH, sender);
+
+ request.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ [DBus (signature = "aaa{ss}")]
+ public async Variant sparql_update_blank (BusName sender, string update) throws Error {
+ var request = DBusRequest.begin (sender, "Resources.SparqlUpdateBlank");
+ request.debug ("query: %s", update);
+ try {
+ var blank_nodes = yield Tracker.Store.sparql_update_blank (update, Tracker.Store.Priority.HIGH, sender);
+
+ request.end ();
+
+ var builder = new VariantBuilder ((VariantType) "aaa{ss}");
+
+ for (int i = 0; i < blank_nodes.length; i++) {
+ var inner_array = blank_nodes[i];
+
+ builder.open ((VariantType) "aa{ss}");
+ for (int j = 0; j < inner_array.length; j++) {
+ builder.add_value (inner_array[j]);
+ }
+ builder.close ();
+ }
+
+ return builder.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ public void sync (BusName sender) {
+ var request = DBusRequest.begin (sender, "Resources.Sync");
+
+ Data.sync ();
+
+ request.end ();
+ }
+
+ public async void batch_sparql_update (BusName sender, string update) throws Error {
+ var request = DBusRequest.begin (sender, "Resources.BatchSparqlUpdate");
+ request.debug ("query: %s", update);
+ try {
+ yield Tracker.Store.sparql_update (update, Tracker.Store.Priority.LOW, sender);
+
+ request.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ public void batch_commit () {
+ /* no longer needed, just return */
+ }
+
+ bool emit_graph_updated (Class cl) {
+ if (cl.has_insert_events () || cl.has_delete_events ()) {
+ var builder = new VariantBuilder ((VariantType) "a(iiii)");
+ cl.foreach_delete_event ((graph_id, subject_id, pred_id, object_id) => {
+ builder.add ("(iiii)", graph_id, subject_id, pred_id, object_id);
+ });
+ var deletes = builder.end ();
+
+ builder = new VariantBuilder ((VariantType) "a(iiii)");
+ cl.foreach_insert_event ((graph_id, subject_id, pred_id, object_id) => {
+ builder.add ("(iiii)", graph_id, subject_id, pred_id, object_id);
+ });
+ var inserts = builder.end ();
+
+ graph_updated (cl.uri, deletes, inserts);
+
+ cl.reset_ready_events ();
+
+ return true;
+ }
+ return false;
+ }
+
+ bool on_emit_signals () {
+ bool had_any = false;
+
+ /* Class signal feature */
+ var iter = Tracker.Events.classes_iter ();
+
+ unowned Class cl;
+ bool value;
+ while (iter.next (out cl, out value)) {
+ if (emit_graph_updated (cl)) {
+ had_any = true;
+ }
+ }
+
+ /* Reset counter */
+ Tracker.Events.get_total (true);
+
+
+ /* Writeback feature */
+ var writebacks = Tracker.Writeback.get_ready ();
+
+ if (writebacks != null) {
+ had_any = true;
+ var builder = new VariantBuilder ((VariantType) "a{iai}");
+
+ var wb_iter = HashTableIter<int, GLib.Array<int>> (writebacks);
+
+ int subject_id;
+ unowned Array<int> types;
+ while (wb_iter.next (out subject_id, out types)) {
+ builder.open ((VariantType) "{iai}");
+
+ builder.add ("i", subject_id);
+
+ builder.open ((VariantType) "ai");
+ for (int i = 0; i < types.length; i++) {
+ builder.add ("i", types.index (i));
+ }
+ builder.close ();
+
+ builder.close ();
+ }
+
+ writeback (builder.end ());
+ }
+
+ Tracker.Writeback.reset_ready ();
+
+ if (!had_any) {
+ signal_timeout = 0;
+ }
+
+ return had_any;
+ }
+
+ void on_statements_committed (bool start_timer) {
+ /* Class signal feature */
+
+ var iter = Tracker.Events.classes_iter ();
+
+ unowned Class cl;
+ bool value;
+ while (iter.next (out cl, out value)) {
+ cl.transact_events ();
+ }
+
+ if (start_timer && signal_timeout == 0) {
+ signal_timeout = Timeout.add_seconds (SIGNALS_SECONDS_PER_EMIT, on_emit_signals);
+ }
+
+ /* Writeback feature */
+ Tracker.Writeback.transact ();
+ }
+
+ void on_statements_rolled_back (bool start_timer) {
+ Tracker.Events.reset_pending ();
+ Tracker.Writeback.reset_pending ();
+ }
+
+ void check_graph_updated_signal () {
+ /* Check for whether we need an immediate emit */
+ if (Tracker.Events.get_total (false) > GRAPH_UPDATED_IMMEDIATE_EMIT_AT) {
+ var iter = Tracker.Events.classes_iter ();
+
+ unowned Class cl;
+ bool value;
+ while (iter.next (out cl, out value)) {
+ emit_graph_updated (cl);
+ }
+
+ /* Reset counter */
+ Tracker.Events.get_total (true);
+ }
+ }
+
+ void on_statement_inserted (int graph_id, string? graph, int subject_id, string subject, int pred_id, int object_id, string object, PtrArray rdf_types) {
+ Tracker.Events.add_insert (graph_id, subject_id, subject, pred_id, object_id, object, rdf_types);
+ Tracker.Writeback.check (graph_id, graph, subject_id, subject, pred_id, object_id, object, rdf_types);
+ check_graph_updated_signal ();
+ }
+
+ void on_statement_deleted (int graph_id, string? graph, int subject_id, string subject, int pred_id, int object_id, string object, PtrArray rdf_types) {
+ Tracker.Events.add_delete (graph_id, subject_id, subject, pred_id, object_id, object, rdf_types);
+ Tracker.Writeback.check (graph_id, graph, subject_id, subject, pred_id, object_id, object, rdf_types);
+ check_graph_updated_signal ();
+ }
+
+ public void enable_signals () {
+ Tracker.Data.add_insert_statement_callback (on_statement_inserted);
+ Tracker.Data.add_delete_statement_callback (on_statement_deleted);
+ Tracker.Data.add_commit_statement_callback (on_statements_committed);
+ Tracker.Data.add_rollback_statement_callback (on_statements_rolled_back);
+ }
+
+ public void disable_signals () {
+ Tracker.Data.remove_insert_statement_callback (on_statement_inserted);
+ Tracker.Data.remove_delete_statement_callback (on_statement_deleted);
+ Tracker.Data.remove_commit_statement_callback (on_statements_committed);
+ Tracker.Data.remove_rollback_statement_callback (on_statements_rolled_back);
+
+ if (signal_timeout != 0) {
+ Source.remove (signal_timeout);
+ }
+ }
+
+ ~Resources () {
+ this.disable_signals ();
+ }
+
+ public void unreg_batches (string old_owner) {
+ Tracker.Store.unreg_batches (old_owner);
+ }
+}
diff --git a/src/tracker-store/tracker-dbus.h b/src/tracker-store/tracker-statistics.vala
similarity index 55%
rename from src/tracker-store/tracker-dbus.h
rename to src/tracker-store/tracker-statistics.vala
index 541b9e3..1e52917 100644
--- a/src/tracker-store/tracker-dbus.h
+++ b/src/tracker-store/tracker-statistics.vala
@@ -18,25 +18,30 @@
* Boston, MA 02110-1301, USA.
*/
-#ifndef __TRACKER_STORE_DBUS_H__
-#define __TRACKER_STORE_DBUS_H__
+[DBus (name = "org.freedesktop.Tracker1.Statistics")]
+public class Tracker.Statistics : Object {
+ public const string PATH = "/org/freedesktop/Tracker1/Statistics";
-#include <glib.h>
+ [DBus (signature = "aas")]
+ public new Variant get (BusName sender) {
+ var request = DBusRequest.begin (sender, "Statistics.Get");
-#include <dbus/dbus-glib-bindings.h>
+ var builder = new VariantBuilder ((VariantType) "aas");
-#include "tracker-status.h"
+ foreach (var cl in Ontologies.get_classes ()) {
+ if (cl.count == 0) {
+ /* skip classes without resources */
+ continue;
+ }
-G_BEGIN_DECLS
+ builder.open ((VariantType) "as");
+ builder.add ("s", cl.name);
+ builder.add ("s", cl.count.to_string ());
+ builder.close ();
+ }
-gboolean tracker_dbus_init (void);
-void tracker_dbus_shutdown (void);
-gboolean tracker_dbus_register_objects (void);
-GObject *tracker_dbus_get_object (GType type);
-TrackerStatus *tracker_dbus_register_notifier (void);
-gboolean tracker_dbus_register_names (void);
-gboolean tracker_dbus_register_prepare_class_signal (void);
+ request.end ();
-G_END_DECLS
-
-#endif /* __TRACKER_STORE_DBUS_H__ */
+ return builder.end ();
+ }
+}
diff --git a/src/tracker-store/tracker-status.vala b/src/tracker-store/tracker-status.vala
new file mode 100644
index 0000000..7d861d7
--- /dev/null
+++ b/src/tracker-store/tracker-status.vala
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *
+ * Authors:
+ * Philip Van Hoof <philip codeminded be>
+ */
+
+[DBus (name = "org.freedesktop.Tracker1.Status")]
+public class Tracker.Status : Object {
+ public const string PATH = "/org/freedesktop/Tracker1/Status";
+
+ const int PROGRESS_TIMEOUT_S = 5;
+
+ class WaitContext : Object {
+ public SourceFunc callback;
+ }
+
+ double _progress;
+ string status = "Idle";
+ uint timer_id;
+ List<WaitContext> wait_list;
+
+ /**
+ * TrackerStatus::progress:
+ * @notifier: the TrackerStatus
+ * @status: store status
+ * @progress: a #gdouble indicating store progress, from 0 to 1.
+ *
+ * the ::progress signal will be emitted by TrackerStatus
+ * to indicate progress about the store process. @status will
+ * contain a translated string with the current status and @progress
+ * will indicate how much has been processed so far.
+ **/
+ public signal void progress (string status, double progres);
+
+ ~Status () {
+ if (timer_id != 0) {
+ Source.remove (timer_id);
+ }
+ }
+
+ bool
+ busy_notification_timeout () {
+ progress (status, _progress);
+
+ timer_id = 0;
+
+ return false;
+ }
+
+ static bool first_time = true;
+
+ void callback (string status, double progress) {
+ this._progress = progress;
+
+ if (progress == 1 && wait_list != null) {
+ /* notify clients that tracker-store is no longer busy */
+
+ wait_list.reverse ();
+ foreach (var context in wait_list) {
+ context.callback ();
+ }
+
+ wait_list = null;
+ }
+
+ if (status != this.status) {
+ this.status = status;
+ }
+
+ if (timer_id == 0) {
+ if (first_time) {
+ this.timer_id = Idle.add (busy_notification_timeout);
+ first_time = false;
+ } else {
+ timer_id = Timeout.add_seconds (PROGRESS_TIMEOUT_S, busy_notification_timeout);
+ }
+ }
+
+ while (MainContext.default ().iteration (false)) {
+ }
+ }
+
+ [DBus (visible = false)]
+ public BusyCallback get_callback () {
+ return callback;
+ }
+
+ public double get_progress () {
+ return this._progress;
+ }
+
+ public string get_status () {
+ return this.status;
+ }
+
+ public async void wait () throws Error {
+ if (_progress == 1) {
+ /* tracker-store is idle */
+ } else {
+ var context = new WaitContext ();
+ context.callback = wait.callback;
+ wait_list.prepend (context);
+ yield;
+ }
+ }
+}
diff --git a/src/tracker-store/tracker-steroids.vala b/src/tracker-store/tracker-steroids.vala
new file mode 100644
index 0000000..cbb320d
--- /dev/null
+++ b/src/tracker-store/tracker-steroids.vala
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2010, Codeminded BVBA <abustany gnome org>
+ *
+ * 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.
+ */
+
+[DBus (name = "org.freedesktop.Tracker1.Steroids")]
+public class Tracker.Steroids : Object {
+ public const string PATH = "/org/freedesktop/Tracker1/Steroids";
+
+ public const int BUFFER_SIZE = 65536;
+
+ public async string[] query (BusName sender, string query, UnixOutputStream output_stream) throws Error {
+ var request = DBusRequest.begin (sender, "Steroids.Query");
+ request.debug ("query: %s", query);
+ try {
+ string[] variable_names = null;
+
+ yield Tracker.Store.sparql_query (query, Tracker.Store.Priority.HIGH, cursor => {
+ var data_output_stream = new DataOutputStream (new BufferedOutputStream.sized (output_stream, BUFFER_SIZE));
+ data_output_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN);
+
+ int n_columns = cursor.n_columns;
+
+ int[] column_sizes = new int[n_columns];
+ int[] column_offsets = new int[n_columns];
+ string[] column_data = new string[n_columns];
+
+ variable_names = new string[n_columns];
+ for (int i = 0; i < n_columns; i++) {
+ variable_names[i] = cursor.get_variable_name (i);
+ }
+
+ while (cursor.next ()) {
+ int last_offset = -1;
+
+ for (int i = 0; i < n_columns ; i++) {
+ unowned string str = cursor.get_string (i);
+
+ column_sizes[i] = str != null ? str.length : 0;
+ column_data[i] = str;
+
+ last_offset += column_sizes[i] + 1;
+ column_offsets[i] = last_offset;
+ }
+
+ data_output_stream.put_int32 (n_columns);
+
+ for (int i = 0; i < n_columns ; i++) {
+ /* Cast from enum to int */
+ data_output_stream.put_int32 ((int) cursor.get_value_type (i));
+ }
+
+ for (int i = 0; i < n_columns ; i++) {
+ data_output_stream.put_int32 (column_offsets[i]);
+ }
+
+ for (int i = 0; i < n_columns ; i++) {
+ data_output_stream.put_string (column_data[i] != null ? column_data[i] : "");
+ data_output_stream.put_byte (0);
+ }
+ }
+ }, sender);
+
+ request.end ();
+
+ return variable_names;
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ async Variant? update_internal (BusName sender, Tracker.Store.Priority priority, bool blank, UnixInputStream input_stream) throws Error {
+ var request = DBusRequest.begin (sender,
+ "Steroids.%sUpdate%s",
+ priority != Tracker.Store.Priority.HIGH ? "Batch" : "",
+ blank ? "Blank" : "");
+ try {
+ size_t bytes_read;
+
+ var data_input_stream = new DataInputStream (input_stream);
+ data_input_stream.set_buffer_size (BUFFER_SIZE);
+ data_input_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN);
+
+ int query_size = data_input_stream.read_int32 (null);
+
+ /* We malloc one more char to ensure string is 0 terminated */
+ uint8[] query = new uint8[query_size + 1];
+
+ data_input_stream.read_all (query[0:query_size], out bytes_read);
+
+ data_input_stream = null;
+ input_stream = null;
+
+ request.debug ("query: %s", (string) query);
+
+ if (!blank) {
+ yield Tracker.Store.sparql_update ((string) query, priority, sender);
+
+ request.end ();
+
+ return null;
+ } else {
+ var blank_nodes = yield Tracker.Store.sparql_update_blank ((string) query, priority, sender);
+
+ request.end ();
+
+ var builder = new VariantBuilder ((VariantType) "aaa{ss}");
+
+ for (int i = 0; i < blank_nodes.length; i++) {
+ var inner_array = blank_nodes[i];
+
+ builder.open ((VariantType) "aa{ss}");
+ for (int j = 0; j < inner_array.length; j++) {
+ builder.add_value (inner_array[j]);
+ }
+ builder.close ();
+ }
+
+ return builder.end ();
+ }
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+
+ public async void update (BusName sender, UnixInputStream input_stream) throws Error {
+ yield update_internal (sender, Tracker.Store.Priority.HIGH, false, input_stream);
+ }
+
+ public async void batch_update (BusName sender, UnixInputStream input_stream) throws Error {
+ yield update_internal (sender, Tracker.Store.Priority.LOW, false, input_stream);
+ }
+
+ [DBus (signature = "aaa{ss}")]
+ public async Variant update_blank (BusName sender, UnixInputStream input_stream) throws Error {
+ return yield update_internal (sender, Tracker.Store.Priority.HIGH, true, input_stream);
+ }
+
+ [DBus (signature = "aaa{ss}")]
+ public async Variant batch_update_blank (BusName sender, UnixInputStream input_stream) throws Error {
+ return yield update_internal (sender, Tracker.Store.Priority.LOW, true, input_stream);
+ }
+
+ [DBus (signature = "as")]
+ public async Variant update_array (BusName sender, UnixInputStream input_stream) throws Error {
+ var request = DBusRequest.begin (sender, "Steroids.UpdateArray");
+ try {
+ var data_input_stream = new DataInputStream (input_stream);
+ data_input_stream.set_buffer_size (BUFFER_SIZE);
+ data_input_stream.set_byte_order (DataStreamByteOrder.HOST_ENDIAN);
+
+ int query_count = data_input_stream.read_int32 ();
+
+ string[] query_array = new string[query_count];
+
+ int i;
+ for (i = 0; i < query_count; i++) {
+ size_t bytes_read;
+
+ int query_size = data_input_stream.read_int32 ();
+
+ /* We malloc one more char to ensure string is 0 terminated */
+ query_array[i] = (string) new uint8[query_size + 1];
+
+ data_input_stream.read_all (((uint8[]) query_array[i])[0:query_size], out bytes_read);
+
+ }
+
+ data_input_stream = null;
+ input_stream = null;
+
+ var builder = new VariantBuilder ((VariantType) "as");
+
+ for (i = 0; i < query_count; i++) {
+ request.debug ("query: %s", query_array[i]);
+
+ try {
+ yield Tracker.Store.sparql_update (query_array[i], Tracker.Store.Priority.HIGH, sender);
+ builder.add ("s", "");
+ builder.add ("s", "");
+ } catch (Error e1) {
+ builder.add ("s", "org.freedesktop.Tracker1.SparqlError.Internal");
+ builder.add ("s", e1.message);
+ }
+
+ }
+
+ request.end ();
+
+ return builder.end ();
+ } catch (Error e) {
+ request.end (e);
+ throw e;
+ }
+ }
+}
diff --git a/src/tracker-store/tracker-store.vala b/src/tracker-store/tracker-store.vala
new file mode 100644
index 0000000..747b487
--- /dev/null
+++ b/src/tracker-store/tracker-store.vala
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2009, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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>
+ */
+
+public class Tracker.Store {
+ const int MAX_CONCURRENT_QUERIES = 2;
+
+ const int MAX_TASK_TIME = 30;
+
+ static Queue<Task> query_queues[3 /* TRACKER_STORE_N_PRIORITIES */];
+ static Queue<Task> update_queues[3 /* TRACKER_STORE_N_PRIORITIES */];
+ static int n_queries_running;
+ static bool update_running;
+ static ThreadPool<Task> update_pool;
+ static ThreadPool<Task> query_pool;
+ static GenericArray<Task> running_tasks;
+ static int max_task_time;
+ static bool active;
+ static SourceFunc active_callback;
+
+ public enum Priority {
+ HIGH,
+ LOW,
+ TURTLE,
+ N_PRIORITIES
+ }
+
+ enum TaskType {
+ QUERY,
+ UPDATE,
+ UPDATE_BLANK,
+ TURTLE,
+ }
+
+ public delegate void SparqlQueryInThread (DBCursor cursor) throws Error;
+
+ abstract class Task {
+ public TaskType type;
+ public string client_id;
+ public Error error;
+ public SourceFunc callback;
+ }
+
+ class QueryTask : Task {
+ public string query;
+ public Cancellable cancellable;
+ public uint watchdog_id;
+ public SparqlQueryInThread in_thread;
+
+ ~QueryTask () {
+ if (watchdog_id > 0) {
+ Source.remove (watchdog_id);
+ }
+ }
+ }
+
+ class UpdateTask : Task {
+ public string query;
+ public GenericArray<GenericArray<HashTable<string,string>>> blank_nodes;
+ public Priority priority;
+ }
+
+ class TurtleTask : Task {
+ public string path;
+ }
+
+ static void sched () {
+ Task task = null;
+
+ if (!active) {
+ return;
+ }
+
+ while (n_queries_running < MAX_CONCURRENT_QUERIES) {
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ task = query_queues[i].pop_head ();
+ if (task != null) {
+ break;
+ }
+ }
+ if (task == null) {
+ /* no pending query */
+ break;
+ }
+ running_tasks.add (task);
+
+ if (max_task_time != 0) {
+ var query_task = (QueryTask) task;
+ query_task.watchdog_id = Timeout.add_seconds (max_task_time, () => {
+ query_task.cancellable.cancel ();
+ return false;
+ });
+ }
+
+ n_queries_running++;
+ try {
+ query_pool.push (task);
+ } catch (Error e) {
+ // ignore harmless thread creation error
+ }
+ }
+
+ if (!update_running) {
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ task = update_queues[i].pop_head ();
+ if (task != null) {
+ break;
+ }
+ }
+ if (task != null) {
+ update_running = true;
+ try {
+ update_pool.push (task);
+ } catch (Error e) {
+ // ignore harmless thread creation error
+ }
+ }
+ }
+ }
+
+ static bool start_timer_or_not (Task task) {
+ bool result;
+
+ switch (task.type) {
+ case TaskType.UPDATE:
+ case TaskType.UPDATE_BLANK:
+ result = !(((UpdateTask) task).priority == Priority.LOW && update_queues[Priority.LOW].get_length () > 0);
+ break;
+ case TaskType.TURTLE:
+ result = update_queues[Priority.TURTLE].get_length () == 0;
+ break;
+ case TaskType.QUERY:
+ default:
+ result = false;
+ break;
+ }
+
+ return result;
+ }
+
+ static bool task_finish_cb (Task task) {
+ if (task.type == TaskType.QUERY) {
+ var query_task = (QueryTask) task;
+
+ if (task.error == null) {
+ try {
+ query_task.cancellable.set_error_if_cancelled ();
+ } catch (Error e) {
+ task.error = e;
+ }
+ }
+
+ task.callback ();
+ task.error = null;
+
+ running_tasks.remove (task);
+ n_queries_running--;
+ } else if (task.type == TaskType.UPDATE || task.type == TaskType.UPDATE_BLANK) {
+ if (task.error == null) {
+ Tracker.Data.notify_transaction (start_timer_or_not (task));
+ }
+
+ task.callback ();
+ task.error = null;
+
+ update_running = false;
+ } else if (task.type == TaskType.TURTLE) {
+ if (task.error == null) {
+ Tracker.Data.notify_transaction (start_timer_or_not (task));
+ }
+
+ task.callback ();
+ task.error = null;
+
+ update_running = false;
+ }
+
+ if (n_queries_running == 0 && !update_running && active_callback != null) {
+ active_callback ();
+ }
+
+ sched ();
+
+ return false;
+ }
+
+ static void pool_dispatch_cb (Task task) {
+ try {
+ if (task.type == TaskType.QUERY) {
+ var query_task = (QueryTask) task;
+
+ var cursor = Tracker.Data.query_sparql_cursor (query_task.query);
+
+ query_task.in_thread (cursor);
+ } else if (task.type == TaskType.UPDATE) {
+ var update_task = (UpdateTask) task;
+
+ Tracker.Data.update_sparql (update_task.query);
+ } else if (task.type == TaskType.UPDATE_BLANK) {
+ var update_task = (UpdateTask) task;
+
+ update_task.blank_nodes = Tracker.Data.update_sparql_blank (update_task.query);
+ } else if (task.type == TaskType.TURTLE) {
+ var turtle_task = (TurtleTask) task;
+
+ var file = File.new_for_path (turtle_task.path);
+
+ Tracker.Events.freeze ();
+ Tracker.Data.load_turtle_file (file);
+ Tracker.Events.reset_pending ();
+ }
+ } catch (Error e) {
+ task.error = e;
+ }
+
+ Idle.add (() => {
+ task_finish_cb (task);
+ return false;
+ });
+ }
+
+ public static void init () {
+ /*if ((tmp = g_getenv("TRACKER_STORE_MAX_TASK_TIME")) != NULL) {
+ max_task_time = atoi (tmp);
+ } else*/ {
+ max_task_time = MAX_TASK_TIME;
+ }
+
+ running_tasks = new GenericArray<Task> ();
+
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ query_queues[i] = new Queue<Task> ();
+ update_queues[i] = new Queue<Task> ();
+ }
+
+ try {
+ update_pool = new ThreadPool<Task> (pool_dispatch_cb, 1, true);
+ query_pool = new ThreadPool<Task> (pool_dispatch_cb, MAX_CONCURRENT_QUERIES, true);
+ } catch (Error e) {
+ // ignore harmless thread creation error
+ warning (e.message);
+ }
+
+ /* as the following settings are global for unknown reasons,
+ let's use the same settings as gio, otherwise the used settings
+ are rather random */
+ ThreadPool.set_max_idle_time (15 * 1000);
+ ThreadPool.set_max_unused_threads (2);
+ }
+
+ public static void shutdown () {
+ query_pool = null;
+ update_pool = null;
+
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ query_queues[i] = null;
+ update_queues[i] = null;
+ }
+ }
+
+ public static async void sparql_query (string sparql, Priority priority, SparqlQueryInThread in_thread, string client_id) throws Error {
+ var task = new QueryTask ();
+ task.type = TaskType.QUERY;
+ task.query = sparql;
+ task.cancellable = new Cancellable ();
+ task.in_thread = in_thread;
+ task.callback = sparql_query.callback;
+ task.client_id = client_id;
+
+ query_queues[priority].push_tail (task);
+
+ sched ();
+
+ yield;
+
+ if (task.error != null) {
+ throw task.error;
+ }
+ }
+
+ public static async void sparql_update (string sparql, Priority priority, string client_id) throws Error {
+ var task = new UpdateTask ();
+ task.type = TaskType.UPDATE;
+ task.query = sparql;
+ task.priority = priority;
+ task.callback = sparql_update.callback;
+ task.client_id = client_id;
+
+ update_queues[priority].push_tail (task);
+
+ sched ();
+
+ yield;
+
+ if (task.error != null) {
+ throw task.error;
+ }
+ }
+
+ public static async GenericArray<GenericArray<HashTable<string,string>>> sparql_update_blank (string sparql, Priority priority, string client_id) throws Error {
+ var task = new UpdateTask ();
+ task.type = TaskType.UPDATE_BLANK;
+ task.query = sparql;
+ task.priority = priority;
+ task.callback = sparql_update.callback;
+ task.client_id = client_id;
+
+ update_queues[priority].push_tail (task);
+
+ sched ();
+
+ yield;
+
+ if (task.error != null) {
+ throw task.error;
+ }
+
+ return task.blank_nodes;
+ }
+
+ public static async void queue_turtle_import (File file, string client_id) throws Error {
+ var task = new TurtleTask ();
+ task.type = TaskType.TURTLE;
+ task.path = file.get_path ();
+ task.callback = queue_turtle_import.callback;
+ task.client_id = client_id;
+
+ update_queues[Priority.TURTLE].push_tail (task);
+
+ sched ();
+
+ yield;
+
+ if (task.error != null) {
+ throw task.error;
+ }
+ }
+
+ public uint get_queue_size () {
+ uint result = 0;
+
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ result += query_queues[i].get_length ();
+ result += update_queues[i].get_length ();
+ }
+ return result;
+ }
+
+ public static void unreg_batches (string client_id) {
+ unowned List<Task> list, cur;
+ unowned Queue<Task> queue;
+
+ for (int i = 0; i < running_tasks.length; i++) {
+ unowned QueryTask task = running_tasks[i] as QueryTask;
+ if (task != null && task.client_id == client_id && task.cancellable != null) {
+ task.cancellable.cancel ();
+ }
+ }
+
+ for (int i = 0; i < Priority.N_PRIORITIES; i++) {
+ queue = query_queues[i];
+ list = queue.head;
+ while (list != null) {
+ cur = list;
+ list = list.next;
+ unowned Task task = cur.data;
+
+ if (task != null && task.client_id == client_id) {
+ queue.delete_link (cur);
+
+ task.error = new DBusError.FAILED ("Client disappeared");
+ task.callback ();
+ }
+ }
+
+ queue = update_queues[i];
+ list = queue.head;
+ while (list != null) {
+ cur = list;
+ list = list.next;
+ unowned Task task = cur.data;
+
+ if (task != null && task.client_id == client_id) {
+ queue.delete_link (cur);
+
+ task.error = new DBusError.FAILED ("Client disappeared");
+ task.callback ();
+ }
+ }
+ }
+
+ sched ();
+ }
+
+ public static async void pause () {
+ Tracker.Store.active = false;
+
+ if (n_queries_running > 0 || update_running) {
+ active_callback = pause.callback;
+ yield;
+ active_callback = null;
+ }
+
+ if (active) {
+ sched ();
+ }
+ }
+
+ public static void resume () {
+ Tracker.Store.active = true;
+
+ sched ();
+ }
+}
diff --git a/src/tracker-store/tracker-writeback.vapi b/src/tracker-store/tracker-writeback.vapi
new file mode 100644
index 0000000..1c50eca
--- /dev/null
+++ b/src/tracker-store/tracker-writeback.vapi
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ */
+
+namespace Tracker {
+ [CCode (has_array_length = false, array_null_terminated = true, has_target = false, cheader_filename = "tracker-store/tracker-writeback.h")]
+ public delegate string[] WritebackGetPredicatesFunc ();
+
+ [CCode (cheader_filename = "tracker-store/tracker-writeback.h")]
+ namespace Writeback {
+ public void init (WritebackGetPredicatesFunc callback);
+ public void shutdown ();
+ public void check (int graph_id, string graph, int subject_id, string subject, int pred_id, int object_id, string object, GLib.PtrArray rdf_types);
+ public unowned GLib.HashTable<int, GLib.Array<int>> get_ready ();
+ public void reset_pending ();
+ public void reset_ready ();
+ public void transact ();
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]