Index: src/trackerd/tracker-xesam-live-search.c =================================================================== --- src/trackerd/tracker-xesam-live-search.c (revision 1331) +++ src/trackerd/tracker-xesam-live-search.c (working copy) @@ -132,7 +132,86 @@ g_signal_emit_by_name (proxy, "search-done", tracker_xesam_live_search_get_id (self)); } + /** + * tracker_xesam_live_search_match_with_events: + * @self: A #TrackerXesamLiveSearch + * @result_set: a #TrackerDBResultSet with all items in Events + * @added: (caller-owns) (out): added items + * @removed: (caller-owns) (out): removed items + * @modified: (caller-owns) (out): modified items + * + * Find all items that match with the current events for @self. + **/ +void +tracker_xesam_live_search_match_with_events (TrackerXesamLiveSearch *self, TrackerDBResultSet *events, GArray **added, GArray **removed, GArray **modified) +{ + TrackerDBusXesam *proxy = TRACKER_DBUS_XESAM (tracker_dbus_get_object (TRACKER_TYPE_DBUS_XESAM)); + DBConnection *db_con = NULL; + TrackerDBResultSet *result_set; + gboolean ls_valid = TRUE; + GArray *m_added = NULL, *m_removed = NULL, *m_modified = NULL; + + g_object_get (proxy, "db-connection", &db_con, NULL); + + result_set = tracker_db_get_live_search_results (db_con, + tracker_xesam_live_search_get_id (self)); + + while (ls_valid) { + GValue ls_value = { 0, }; + gboolean ev_valid = TRUE; + + _tracker_db_result_set_get_value (result_set, 0, &ls_value); + + while (ev_valid) { + GValue ev_value = { 0, }; + gint ev_i_value; + + _tracker_db_result_set_get_value (result_set, 1, &ev_value); + + ev_i_value = g_value_get_int (&ev_value); + + if (ev_i_value == g_value_get_int (&ls_value)) { + GValue ev_type = { 0, }; + const gchar *str = g_value_get_string (&ev_type); + + _tracker_db_result_set_get_value (events, 2, &ev_type); + + if (!strcmp (str, "Create")) { + if (m_added == NULL) + m_added = g_array_new (FALSE, TRUE, sizeof (guint32)); + g_array_append_val (m_added, ev_i_value); + } else if (!strcmp (str, "Update")) { + if (m_modified == NULL) + m_modified = g_array_new (FALSE, TRUE, sizeof (guint32)); + g_array_append_val (m_modified, ev_i_value); + } else if (!strcmp (str, "Delete")) { + if (*removed == NULL) + m_removed = g_array_new (FALSE, TRUE, sizeof (guint32)); + g_array_append_val (m_removed, ev_i_value); + } + + g_value_unset (&ev_type); + } + + g_value_unset (&ev_value); + ev_valid = tracker_db_result_set_iter_next (events); + } + + tracker_db_result_set_rewind (events); + + g_value_unset (&ls_value); + ls_valid = tracker_db_result_set_iter_next (result_set); + } + + *added = m_added; + *removed = m_removed; + *modified = m_modified; + + g_object_unref (result_set); +} + +/** * tracker_xesam_live_search_close: * @self: a #TrackerXesamLiveSearch * @error: (null-ok) (out): a #GError Index: src/trackerd/tracker-xesam-live-search.h =================================================================== --- src/trackerd/tracker-xesam-live-search.h (revision 1331) +++ src/trackerd/tracker-xesam-live-search.h (working copy) @@ -24,6 +24,8 @@ #include #include +#include + G_BEGIN_DECLS #define TRACKER_TYPE_XESAM_LIVE_SEARCH (tracker_xesam_live_search_get_type ()) @@ -76,6 +78,11 @@ void tracker_xesam_live_search_emit_hits_modified (TrackerXesamLiveSearch *self, GArray *hit_ids); void tracker_xesam_live_search_emit_done (TrackerXesamLiveSearch *self); +void tracker_xesam_live_search_match_with_events (TrackerXesamLiveSearch *self, + TrackerDBResultSet *events, + GArray **added, + GArray **removed, + GArray **modified); G_END_DECLS Index: src/trackerd/tracker-dbus.c =================================================================== --- src/trackerd/tracker-dbus.c (revision 1331) +++ src/trackerd/tracker-dbus.c (working copy) @@ -237,6 +237,8 @@ return FALSE; } + g_object_set (object, "db-connection", tracker->index_db, NULL); + dbus_g_proxy_add_signal (proxy, "NameOwnerChanged", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); Index: src/trackerd/tracker-dbus-xesam.c =================================================================== --- src/trackerd/tracker-dbus-xesam.c (revision 1331) +++ src/trackerd/tracker-dbus-xesam.c (working copy) @@ -42,18 +42,62 @@ XESAM_LAST_SIGNAL }; +enum { + PROP_0, + PROP_DB_CONNECTION, +}; + +typedef struct { + DBConnection *db_con; +} TrackerDBusXesamPriv; + static GHashTable *sessions = NULL; static guint signals[XESAM_LAST_SIGNAL] = {0}; G_DEFINE_TYPE(TrackerDBusXesam, tracker_dbus_xesam, G_TYPE_OBJECT) +#define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_DBUS_XESAM, TrackerDBusXesamPriv)) + static void xesam_search_finalize (GObject *object) { G_OBJECT_CLASS (tracker_dbus_xesam_parent_class)->finalize (object); } + +void +tracker_dbus_xesam_set_db_connection (TrackerDBusXesam *object, + DBConnection *db_con) +{ + TrackerDBusXesamPriv *priv; + + priv = GET_PRIV (object); + + priv->db_con = db_con; + + g_object_notify (G_OBJECT (object), "db-connection"); +} + static void +xesam_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (param_id) { + case PROP_DB_CONNECTION: + tracker_dbus_xesam_set_db_connection (TRACKER_DBUS_XESAM (object), + g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + }; +} + + + +static void tracker_dbus_xesam_class_init (TrackerDBusXesamClass *klass) { GObjectClass *object_class; @@ -62,6 +106,15 @@ object_class->finalize = xesam_search_finalize; + object_class->set_property = xesam_set_property; + + g_object_class_install_property (object_class, + PROP_DB_CONNECTION, + g_param_spec_pointer ("db-connection", + "DB connection", + "Database connection to use in transactions", + G_PARAM_WRITABLE)); + signals[XESAM_HITS_ADDED] = g_signal_new ("hits-added", G_TYPE_FROM_CLASS (klass), @@ -120,17 +173,23 @@ G_TYPE_NONE, 1, G_TYPE_STRV); + + g_type_class_add_private (object_class, sizeof (TrackerDBusXesamPriv)); } static void tracker_dbus_xesam_init (TrackerDBusXesam *object) { + TrackerDBusXesamPriv *priv = GET_PRIV (object); + priv->db_con = NULL; } TrackerDBusXesam * -tracker_dbus_xesam_new (void) +tracker_dbus_xesam_new (DBConnection *db_con) { - return g_object_new (TRACKER_TYPE_DBUS_XESAM, NULL); + return g_object_new (TRACKER_TYPE_DBUS_XESAM, + "db-connection", db_con, + NULL); } static void Index: src/trackerd/tracker-dbus-xesam.h =================================================================== --- src/trackerd/tracker-dbus-xesam.h (revision 1331) +++ src/trackerd/tracker-dbus-xesam.h (working copy) @@ -56,7 +56,7 @@ GType tracker_dbus_xesam_get_type (void); TrackerDBusXesam * - tracker_dbus_xesam_new (void); + tracker_dbus_xesam_new (DBConnection *db_con); void tracker_dbus_xesam_new_session (TrackerDBusXesam *object, DBusGMethodInvocation *context); void tracker_dbus_xesam_set_property (TrackerDBusXesam *object, @@ -102,6 +102,8 @@ const char *prev_owner, const char *new_owner, TrackerDBusXesam *self); +void tracker_dbus_xesam_set_db_connection (TrackerDBusXesam *object, + DBConnection *db_con); G_END_DECLS Index: src/trackerd/tracker-xesam.c =================================================================== --- src/trackerd/tracker-xesam.c (revision 1331) +++ src/trackerd/tracker-xesam.c (working copy) @@ -88,14 +88,21 @@ while (sessions) { TrackerXesamLiveSearch *search = tracker_xesam_session_get_search (sessions->data, search_id, NULL); if (search) { + + /* Search got a reference added already */ if (search_in) - *search_in = g_object_ref (search); + *search_in = search; + else + g_object_unref (search); + retval = g_object_ref (sessions->data); break; } sessions = g_list_next (sessions); } + g_list_free (sessions); + if (!retval) g_set_error (error, TRACKER_XESAM_ERROR, TRACKER_XESAM_ERROR_SEARCH_ID_NOT_REGISTERED, @@ -114,12 +121,15 @@ while (sessions) { TrackerXesamLiveSearch *search = tracker_xesam_session_get_search (sessions->data, search_id, NULL); if (search) { - retval = g_object_ref (search); + /* Search got a reference added already */ + retval = search; break; } sessions = g_list_next (sessions); } + g_list_free (sessions); + if (!retval) g_set_error (error, TRACKER_XESAM_ERROR, TRACKER_XESAM_ERROR_SEARCH_ID_NOT_REGISTERED, @@ -128,4 +138,88 @@ return retval; } +static gboolean +live_search_handler (gpointer data) +{ + gboolean reason_to_live = FALSE; + GList * sessions = g_hash_table_get_values (tracker->xesam_sessions); + TrackerDBResultSet *result_set; + TrackerDBusXesam *proxy = TRACKER_DBUS_XESAM (tracker_dbus_get_object (TRACKER_TYPE_DBUS_XESAM)); + DBConnection *db_con = NULL; + g_object_get (proxy, "db-connection", &db_con, NULL); + + // lock (indexer) + result_set = tracker_db_get_events (db_con); + // lock (indexer) + + if (result_set /* TODO: If there are events */) { + + reason_to_live = TRUE; + + while (sessions) { + GList *searches = tracker_xesam_session_get_searches (sessions->data); + while (searches) { + GArray *added = NULL, *removed = NULL, *modified = NULL; + TrackerXesamLiveSearch *search = searches->data; + + tracker_xesam_live_search_match_with_events (search, result_set, &added, &removed, &modified); + + if (added && added->len > 0) { + tracker_xesam_live_search_emit_hits_added (search, added->len); + g_array_free (added, TRUE); + } + if (removed && removed->len > 0) { + tracker_xesam_live_search_emit_hits_removed (search, removed); + g_array_free (removed, TRUE); + } + if (modified && modified->len > 0) { + tracker_xesam_live_search_emit_hits_modified (search, modified); + g_array_free (modified, TRUE); + } + + searches = g_list_next (searches); + } + g_list_free (searches); + + sessions = g_list_next (sessions); + } + g_list_free (sessions); + + // lock (indexer) + tracker_db_delete_handled (db_con, result_set); + // unlock (indexer) + } + + g_object_unref (result_set); + + return reason_to_live; +} + +/* Should be set initially to FALSE instead (but then we activate this + * unfinished code)*/ + +static gboolean live_search_handler_running = TRUE; + +static void +live_search_handler_destroy (gpointer data) +{ + live_search_handler_running = FALSE; +} + +void +tracker_xesam_wakeup (guint32 last_id) +{ + // This happens each time a new event is created + + if (!live_search_handler_running) { + live_search_handler_running = TRUE; + g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, + 2000, /* 2 seconds */ + live_search_handler, + NULL, + live_search_handler_destroy); + } +} + + Index: src/trackerd/tracker-xesam.h =================================================================== --- src/trackerd/tracker-xesam.h (revision 1331) +++ src/trackerd/tracker-xesam.h (working copy) @@ -51,5 +51,6 @@ void tracker_xesam_close_session (const gchar *session_id, GError **error); void tracker_xesam_init (void); +void tracker_xesam_wakeup (guint32 last_id); #endif Index: src/trackerd/tracker-db-sqlite.c =================================================================== --- src/trackerd/tracker-db-sqlite.c (revision 1331) +++ src/trackerd/tracker-db-sqlite.c (working copy) @@ -60,6 +60,7 @@ #include "tracker-watch.h" #include "tracker-service-manager.h" #include "tracker-query-tree.h" +#include "tracker-xesam.h" #define MAX_TEXT_BUFFER 65567 #define MAX_COMPRESS_BUFFER 65565 @@ -896,6 +897,7 @@ tracker_db_exec_no_reply (db_con, "ANALYZE"); } + load_sql_file (db_con, "sqlite-temp-tables.sql"); tracker_db_attach_db (db_con, "common"); tracker_db_attach_db (db_con, "cache"); @@ -3245,6 +3247,67 @@ } +TrackerDBResultSet* +tracker_db_get_live_search_results (DBConnection *db_con, const gchar *search_id) +{ + TrackerDBResultSet *result; + result = tracker_exec_proc (db_con->common, "GetXesamLiveSearch", NULL); + return result; +} + +TrackerDBResultSet* +tracker_db_get_events (DBConnection *db_con) +{ + TrackerDBResultSet *result_set, *result; + result = tracker_exec_proc (db_con->common, "GetEvents", NULL); + result_set = tracker_exec_proc (db_con->common, "SetBeingHandled", NULL); + g_object_unref (result_set); + return result; +} + +void +tracker_db_delete_handled (DBConnection *db_con, TrackerDBResultSet *events) +{ + TrackerDBResultSet *result_set; + result_set = tracker_exec_proc (db_con->common, "DeleteHandled", NULL); + g_object_unref (result_set); +} + +static guint32 +tracker_db_create_event (DBConnection *db_con, const char *service_id_str, const char *type) +{ + TrackerDBResultSet *result_set; + char *eid; + int i; + guint32 id = 0; + + result_set = tracker_exec_proc (db_con->common, "GetNewEventID", NULL); + + if (!result_set) { + tracker_error ("ERROR: could not create event - GetNewEventID failed"); + return 0; + } + + tracker_db_result_set_get (result_set, 0, &eid, -1); + i = atoi (eid); + g_free (eid); + i++; + eid = tracker_int_to_string (i); + + result_set = tracker_exec_proc (db_con->common, "UpdateNewEventID", eid, NULL); + g_object_unref (result_set); + + result_set = tracker_exec_proc (db_con, "CreateEvent", eid, service_id_str, type, NULL); + id = tracker_db_interface_sqlite_get_last_insert_id (TRACKER_DB_INTERFACE_SQLITE (db_con->db)); + g_object_unref (result_set); + + tracker_xesam_wakeup (id); + + g_free (eid); + + return id; +} + guint32 tracker_db_create_service (DBConnection *db_con, const char *service, TrackerDBFileInfo *info) { @@ -3361,7 +3424,9 @@ g_free (parent); } + tracker_db_create_event (db_con, sid, "Create"); } + g_free (name); g_free (path); g_free (str_aux); @@ -3549,6 +3614,8 @@ tracker_exec_proc (db_con->common, "DeleteService7", path, name, NULL); tracker_exec_proc (db_con->common, "DeleteService9", path, name, NULL); + tracker_db_create_event (db_con, str_file_id, "Delete"); + g_free (name); g_free (path); } @@ -3638,7 +3705,9 @@ path = g_path_get_dirname (info->uri); tracker_exec_proc (db_con->index, "UpdateFile", str_service_type_id, path, name, info->mime, str_size, str_mtime, str_offset, str_file_id, NULL); - + + tracker_db_create_event (db_con, str_file_id, "Update"); + g_free (str_service_type_id); g_free (str_size); g_free (str_offset); @@ -4248,6 +4317,8 @@ /* update db so that fileID reflects new uri */ tracker_exec_proc (db_con, "UpdateFileMove", path, name, str_file_id, NULL); + tracker_db_create_event (db_con, str_file_id, "Update"); + /* update File:Path and File:Filename metadata */ tracker_db_set_single_metadata (db_con, "Files", str_file_id, "File:Path", path, FALSE); tracker_db_set_single_metadata (db_con, "Files", str_file_id, "File:Name", name, FALSE); Index: src/trackerd/tracker-db-sqlite.h =================================================================== --- src/trackerd/tracker-db-sqlite.h (revision 1331) +++ src/trackerd/tracker-db-sqlite.h (working copy) @@ -344,5 +344,10 @@ const gchar *option, gint value); gboolean tracker_db_integrity_check (DBConnection *db_con); +TrackerDBResultSet *tracker_db_get_events (DBConnection *db_con); +void tracker_db_delete_handled (DBConnection *db_con, + TrackerDBResultSet *events); +TrackerDBResultSet *tracker_db_get_live_search_results (DBConnection *db_con, + const gchar *search_id); #endif Index: data/sqlite-stored-procs.sql =================================================================== --- data/sqlite-stored-procs.sql (revision 1331) +++ data/sqlite-stored-procs.sql (working copy) @@ -24,7 +24,16 @@ GetNewID SELECT OptionValue FROM Options WHERE OptionKey = 'Sequence'; UpdateNewID UPDATE Options set OptionValue = ? WHERE OptionKey = 'Sequence'; +CreateEvent INSERT INTO Events (ID, ServiceID, EventType) VALUES (?,?,?); +DeleteHandled DELETE FROM Events WHERE BeingHandled = 1; +GetEvents SELECT ID, ServiceID, EventType FROM Events WHERE BeingHandled = 0; +SetBeingHandled UPDATE Events SET BeingHandled = 1; +GetXesamLiveSearch SELECT ServiceID FROM XesamLiveSearches WHERE SearchID = ?; + +GetNewEventID SELECT OptionValue FROM Options WHERE OptionKey = 'EventSequence'; +UpdateNewEventID UPDATE Options set OptionValue = ? WHERE OptionKey = 'EventSequence'; + GetUpdateCount SELECT OptionValue FROM Options WHERE OptionKey = 'UpdateCount'; SetUpdateCount UPDATE Options set OptionValue = ? WHERE OptionKey = 'UpdateCount'; @@ -33,6 +42,7 @@ CreateService INSERT INTO Services (ID, Path, Name, ServiceTypeID, Mime, Size, IsDirectory, IsLink, Offset, IndexTime, AuxilaryID) VALUES (?,?,?,?,?,?,?,?,?,?,?); + GetServiceID SELECT ID, IndexTime, IsDirectory, ServiceTypeID FROM Services WHERE Path = ? AND Name = ?; SelectFileChild SELECT ID, Path, Name, IsDirectory FROM Services WHERE Path = ?; Index: data/sqlite-tracker.sql =================================================================== --- data/sqlite-tracker.sql (revision 1331) +++ data/sqlite-tracker.sql (working copy) @@ -6,6 +6,7 @@ insert Into Options (OptionKey, OptionValue) values ('DBVersion', '20'); insert Into Options (OptionKey, OptionValue) values ('Sequence', '1'); +insert Into Options (OptionKey, OptionValue) values ('EventSequence', '1'); insert Into Options (OptionKey, OptionValue) values ('UpdateCount', '0'); Index: data/Makefile.am =================================================================== --- data/Makefile.am (revision 1331) +++ data/Makefile.am (working copy) @@ -19,7 +19,8 @@ sqlite-stored-procs.sql \ sqlite-service.sql \ sqlite-service-types.sql \ - sqlite-metadata.sql + sqlite-metadata.sql \ + sqlite-temp-tables.sql servicedir = $(DBUS_SERVICES_DIR) service_in_files = tracker.service.in Index: data/sqlite-temp-tables.sql =================================================================== --- data/sqlite-temp-tables.sql (revision 0) +++ data/sqlite-temp-tables.sql (revision 0) @@ -0,0 +1,14 @@ +CREATE TEMPORARY TABLE Events +( + ID Integer primary key not null, + ServiceID Integer not null, + BeingHandled Integer default 0, + EventType Text +); + +CREATE TEMPORARY TABLE XesamLiveSearches +( + ID Integer primary key not null, + ServiceID Integer not null, + SearchID Text +);