~ubuntu-branches/ubuntu/oneiric/tracker/oneiric

« back to all changes in this revision

Viewing changes to src/tracker-writeback/tracker-writeback.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl
  • Date: 2011-08-26 00:26:14 UTC
  • mfrom: (4.3.17 sid)
  • Revision ID: package-import@ubuntu.com-20110826002614-4qjfs9jhh5gs4p13
Tags: 0.10.24-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (C) 2009, Nokia <ivan.frade@nokia.com>
 
2
 * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
3
3
 *
4
4
 * This library is free software; you can redistribute it and/or
5
5
 * modify it under the terms of the GNU General Public
17
17
 * Boston, MA  02110-1301, USA.
18
18
 */
19
19
 
20
 
#include "config.h"
21
 
 
22
20
#include "tracker-writeback.h"
23
 
 
24
 
G_DEFINE_ABSTRACT_TYPE (TrackerWriteback, tracker_writeback, G_TYPE_OBJECT)
25
 
 
26
 
static TrackerMinerManager *manager = NULL;
27
 
 
28
 
static void
29
 
tracker_writeback_class_init (TrackerWritebackClass *klass)
30
 
{
31
 
}
32
 
 
33
 
static void
34
 
tracker_writeback_init (TrackerWriteback *writeback)
35
 
{
36
 
}
37
 
 
38
 
gboolean
39
 
tracker_writeback_update_metadata (TrackerWriteback        *writeback,
40
 
                                   GPtrArray               *values,
41
 
                                   TrackerSparqlConnection *connection)
42
 
{
43
 
        g_return_val_if_fail (TRACKER_IS_WRITEBACK (writeback), FALSE);
44
 
        g_return_val_if_fail (values != NULL, FALSE);
45
 
 
46
 
        if (TRACKER_WRITEBACK_GET_CLASS (writeback)->update_metadata) {
47
 
                return TRACKER_WRITEBACK_GET_CLASS (writeback)->update_metadata (writeback, values, connection);
48
 
        }
49
 
 
50
 
        return FALSE;
51
 
}
52
 
 
53
 
TrackerMinerManager*
54
 
tracker_writeback_get_miner_manager (void)
55
 
{
56
 
        if (!manager) {
57
 
                manager = tracker_miner_manager_new ();
58
 
        }
59
 
 
60
 
        return manager;
 
21
#include "tracker-writeback-module.h"
 
22
 
 
23
#include <libtracker-common/tracker-common.h>
 
24
#include <libtracker-miner/tracker-miner.h>
 
25
#include <libtracker-sparql/tracker-sparql.h>
 
26
 
 
27
#include <gio/gio.h>
 
28
 
 
29
#ifdef STAYALIVE_ENABLE_TRACE
 
30
#warning Stayalive traces enabled
 
31
#endif /* STAYALIVE_ENABLE_TRACE */
 
32
 
 
33
#define THREAD_ENABLE_TRACE
 
34
 
 
35
#ifdef THREAD_ENABLE_TRACE
 
36
#warning Controller thread traces enabled
 
37
#endif /* THREAD_ENABLE_TRACE */
 
38
 
 
39
typedef struct {
 
40
        TrackerController *controller;
 
41
        GCancellable *cancellable;
 
42
        GDBusMethodInvocation *invocation;
 
43
        TrackerDBusRequest *request;
 
44
        gchar *subject;
 
45
        GPtrArray *results;
 
46
        TrackerSparqlConnection *connection;
 
47
        TrackerWriteback *writeback;
 
48
        guint cancel_id;
 
49
} WritebackData;
 
50
 
 
51
typedef struct {
 
52
        GMainContext *context;
 
53
        GMainLoop *main_loop;
 
54
 
 
55
        TrackerStorage *storage;
 
56
 
 
57
        GDBusConnection *d_connection;
 
58
        GDBusNodeInfo *introspection_data;
 
59
        guint registration_id;
 
60
        guint bus_name_id;
 
61
 
 
62
        GList *ongoing_tasks;
 
63
 
 
64
        guint shutdown_timeout;
 
65
        GSource *shutdown_source;
 
66
 
 
67
        GCond *initialization_cond;
 
68
        GMutex *initialization_mutex, *mutex;
 
69
        GError *initialization_error;
 
70
 
 
71
        guint initialized : 1;
 
72
 
 
73
        GHashTable *modules;
 
74
        TrackerSparqlConnection *connection;
 
75
        WritebackData *current;
 
76
} TrackerControllerPrivate;
 
77
 
 
78
#define TRACKER_WRITEBACK_SERVICE   "org.freedesktop.Tracker1.Writeback"
 
79
#define TRACKER_WRITEBACK_PATH      "/org/freedesktop/Tracker1/Writeback"
 
80
#define TRACKER_WRITEBACK_INTERFACE "org.freedesktop.Tracker1.Writeback"
 
81
 
 
82
static const gchar *introspection_xml =
 
83
        "<node>"
 
84
        "  <interface name='org.freedesktop.Tracker1.Writeback'>"
 
85
        "    <method name='GetPid'>"
 
86
        "      <arg type='i' name='value' direction='out' />"
 
87
        "    </method>"
 
88
        "    <method name='PerformWriteback'>"
 
89
        "      <arg type='s' name='subject' direction='in' />"
 
90
        "      <arg type='as' name='rdf_types' direction='in' />"
 
91
        "      <arg type='aas' name='results' direction='in' />"
 
92
        "    </method>"
 
93
        "    <method name='CancelTasks'>"
 
94
        "      <arg type='as' name='subjects' direction='in' />"
 
95
        "    </method>"
 
96
        "  </interface>"
 
97
        "</node>";
 
98
 
 
99
enum {
 
100
        PROP_0,
 
101
        PROP_SHUTDOWN_TIMEOUT,
 
102
};
 
103
 
 
104
static void     tracker_controller_initable_iface_init  (GInitableIface     *iface);
 
105
static gboolean tracker_controller_dbus_start           (TrackerController  *controller,
 
106
                                                         GError            **error);
 
107
static void     tracker_controller_dbus_stop            (TrackerController  *controller);
 
108
static gboolean tracker_controller_start                (TrackerController  *controller,
 
109
                                                         GError            **error);
 
110
 
 
111
G_DEFINE_TYPE_WITH_CODE (TrackerController, tracker_controller, G_TYPE_OBJECT,
 
112
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
 
113
                                                tracker_controller_initable_iface_init));
 
114
 
 
115
static gboolean
 
116
tracker_controller_initable_init (GInitable     *initable,
 
117
                                  GCancellable  *cancellable,
 
118
                                  GError       **error)
 
119
{
 
120
        return tracker_controller_start (TRACKER_CONTROLLER (initable), error);
 
121
}
 
122
 
 
123
static void
 
124
tracker_controller_initable_iface_init (GInitableIface *iface)
 
125
{
 
126
        iface->init = tracker_controller_initable_init;
 
127
}
 
128
 
 
129
static void
 
130
tracker_controller_finalize (GObject *object)
 
131
{
 
132
        TrackerControllerPrivate *priv;
 
133
        TrackerController *controller;
 
134
 
 
135
        controller = TRACKER_CONTROLLER (object);
 
136
        priv = controller->priv;
 
137
 
 
138
        if (priv->shutdown_source) {
 
139
                g_source_destroy (priv->shutdown_source);
 
140
                priv->shutdown_source = NULL;
 
141
        }
 
142
 
 
143
        tracker_controller_dbus_stop (controller);
 
144
 
 
145
        g_object_unref (priv->storage);
 
146
        g_hash_table_unref (priv->modules);
 
147
 
 
148
        g_main_loop_unref (priv->main_loop);
 
149
        g_main_context_unref (priv->context);
 
150
 
 
151
        g_cond_free (priv->initialization_cond);
 
152
        g_mutex_free (priv->initialization_mutex);
 
153
        g_mutex_free (priv->mutex);
 
154
 
 
155
        G_OBJECT_CLASS (tracker_controller_parent_class)->finalize (object);
 
156
}
 
157
 
 
158
static void
 
159
tracker_controller_get_property (GObject    *object,
 
160
                                 guint       param_id,
 
161
                                 GValue     *value,
 
162
                                 GParamSpec *pspec)
 
163
{
 
164
        TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
 
165
 
 
166
        switch (param_id) {
 
167
        case PROP_SHUTDOWN_TIMEOUT:
 
168
                g_value_set_uint (value, priv->shutdown_timeout);
 
169
                break;
 
170
        }
 
171
}
 
172
 
 
173
static void
 
174
tracker_controller_set_property (GObject      *object,
 
175
                                 guint         param_id,
 
176
                                 const GValue *value,
 
177
                                 GParamSpec   *pspec)
 
178
{
 
179
        TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
 
180
 
 
181
        switch (param_id) {
 
182
        case PROP_SHUTDOWN_TIMEOUT:
 
183
                priv->shutdown_timeout = g_value_get_uint (value);
 
184
                break;
 
185
        }
 
186
}
 
187
 
 
188
static void
 
189
tracker_controller_class_init (TrackerControllerClass *klass)
 
190
{
 
191
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
192
 
 
193
        object_class->finalize = tracker_controller_finalize;
 
194
        object_class->get_property = tracker_controller_get_property;
 
195
        object_class->set_property = tracker_controller_set_property;
 
196
 
 
197
        g_object_class_install_property (object_class,
 
198
                                         PROP_SHUTDOWN_TIMEOUT,
 
199
                                         g_param_spec_uint ("shutdown-timeout",
 
200
                                                            "Shutdown timeout",
 
201
                                                            "Shutdown timeout, 0 to disable",
 
202
                                                            0, 1000, 0,
 
203
                                                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
204
 
 
205
        g_type_class_add_private (object_class, sizeof (TrackerControllerPrivate));
 
206
}
 
207
 
 
208
static void
 
209
task_cancellable_cancelled_cb (GCancellable  *cancellable,
 
210
                               WritebackData *data)
 
211
{
 
212
        TrackerControllerPrivate *priv;
 
213
 
 
214
        priv = data->controller->priv;
 
215
 
 
216
        g_mutex_lock (priv->mutex);
 
217
 
 
218
        if (priv->current == data) {
 
219
                g_message ("Cancelled writeback task for '%s' was currently being "
 
220
                           "processed, _exit()ing immediately",
 
221
                           data->subject);
 
222
                _exit (0);
 
223
        }
 
224
 
 
225
        g_mutex_unlock (priv->mutex);
 
226
}
 
227
 
 
228
 
 
229
static WritebackData *
 
230
writeback_data_new (TrackerController       *controller,
 
231
                    TrackerWriteback        *writeback,
 
232
                    TrackerSparqlConnection *connection,
 
233
                    const gchar             *subject,
 
234
                    GPtrArray               *results,
 
235
                    GDBusMethodInvocation   *invocation,
 
236
                    TrackerDBusRequest      *request)
 
237
{
 
238
        WritebackData *data;
 
239
 
 
240
        data = g_slice_new (WritebackData);
 
241
        data->cancellable = g_cancellable_new ();
 
242
        data->controller = g_object_ref (controller);
 
243
        data->subject = g_strdup (subject);
 
244
        data->results = g_ptr_array_ref (results);
 
245
        data->invocation = invocation;
 
246
        data->connection = g_object_ref (connection);
 
247
        data->writeback = g_object_ref (writeback);
 
248
        data->request = request;
 
249
 
 
250
        data->cancel_id = g_cancellable_connect (data->cancellable,
 
251
                                                 G_CALLBACK (task_cancellable_cancelled_cb),
 
252
                                                 data, NULL);
 
253
 
 
254
        return data;
 
255
}
 
256
 
 
257
static void
 
258
writeback_data_free (WritebackData *data)
 
259
{
 
260
        /* We rely on data->invocation being freed through
 
261
         * the g_dbus_method_invocation_return_* methods
 
262
         */
 
263
        g_cancellable_disconnect (data->cancellable, data->cancel_id);
 
264
        g_free (data->subject);
 
265
        g_object_unref (data->connection);
 
266
        g_object_unref (data->writeback);
 
267
        g_ptr_array_unref (data->results);
 
268
        g_object_unref (data->cancellable);
 
269
        g_slice_free (WritebackData, data);
 
270
}
 
271
 
 
272
static void
 
273
cancel_tasks (TrackerController *controller,
 
274
              const gchar       *subject,
 
275
              GFile             *file)
 
276
{
 
277
        TrackerControllerPrivate *priv;
 
278
        GList *elem;
 
279
 
 
280
        priv = controller->priv;
 
281
 
 
282
        for (elem = priv->ongoing_tasks; elem; elem = elem->next) {
 
283
                WritebackData *data = elem->data;
 
284
 
 
285
                if (g_strcmp0 (subject, data->subject) == 0) {
 
286
                        g_message ("Cancelling not yet processed task ('%s')",
 
287
                                   data->subject);
 
288
                        g_cancellable_cancel (data->cancellable);
 
289
                }
 
290
 
 
291
                if (file) {
 
292
                        guint i;
 
293
                        for (i = 0; i < data->results->len; i++) {
 
294
                                GStrv row = g_ptr_array_index (data->results, i);
 
295
                                if (row[0] != NULL) {
 
296
                                        GFile *task_file;
 
297
                                        task_file = g_file_new_for_uri (row[0]);
 
298
                                        if (g_file_equal (task_file, file) ||
 
299
                                            g_file_has_prefix (task_file, file)) {
 
300
                                                /* Mount path contains some file being processed */
 
301
                                                g_message ("Cancelling task ('%s')", row[0]);
 
302
                                                g_cancellable_cancel (data->cancellable);
 
303
                                        }
 
304
                                        g_object_unref (task_file);
 
305
                                }
 
306
                        }
 
307
                }
 
308
        }
 
309
}
 
310
 
 
311
static void
 
312
mount_point_removed_cb (TrackerStorage *storage,
 
313
                        const gchar    *uuid,
 
314
                        const gchar    *mount_point,
 
315
                        gpointer        user_data)
 
316
{
 
317
        GFile *mount_file;
 
318
 
 
319
        mount_file = g_file_new_for_path (mount_point);
 
320
        cancel_tasks (TRACKER_CONTROLLER (user_data), NULL, mount_file);
 
321
        g_object_unref (mount_file);
 
322
}
 
323
 
 
324
static gboolean
 
325
reset_shutdown_timeout_cb (gpointer user_data)
 
326
{
 
327
        TrackerControllerPrivate *priv;
 
328
 
 
329
#ifdef STAYALIVE_ENABLE_TRACE
 
330
        g_debug ("Stayalive --- time has expired");
 
331
#endif /* STAYALIVE_ENABLE_TRACE */
 
332
 
 
333
        g_message ("Shutting down due to no activity");
 
334
 
 
335
        priv = TRACKER_CONTROLLER (user_data)->priv;
 
336
        g_main_loop_quit (priv->main_loop);
 
337
 
 
338
        return FALSE;
 
339
}
 
340
 
 
341
static void
 
342
reset_shutdown_timeout (TrackerController *controller)
 
343
{
 
344
        TrackerControllerPrivate *priv;
 
345
        GSource *source;
 
346
 
 
347
        priv = controller->priv;
 
348
 
 
349
        if (priv->shutdown_timeout == 0) {
 
350
                return;
 
351
        }
 
352
 
 
353
#ifdef STAYALIVE_ENABLE_TRACE
 
354
        g_debug ("Stayalive --- (Re)setting timeout");
 
355
#endif /* STAYALIVE_ENABLE_TRACE */
 
356
 
 
357
        if (priv->shutdown_source) {
 
358
                g_source_destroy (priv->shutdown_source);
 
359
                priv->shutdown_source = NULL;
 
360
        }
 
361
 
 
362
        source = g_timeout_source_new_seconds (priv->shutdown_timeout);
 
363
        g_source_set_callback (source,
 
364
                               reset_shutdown_timeout_cb,
 
365
                               controller, NULL);
 
366
 
 
367
        g_source_attach (source, priv->context);
 
368
        priv->shutdown_source = source;
 
369
}
 
370
 
 
371
static void
 
372
tracker_controller_init (TrackerController *controller)
 
373
{
 
374
        TrackerControllerPrivate *priv;
 
375
 
 
376
        priv = controller->priv = G_TYPE_INSTANCE_GET_PRIVATE (controller,
 
377
                                                               TRACKER_TYPE_CONTROLLER,
 
378
                                                               TrackerControllerPrivate);
 
379
 
 
380
        priv->context = g_main_context_new ();
 
381
        priv->main_loop = g_main_loop_new (priv->context, FALSE);
 
382
 
 
383
        priv->storage = tracker_storage_new ();
 
384
        g_signal_connect (priv->storage, "mount-point-removed",
 
385
                          G_CALLBACK (mount_point_removed_cb), controller);
 
386
 
 
387
        priv->initialization_cond = g_cond_new ();
 
388
        priv->initialization_mutex = g_mutex_new ();
 
389
        priv->mutex = g_mutex_new ();
 
390
}
 
391
 
 
392
static void
 
393
handle_method_call_get_pid (TrackerController     *controller,
 
394
                            GDBusMethodInvocation *invocation,
 
395
                            GVariant              *parameters)
 
396
{
 
397
        TrackerDBusRequest *request;
 
398
        pid_t value;
 
399
 
 
400
        request = tracker_g_dbus_request_begin (invocation,
 
401
                                                "%s()",
 
402
                                                __FUNCTION__);
 
403
 
 
404
        reset_shutdown_timeout (controller);
 
405
        value = getpid ();
 
406
        tracker_dbus_request_debug (request,
 
407
                                    "PID is %d",
 
408
                                    value);
 
409
 
 
410
        tracker_dbus_request_end (request, NULL);
 
411
 
 
412
        g_dbus_method_invocation_return_value (invocation,
 
413
                                               g_variant_new ("(i)", (gint) value));
 
414
}
 
415
 
 
416
static gboolean
 
417
perform_writeback_cb (gpointer user_data)
 
418
{
 
419
        TrackerControllerPrivate *priv;
 
420
        WritebackData *data;
 
421
 
 
422
        data = user_data;
 
423
        priv = data->controller->priv;
 
424
        priv->ongoing_tasks = g_list_remove (priv->ongoing_tasks, data);
 
425
        g_dbus_method_invocation_return_value (data->invocation, NULL);
 
426
        tracker_dbus_request_end (data->request, NULL);
 
427
 
 
428
        g_mutex_lock (priv->mutex);
 
429
        priv->current = NULL;
 
430
        g_mutex_unlock (priv->mutex);
 
431
 
 
432
        writeback_data_free (data);
 
433
 
 
434
        return FALSE;
 
435
}
 
436
 
 
437
static gboolean
 
438
sparql_rdf_types_match (const gchar * const *module_types,
 
439
                        const gchar * const *rdf_types)
 
440
{
 
441
        guint n;
 
442
 
 
443
        for (n = 0; rdf_types[n] != NULL; n++) {
 
444
                guint i;
 
445
 
 
446
                for (i = 0; module_types[i] != NULL; i++) {
 
447
                        if (g_strcmp0 (module_types[i], rdf_types[n]) == 0) {
 
448
                                return TRUE;
 
449
                        }
 
450
                }
 
451
        }
 
452
 
 
453
        return FALSE;
 
454
}
 
455
 
 
456
static gboolean
 
457
io_writeback_job (GIOSchedulerJob *job,
 
458
                  GCancellable    *cancellable,
 
459
                  gpointer         user_data)
 
460
{
 
461
        WritebackData *data = user_data;
 
462
        TrackerControllerPrivate *priv = data->controller->priv;
 
463
 
 
464
        g_mutex_lock (priv->mutex);
 
465
        priv->current = data;
 
466
        g_mutex_unlock (priv->mutex);
 
467
 
 
468
        tracker_writeback_update_metadata (data->writeback,
 
469
                                           data->results,
 
470
                                           data->connection,
 
471
                                           data->cancellable);
 
472
 
 
473
        g_idle_add (perform_writeback_cb, data);
 
474
 
 
475
        return FALSE;
 
476
}
 
477
 
 
478
static void
 
479
handle_method_call_perform_writeback (TrackerController     *controller,
 
480
                                      GDBusMethodInvocation *invocation,
 
481
                                      GVariant              *parameters)
 
482
{
 
483
        TrackerControllerPrivate *priv;
 
484
        TrackerDBusRequest *request;
 
485
        const gchar *subject;
 
486
        GPtrArray *results = NULL;
 
487
        GHashTableIter iter;
 
488
        gpointer key, value;
 
489
        GVariantIter *iter1, *iter2, *iter3;
 
490
        GArray *rdf_types_array;
 
491
        GStrv rdf_types;
 
492
        gchar *rdf_type = NULL;
 
493
 
 
494
        priv = controller->priv;
 
495
 
 
496
        results = g_ptr_array_new_with_free_func ((GDestroyNotify) g_strfreev);
 
497
        g_variant_get (parameters, "(&sasaas)", &subject, &iter1, &iter2);
 
498
 
 
499
        rdf_types_array = g_array_new (TRUE, TRUE, sizeof (gchar *));
 
500
        while (g_variant_iter_loop (iter1, "&s", &rdf_type)) {
 
501
                g_array_append_val (rdf_types_array, rdf_type);
 
502
        }
 
503
 
 
504
        rdf_types = (GStrv) rdf_types_array->data;
 
505
        g_array_free (rdf_types_array, FALSE);
 
506
 
 
507
        while (g_variant_iter_loop (iter2, "as", &iter3)) {
 
508
                GArray *row_array = g_array_new (TRUE, TRUE, sizeof (gchar *));
 
509
                gchar *cell = NULL;
 
510
 
 
511
                while (g_variant_iter_loop (iter3, "&s", &cell)) {
 
512
                        g_array_append_val (row_array, cell);
 
513
                }
 
514
 
 
515
                g_ptr_array_add (results, row_array->data);
 
516
                g_array_free (row_array, FALSE);
 
517
        }
 
518
 
 
519
        g_variant_iter_free (iter1);
 
520
        g_variant_iter_free (iter2);
 
521
 
 
522
        reset_shutdown_timeout (controller);
 
523
        request = tracker_dbus_request_begin (NULL, "%s (%s)", __FUNCTION__, subject);
 
524
 
 
525
        g_hash_table_iter_init (&iter, priv->modules);
 
526
 
 
527
        while (g_hash_table_iter_next (&iter, &key, &value)) {
 
528
                TrackerWritebackModule *module;
 
529
                const gchar * const *module_types;
 
530
 
 
531
                module = value;
 
532
                module_types = tracker_writeback_module_get_rdf_types (module);
 
533
 
 
534
                if (sparql_rdf_types_match (module_types, (const gchar * const *) rdf_types)) {
 
535
                        WritebackData *data;
 
536
                        TrackerWriteback *writeback;
 
537
 
 
538
                        g_message ("  Updating metadata for subject:'%s' using module:'%s'",
 
539
                                   subject,
 
540
                                   module->name);
 
541
 
 
542
                        writeback = tracker_writeback_module_create (module);
 
543
                        data = writeback_data_new (controller,
 
544
                                                   writeback,
 
545
                                                   priv->connection,
 
546
                                                   subject,
 
547
                                                   results,
 
548
                                                   invocation,
 
549
                                                   request);
 
550
 
 
551
                        g_io_scheduler_push_job (io_writeback_job, data, NULL, 0,
 
552
                                                 data->cancellable);
 
553
 
 
554
                        g_object_unref (writeback);
 
555
                }
 
556
        }
 
557
 
 
558
        g_free (rdf_types);
 
559
}
 
560
 
 
561
static void
 
562
handle_method_call_cancel_tasks (TrackerController     *controller,
 
563
                                 GDBusMethodInvocation *invocation,
 
564
                                 GVariant              *parameters)
 
565
{
 
566
        TrackerDBusRequest *request;
 
567
        gchar **subjects;
 
568
        gint i;
 
569
 
 
570
#ifdef THREAD_ENABLE_TRACE
 
571
        g_debug ("Thread:%p (Controller) --> Got Tasks cancellation request",
 
572
                 g_thread_self ());
 
573
#endif /* THREAD_ENABLE_TRACE */
 
574
 
 
575
 
 
576
        g_variant_get (parameters, "(^as)", &subjects);
 
577
 
 
578
        request = tracker_dbus_request_begin (NULL, "%s (%s, ...)", __FUNCTION__, subjects[0]);
 
579
 
 
580
        for (i = 0; subjects[i] != NULL; i++) {
 
581
                cancel_tasks (controller, subjects[i], NULL);
 
582
        }
 
583
 
 
584
        g_strfreev (subjects);
 
585
        tracker_dbus_request_end (request, NULL);
 
586
        g_dbus_method_invocation_return_value (invocation, NULL);
 
587
}
 
588
 
 
589
static void
 
590
handle_method_call (GDBusConnection       *connection,
 
591
                    const gchar           *sender,
 
592
                    const gchar           *object_path,
 
593
                    const gchar           *interface_name,
 
594
                    const gchar           *method_name,
 
595
                    GVariant              *parameters,
 
596
                    GDBusMethodInvocation *invocation,
 
597
                    gpointer               user_data)
 
598
{
 
599
        TrackerController *controller = user_data;
 
600
 
 
601
        if (g_strcmp0 (method_name, "GetPid") == 0) {
 
602
                handle_method_call_get_pid (controller, invocation, parameters);
 
603
        } else if (g_strcmp0 (method_name, "PerformWriteback") == 0) {
 
604
                handle_method_call_perform_writeback (controller, invocation, parameters);
 
605
        } else if (g_strcmp0 (method_name, "CancelTasks") == 0) {
 
606
                handle_method_call_cancel_tasks (controller, invocation, parameters);
 
607
        } else {
 
608
                g_warning ("Unknown method '%s' called", method_name);
 
609
        }
 
610
}
 
611
 
 
612
static void
 
613
controller_notify_main_thread (TrackerController *controller,
 
614
                               GError            *error)
 
615
{
 
616
        TrackerControllerPrivate *priv;
 
617
 
 
618
        priv = controller->priv;
 
619
 
 
620
        g_mutex_lock (priv->initialization_mutex);
 
621
 
 
622
        priv->initialized = TRUE;
 
623
        priv->initialization_error = error;
 
624
 
 
625
        /* Notify about the initialization */
 
626
        g_cond_signal (priv->initialization_cond);
 
627
 
 
628
        g_mutex_unlock (priv->initialization_mutex);
 
629
}
 
630
 
 
631
static void
 
632
bus_name_acquired_cb (GDBusConnection *connection,
 
633
                      const gchar     *name,
 
634
                      gpointer         user_data)
 
635
{
 
636
        controller_notify_main_thread (TRACKER_CONTROLLER (user_data), NULL);
 
637
}
 
638
 
 
639
static void
 
640
bus_name_vanished_cb (GDBusConnection *connection,
 
641
                      const gchar     *name,
 
642
                      gpointer         user_data)
 
643
{
 
644
        TrackerController *controller;
 
645
        TrackerControllerPrivate *priv;
 
646
 
 
647
        controller = user_data;
 
648
        priv = controller->priv;
 
649
 
 
650
        if (!priv->initialized) {
 
651
                GError *error;
 
652
 
 
653
                error = g_error_new_literal (TRACKER_DBUS_ERROR, 0,
 
654
                                             "Could not acquire bus name, "
 
655
                                             "perhaps it's already taken?");
 
656
                controller_notify_main_thread (controller, error);
 
657
        } else {
 
658
                /* We're already in control of the program
 
659
                 * lifetime, so just quit the mainloop
 
660
                 */
 
661
                g_main_loop_quit (priv->main_loop);
 
662
        }
 
663
}
 
664
 
 
665
static gboolean
 
666
tracker_controller_dbus_start (TrackerController   *controller,
 
667
                               GError             **error)
 
668
{
 
669
        TrackerControllerPrivate *priv;
 
670
        GError *err = NULL;
 
671
        GDBusInterfaceVTable interface_vtable = {
 
672
                handle_method_call,
 
673
                NULL, NULL
 
674
        };
 
675
 
 
676
        priv = controller->priv;
 
677
 
 
678
        priv->connection = tracker_sparql_connection_get (NULL, &err);
 
679
 
 
680
        if (!priv->connection) {
 
681
                g_propagate_error (error, err);
 
682
                return FALSE;
 
683
        }
 
684
 
 
685
        priv->d_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err);
 
686
 
 
687
        if (!priv->d_connection) {
 
688
                g_propagate_error (error, err);
 
689
                return FALSE;
 
690
        }
 
691
 
 
692
        priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &err);
 
693
        if (!priv->introspection_data) {
 
694
                g_propagate_error (error, err);
 
695
                return FALSE;
 
696
        }
 
697
 
 
698
        g_message ("Registering D-Bus object...");
 
699
        g_message ("  Path:'" TRACKER_WRITEBACK_PATH "'");
 
700
        g_message ("  Object Type:'%s'", G_OBJECT_TYPE_NAME (controller));
 
701
 
 
702
        priv->bus_name_id =
 
703
                g_bus_own_name_on_connection (priv->d_connection,
 
704
                                              TRACKER_WRITEBACK_SERVICE,
 
705
                                              G_BUS_NAME_OWNER_FLAGS_NONE,
 
706
                                              bus_name_acquired_cb,
 
707
                                              bus_name_vanished_cb,
 
708
                                              controller, NULL);
 
709
 
 
710
        priv->registration_id =
 
711
                g_dbus_connection_register_object (priv->d_connection,
 
712
                                                   TRACKER_WRITEBACK_PATH,
 
713
                                                   priv->introspection_data->interfaces[0],
 
714
                                                   &interface_vtable,
 
715
                                                   controller,
 
716
                                                   NULL,
 
717
                                                   &err);
 
718
 
 
719
        if (err) {
 
720
                g_propagate_error (error, err);
 
721
                return FALSE;
 
722
        }
 
723
 
 
724
        return TRUE;
 
725
}
 
726
 
 
727
static void
 
728
tracker_controller_dbus_stop (TrackerController *controller)
 
729
{
 
730
        TrackerControllerPrivate *priv;
 
731
 
 
732
        priv = controller->priv;
 
733
 
 
734
        if (priv->registration_id != 0) {
 
735
                g_dbus_connection_unregister_object (priv->d_connection,
 
736
                                                     priv->registration_id);
 
737
        }
 
738
 
 
739
        if (priv->bus_name_id != 0) {
 
740
                g_bus_unown_name (priv->bus_name_id);
 
741
        }
 
742
 
 
743
        if (priv->introspection_data) {
 
744
                g_dbus_node_info_unref (priv->introspection_data);
 
745
        }
 
746
 
 
747
        if (priv->d_connection) {
 
748
                g_object_unref (priv->d_connection);
 
749
        }
 
750
 
 
751
        if (priv->connection) {
 
752
                g_object_unref (priv->connection);
 
753
        }
 
754
}
 
755
 
 
756
TrackerController *
 
757
tracker_controller_new (guint             shutdown_timeout,
 
758
                        GError          **error)
 
759
{
 
760
        return g_initable_new (TRACKER_TYPE_CONTROLLER,
 
761
                               NULL, error,
 
762
                               "shutdown-timeout", shutdown_timeout,
 
763
                               NULL);
 
764
}
 
765
 
 
766
static gpointer
 
767
tracker_controller_thread_func (gpointer user_data)
 
768
{
 
769
        TrackerController *controller;
 
770
        TrackerControllerPrivate *priv;
 
771
        GError *error = NULL;
 
772
 
 
773
#ifdef THREAD_ENABLE_TRACE
 
774
        g_debug ("Thread:%p (Controller) --- Created, dispatching...",
 
775
                 g_thread_self ());
 
776
#endif /* THREAD_ENABLE_TRACE */
 
777
 
 
778
        controller = user_data;
 
779
        priv = controller->priv;
 
780
        g_main_context_push_thread_default (priv->context);
 
781
 
 
782
        reset_shutdown_timeout (controller);
 
783
 
 
784
        if (!tracker_controller_dbus_start (controller, &error)) {
 
785
                /* Error has been filled in, so we return
 
786
                 * in this thread. The main thread will be
 
787
                 * notified about the error and exit.
 
788
                 */
 
789
                controller_notify_main_thread (controller, error);
 
790
                return NULL;
 
791
        }
 
792
 
 
793
        g_main_loop_run (priv->main_loop);
 
794
 
 
795
#ifdef THREAD_ENABLE_TRACE
 
796
        g_debug ("Thread:%p (Controller) --- Shutting down...",
 
797
                 g_thread_self ());
 
798
#endif /* THREAD_ENABLE_TRACE */
 
799
 
 
800
        g_object_unref (controller);
 
801
 
 
802
        /* This is where we exit, be it
 
803
         * either through umount events on monitored
 
804
         * files' volumes or the timeout being reached
 
805
         */
 
806
        exit (0);
 
807
        return NULL;
 
808
}
 
809
 
 
810
static gboolean
 
811
tracker_controller_start (TrackerController  *controller,
 
812
                          GError            **error)
 
813
{
 
814
        TrackerControllerPrivate *priv;
 
815
        GList *modules;
 
816
 
 
817
        priv = controller->priv;
 
818
 
 
819
        priv->modules = g_hash_table_new_full (g_str_hash,
 
820
                                               g_str_equal,
 
821
                                               (GDestroyNotify) g_free,
 
822
                                               NULL);
 
823
 
 
824
        modules = tracker_writeback_modules_list ();
 
825
 
 
826
        while (modules) {
 
827
                TrackerWritebackModule *module;
 
828
                const gchar *path;
 
829
 
 
830
                path = modules->data;
 
831
                module = tracker_writeback_module_get (path);
 
832
 
 
833
                if (module) {
 
834
                        g_hash_table_insert (priv->modules, g_strdup (path), module);
 
835
                }
 
836
 
 
837
                modules = modules->next;
 
838
        }
 
839
 
 
840
        if (!g_thread_create (tracker_controller_thread_func,
 
841
                              controller, FALSE, error)) {
 
842
                return FALSE;
 
843
        }
 
844
 
 
845
 
 
846
#ifdef THREAD_ENABLE_TRACE
 
847
        g_debug ("Thread:%p (Controller) --- Waiting for controller thread to initialize...",
 
848
                 g_thread_self ());
 
849
#endif /* THREAD_ENABLE_TRACE */
 
850
 
 
851
        /* Wait for the controller thread to notify initialization */
 
852
        g_mutex_lock (priv->initialization_mutex);
 
853
 
 
854
        while (!priv->initialized) {
 
855
                g_cond_wait (priv->initialization_cond, priv->initialization_mutex);
 
856
        }
 
857
 
 
858
        g_mutex_unlock (priv->initialization_mutex);
 
859
 
 
860
        /* If there was any error resulting from initialization, propagate it */
 
861
        if (priv->initialization_error != NULL) {
 
862
                g_propagate_error (error, priv->initialization_error);
 
863
                return FALSE;
 
864
        }
 
865
 
 
866
#ifdef THREAD_ENABLE_TRACE
 
867
        g_debug ("Thread:%p (Controller) --- Initialized",
 
868
                 g_thread_self ());
 
869
#endif /* THREAD_ENABLE_TRACE */
 
870
 
 
871
        return TRUE;
61
872
}