Coverage Report

Created: 2026-02-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tinysparql/src/libtinysparql/direct/tracker-direct.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2010, Nokia <ivan.frade@nokia.com>
3
 * Copyright (C) 2017, Red Hat, Inc.
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the
17
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18
 * Boston, MA  02110-1301, USA.
19
 */
20
21
#include "config.h"
22
23
#include "tracker-direct.h"
24
#include "tracker-direct-batch.h"
25
#include "tracker-direct-statement.h"
26
27
#include <tracker-common.h>
28
29
#include "core/tracker-data.h"
30
#include "tracker-deserializer-directory.h"
31
#include "tracker-notifier-private.h"
32
#include "tracker-private.h"
33
#include "tracker-serializer.h"
34
35
typedef struct _TrackerDirectConnectionPrivate TrackerDirectConnectionPrivate;
36
37
struct _TrackerDirectConnectionPrivate
38
{
39
  TrackerSparqlConnectionFlags flags;
40
  GFile *store;
41
  GFile *ontology;
42
  GInputStream *ontology_rdf;
43
44
  TrackerNamespaceManager *namespace_manager;
45
  TrackerDataManager *data_manager;
46
  GMutex update_mutex;
47
48
  GThreadPool *update_thread; /* Contains 1 exclusive thread */
49
  GThreadPool *select_pool;
50
51
  GList *notifiers;
52
53
  gint64 timestamp;
54
  gint64 cleanup_timestamp;
55
56
  guint cleanup_timeout_id;
57
  TrackerRdfFormat ontology_rdf_format;
58
59
  guint initialized : 1;
60
  guint closing     : 1;
61
};
62
63
typedef enum {
64
  TASK_TYPE_QUERY,
65
  TASK_TYPE_QUERY_STATEMENT,
66
  TASK_TYPE_SERIALIZE,
67
  TASK_TYPE_SERIALIZE_STATEMENT,
68
  TASK_TYPE_UPDATE,
69
  TASK_TYPE_UPDATE_BLANK,
70
  TASK_TYPE_UPDATE_RESOURCE,
71
  TASK_TYPE_UPDATE_BATCH,
72
  TASK_TYPE_UPDATE_STATEMENT,
73
  TASK_TYPE_DESERIALIZE,
74
  TASK_TYPE_RELEASE_MEMORY,
75
} TaskType;
76
77
typedef struct {
78
  TaskType type;
79
80
  union {
81
    gchar *sparql;
82
83
    TrackerBatch *batch;
84
85
    struct {
86
      TrackerSparqlStatement *stmt;
87
      GHashTable *parameters;
88
    } statement;
89
90
    struct {
91
      gchar *graph;
92
      TrackerResource *resource;
93
    } update_resource;
94
95
    struct {
96
      gchar *sparql;
97
      TrackerRdfFormat format;
98
      TrackerSerializeFlags flags;
99
    } serialize;
100
101
    struct {
102
      TrackerSparqlStatement *stmt;
103
      GHashTable *parameters;
104
      TrackerRdfFormat format;
105
      TrackerSerializeFlags flags;
106
    } serialize_statement;
107
108
    struct {
109
      GInputStream *stream;
110
      gchar *default_graph;
111
      TrackerRdfFormat format;
112
      TrackerDeserializeFlags flags;
113
    } deserialize;
114
  } d;
115
} TaskData;
116
117
enum {
118
  PROP_0,
119
  PROP_FLAGS,
120
  PROP_STORE_LOCATION,
121
  PROP_ONTOLOGY_LOCATION,
122
  PROP_ONTOLOGY_STREAM,
123
  PROP_ONTOLOGY_STREAM_FORMAT,
124
  N_PROPS
125
};
126
127
static GParamSpec *props[N_PROPS] = { NULL };
128
129
static void tracker_direct_connection_initable_iface_init (GInitableIface *iface);
130
static void tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface);
131
132
G_DEFINE_QUARK (TrackerDirectNotifier, tracker_direct_notifier)
133
134
47.1k
G_DEFINE_TYPE_WITH_CODE (TrackerDirectConnection, tracker_direct_connection,
135
47.1k
                         TRACKER_TYPE_SPARQL_CONNECTION,
136
47.1k
                         G_ADD_PRIVATE (TrackerDirectConnection)
137
47.1k
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
138
47.1k
                                                tracker_direct_connection_initable_iface_init)
139
47.1k
                         G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
140
47.1k
                                                tracker_direct_connection_async_initable_iface_init))
141
47.1k
142
47.1k
static TaskData *
143
47.1k
task_data_new (TaskType type)
144
47.1k
{
145
0
  TaskData *task;
146
147
0
  task = g_new0 (TaskData, 1);
148
0
  task->type = type;
149
150
0
  return task;
151
0
}
152
153
static void
154
task_data_free (TaskData *task)
155
0
{
156
0
  switch (task->type) {
157
0
  case TASK_TYPE_QUERY:
158
0
  case TASK_TYPE_UPDATE:
159
0
  case TASK_TYPE_UPDATE_BLANK:
160
0
    g_free (task->d.sparql);
161
0
    break;
162
0
  case TASK_TYPE_SERIALIZE:
163
0
    g_free (task->d.serialize.sparql);
164
0
    break;
165
0
  case TASK_TYPE_UPDATE_RESOURCE:
166
0
    g_free (task->d.update_resource.graph);
167
0
    g_object_unref (task->d.update_resource.resource);
168
0
    break;
169
0
  case TASK_TYPE_UPDATE_BATCH:
170
0
    g_clear_object (&task->d.batch);
171
0
    break;
172
0
  case TASK_TYPE_UPDATE_STATEMENT:
173
0
  case TASK_TYPE_QUERY_STATEMENT:
174
0
    g_clear_object (&task->d.statement.stmt);
175
0
    g_clear_pointer (&task->d.statement.parameters, g_hash_table_unref);
176
0
    break;
177
0
  case TASK_TYPE_SERIALIZE_STATEMENT:
178
0
    g_clear_object (&task->d.serialize_statement.stmt);
179
0
    g_clear_pointer (&task->d.serialize_statement.parameters,
180
0
                     g_hash_table_unref);
181
0
    break;
182
0
  case TASK_TYPE_RELEASE_MEMORY:
183
0
    break;
184
0
  case TASK_TYPE_DESERIALIZE:
185
0
    g_clear_object (&task->d.deserialize.stream);
186
0
    g_free (task->d.deserialize.default_graph);
187
0
    break;
188
0
  }
189
0
  g_free (task);
190
0
}
191
192
static gboolean
193
cleanup_timeout_cb (gpointer user_data)
194
0
{
195
0
  TrackerDirectConnection *conn = user_data;
196
0
  TrackerDirectConnectionPrivate *priv;
197
0
  gint64 timestamp;
198
0
  GTask *task;
199
200
0
  priv = tracker_direct_connection_get_instance_private (conn);
201
0
  timestamp = g_get_monotonic_time ();
202
203
  /* If we already cleaned up */
204
0
  if (priv->timestamp < priv->cleanup_timestamp)
205
0
    return G_SOURCE_CONTINUE;
206
  /* If the connection was used less than 10s ago */
207
0
  if (timestamp - priv->timestamp < 10 * G_USEC_PER_SEC)
208
0
    return G_SOURCE_CONTINUE;
209
210
0
  priv->cleanup_timestamp = timestamp;
211
212
0
  task = g_task_new (conn, NULL, NULL, NULL);
213
0
  g_task_set_task_data (task,
214
0
                        task_data_new (TASK_TYPE_RELEASE_MEMORY),
215
0
                        (GDestroyNotify) task_data_free);
216
217
0
  g_thread_pool_push (priv->update_thread, task, NULL);
218
219
0
  return G_SOURCE_CONTINUE;
220
0
}
221
222
gboolean
223
update_resource (TrackerData      *data,
224
                 const gchar      *graph,
225
                 TrackerResource  *resource,
226
                 GError          **error)
227
0
{
228
0
  GError *inner_error = NULL;
229
0
  GHashTable *visited;
230
231
0
  if (!tracker_data_begin_transaction (data, &inner_error))
232
0
    goto error;
233
234
0
  visited = g_hash_table_new_full (NULL, NULL, NULL,
235
0
                                   (GDestroyNotify) tracker_rowid_free);
236
237
0
  tracker_data_update_resource (data,
238
0
                                graph,
239
0
                                resource,
240
0
                                NULL,
241
0
                                visited,
242
0
                                &inner_error);
243
244
0
  g_hash_table_unref (visited);
245
246
0
  if (inner_error) {
247
0
    tracker_data_rollback_transaction (data);
248
0
    goto error;
249
0
  }
250
251
0
  if (!tracker_data_commit_transaction (data, &inner_error))
252
0
    goto error;
253
254
0
  return TRUE;
255
256
0
error:
257
0
  g_propagate_error (error, inner_error);
258
0
  return FALSE;
259
0
}
260
261
static TrackerSerializerFormat
262
convert_format (TrackerRdfFormat format)
263
0
{
264
0
  switch (format) {
265
0
  case TRACKER_RDF_FORMAT_TURTLE:
266
0
    return TRACKER_SERIALIZER_FORMAT_TTL;
267
0
  case TRACKER_RDF_FORMAT_TRIG:
268
0
    return TRACKER_SERIALIZER_FORMAT_TRIG;
269
0
  case TRACKER_RDF_FORMAT_JSON_LD:
270
0
    return TRACKER_SERIALIZER_FORMAT_JSON_LD;
271
0
  default:
272
0
    g_assert_not_reached ();
273
0
  }
274
0
}
275
276
static void
277
update_thread_func (gpointer data,
278
                    gpointer user_data)
279
0
{
280
0
  TrackerDirectConnectionPrivate *priv;
281
0
  TrackerDirectConnection *conn;
282
0
  GTask *task = data;
283
0
  TaskData *task_data = g_task_get_task_data (task);
284
0
  TrackerData *tracker_data;
285
0
  GError *error = NULL;
286
0
  gpointer retval = NULL;
287
0
  GDestroyNotify destroy_notify = NULL;
288
0
  gboolean update_timestamp = TRUE;
289
290
0
  conn = user_data;
291
0
  priv = tracker_direct_connection_get_instance_private (conn);
292
293
0
  g_mutex_lock (&priv->update_mutex);
294
0
  tracker_data = tracker_data_manager_get_data (priv->data_manager);
295
296
0
  switch (task_data->type) {
297
0
  case TASK_TYPE_QUERY:
298
0
  case TASK_TYPE_QUERY_STATEMENT:
299
0
  case TASK_TYPE_SERIALIZE:
300
0
  case TASK_TYPE_SERIALIZE_STATEMENT:
301
0
    g_warning ("Queries don't go through this thread");
302
0
    break;
303
0
  case TASK_TYPE_UPDATE:
304
0
    tracker_data_update_sparql (tracker_data, task_data->d.sparql, &error);
305
0
    break;
306
0
  case TASK_TYPE_UPDATE_BLANK:
307
0
    retval = tracker_data_update_sparql_blank (tracker_data, task_data->d.sparql, &error);
308
0
    destroy_notify = (GDestroyNotify) g_variant_unref;
309
0
    break;
310
0
  case TASK_TYPE_UPDATE_RESOURCE:
311
0
    update_resource (tracker_data,
312
0
                     task_data->d.update_resource.graph,
313
0
                     task_data->d.update_resource.resource,
314
0
                     &error);
315
0
    break;
316
0
  case TASK_TYPE_DESERIALIZE: {
317
0
    TrackerSparqlCursor *deserializer;
318
319
0
    if (!tracker_data_begin_transaction (tracker_data, &error))
320
0
      break;
321
322
0
    deserializer = tracker_deserializer_new (task_data->d.deserialize.stream,
323
0
               NULL,
324
0
                                             convert_format (task_data->d.deserialize.format));
325
326
0
    if (tracker_data_load_from_deserializer (tracker_data,
327
0
                                             TRACKER_DESERIALIZER (deserializer),
328
0
                                             task_data->d.deserialize.default_graph,
329
0
                                             NULL,
330
0
                                             &error)) {
331
0
      tracker_data_commit_transaction (tracker_data, &error);
332
0
    } else {
333
0
      tracker_data_rollback_transaction (tracker_data);
334
0
    }
335
0
    g_object_unref (deserializer);
336
0
    break;
337
0
  }
338
0
  case TASK_TYPE_UPDATE_BATCH:
339
0
    tracker_direct_batch_update (TRACKER_DIRECT_BATCH (task_data->d.batch),
340
0
                                 priv->data_manager, &error);
341
0
    break;
342
0
  case TASK_TYPE_UPDATE_STATEMENT:
343
0
    if (!tracker_data_begin_transaction (tracker_data, &error))
344
0
      break;
345
346
0
    if (tracker_direct_statement_execute_update (task_data->d.statement.stmt,
347
0
                                                 task_data->d.statement.parameters,
348
0
                                                 NULL,
349
0
                                                 &error)) {
350
0
      tracker_data_commit_transaction (tracker_data, &error);
351
0
    } else {
352
0
      tracker_data_rollback_transaction (tracker_data);
353
0
    }
354
0
    break;
355
0
  case TASK_TYPE_RELEASE_MEMORY:
356
0
    tracker_data_manager_release_memory (priv->data_manager);
357
0
    update_timestamp = FALSE;
358
0
    break;
359
0
  }
360
361
0
  if (error)
362
0
    g_task_return_error (task, error);
363
0
  else if (retval)
364
0
    g_task_return_pointer (task, retval, destroy_notify);
365
0
  else
366
0
    g_task_return_boolean (task, TRUE);
367
368
0
  g_object_unref (task);
369
370
0
  if (update_timestamp)
371
0
    tracker_direct_connection_update_timestamp (conn);
372
373
0
  g_mutex_unlock (&priv->update_mutex);
374
0
}
375
376
static void
377
execute_query_in_thread (GTask    *task,
378
                         TaskData *task_data)
379
0
{
380
0
  TrackerSparqlConnection *conn;
381
0
  TrackerSparqlCursor *cursor;
382
0
  GError *error = NULL;
383
384
0
  if (g_task_return_error_if_cancelled (task))
385
0
    return;
386
387
0
  conn = g_task_get_source_object (task);
388
389
0
  if (task_data->type == TASK_TYPE_QUERY) {
390
0
    cursor = tracker_sparql_connection_query (conn,
391
0
                                              task_data->d.sparql,
392
0
                                              g_task_get_cancellable (task),
393
0
                                              &error);
394
0
  } else if (task_data->type == TASK_TYPE_QUERY_STATEMENT) {
395
0
    TrackerSparql *sparql;
396
397
0
    sparql = tracker_direct_statement_get_sparql (task_data->d.statement.stmt);
398
0
    cursor = tracker_sparql_execute_cursor (sparql,
399
0
                                            task_data->d.statement.parameters,
400
0
                                            &error);
401
0
  } else {
402
0
    g_assert_not_reached ();
403
0
  }
404
405
0
  if (cursor) {
406
0
    tracker_direct_connection_update_timestamp (TRACKER_DIRECT_CONNECTION (conn));
407
0
    g_task_return_pointer (task, cursor, g_object_unref);
408
0
  } else {
409
0
    g_task_return_error (task, error);
410
0
  }
411
0
}
412
413
static void
414
serialize_in_thread (GTask    *task,
415
                     TaskData *task_data)
416
0
{
417
0
  TrackerDirectConnectionPrivate *priv;
418
0
  TrackerDirectConnection *conn;
419
0
  TrackerSparql *query = NULL;
420
0
  TrackerSparqlCursor *cursor = NULL;
421
0
  TrackerNamespaceManager *namespaces;
422
0
  TrackerRdfFormat format;
423
0
  GInputStream *istream = NULL;
424
0
  GHashTable *parameters = NULL;
425
0
  GError *error = NULL;
426
427
0
  conn = g_task_get_source_object (task);
428
0
  priv = tracker_direct_connection_get_instance_private (conn);
429
430
0
  if (task_data->type == TASK_TYPE_SERIALIZE) {
431
0
    format = task_data->d.serialize.format;
432
0
    query = tracker_sparql_new (priv->data_manager,
433
0
                                task_data->d.serialize.sparql,
434
0
                                &error);
435
0
    if (!query)
436
0
      goto out;
437
0
  } else if (task_data->type == TASK_TYPE_SERIALIZE_STATEMENT) {
438
0
    TrackerSparqlStatement *stmt;
439
440
0
    format = task_data->d.serialize_statement.format;
441
0
    stmt = task_data->d.serialize_statement.stmt;
442
0
    query = g_object_ref (tracker_direct_statement_get_sparql (stmt));
443
0
    parameters = task_data->d.serialize_statement.parameters;
444
0
  } else {
445
0
    g_assert_not_reached ();
446
0
  }
447
448
0
  if (!tracker_sparql_is_serializable (query)) {
449
0
    g_set_error (&error,
450
0
                 TRACKER_SPARQL_ERROR,
451
0
                 TRACKER_SPARQL_ERROR_PARSE,
452
0
                 "Query is not DESCRIBE or CONSTRUCT");
453
0
    goto out;
454
0
  }
455
456
0
  cursor = tracker_sparql_execute_cursor (query, parameters, &error);
457
0
  if (!cursor)
458
0
    goto out;
459
460
0
  tracker_direct_connection_update_timestamp (conn);
461
0
  tracker_sparql_cursor_set_connection (cursor, TRACKER_SPARQL_CONNECTION (conn));
462
0
  namespaces = tracker_sparql_connection_get_namespace_manager (TRACKER_SPARQL_CONNECTION (conn));
463
0
  istream = tracker_serializer_new (cursor, namespaces, convert_format (format));
464
465
0
 out:
466
0
  g_clear_object (&query);
467
0
  g_clear_object (&cursor);
468
469
0
  if (istream)
470
0
    g_task_return_pointer (task, istream, g_object_unref);
471
0
  else
472
0
    g_task_return_error (task, error);
473
0
}
474
475
static void
476
query_thread_pool_func (gpointer data,
477
                        gpointer user_data)
478
0
{
479
0
  TrackerDirectConnection *conn = user_data;
480
0
  TrackerDirectConnectionPrivate *priv;
481
0
  GTask *task = data;
482
0
  TaskData *task_data = g_task_get_task_data (task);
483
484
0
  priv = tracker_direct_connection_get_instance_private (conn);
485
486
0
  if (priv->closing) {
487
0
    g_task_return_new_error (task,
488
0
                             G_IO_ERROR,
489
0
                             G_IO_ERROR_CONNECTION_CLOSED,
490
0
                             "Connection is closed");
491
0
    g_object_unref (task);
492
0
    return;
493
0
  }
494
495
0
  switch (task_data->type) {
496
0
  case TASK_TYPE_QUERY:
497
0
  case TASK_TYPE_QUERY_STATEMENT:
498
0
    execute_query_in_thread (task, task_data);
499
0
    break;
500
0
  case TASK_TYPE_SERIALIZE:
501
0
  case TASK_TYPE_SERIALIZE_STATEMENT:
502
0
    serialize_in_thread (task, task_data);
503
0
    break;
504
0
  default:
505
0
    g_assert_not_reached ();
506
0
  }
507
508
0
  g_object_unref (task);
509
0
}
510
511
static gboolean
512
set_up_thread_pools (TrackerDirectConnection  *conn,
513
         GError                  **error)
514
15.7k
{
515
15.7k
  TrackerDirectConnectionPrivate *priv;
516
517
15.7k
  priv = tracker_direct_connection_get_instance_private (conn);
518
519
15.7k
  priv->select_pool = g_thread_pool_new (query_thread_pool_func,
520
15.7k
                                         conn, 16, FALSE, error);
521
15.7k
  if (!priv->select_pool)
522
0
    return FALSE;
523
524
15.7k
  priv->update_thread = g_thread_pool_new (update_thread_func,
525
15.7k
                                           conn, 1, TRUE, error);
526
15.7k
  if (!priv->update_thread)
527
0
    return FALSE;
528
529
15.7k
  return TRUE;
530
15.7k
}
531
532
static TrackerDBManagerFlags
533
translate_flags (TrackerSparqlConnectionFlags flags)
534
15.7k
{
535
15.7k
  TrackerDBManagerFlags db_flags = TRACKER_DB_MANAGER_FLAGS_NONE;
536
537
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_READONLY) != 0)
538
0
    db_flags |= TRACKER_DB_MANAGER_READONLY;
539
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STEMMER) != 0)
540
0
    db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STEMMER;
541
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_UNACCENT) != 0)
542
0
    db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_UNACCENT;
543
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_ENABLE_STOP_WORDS) != 0)
544
0
    db_flags |= TRACKER_DB_MANAGER_FTS_ENABLE_STOP_WORDS;
545
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_FTS_IGNORE_NUMBERS) != 0)
546
0
    db_flags |= TRACKER_DB_MANAGER_FTS_IGNORE_NUMBERS;
547
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_ANONYMOUS_BNODES) != 0)
548
5.77k
    db_flags |= TRACKER_DB_MANAGER_ANONYMOUS_BNODES;
549
550
  /* This flag is inverted */
551
15.7k
  if ((flags & TRACKER_SPARQL_CONNECTION_FLAGS_DISABLE_SYNTAX_EXTENSIONS) == 0)
552
9.94k
    db_flags |= TRACKER_DB_MANAGER_ENABLE_SYNTAX_EXTENSIONS;
553
554
15.7k
  return db_flags;
555
15.7k
}
556
557
static gboolean
558
tracker_direct_connection_initable_init (GInitable     *initable,
559
                                         GCancellable  *cancellable,
560
                                         GError       **error)
561
15.7k
{
562
15.7k
  TrackerDirectConnectionPrivate *priv;
563
15.7k
  TrackerDirectConnection *conn;
564
15.7k
  TrackerDBManagerFlags db_flags;
565
15.7k
  TrackerSparqlCursor *ontology_data = NULL;
566
15.7k
  GHashTable *namespaces;
567
15.7k
  GHashTableIter iter;
568
15.7k
  gchar *prefix, *ns;
569
15.7k
  GError *inner_error = NULL;
570
571
15.7k
  conn = TRACKER_DIRECT_CONNECTION (initable);
572
15.7k
  priv = tracker_direct_connection_get_instance_private (conn);
573
574
15.7k
  if (!set_up_thread_pools (conn, error))
575
0
    return FALSE;
576
577
15.7k
  if (priv->ontology &&
578
5.77k
      g_file_query_file_type (priv->ontology, G_FILE_QUERY_INFO_NONE, NULL) != G_FILE_TYPE_DIRECTORY) {
579
0
    gchar *uri;
580
581
0
    uri = g_file_get_uri (priv->ontology);
582
0
    g_set_error (error, TRACKER_DATA_ONTOLOGY_ERROR,
583
0
                 TRACKER_DATA_ONTOLOGY_NOT_FOUND,
584
0
                 "'%s' is not a ontology location", uri);
585
0
    g_free (uri);
586
0
    return FALSE;
587
0
  }
588
589
15.7k
  db_flags = translate_flags (priv->flags);
590
591
15.7k
  if (!priv->store) {
592
15.7k
    db_flags |= TRACKER_DB_MANAGER_IN_MEMORY;
593
15.7k
  }
594
595
15.7k
  if (priv->ontology) {
596
5.77k
    ontology_data = tracker_deserializer_directory_new (priv->ontology, NULL);
597
9.94k
  } else if (priv->ontology_rdf) {
598
9.94k
    TrackerSerializerFormat format;
599
600
9.94k
    switch (priv->ontology_rdf_format) {
601
9.94k
    case TRACKER_RDF_FORMAT_TURTLE:
602
9.94k
      format = TRACKER_SERIALIZER_FORMAT_TTL;
603
9.94k
      break;
604
0
    case TRACKER_RDF_FORMAT_TRIG:
605
0
      format = TRACKER_SERIALIZER_FORMAT_TRIG;
606
0
      break;
607
0
    case TRACKER_RDF_FORMAT_JSON_LD:
608
0
      format = TRACKER_SERIALIZER_FORMAT_JSON_LD;
609
0
      break;
610
0
    default:
611
0
      g_assert_not_reached ();
612
0
      break;
613
9.94k
    }
614
615
9.94k
    ontology_data = tracker_deserializer_new (priv->ontology_rdf, NULL, format);
616
9.94k
  }
617
618
15.7k
  priv->data_manager = tracker_data_manager_new (db_flags, priv->store,
619
15.7k
                                                 TRACKER_DESERIALIZER (ontology_data),
620
15.7k
                                                 100);
621
15.7k
  g_clear_object (&ontology_data);
622
623
15.7k
  if (!g_initable_init (G_INITABLE (priv->data_manager), cancellable, &inner_error)) {
624
6.35k
    g_propagate_error (error, _translate_internal_error (inner_error));
625
6.35k
    g_clear_object (&priv->data_manager);
626
6.35k
    return FALSE;
627
6.35k
  }
628
629
  /* Initialize namespace manager */
630
9.36k
  priv->namespace_manager = tracker_namespace_manager_new ();
631
9.36k
  namespaces = tracker_data_manager_get_namespaces (priv->data_manager);
632
9.36k
  g_hash_table_iter_init (&iter, namespaces);
633
634
78.2k
  while (g_hash_table_iter_next (&iter, (gpointer*) &prefix, (gpointer*) &ns)) {
635
68.9k
    tracker_namespace_manager_add_prefix (priv->namespace_manager,
636
68.9k
                                          prefix, ns);
637
68.9k
  }
638
639
9.36k
  g_hash_table_unref (namespaces);
640
641
9.36k
  priv->cleanup_timeout_id =
642
9.36k
    g_timeout_add_seconds (30, cleanup_timeout_cb, conn);
643
644
9.36k
  return TRUE;
645
15.7k
}
646
647
static void
648
tracker_direct_connection_initable_iface_init (GInitableIface *iface)
649
5
{
650
5
  iface->init = tracker_direct_connection_initable_init;
651
5
}
652
653
static void
654
async_initable_thread_func (GTask        *task,
655
                            gpointer      source_object,
656
                            gpointer      task_data,
657
                            GCancellable *cancellable)
658
0
{
659
0
  GError *error = NULL;
660
661
0
  if (!g_initable_init (G_INITABLE (source_object), cancellable, &error))
662
0
    g_task_return_error (task, error);
663
0
  else
664
0
    g_task_return_boolean (task, TRUE);
665
666
0
  g_object_unref (task);
667
0
}
668
669
static void
670
tracker_direct_connection_async_initable_init_async (GAsyncInitable      *async_initable,
671
                                                     gint                 priority,
672
                                                     GCancellable        *cancellable,
673
                                                     GAsyncReadyCallback  callback,
674
                                                     gpointer             user_data)
675
0
{
676
0
  GTask *task;
677
678
0
  task = g_task_new (async_initable, cancellable, callback, user_data);
679
0
  g_task_set_priority (task, priority);
680
0
  g_task_run_in_thread (task, async_initable_thread_func);
681
0
}
682
683
static gboolean
684
tracker_direct_connection_async_initable_init_finish (GAsyncInitable  *async_initable,
685
                                                      GAsyncResult    *res,
686
                                                      GError         **error)
687
0
{
688
0
  return g_task_propagate_boolean (G_TASK (res), error);
689
0
}
690
691
static void
692
tracker_direct_connection_async_initable_iface_init (GAsyncInitableIface *iface)
693
5
{
694
5
  iface->init_async = tracker_direct_connection_async_initable_init_async;
695
5
  iface->init_finish = tracker_direct_connection_async_initable_init_finish;
696
5
}
697
698
static void
699
tracker_direct_connection_init (TrackerDirectConnection *conn)
700
15.7k
{
701
15.7k
}
702
703
static GHashTable *
704
get_event_cache_ht (TrackerNotifier *notifier)
705
0
{
706
0
  GHashTable *events;
707
708
0
  events = g_object_get_qdata (G_OBJECT (notifier), tracker_direct_notifier_quark ());
709
0
  if (!events) {
710
0
    events = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
711
0
                                    (GDestroyNotify) _tracker_notifier_event_cache_free);
712
0
    g_object_set_qdata_full (G_OBJECT (notifier), tracker_direct_notifier_quark (),
713
0
                             events, (GDestroyNotify) g_hash_table_unref);
714
0
  }
715
716
0
  return events;
717
0
}
718
719
static TrackerNotifierEventCache *
720
lookup_event_cache (TrackerNotifier *notifier,
721
                    const gchar     *graph)
722
0
{
723
0
  TrackerNotifierEventCache *cache;
724
0
  GHashTable *events;
725
726
0
  if (!graph)
727
0
    graph = "";
728
729
0
  events = get_event_cache_ht (notifier);
730
0
  cache = g_hash_table_lookup (events, graph);
731
732
0
  if (!cache) {
733
0
    cache = _tracker_notifier_event_cache_new (notifier, graph);
734
0
    g_hash_table_insert (events,
735
0
                         (gpointer) tracker_notifier_event_cache_get_graph (cache),
736
0
                         cache);
737
0
  }
738
739
0
  return cache;
740
0
}
741
742
/* These callbacks will be called from a different thread
743
 * (always the same one though), handle with care.
744
 */
745
static void
746
statement_cb (TrackerDataUpdateType  type,
747
              const gchar           *graph,
748
              TrackerRowid           subject_id,
749
              TrackerRowid           predicate_id,
750
              TrackerRowid           object_id,
751
              GPtrArray             *rdf_types,
752
              gpointer               user_data)
753
0
{
754
0
  TrackerNotifier *notifier = user_data;
755
0
  TrackerSparqlConnection *conn = _tracker_notifier_get_connection (notifier);
756
0
  TrackerDirectConnection *direct = TRACKER_DIRECT_CONNECTION (conn);
757
0
  TrackerDirectConnectionPrivate *priv = tracker_direct_connection_get_instance_private (direct);
758
0
  TrackerOntologies *ontologies = tracker_data_manager_get_ontologies (priv->data_manager);
759
0
  TrackerProperty *rdf_type = tracker_ontologies_get_rdf_type (ontologies);
760
0
  TrackerNotifierEventCache *cache;
761
0
  TrackerClass *rdf_type_class = NULL;
762
0
  guint i;
763
764
0
  cache = lookup_event_cache (notifier, graph);
765
766
0
  if (predicate_id == tracker_property_get_id (rdf_type)) {
767
0
    const gchar *uri;
768
769
0
    uri = tracker_ontologies_get_uri_by_id (ontologies, object_id);
770
0
    rdf_type_class = tracker_ontologies_get_class_by_uri (ontologies, uri);
771
0
  }
772
773
0
  for (i = 0; i < rdf_types->len; i++) {
774
0
    TrackerClass *class = g_ptr_array_index (rdf_types, i);
775
0
    TrackerNotifierEventType event_type;
776
777
0
    if (!tracker_class_get_notify (class))
778
0
      continue;
779
780
0
    if (rdf_type_class && class == rdf_type_class) {
781
0
      if (type == TRACKER_DATA_INSERT)
782
0
        event_type = TRACKER_NOTIFIER_EVENT_CREATE;
783
0
      else
784
0
        event_type = TRACKER_NOTIFIER_EVENT_DELETE;
785
0
    } else {
786
0
      event_type = TRACKER_NOTIFIER_EVENT_UPDATE;
787
0
    }
788
789
0
    _tracker_notifier_event_cache_push_event (cache, subject_id, event_type);
790
0
  }
791
0
}
792
793
static void
794
transaction_cb (TrackerDataTransactionType type,
795
                gpointer                   user_data)
796
0
{
797
0
  TrackerNotifier *notifier = user_data;
798
0
  GHashTable *events;
799
800
0
  events = get_event_cache_ht (notifier);
801
802
0
  if (type == TRACKER_DATA_COMMIT) {
803
0
    TrackerNotifierEventCache *cache;
804
0
    GHashTableIter iter;
805
806
0
    g_hash_table_iter_init (&iter, events);
807
808
0
    while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cache)) {
809
0
      g_hash_table_iter_steal (&iter);
810
0
      _tracker_notifier_event_cache_flush_events (notifier, cache);
811
0
    }
812
0
  } else {
813
0
    g_hash_table_remove_all (events);
814
0
  }
815
0
}
816
817
static void
818
detach_notifier (TrackerDirectConnection *conn,
819
                 TrackerNotifier         *notifier)
820
0
{
821
0
  TrackerDirectConnectionPrivate *priv;
822
0
  TrackerData *tracker_data;
823
824
0
  priv = tracker_direct_connection_get_instance_private (conn);
825
826
0
  priv->notifiers = g_list_remove (priv->notifiers, notifier);
827
828
0
  tracker_notifier_stop (notifier);
829
0
  tracker_data = tracker_data_manager_get_data (priv->data_manager);
830
831
0
  tracker_data_remove_callbacks (tracker_data,
832
0
                                 statement_cb,
833
0
                                 transaction_cb,
834
0
                                 notifier);
835
0
}
836
837
static void
838
weak_ref_notify (gpointer  data,
839
                 GObject  *prev_location)
840
0
{
841
0
  TrackerDirectConnection *conn = data;
842
843
0
  detach_notifier (conn, (TrackerNotifier *) prev_location);
844
0
}
845
846
static void
847
tracker_direct_connection_finalize (GObject *object)
848
15.7k
{
849
15.7k
  TrackerDirectConnectionPrivate *priv;
850
15.7k
  TrackerDirectConnection *conn;
851
852
15.7k
  conn = TRACKER_DIRECT_CONNECTION (object);
853
15.7k
  priv = tracker_direct_connection_get_instance_private (conn);
854
855
15.7k
  if (!priv->closing)
856
0
    tracker_sparql_connection_close (TRACKER_SPARQL_CONNECTION (object));
857
858
15.7k
  g_clear_object (&priv->store);
859
15.7k
  g_clear_object (&priv->ontology);
860
15.7k
  g_clear_object (&priv->namespace_manager);
861
15.7k
  g_clear_object (&priv->ontology_rdf);
862
863
15.7k
  G_OBJECT_CLASS (tracker_direct_connection_parent_class)->finalize (object);
864
15.7k
}
865
866
static void
867
tracker_direct_connection_set_property (GObject      *object,
868
                                        guint         prop_id,
869
                                        const GValue *value,
870
                                        GParamSpec   *pspec)
871
78.6k
{
872
78.6k
  TrackerDirectConnectionPrivate *priv;
873
78.6k
  TrackerDirectConnection *conn;
874
875
78.6k
  conn = TRACKER_DIRECT_CONNECTION (object);
876
78.6k
  priv = tracker_direct_connection_get_instance_private (conn);
877
878
78.6k
  switch (prop_id) {
879
15.7k
  case PROP_FLAGS:
880
15.7k
    priv->flags = g_value_get_flags (value);
881
15.7k
    break;
882
15.7k
  case PROP_STORE_LOCATION:
883
15.7k
    priv->store = g_value_dup_object (value);
884
15.7k
    break;
885
15.7k
  case PROP_ONTOLOGY_LOCATION:
886
15.7k
    priv->ontology = g_value_dup_object (value);
887
15.7k
    break;
888
15.7k
  case PROP_ONTOLOGY_STREAM:
889
15.7k
    priv->ontology_rdf = g_value_dup_object (value);
890
15.7k
    break;
891
15.7k
  case PROP_ONTOLOGY_STREAM_FORMAT:
892
15.7k
    priv->ontology_rdf_format = g_value_get_enum (value);
893
15.7k
    break;
894
0
  default:
895
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
896
0
    break;
897
78.6k
  }
898
78.6k
}
899
900
static void
901
tracker_direct_connection_get_property (GObject    *object,
902
                                        guint       prop_id,
903
                                        GValue     *value,
904
                                        GParamSpec *pspec)
905
0
{
906
0
  TrackerDirectConnectionPrivate *priv;
907
0
  TrackerDirectConnection *conn;
908
909
0
  conn = TRACKER_DIRECT_CONNECTION (object);
910
0
  priv = tracker_direct_connection_get_instance_private (conn);
911
912
0
  switch (prop_id) {
913
0
  case PROP_FLAGS:
914
0
    g_value_set_flags (value, priv->flags);
915
0
    break;
916
0
  case PROP_STORE_LOCATION:
917
0
    g_value_set_object (value, priv->store);
918
0
    break;
919
0
  case PROP_ONTOLOGY_LOCATION:
920
0
    g_value_set_object (value, priv->ontology);
921
0
    break;
922
0
  default:
923
0
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
924
0
    break;
925
0
  }
926
0
}
927
928
static TrackerSparqlCursor *
929
tracker_direct_connection_query (TrackerSparqlConnection  *self,
930
                                 const gchar              *sparql,
931
                                 GCancellable             *cancellable,
932
                                 GError                  **error)
933
0
{
934
0
  TrackerDirectConnectionPrivate *priv;
935
0
  TrackerDirectConnection *conn;
936
0
  TrackerSparql *query;
937
0
  TrackerSparqlCursor *cursor = NULL;
938
0
  GError *inner_error = NULL;
939
940
0
  conn = TRACKER_DIRECT_CONNECTION (self);
941
0
  priv = tracker_direct_connection_get_instance_private (conn);
942
943
0
  query = tracker_sparql_new (priv->data_manager, sparql, &inner_error);
944
0
  if (query) {
945
0
    cursor = tracker_sparql_execute_cursor (query, NULL, &inner_error);
946
0
    tracker_direct_connection_update_timestamp (conn);
947
0
    g_object_unref (query);
948
0
  }
949
950
0
  if (inner_error)
951
0
    g_propagate_error (error, _translate_internal_error (inner_error));
952
953
0
  return cursor;
954
0
}
955
956
static void
957
tracker_direct_connection_query_async (TrackerSparqlConnection *self,
958
                                       const gchar             *sparql,
959
                                       GCancellable            *cancellable,
960
                                       GAsyncReadyCallback      callback,
961
                                       gpointer                 user_data)
962
0
{
963
0
  TrackerDirectConnectionPrivate *priv;
964
0
  TrackerDirectConnection *conn;
965
0
  TaskData *task_data;
966
0
  GError *error = NULL;
967
0
  GTask *task;
968
969
0
  conn = TRACKER_DIRECT_CONNECTION (self);
970
0
  priv = tracker_direct_connection_get_instance_private (conn);
971
972
0
  task_data = task_data_new (TASK_TYPE_QUERY);
973
0
  task_data->d.sparql = g_strdup (sparql);
974
975
0
  task = g_task_new (self, cancellable, callback, user_data);
976
0
  g_task_set_task_data (task, task_data,
977
0
                        (GDestroyNotify) task_data_free);
978
979
0
  if (!g_thread_pool_push (priv->select_pool, task, &error)) {
980
0
    g_task_return_error (task, _translate_internal_error (error));
981
0
    g_object_unref (task);
982
0
  }
983
0
}
984
985
static TrackerSparqlCursor *
986
tracker_direct_connection_query_finish (TrackerSparqlConnection  *self,
987
                                        GAsyncResult             *res,
988
                                        GError                  **error)
989
0
{
990
0
  return g_task_propagate_pointer (G_TASK (res), error);
991
0
}
992
993
static TrackerSparqlStatement *
994
tracker_direct_connection_query_statement (TrackerSparqlConnection  *self,
995
                                            const gchar              *query,
996
                                            GCancellable             *cancellable,
997
                                            GError                  **error)
998
5.52k
{
999
5.52k
  return TRACKER_SPARQL_STATEMENT (tracker_direct_statement_new (self, query, error));
1000
5.52k
}
1001
1002
static TrackerSparqlStatement *
1003
tracker_direct_connection_update_statement (TrackerSparqlConnection  *self,
1004
                                            const gchar              *query,
1005
                                            GCancellable             *cancellable,
1006
                                            GError                  **error)
1007
5.52k
{
1008
5.52k
  return TRACKER_SPARQL_STATEMENT (tracker_direct_statement_new_update (self, query, error));
1009
5.52k
}
1010
1011
static void
1012
tracker_direct_connection_update (TrackerSparqlConnection  *self,
1013
                                  const gchar              *sparql,
1014
                                  GCancellable             *cancellable,
1015
                                  GError                  **error)
1016
0
{
1017
0
  TrackerDirectConnectionPrivate *priv;
1018
0
  TrackerDirectConnection *conn;
1019
0
  TrackerData *data;
1020
0
  GError *inner_error = NULL;
1021
1022
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1023
0
  priv = tracker_direct_connection_get_instance_private (conn);
1024
1025
0
  g_mutex_lock (&priv->update_mutex);
1026
0
  data = tracker_data_manager_get_data (priv->data_manager);
1027
0
  tracker_data_update_sparql (data, sparql, &inner_error);
1028
0
  tracker_direct_connection_update_timestamp (conn);
1029
0
  g_mutex_unlock (&priv->update_mutex);
1030
1031
0
  if (inner_error)
1032
0
    g_propagate_error (error, inner_error);
1033
0
}
1034
1035
static void
1036
tracker_direct_connection_update_async (TrackerSparqlConnection *self,
1037
                                        const gchar             *sparql,
1038
                                        GCancellable            *cancellable,
1039
                                        GAsyncReadyCallback      callback,
1040
                                        gpointer                 user_data)
1041
0
{
1042
0
  TrackerDirectConnectionPrivate *priv;
1043
0
  TrackerDirectConnection *conn;
1044
0
  TaskData *task_data;
1045
0
  GTask *task;
1046
1047
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1048
0
  priv = tracker_direct_connection_get_instance_private (conn);
1049
1050
0
  task_data = task_data_new (TASK_TYPE_UPDATE);
1051
0
  task_data->d.sparql = g_strdup (sparql);
1052
1053
0
  task = g_task_new (self, cancellable, callback, user_data);
1054
0
  g_task_set_task_data (task, task_data,
1055
0
                        (GDestroyNotify) task_data_free);
1056
1057
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1058
0
}
1059
1060
static void
1061
tracker_direct_connection_update_finish (TrackerSparqlConnection  *self,
1062
                                         GAsyncResult             *res,
1063
                                         GError                  **error)
1064
0
{
1065
0
  GError *inner_error = NULL;
1066
1067
0
  g_task_propagate_boolean (G_TASK (res), &inner_error);
1068
0
  if (inner_error)
1069
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1070
0
}
1071
1072
static void
1073
on_batch_finished (GObject      *source,
1074
                   GAsyncResult *result,
1075
                   gpointer      user_data)
1076
0
{
1077
0
  TrackerBatch *batch = TRACKER_BATCH (source);
1078
0
  GTask *task = user_data;
1079
0
  GError *error = NULL;
1080
0
  gboolean retval;
1081
1082
0
  retval = tracker_batch_execute_finish (batch, result, &error);
1083
1084
0
  if (retval)
1085
0
    g_task_return_boolean (task, TRUE);
1086
0
  else
1087
0
    g_task_return_error (task, error);
1088
1089
0
  g_object_unref (task);
1090
0
}
1091
1092
static void
1093
tracker_direct_connection_update_array_async (TrackerSparqlConnection  *self,
1094
                                              gchar                   **updates,
1095
                                              gint                      n_updates,
1096
                                              GCancellable             *cancellable,
1097
                                              GAsyncReadyCallback       callback,
1098
                                              gpointer                  user_data)
1099
0
{
1100
0
  TrackerBatch *batch;
1101
0
  GTask *task;
1102
0
  gint i;
1103
1104
0
  batch = tracker_sparql_connection_create_batch (self);
1105
1106
0
  for (i = 0; i < n_updates; i++)
1107
0
    tracker_batch_add_sparql (batch, updates[i]);
1108
1109
0
  task = g_task_new (self, cancellable, callback, user_data);
1110
0
  tracker_batch_execute_async (batch, cancellable, on_batch_finished, task);
1111
0
  g_object_unref (batch);
1112
0
}
1113
1114
static gboolean
1115
tracker_direct_connection_update_array_finish (TrackerSparqlConnection  *self,
1116
                                               GAsyncResult             *res,
1117
                                               GError                  **error)
1118
0
{
1119
0
  GError *inner_error = NULL;
1120
0
  gboolean result;
1121
1122
0
  result = g_task_propagate_boolean (G_TASK (res), &inner_error);
1123
0
  if (inner_error)
1124
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1125
1126
0
  return result;
1127
0
}
1128
1129
static GVariant *
1130
tracker_direct_connection_update_blank (TrackerSparqlConnection  *self,
1131
                                        const gchar              *sparql,
1132
                                        GCancellable             *cancellable,
1133
                                        GError                  **error)
1134
0
{
1135
0
  TrackerDirectConnectionPrivate *priv;
1136
0
  TrackerDirectConnection *conn;
1137
0
  TrackerData *data;
1138
0
  GVariant *blank_nodes;
1139
0
  GError *inner_error = NULL;
1140
1141
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1142
0
  priv = tracker_direct_connection_get_instance_private (conn);
1143
1144
0
  g_mutex_lock (&priv->update_mutex);
1145
0
  data = tracker_data_manager_get_data (priv->data_manager);
1146
0
  blank_nodes = tracker_data_update_sparql_blank (data, sparql, &inner_error);
1147
0
  tracker_direct_connection_update_timestamp (conn);
1148
0
  g_mutex_unlock (&priv->update_mutex);
1149
1150
0
  if (inner_error)
1151
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1152
0
  return blank_nodes;
1153
0
}
1154
1155
static void
1156
tracker_direct_connection_update_blank_async (TrackerSparqlConnection *self,
1157
                                              const gchar             *sparql,
1158
                                              GCancellable            *cancellable,
1159
                                              GAsyncReadyCallback      callback,
1160
                                              gpointer                 user_data)
1161
0
{
1162
0
  TrackerDirectConnectionPrivate *priv;
1163
0
  TrackerDirectConnection *conn;
1164
0
  TaskData *task_data;
1165
0
  GTask *task;
1166
1167
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1168
0
  priv = tracker_direct_connection_get_instance_private (conn);
1169
1170
0
  task_data = task_data_new (TASK_TYPE_UPDATE_BLANK);
1171
0
  task_data->d.sparql = g_strdup (sparql);
1172
1173
0
  task = g_task_new (self, cancellable, callback, user_data);
1174
0
  g_task_set_task_data (task, task_data,
1175
0
                        (GDestroyNotify) task_data_free);
1176
1177
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1178
0
}
1179
1180
static GVariant *
1181
tracker_direct_connection_update_blank_finish (TrackerSparqlConnection  *self,
1182
                                               GAsyncResult             *res,
1183
                                               GError                  **error)
1184
0
{
1185
0
  GError *inner_error = NULL;
1186
0
  GVariant *result;
1187
1188
0
  result = g_task_propagate_pointer (G_TASK (res), &inner_error);
1189
0
  if (inner_error)
1190
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1191
1192
0
  return result;
1193
0
}
1194
1195
static TrackerNamespaceManager *
1196
tracker_direct_connection_get_namespace_manager (TrackerSparqlConnection *self)
1197
0
{
1198
0
  TrackerDirectConnectionPrivate *priv;
1199
1200
0
  priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self));
1201
1202
0
  return priv->namespace_manager;
1203
0
}
1204
1205
static TrackerNotifier *
1206
tracker_direct_connection_create_notifier (TrackerSparqlConnection *self)
1207
0
{
1208
0
  TrackerDirectConnectionPrivate *priv;
1209
0
  TrackerNotifier *notifier;
1210
0
  TrackerData *tracker_data;
1211
1212
0
  priv = tracker_direct_connection_get_instance_private (TRACKER_DIRECT_CONNECTION (self));
1213
1214
0
  notifier = g_object_new (TRACKER_TYPE_NOTIFIER,
1215
0
                           "connection", self,
1216
0
         NULL);
1217
1218
0
  tracker_data = tracker_data_manager_get_data (priv->data_manager);
1219
0
  tracker_data_add_callbacks (tracker_data,
1220
0
                              statement_cb,
1221
0
                              transaction_cb,
1222
0
                              notifier);
1223
1224
0
  g_object_weak_ref (G_OBJECT (notifier), weak_ref_notify, self);
1225
0
  priv->notifiers = g_list_prepend (priv->notifiers, notifier);
1226
1227
0
  return notifier;
1228
0
}
1229
1230
static void
1231
tracker_direct_connection_close (TrackerSparqlConnection *self)
1232
15.7k
{
1233
15.7k
  TrackerDirectConnectionPrivate *priv;
1234
15.7k
  TrackerDirectConnection *conn;
1235
1236
15.7k
  conn = TRACKER_DIRECT_CONNECTION (self);
1237
15.7k
  priv = tracker_direct_connection_get_instance_private (conn);
1238
15.7k
  priv->closing = TRUE;
1239
1240
15.7k
  if (priv->cleanup_timeout_id) {
1241
9.36k
    g_source_remove (priv->cleanup_timeout_id);
1242
9.36k
    priv->cleanup_timeout_id = 0;
1243
9.36k
  }
1244
1245
15.7k
  if (priv->update_thread) {
1246
15.7k
    g_thread_pool_free (priv->update_thread, TRUE, TRUE);
1247
15.7k
    priv->update_thread = NULL;
1248
15.7k
  }
1249
1250
15.7k
  if (priv->select_pool) {
1251
15.7k
    g_thread_pool_free (priv->select_pool, TRUE, TRUE);
1252
15.7k
    priv->select_pool = NULL;
1253
15.7k
  }
1254
1255
15.7k
  while (priv->notifiers) {
1256
0
    TrackerNotifier *notifier = priv->notifiers->data;
1257
1258
0
    g_object_weak_unref (G_OBJECT (notifier),
1259
0
                         weak_ref_notify,
1260
0
                         conn);
1261
0
    detach_notifier (conn, notifier);
1262
0
  }
1263
1264
15.7k
  if (priv->data_manager) {
1265
9.36k
    tracker_data_manager_shutdown (priv->data_manager);
1266
9.36k
    g_clear_object (&priv->data_manager);
1267
9.36k
  }
1268
15.7k
}
1269
1270
static void
1271
async_close_thread_func (GTask        *task,
1272
                         gpointer      source_object,
1273
                         gpointer      task_data,
1274
                         GCancellable *cancellable)
1275
0
{
1276
0
  if (g_task_return_error_if_cancelled (task))
1277
0
    return;
1278
1279
0
  tracker_sparql_connection_close (source_object);
1280
0
  g_task_return_boolean (task, TRUE);
1281
0
}
1282
1283
static void
1284
tracker_direct_connection_close_async (TrackerSparqlConnection *connection,
1285
                                       GCancellable            *cancellable,
1286
                                       GAsyncReadyCallback      callback,
1287
                                       gpointer                 user_data)
1288
0
{
1289
0
  GTask *task;
1290
1291
0
  task = g_task_new (connection, cancellable, callback, user_data);
1292
0
  g_task_run_in_thread (task, async_close_thread_func);
1293
0
  g_object_unref (task);
1294
0
}
1295
1296
static gboolean
1297
tracker_direct_connection_close_finish (TrackerSparqlConnection  *connection,
1298
                                        GAsyncResult             *res,
1299
                                        GError                  **error)
1300
0
{
1301
0
  return g_task_propagate_boolean (G_TASK (res), error);
1302
0
}
1303
1304
static gboolean
1305
tracker_direct_connection_update_resource (TrackerSparqlConnection  *self,
1306
                                           const gchar              *graph,
1307
                                           TrackerResource          *resource,
1308
                                           GCancellable             *cancellable,
1309
                                           GError                  **error)
1310
0
{
1311
0
  TrackerDirectConnectionPrivate *priv;
1312
0
  TrackerDirectConnection *conn;
1313
0
  TrackerData *data;
1314
0
  GError *inner_error = NULL;
1315
1316
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1317
0
  priv = tracker_direct_connection_get_instance_private (conn);
1318
1319
0
  g_mutex_lock (&priv->update_mutex);
1320
0
  data = tracker_data_manager_get_data (priv->data_manager);
1321
0
  update_resource (data, graph, resource, &inner_error);
1322
0
  tracker_direct_connection_update_timestamp (conn);
1323
0
  g_mutex_unlock (&priv->update_mutex);
1324
1325
0
  if (inner_error) {
1326
0
    g_propagate_error (error, inner_error);
1327
0
    return FALSE;
1328
0
  }
1329
1330
0
  return TRUE;
1331
0
}
1332
1333
static void
1334
tracker_direct_connection_update_resource_async (TrackerSparqlConnection *self,
1335
                                                 const gchar             *graph,
1336
                                                 TrackerResource         *resource,
1337
                                                 GCancellable            *cancellable,
1338
                                                 GAsyncReadyCallback      callback,
1339
                                                 gpointer                 user_data)
1340
0
{
1341
0
  TrackerDirectConnectionPrivate *priv;
1342
0
  TrackerDirectConnection *conn;
1343
0
  TaskData *task_data;
1344
0
  GTask *task;
1345
1346
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1347
0
  priv = tracker_direct_connection_get_instance_private (conn);
1348
1349
0
  task_data = task_data_new (TASK_TYPE_UPDATE_RESOURCE);
1350
0
  task_data->d.update_resource.graph = g_strdup (graph);
1351
0
  task_data->d.update_resource.resource = g_object_ref (resource);
1352
1353
0
  task = g_task_new (self, cancellable, callback, user_data);
1354
0
  g_task_set_task_data (task, task_data,
1355
0
                        (GDestroyNotify) task_data_free);
1356
1357
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1358
0
}
1359
1360
static gboolean
1361
tracker_direct_connection_update_resource_finish (TrackerSparqlConnection  *connection,
1362
                                                  GAsyncResult             *res,
1363
                                                  GError                  **error)
1364
0
{
1365
0
  return g_task_propagate_boolean (G_TASK (res), error);
1366
0
}
1367
1368
static TrackerBatch *
1369
tracker_direct_connection_create_batch (TrackerSparqlConnection *connection)
1370
24.0k
{
1371
24.0k
  TrackerDirectConnectionPrivate *priv;
1372
24.0k
  TrackerDirectConnection *conn;
1373
1374
24.0k
  conn = TRACKER_DIRECT_CONNECTION (connection);
1375
24.0k
  priv = tracker_direct_connection_get_instance_private (conn);
1376
1377
24.0k
  if (priv->flags & TRACKER_SPARQL_CONNECTION_FLAGS_READONLY)
1378
0
    return NULL;
1379
1380
24.0k
  return tracker_direct_batch_new (connection);
1381
24.0k
}
1382
1383
static gboolean
1384
tracker_direct_connection_lookup_dbus_service (TrackerSparqlConnection  *connection,
1385
                                               const gchar              *dbus_name,
1386
                                               const gchar              *dbus_path,
1387
                                               gchar                   **name,
1388
                                               gchar                   **path)
1389
0
{
1390
0
  TrackerDirectConnectionPrivate *priv;
1391
0
  TrackerDirectConnection *conn;
1392
0
  TrackerSparqlConnection *remote;
1393
0
  GError *error = NULL;
1394
0
  gchar *uri;
1395
1396
0
  conn = TRACKER_DIRECT_CONNECTION (connection);
1397
0
  priv = tracker_direct_connection_get_instance_private (conn);
1398
1399
0
  uri = tracker_util_build_dbus_uri (G_BUS_TYPE_SESSION,
1400
0
                                     dbus_name, dbus_path);
1401
0
  remote = tracker_data_manager_get_remote_connection (priv->data_manager,
1402
0
                                                       uri, &error);
1403
0
  if (error) {
1404
0
    g_warning ("Error getting remote connection '%s': %s", uri, error->message);
1405
0
    g_error_free (error);
1406
0
  }
1407
1408
0
  g_free (uri);
1409
1410
0
  if (!remote)
1411
0
    return FALSE;
1412
0
  if (!g_object_class_find_property (G_OBJECT_GET_CLASS (remote), "bus-name"))
1413
0
    return FALSE;
1414
1415
0
  g_object_get (remote,
1416
0
                "bus-name", name,
1417
0
                "bus-object-path", path,
1418
0
                NULL);
1419
1420
0
  return TRUE;
1421
0
}
1422
1423
static void
1424
tracker_direct_connection_serialize_async (TrackerSparqlConnection  *self,
1425
                                           TrackerSerializeFlags     flags,
1426
                                           TrackerRdfFormat          format,
1427
                                           const gchar              *query,
1428
                                           GCancellable             *cancellable,
1429
                                           GAsyncReadyCallback      callback,
1430
                                           gpointer                 user_data)
1431
0
{
1432
0
  TrackerDirectConnectionPrivate *priv;
1433
0
  TrackerDirectConnection *conn;
1434
0
  GError *error = NULL;
1435
0
  TaskData *task_data;
1436
0
  GTask *task;
1437
1438
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1439
0
  priv = tracker_direct_connection_get_instance_private (conn);
1440
1441
0
  task_data = task_data_new (TASK_TYPE_SERIALIZE);
1442
0
  task_data->d.serialize.sparql = g_strdup (query);
1443
0
  task_data->d.serialize.format = format;
1444
0
  task_data->d.serialize.flags = flags;
1445
1446
0
  task = g_task_new (self, cancellable, callback, user_data);
1447
0
  g_task_set_task_data (task, task_data,
1448
0
                        (GDestroyNotify) task_data_free);
1449
1450
0
  if (!g_thread_pool_push (priv->select_pool, task, &error)) {
1451
0
    g_task_return_error (task, _translate_internal_error (error));
1452
0
    g_object_unref (task);
1453
0
  }
1454
0
}
1455
1456
static GInputStream *
1457
tracker_direct_connection_serialize_finish (TrackerSparqlConnection  *connection,
1458
                                            GAsyncResult             *res,
1459
                                            GError                  **error)
1460
0
{
1461
0
  return g_task_propagate_pointer (G_TASK (res), error);
1462
0
}
1463
1464
static void
1465
tracker_direct_connection_deserialize_async (TrackerSparqlConnection *self,
1466
                                             TrackerDeserializeFlags  flags,
1467
                                             TrackerRdfFormat         format,
1468
                                             const gchar             *default_graph,
1469
                                             GInputStream            *stream,
1470
                                             GCancellable            *cancellable,
1471
                                             GAsyncReadyCallback      callback,
1472
                                             gpointer                 user_data)
1473
0
{
1474
0
  TrackerDirectConnectionPrivate *priv;
1475
0
  TrackerDirectConnection *conn;
1476
0
  TaskData *task_data;
1477
0
  GTask *task;
1478
1479
0
  conn = TRACKER_DIRECT_CONNECTION (self);
1480
0
  priv = tracker_direct_connection_get_instance_private (conn);
1481
1482
0
  task_data = task_data_new (TASK_TYPE_DESERIALIZE);
1483
0
  task_data->d.deserialize.stream = g_object_ref (stream);
1484
0
  task_data->d.deserialize.default_graph = g_strdup (default_graph);
1485
0
  task_data->d.deserialize.format = format;
1486
0
  task_data->d.deserialize.flags = flags;
1487
1488
0
  task = g_task_new (self, cancellable, callback, user_data);
1489
0
  g_task_set_task_data (task, task_data,
1490
0
                        (GDestroyNotify) task_data_free);
1491
1492
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1493
0
}
1494
1495
static gboolean
1496
tracker_direct_connection_deserialize_finish (TrackerSparqlConnection  *connection,
1497
                                              GAsyncResult             *res,
1498
                                              GError                  **error)
1499
0
{
1500
0
  return g_task_propagate_boolean (G_TASK (res), error);
1501
0
}
1502
1503
static void
1504
tracker_direct_connection_map_connection (TrackerSparqlConnection *connection,
1505
            const gchar             *handle_name,
1506
            TrackerSparqlConnection *service_connection)
1507
0
{
1508
0
  TrackerDirectConnectionPrivate *priv;
1509
0
  TrackerDirectConnection *conn;
1510
1511
0
  conn = TRACKER_DIRECT_CONNECTION (connection);
1512
0
  priv = tracker_direct_connection_get_instance_private (conn);
1513
1514
0
  tracker_data_manager_map_connection (priv->data_manager,
1515
0
                                       handle_name,
1516
0
                                       service_connection);
1517
0
}
1518
1519
static void
1520
tracker_direct_connection_class_init (TrackerDirectConnectionClass *klass)
1521
5
{
1522
5
  TrackerSparqlConnectionClass *sparql_connection_class;
1523
5
  GObjectClass *object_class;
1524
1525
5
  object_class = G_OBJECT_CLASS (klass);
1526
5
  sparql_connection_class = TRACKER_SPARQL_CONNECTION_CLASS (klass);
1527
1528
5
  object_class->finalize = tracker_direct_connection_finalize;
1529
5
  object_class->set_property = tracker_direct_connection_set_property;
1530
5
  object_class->get_property = tracker_direct_connection_get_property;
1531
1532
5
  sparql_connection_class->query = tracker_direct_connection_query;
1533
5
  sparql_connection_class->query_async = tracker_direct_connection_query_async;
1534
5
  sparql_connection_class->query_finish = tracker_direct_connection_query_finish;
1535
5
  sparql_connection_class->query_statement = tracker_direct_connection_query_statement;
1536
5
  sparql_connection_class->update_statement = tracker_direct_connection_update_statement;
1537
5
  sparql_connection_class->update = tracker_direct_connection_update;
1538
5
  sparql_connection_class->update_async = tracker_direct_connection_update_async;
1539
5
  sparql_connection_class->update_finish = tracker_direct_connection_update_finish;
1540
5
  sparql_connection_class->update_array_async = tracker_direct_connection_update_array_async;
1541
5
  sparql_connection_class->update_array_finish = tracker_direct_connection_update_array_finish;
1542
5
  sparql_connection_class->update_blank = tracker_direct_connection_update_blank;
1543
5
  sparql_connection_class->update_blank_async = tracker_direct_connection_update_blank_async;
1544
5
  sparql_connection_class->update_blank_finish = tracker_direct_connection_update_blank_finish;
1545
5
  sparql_connection_class->get_namespace_manager = tracker_direct_connection_get_namespace_manager;
1546
5
  sparql_connection_class->create_notifier = tracker_direct_connection_create_notifier;
1547
5
  sparql_connection_class->close = tracker_direct_connection_close;
1548
5
  sparql_connection_class->close_async = tracker_direct_connection_close_async;
1549
5
  sparql_connection_class->close_finish = tracker_direct_connection_close_finish;
1550
5
  sparql_connection_class->update_resource = tracker_direct_connection_update_resource;
1551
5
  sparql_connection_class->update_resource_async = tracker_direct_connection_update_resource_async;
1552
5
  sparql_connection_class->update_resource_finish = tracker_direct_connection_update_resource_finish;
1553
5
  sparql_connection_class->create_batch = tracker_direct_connection_create_batch;
1554
5
  sparql_connection_class->lookup_dbus_service = tracker_direct_connection_lookup_dbus_service;
1555
5
  sparql_connection_class->serialize_async = tracker_direct_connection_serialize_async;
1556
5
  sparql_connection_class->serialize_finish = tracker_direct_connection_serialize_finish;
1557
5
  sparql_connection_class->deserialize_async = tracker_direct_connection_deserialize_async;
1558
5
  sparql_connection_class->deserialize_finish = tracker_direct_connection_deserialize_finish;
1559
5
  sparql_connection_class->map_connection = tracker_direct_connection_map_connection;
1560
1561
5
  props[PROP_FLAGS] =
1562
5
    g_param_spec_flags ("flags",
1563
5
                        "Flags",
1564
5
                        "Flags",
1565
5
                        TRACKER_TYPE_SPARQL_CONNECTION_FLAGS,
1566
5
                        TRACKER_SPARQL_CONNECTION_FLAGS_NONE,
1567
5
                        G_PARAM_READWRITE |
1568
5
                        G_PARAM_CONSTRUCT_ONLY);
1569
5
  props[PROP_STORE_LOCATION] =
1570
5
    g_param_spec_object ("store-location",
1571
5
                         "Store location",
1572
5
                         "Store location",
1573
5
                         G_TYPE_FILE,
1574
5
                         G_PARAM_READWRITE |
1575
5
                         G_PARAM_CONSTRUCT_ONLY);
1576
5
  props[PROP_ONTOLOGY_LOCATION] =
1577
5
    g_param_spec_object ("ontology-location",
1578
5
                         "Ontology location",
1579
5
                         "Ontology location",
1580
5
                         G_TYPE_FILE,
1581
5
                         G_PARAM_READWRITE |
1582
5
                         G_PARAM_CONSTRUCT_ONLY);
1583
5
  props[PROP_ONTOLOGY_STREAM] =
1584
5
    g_param_spec_object ("ontology-stream", NULL, NULL,
1585
5
                         G_TYPE_INPUT_STREAM,
1586
5
                         G_PARAM_WRITABLE |
1587
5
                         G_PARAM_CONSTRUCT_ONLY);
1588
5
  props[PROP_ONTOLOGY_STREAM_FORMAT] =
1589
5
    g_param_spec_enum ("ontology-stream-format", NULL, NULL,
1590
5
                       TRACKER_TYPE_RDF_FORMAT,
1591
5
                       TRACKER_RDF_FORMAT_TURTLE,
1592
5
                       G_PARAM_WRITABLE |
1593
5
                       G_PARAM_CONSTRUCT_ONLY);
1594
1595
5
  g_object_class_install_properties (object_class, N_PROPS, props);
1596
5
}
1597
1598
TrackerSparqlConnection *
1599
tracker_direct_connection_new (TrackerSparqlConnectionFlags   flags,
1600
                               GFile                         *store,
1601
                               GFile                         *ontology,
1602
                               GError                       **error)
1603
5.77k
{
1604
5.77k
  return g_initable_new (TRACKER_TYPE_DIRECT_CONNECTION,
1605
5.77k
                         NULL, error,
1606
5.77k
                         "flags", flags,
1607
5.77k
                         "store-location", store,
1608
5.77k
                         "ontology-location", ontology,
1609
5.77k
                         NULL);
1610
5.77k
}
1611
1612
void
1613
tracker_direct_connection_new_async (TrackerSparqlConnectionFlags  flags,
1614
                                     GFile                        *store,
1615
                                     GFile                        *ontology,
1616
                                     GCancellable                 *cancellable,
1617
                                     GAsyncReadyCallback           cb,
1618
                                     gpointer                      user_data)
1619
0
{
1620
0
  g_async_initable_new_async (TRACKER_TYPE_DIRECT_CONNECTION,
1621
0
                              G_PRIORITY_DEFAULT,
1622
0
                              cancellable,
1623
0
                              cb,
1624
0
                              user_data,
1625
0
                              "flags", flags,
1626
0
                              "store-location", store,
1627
0
                              "ontology-location", ontology,
1628
0
                              NULL);
1629
0
}
1630
1631
TrackerSparqlConnection *
1632
tracker_direct_connection_new_finish (GAsyncResult  *res,
1633
                                      GError       **error)
1634
0
{
1635
0
  GAsyncInitable *initable;
1636
1637
0
  initable = g_task_get_source_object (G_TASK (res));
1638
1639
0
  return TRACKER_SPARQL_CONNECTION (g_async_initable_new_finish (initable,
1640
0
                                                                 res,
1641
0
                                                                 error));
1642
0
}
1643
1644
TrackerSparqlConnection *
1645
tracker_direct_connection_new_from_rdf (TrackerSparqlConnectionFlags   flags,
1646
                                        GFile                         *store,
1647
                                        TrackerDeserializeFlags        deserialize_flags,
1648
                                        TrackerRdfFormat               rdf_format,
1649
                                        GInputStream                  *rdf_stream,
1650
                                        GCancellable                  *cancellable,
1651
                                        GError                       **error)
1652
9.94k
{
1653
9.94k
  return g_initable_new (TRACKER_TYPE_DIRECT_CONNECTION,
1654
9.94k
                         cancellable, error,
1655
9.94k
                         "flags", flags,
1656
9.94k
                         "store-location", store,
1657
9.94k
                         "ontology-stream-format", rdf_format,
1658
9.94k
                         "ontology-stream", rdf_stream,
1659
9.94k
                         NULL);
1660
9.94k
}
1661
1662
void
1663
tracker_direct_connection_new_from_rdf_async (TrackerSparqlConnectionFlags  flags,
1664
                                              GFile                        *store,
1665
                                              TrackerDeserializeFlags       deserialize_flags,
1666
                                              TrackerRdfFormat              rdf_format,
1667
                                              GInputStream                 *rdf_stream,
1668
                                              GCancellable                 *cancellable,
1669
                                              GAsyncReadyCallback           cb,
1670
                                              gpointer                      user_data)
1671
0
{
1672
0
  g_async_initable_new_async (TRACKER_TYPE_DIRECT_CONNECTION,
1673
0
                              G_PRIORITY_DEFAULT,
1674
0
                              cancellable,
1675
0
                              cb,
1676
0
                              user_data,
1677
0
                              "flags", flags,
1678
0
                              "store-location", store,
1679
0
                              "ontology-stream-format", rdf_format,
1680
0
                              "ontology-stream", rdf_stream,
1681
0
                              NULL);
1682
0
}
1683
1684
TrackerSparqlConnection *
1685
tracker_direct_connection_new_from_rdf_finish (GAsyncResult  *res,
1686
                                               GError       **error)
1687
0
{
1688
0
  GAsyncInitable *initable;
1689
1690
0
  initable = g_task_get_source_object (G_TASK (res));
1691
1692
0
  return TRACKER_SPARQL_CONNECTION (g_async_initable_new_finish (initable,
1693
0
                                                                 res,
1694
0
                                                                 error));
1695
0
}
1696
1697
TrackerDataManager *
1698
tracker_direct_connection_get_data_manager (TrackerDirectConnection *conn)
1699
11.0k
{
1700
11.0k
  TrackerDirectConnectionPrivate *priv;
1701
1702
11.0k
  priv = tracker_direct_connection_get_instance_private (conn);
1703
11.0k
  return priv->data_manager;
1704
11.0k
}
1705
1706
void
1707
tracker_direct_connection_update_timestamp (TrackerDirectConnection *conn)
1708
24.0k
{
1709
24.0k
  TrackerDirectConnectionPrivate *priv;
1710
1711
24.0k
  priv = tracker_direct_connection_get_instance_private (conn);
1712
24.0k
  priv->timestamp = g_get_monotonic_time ();
1713
24.0k
}
1714
1715
gboolean
1716
tracker_direct_connection_update_batch (TrackerDirectConnection  *conn,
1717
                                        TrackerBatch             *batch,
1718
                                        GError                  **error)
1719
24.0k
{
1720
24.0k
  TrackerDirectConnectionPrivate *priv;
1721
24.0k
  GError *inner_error = NULL;
1722
1723
24.0k
  priv = tracker_direct_connection_get_instance_private (conn);
1724
1725
24.0k
  g_mutex_lock (&priv->update_mutex);
1726
24.0k
  tracker_direct_batch_update (TRACKER_DIRECT_BATCH (batch),
1727
24.0k
                               priv->data_manager, &inner_error);
1728
24.0k
  tracker_direct_connection_update_timestamp (conn);
1729
24.0k
  g_mutex_unlock (&priv->update_mutex);
1730
1731
24.0k
  if (inner_error) {
1732
18.2k
    g_propagate_error (error, inner_error);
1733
18.2k
    return FALSE;
1734
18.2k
  }
1735
1736
5.76k
  return TRUE;
1737
24.0k
}
1738
1739
void
1740
tracker_direct_connection_update_batch_async (TrackerDirectConnection  *conn,
1741
                                              TrackerBatch             *batch,
1742
                                              GCancellable             *cancellable,
1743
                                              GAsyncReadyCallback       callback,
1744
                                              gpointer                  user_data)
1745
0
{
1746
0
  TrackerDirectConnectionPrivate *priv;
1747
0
  TaskData *task_data;
1748
0
  GTask *task;
1749
1750
0
  priv = tracker_direct_connection_get_instance_private (conn);
1751
1752
0
  task_data = task_data_new (TASK_TYPE_UPDATE_BATCH);
1753
0
  task_data->d.batch = g_object_ref (batch);
1754
1755
0
  task = g_task_new (batch, cancellable, callback, user_data);
1756
0
  g_task_set_task_data (task, task_data,
1757
0
                        (GDestroyNotify) task_data_free);
1758
1759
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1760
0
}
1761
1762
gboolean
1763
tracker_direct_connection_update_batch_finish (TrackerDirectConnection  *conn,
1764
                                               GAsyncResult             *res,
1765
                                               GError                  **error)
1766
0
{
1767
0
  GError *inner_error = NULL;
1768
1769
0
  g_task_propagate_boolean (G_TASK (res), &inner_error);
1770
0
  if (inner_error) {
1771
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1772
0
    return FALSE;
1773
0
  }
1774
1775
0
  return TRUE;
1776
0
}
1777
1778
gboolean
1779
tracker_direct_connection_execute_update_statement (TrackerDirectConnection  *conn,
1780
                                                    TrackerSparqlStatement   *stmt,
1781
                                                    GHashTable               *parameters,
1782
                                                    GError                  **error)
1783
0
{
1784
0
  TrackerDirectConnectionPrivate *priv;
1785
0
  TrackerData *tracker_data;
1786
0
  GError *inner_error = NULL;
1787
1788
0
  priv = tracker_direct_connection_get_instance_private (conn);
1789
1790
0
  g_mutex_lock (&priv->update_mutex);
1791
1792
0
  tracker_data = tracker_data_manager_get_data (priv->data_manager);
1793
0
  if (!tracker_data_begin_transaction (tracker_data, &inner_error))
1794
0
    goto out;
1795
1796
0
  if (tracker_direct_statement_execute_update (stmt, parameters, NULL, &inner_error)) {
1797
0
    if (tracker_data_commit_transaction (tracker_data, &inner_error))
1798
0
      tracker_direct_connection_update_timestamp (conn);
1799
0
  } else {
1800
0
    tracker_data_rollback_transaction (tracker_data);
1801
0
  }
1802
1803
0
 out:
1804
0
  g_mutex_unlock (&priv->update_mutex);
1805
1806
0
  if (inner_error) {
1807
0
    g_propagate_error (error, inner_error);
1808
0
    return FALSE;
1809
0
  }
1810
1811
0
  return TRUE;
1812
0
}
1813
1814
void
1815
tracker_direct_connection_execute_query_statement_async (TrackerDirectConnection *conn,
1816
                                                         TrackerSparqlStatement  *stmt,
1817
                                                         GHashTable              *parameters,
1818
                                                         GCancellable            *cancellable,
1819
                                                         GAsyncReadyCallback      callback,
1820
                                                         gpointer                 user_data)
1821
0
{
1822
0
  TrackerDirectConnectionPrivate *priv =
1823
0
    tracker_direct_connection_get_instance_private (conn);
1824
0
  GError *error = NULL;
1825
0
  TaskData *task_data;
1826
0
  GTask *task;
1827
1828
0
  task_data = task_data_new (TASK_TYPE_QUERY_STATEMENT);
1829
0
  task_data->d.statement.stmt = g_object_ref (stmt);
1830
0
  task_data->d.statement.parameters =
1831
0
    parameters ? g_hash_table_ref (parameters) : NULL;
1832
1833
0
  task = g_task_new (conn, cancellable, callback, user_data);
1834
0
  g_task_set_task_data (task, task_data,
1835
0
                        (GDestroyNotify) task_data_free);
1836
1837
0
  if (!g_thread_pool_push (priv->select_pool, task, &error)) {
1838
0
    g_task_return_error (task, _translate_internal_error (error));
1839
0
    g_object_unref (task);
1840
0
  }
1841
0
}
1842
1843
TrackerSparqlCursor *
1844
tracker_direct_connection_execute_query_statement_finish (TrackerDirectConnection  *conn,
1845
                                                          GAsyncResult             *res,
1846
                                                          GError                  **error)
1847
0
{
1848
0
  return g_task_propagate_pointer (G_TASK (res), error);
1849
0
}
1850
1851
void
1852
tracker_direct_connection_execute_serialize_statement_async (TrackerDirectConnection *conn,
1853
                                                             TrackerSparqlStatement  *stmt,
1854
                                                             GHashTable              *parameters,
1855
                                                             TrackerSerializeFlags    flags,
1856
                                                             TrackerRdfFormat         format,
1857
                                                             GCancellable            *cancellable,
1858
                                                             GAsyncReadyCallback      callback,
1859
                                                             gpointer                 user_data)
1860
0
{
1861
0
  TrackerDirectConnectionPrivate *priv =
1862
0
    tracker_direct_connection_get_instance_private (conn);
1863
0
  GError *error = NULL;
1864
0
  TaskData *task_data;
1865
0
  GTask *task;
1866
1867
0
  task_data = task_data_new (TASK_TYPE_SERIALIZE_STATEMENT);
1868
0
  task_data->d.serialize_statement.stmt = g_object_ref (stmt);
1869
0
  task_data->d.serialize_statement.parameters =
1870
0
    parameters ? g_hash_table_ref (parameters) : NULL;
1871
0
  task_data->d.serialize_statement.flags = flags;
1872
0
  task_data->d.serialize_statement.format = format;
1873
1874
0
  task = g_task_new (conn, cancellable, callback, user_data);
1875
0
  g_task_set_task_data (task, task_data,
1876
0
                        (GDestroyNotify) task_data_free);
1877
1878
0
  if (!g_thread_pool_push (priv->select_pool, task, &error)) {
1879
0
    g_task_return_error (task, _translate_internal_error (error));
1880
0
    g_object_unref (task);
1881
0
  }
1882
0
}
1883
1884
GInputStream *
1885
tracker_direct_connection_execute_serialize_statement_finish (TrackerDirectConnection  *conn,
1886
                                                              GAsyncResult             *res,
1887
                                                              GError                  **error)
1888
0
{
1889
0
  return g_task_propagate_pointer (G_TASK (res), error);
1890
0
}
1891
1892
1893
void
1894
tracker_direct_connection_execute_update_statement_async (TrackerDirectConnection  *conn,
1895
                                                          TrackerSparqlStatement   *stmt,
1896
                                                          GHashTable               *parameters,
1897
                                                          GCancellable             *cancellable,
1898
                                                          GAsyncReadyCallback       callback,
1899
                                                          gpointer                  user_data)
1900
0
{
1901
0
  TrackerDirectConnectionPrivate *priv;
1902
0
  TaskData *task_data;
1903
0
  GTask *task;
1904
1905
0
  priv = tracker_direct_connection_get_instance_private (conn);
1906
1907
0
  task_data = task_data_new (TASK_TYPE_UPDATE_STATEMENT);
1908
0
  task_data->d.statement.stmt = g_object_ref (stmt);
1909
0
  task_data->d.statement.parameters =
1910
0
    parameters ? g_hash_table_ref (parameters) : NULL;
1911
1912
0
  task = g_task_new (stmt, cancellable, callback, user_data);
1913
0
  g_task_set_task_data (task, task_data,
1914
0
                        (GDestroyNotify) task_data_free);
1915
1916
0
  g_thread_pool_push (priv->update_thread, task, NULL);
1917
0
}
1918
1919
gboolean
1920
tracker_direct_connection_execute_update_statement_finish (TrackerDirectConnection  *conn,
1921
                                                           GAsyncResult             *res,
1922
                                                           GError                  **error)
1923
0
{
1924
0
  GError *inner_error = NULL;
1925
1926
0
  g_task_propagate_boolean (G_TASK (res), &inner_error);
1927
0
  if (inner_error) {
1928
0
    g_propagate_error (error, _translate_internal_error (inner_error));
1929
0
    return FALSE;
1930
0
  }
1931
1932
0
  return TRUE;
1933
0
}