No issues found
1 /*
2 * Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org>
3 * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
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 Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21 #include "config.h"
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 #include <glib.h>
27
28 #include "tracker-class.h"
29 #include "tracker-namespace.h"
30 #include "tracker-ontologies.h"
31
32 #define GET_PRIV(obj) (((TrackerClass*) obj)->priv)
33 #define TRACKER_CLASS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), TRACKER_TYPE_CLASS, TrackerClassPrivate))
34
35 struct _TrackerClassPrivate {
36 gchar *uri;
37 gchar *name;
38 gint count;
39 gint id;
40 gboolean is_new;
41 gboolean db_schema_changed;
42 gboolean notify;
43
44 gboolean use_gvdb;
45
46 GArray *super_classes;
47 GArray *domain_indexes;
48 GArray *last_domain_indexes;
49 GArray *last_super_classes;
50
51 struct {
52 struct {
53 GArray *sub_pred_ids;
54 GArray *obj_graph_ids;
55 } pending;
56 struct {
57 GArray *sub_pred_ids;
58 GArray *obj_graph_ids;
59 } ready;
60 } deletes;
61 struct {
62 struct {
63 GArray *sub_pred_ids;
64 GArray *obj_graph_ids;
65 } pending;
66 struct {
67 GArray *sub_pred_ids;
68 GArray *obj_graph_ids;
69 } ready;
70 } inserts;
71 };
72
73 static void class_finalize (GObject *object);
74
75 G_DEFINE_TYPE (TrackerClass, tracker_class, G_TYPE_OBJECT);
76
77 static void
78 tracker_class_class_init (TrackerClassClass *klass)
79 {
80 GObjectClass *object_class = G_OBJECT_CLASS (klass);
81
82 object_class->finalize = class_finalize;
83
84 g_type_class_add_private (object_class, sizeof (TrackerClassPrivate));
85 }
86
87 static void
88 tracker_class_init (TrackerClass *service)
89 {
90 TrackerClassPrivate *priv;
91
92 priv = TRACKER_CLASS_GET_PRIVATE (service);
93
94 priv->id = 0;
95 priv->super_classes = g_array_new (TRUE, TRUE, sizeof (TrackerClass *));
96 priv->domain_indexes = g_array_new (TRUE, TRUE, sizeof (TrackerProperty *));
97 priv->last_domain_indexes = NULL;
98 priv->last_super_classes = NULL;
99
100 priv->deletes.pending.sub_pred_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
101 priv->deletes.pending.obj_graph_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
102 priv->deletes.ready.sub_pred_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
103 priv->deletes.ready.obj_graph_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
104
105 priv->inserts.pending.sub_pred_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
106 priv->inserts.pending.obj_graph_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
107 priv->inserts.ready.sub_pred_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
108 priv->inserts.ready.obj_graph_ids = g_array_new (FALSE, FALSE, sizeof (gint64));
109
110 /* Make GET_PRIV working */
111 service->priv = priv;
112 }
113
114 static void
115 class_finalize (GObject *object)
116 {
117 TrackerClassPrivate *priv;
118
119 priv = GET_PRIV (object);
120
121 g_free (priv->uri);
122 g_free (priv->name);
123
124 g_array_free (priv->super_classes, TRUE);
125 g_array_free (priv->domain_indexes, TRUE);
126
127 g_array_free (priv->deletes.pending.sub_pred_ids, TRUE);
128 g_array_free (priv->deletes.pending.obj_graph_ids, TRUE);
129 g_array_free (priv->deletes.ready.sub_pred_ids, TRUE);
130 g_array_free (priv->deletes.ready.obj_graph_ids, TRUE);
131
132 g_array_free (priv->inserts.pending.sub_pred_ids, TRUE);
133 g_array_free (priv->inserts.pending.obj_graph_ids, TRUE);
134 g_array_free (priv->inserts.ready.sub_pred_ids, TRUE);
135 g_array_free (priv->inserts.ready.obj_graph_ids, TRUE);
136
137 if (priv->last_domain_indexes) {
138 g_array_free (priv->last_domain_indexes, TRUE);
139 }
140
141 if (priv->last_super_classes) {
142 g_array_free (priv->last_super_classes, TRUE);
143 }
144
145 (G_OBJECT_CLASS (tracker_class_parent_class)->finalize) (object);
146 }
147
148 TrackerClass *
149 tracker_class_new (gboolean use_gvdb)
150 {
151 TrackerClass *service;
152 TrackerClassPrivate *priv;
153
154 service = g_object_new (TRACKER_TYPE_CLASS, NULL);
155
156 if (use_gvdb) {
157 priv = GET_PRIV (service);
158 priv->use_gvdb = use_gvdb;
159 }
160
161 return service;
162 }
163
164 const gchar *
165 tracker_class_get_uri (TrackerClass *service)
166 {
167 TrackerClassPrivate *priv;
168
169 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
170
171 priv = GET_PRIV (service);
172
173 return priv->uri;
174 }
175
176 const gchar *
177 tracker_class_get_name (TrackerClass *service)
178 {
179 TrackerClassPrivate *priv;
180
181 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
182
183 priv = GET_PRIV (service);
184
185 return priv->name;
186 }
187
188 gint
189 tracker_class_get_count (TrackerClass *service)
190 {
191 TrackerClassPrivate *priv;
192
193 g_return_val_if_fail (TRACKER_IS_CLASS (service), 0);
194
195 priv = GET_PRIV (service);
196
197 return priv->count;
198 }
199
200 gint
201 tracker_class_get_id (TrackerClass *service)
202 {
203 TrackerClassPrivate *priv;
204
205 g_return_val_if_fail (TRACKER_IS_CLASS (service), 0);
206
207 priv = GET_PRIV (service);
208
209 return priv->id;
210 }
211
212 TrackerClass **
213 tracker_class_get_super_classes (TrackerClass *service)
214 {
215 TrackerClassPrivate *priv;
216
217 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
218
219 priv = GET_PRIV (service);
220
221 if (priv->use_gvdb) {
222 TrackerClass *super_class;
223 GVariant *variant;
224
225 tracker_class_reset_super_classes (service);
226
227 variant = tracker_ontologies_get_class_value_gvdb (priv->uri, "super-classes");
228 if (variant) {
229 GVariantIter iter;
230 const gchar *uri;
231
232 g_variant_iter_init (&iter, variant);
233 while (g_variant_iter_loop (&iter, "&s", &uri)) {
234 super_class = tracker_ontologies_get_class_by_uri (uri);
235
236 tracker_class_add_super_class (service, super_class);
237 }
238
239 g_variant_unref (variant);
240 }
241 }
242
243 return (TrackerClass **) priv->super_classes->data;
244 }
245
246 TrackerProperty **
247 tracker_class_get_domain_indexes (TrackerClass *service)
248 {
249 TrackerClassPrivate *priv;
250
251 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
252
253 priv = GET_PRIV (service);
254
255 return (TrackerProperty **) priv->domain_indexes->data;
256 }
257
258
259 TrackerProperty **
260 tracker_class_get_last_domain_indexes (TrackerClass *service)
261 {
262 TrackerClassPrivate *priv;
263
264 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
265
266 priv = GET_PRIV (service);
267
268 return (TrackerProperty **) (priv->last_domain_indexes ? priv->last_domain_indexes->data : NULL);
269 }
270
271 TrackerClass **
272 tracker_class_get_last_super_classes (TrackerClass *service)
273 {
274 TrackerClassPrivate *priv;
275
276 g_return_val_if_fail (TRACKER_IS_CLASS (service), NULL);
277
278 priv = GET_PRIV (service);
279
280 return (TrackerClass **) (priv->last_super_classes ? priv->last_super_classes->data : NULL);
281 }
282
283 gboolean
284 tracker_class_get_is_new (TrackerClass *service)
285 {
286 TrackerClassPrivate *priv;
287
288 g_return_val_if_fail (TRACKER_IS_CLASS (service), FALSE);
289
290 priv = GET_PRIV (service);
291
292 return priv->is_new;
293 }
294
295 gboolean
296 tracker_class_get_notify (TrackerClass *service)
297 {
298 TrackerClassPrivate *priv;
299
300 g_return_val_if_fail (TRACKER_IS_CLASS (service), FALSE);
301
302 priv = GET_PRIV (service);
303
304 return priv->notify;
305 }
306
307 gboolean
308 tracker_class_get_db_schema_changed (TrackerClass *service)
309 {
310 TrackerClassPrivate *priv;
311
312 g_return_val_if_fail (TRACKER_IS_CLASS (service), FALSE);
313
314 priv = GET_PRIV (service);
315
316 return priv->db_schema_changed;
317 }
318
319 void
320 tracker_class_set_uri (TrackerClass *service,
321 const gchar *value)
322 {
323 TrackerClassPrivate *priv;
324
325 g_return_if_fail (TRACKER_IS_CLASS (service));
326
327 priv = GET_PRIV (service);
328
329 g_free (priv->uri);
330 g_free (priv->name);
331 priv->uri = NULL;
332 priv->name = NULL;
333
334 if (value) {
335 gchar *namespace_uri, *hash;
336 TrackerNamespace *namespace;
337
338 priv->uri = g_strdup (value);
339
340 hash = strrchr (priv->uri, '#');
341 if (hash == NULL) {
342 /* support ontologies whose namespace uri does not end in a hash, e.g. dc */
343 hash = strrchr (priv->uri, '/');
344 }
345 if (hash == NULL) {
346 g_critical ("Unknown namespace of class %s", priv->uri);
347 } else {
348 namespace_uri = g_strndup (priv->uri, hash - priv->uri + 1);
349 namespace = tracker_ontologies_get_namespace_by_uri (namespace_uri);
350 if (namespace == NULL) {
351 g_critical ("Unknown namespace %s of class %s", namespace_uri, priv->uri);
352 } else {
353 priv->name = g_strdup_printf ("%s:%s", tracker_namespace_get_prefix (namespace), hash + 1);
354 }
355 g_free (namespace_uri);
356 }
357 }
358 }
359
360 void
361 tracker_class_set_count (TrackerClass *service,
362 gint value)
363 {
364 TrackerClassPrivate *priv;
365
366 g_return_if_fail (TRACKER_IS_CLASS (service));
367
368 priv = GET_PRIV (service);
369
370 priv->count = value;
371 }
372
373
374 void
375 tracker_class_set_id (TrackerClass *service,
376 gint value)
377 {
378 TrackerClassPrivate *priv;
379
380 g_return_if_fail (TRACKER_IS_CLASS (service));
381
382 priv = GET_PRIV (service);
383
384 priv->id = value;
385 }
386
387 void
388 tracker_class_add_super_class (TrackerClass *service,
389 TrackerClass *value)
390 {
391 TrackerClassPrivate *priv;
392
393 g_return_if_fail (TRACKER_IS_CLASS (service));
394 g_return_if_fail (TRACKER_IS_CLASS (value));
395
396 priv = GET_PRIV (service);
397
398 g_array_append_val (priv->super_classes, value);
399 }
400
401 void
402 tracker_class_reset_super_classes (TrackerClass *service)
403 {
404 TrackerClassPrivate *priv;
405
406 g_return_if_fail (TRACKER_IS_CLASS (service));
407
408 priv = GET_PRIV (service);
409
410 if (priv->last_super_classes) {
411 g_array_free (priv->last_super_classes, TRUE);
412 }
413
414 priv->last_super_classes = priv->super_classes;
415 priv->super_classes = g_array_new (TRUE, TRUE, sizeof (TrackerClass *));
416 }
417
418 void
419 tracker_class_add_domain_index (TrackerClass *service,
420 TrackerProperty *value)
421 {
422 TrackerClassPrivate *priv;
423
424 g_return_if_fail (TRACKER_IS_CLASS (service));
425 g_return_if_fail (TRACKER_IS_PROPERTY (value));
426
427 priv = GET_PRIV (service);
428
429 g_array_append_val (priv->domain_indexes, value);
430 }
431
432 void
433 tracker_class_del_domain_index (TrackerClass *service,
434 TrackerProperty *value)
435 {
436 TrackerClassPrivate *priv;
437 gint i = 0, found = -1;
438 TrackerProperty **properties;
439
440 g_return_if_fail (TRACKER_IS_CLASS (service));
441 g_return_if_fail (TRACKER_IS_PROPERTY (value));
442
443 priv = GET_PRIV (service);
444
445 properties = (TrackerProperty **) priv->domain_indexes->data;
446 while (*properties) {
447 if (*properties == value) {
448 found = i;
449 break;
450 }
451 i++;
452 properties++;
453 }
454
455 if (found != -1) {
456 g_array_remove_index (priv->domain_indexes, found);
457 }
458 }
459
460 void
461 tracker_class_reset_domain_indexes (TrackerClass *service)
462 {
463 TrackerClassPrivate *priv;
464
465 g_return_if_fail (TRACKER_IS_CLASS (service));
466
467 priv = GET_PRIV (service);
468 priv->last_domain_indexes = priv->domain_indexes;
469 priv->domain_indexes = g_array_new (TRUE, TRUE, sizeof (TrackerProperty *));
470 }
471
472 void
473 tracker_class_set_is_new (TrackerClass *service,
474 gboolean value)
475 {
476 TrackerClassPrivate *priv;
477
478 g_return_if_fail (TRACKER_IS_CLASS (service));
479
480 priv = GET_PRIV (service);
481
482 priv->is_new = value;
483 }
484
485
486 void
487 tracker_class_set_notify (TrackerClass *service,
488 gboolean value)
489 {
490 TrackerClassPrivate *priv;
491
492 g_return_if_fail (TRACKER_IS_CLASS (service));
493
494 priv = GET_PRIV (service);
495
496 priv->notify = value;
497 }
498
499 void
500 tracker_class_set_db_schema_changed (TrackerClass *service,
501 gboolean value)
502 {
503 TrackerClassPrivate *priv;
504
505 g_return_if_fail (TRACKER_IS_CLASS (service));
506
507 priv = GET_PRIV (service);
508
509 priv->db_schema_changed = value;
510 }
511
512 gboolean
513 tracker_class_has_insert_events (TrackerClass *class)
514 {
515 TrackerClassPrivate *priv;
516
517 g_return_val_if_fail (TRACKER_IS_CLASS (class), FALSE);
518
519 priv = GET_PRIV (class);
520
521 return (priv->inserts.ready.sub_pred_ids->len > 0);
522 }
523
524 gboolean
525 tracker_class_has_delete_events (TrackerClass *class)
526 {
527 TrackerClassPrivate *priv;
528
529 g_return_val_if_fail (TRACKER_IS_CLASS (class), FALSE);
530
531 priv = GET_PRIV (class);
532
533 return (priv->deletes.ready.sub_pred_ids->len > 0);
534 }
535
536 void
537 tracker_class_foreach_insert_event (TrackerClass *class,
538 TrackerEventsForeach foreach,
539 gpointer user_data)
540 {
541 guint i;
542 TrackerClassPrivate *priv;
543
544 g_return_if_fail (TRACKER_IS_CLASS (class));
545 g_return_if_fail (foreach != NULL);
546
547 priv = GET_PRIV (class);
548
549 for (i = 0; i < priv->inserts.ready.sub_pred_ids->len; i++) {
550 gint graph_id, subject_id, pred_id, object_id;
551 gint64 sub_pred_id;
552 gint64 obj_graph_id;
553
554 sub_pred_id = g_array_index (priv->inserts.ready.sub_pred_ids, gint64, i);
555 obj_graph_id = g_array_index (priv->inserts.ready.obj_graph_ids, gint64, i);
556
557 pred_id = sub_pred_id & 0xffffffff;
558 subject_id = sub_pred_id >> 32;
559 graph_id = obj_graph_id & 0xffffffff;
560 object_id = obj_graph_id >> 32;
561
562 foreach (graph_id, subject_id, pred_id, object_id, user_data);
563 }
564 }
565
566 void
567 tracker_class_foreach_delete_event (TrackerClass *class,
568 TrackerEventsForeach foreach,
569 gpointer user_data)
570 {
571 guint i;
572 TrackerClassPrivate *priv;
573
574 g_return_if_fail (TRACKER_IS_CLASS (class));
575 g_return_if_fail (foreach != NULL);
576
577 priv = GET_PRIV (class);
578
579 for (i = 0; i < priv->deletes.ready.sub_pred_ids->len; i++) {
580 gint graph_id, subject_id, pred_id, object_id;
581 gint64 sub_pred_id;
582 gint64 obj_graph_id;
583
584 sub_pred_id = g_array_index (priv->deletes.ready.sub_pred_ids, gint64, i);
585 obj_graph_id = g_array_index (priv->deletes.ready.obj_graph_ids, gint64, i);
586
587 pred_id = sub_pred_id & 0xffffffff;
588 subject_id = sub_pred_id >> 32;
589 graph_id = obj_graph_id & 0xffffffff;
590 object_id = obj_graph_id >> 32;
591
592 foreach (graph_id, subject_id, pred_id, object_id, user_data);
593 }
594 }
595
596 void
597 tracker_class_reset_ready_events (TrackerClass *class)
598 {
599 TrackerClassPrivate *priv;
600
601 g_return_if_fail (TRACKER_IS_CLASS (class));
602
603 priv = GET_PRIV (class);
604
605 /* Reset */
606 g_array_set_size (priv->deletes.ready.sub_pred_ids, 0);
607 g_array_set_size (priv->deletes.ready.obj_graph_ids, 0);
608
609 g_array_set_size (priv->inserts.ready.sub_pred_ids, 0);
610 g_array_set_size (priv->inserts.ready.obj_graph_ids, 0);
611
612 }
613
614 void
615 tracker_class_reset_pending_events (TrackerClass *class)
616 {
617 TrackerClassPrivate *priv;
618
619 g_return_if_fail (TRACKER_IS_CLASS (class));
620
621 priv = GET_PRIV (class);
622
623 /* Reset */
624 g_array_set_size (priv->deletes.pending.sub_pred_ids, 0);
625 g_array_set_size (priv->deletes.pending.obj_graph_ids, 0);
626
627 g_array_set_size (priv->inserts.pending.sub_pred_ids, 0);
628 g_array_set_size (priv->inserts.pending.obj_graph_ids, 0);
629
630 }
631
632 void
633 tracker_class_transact_events (TrackerClass *class)
634 {
635 TrackerClassPrivate *priv;
636
637 g_return_if_fail (TRACKER_IS_CLASS (class));
638 priv = GET_PRIV (class);
639
640 /* Move */
641 g_array_insert_vals (priv->deletes.ready.obj_graph_ids,
642 priv->deletes.ready.obj_graph_ids->len,
643 priv->deletes.pending.obj_graph_ids->data,
644 priv->deletes.pending.obj_graph_ids->len);
645
646 g_array_insert_vals (priv->deletes.ready.sub_pred_ids,
647 priv->deletes.ready.sub_pred_ids->len,
648 priv->deletes.pending.sub_pred_ids->data,
649 priv->deletes.pending.sub_pred_ids->len);
650
651 /* Reset */
652 g_array_set_size (priv->deletes.pending.sub_pred_ids, 0);
653 g_array_set_size (priv->deletes.pending.obj_graph_ids, 0);
654
655
656 /* Move */
657 g_array_insert_vals (priv->inserts.ready.obj_graph_ids,
658 priv->inserts.ready.obj_graph_ids->len,
659 priv->inserts.pending.obj_graph_ids->data,
660 priv->inserts.pending.obj_graph_ids->len);
661
662 g_array_insert_vals (priv->inserts.ready.sub_pred_ids,
663 priv->inserts.ready.sub_pred_ids->len,
664 priv->inserts.pending.sub_pred_ids->data,
665 priv->inserts.pending.sub_pred_ids->len);
666
667 /* Reset */
668 g_array_set_size (priv->inserts.pending.sub_pred_ids, 0);
669 g_array_set_size (priv->inserts.pending.obj_graph_ids, 0);
670
671 }
672
673 static void
674 insert_vals_into_arrays (GArray *sub_pred_ids,
675 GArray *obj_graph_ids,
676 gint graph_id,
677 gint subject_id,
678 gint pred_id,
679 gint object_id)
680 {
681 gint i, j, k;
682 gint64 tmp;
683 gint64 sub_pred_id;
684 gint64 obj_graph_id;
685
686 sub_pred_id = (gint64) subject_id;
687 sub_pred_id = sub_pred_id << 32 | pred_id;
688 obj_graph_id = (gint64) object_id;
689 obj_graph_id = obj_graph_id << 32 | graph_id;
690
691 i = 0;
692 j = sub_pred_ids->len - 1;
693
694 while (j - i > 0) {
695 k = (i + j) / 2;
696 tmp = g_array_index (sub_pred_ids, gint64, k);
697 if (tmp == sub_pred_id) {
698 i = k + 1;
699 break;
700 } else if (tmp > sub_pred_id)
701 j = k;
702 else
703 i = k + 1;
704 }
705
706 g_array_insert_val (sub_pred_ids, i, sub_pred_id);
707 g_array_insert_val (obj_graph_ids, i, obj_graph_id);
708 }
709
710 void
711 tracker_class_add_insert_event (TrackerClass *class,
712 gint graph_id,
713 gint subject_id,
714 gint pred_id,
715 gint object_id)
716 {
717 TrackerClassPrivate *priv;
718
719 g_return_if_fail (TRACKER_IS_CLASS (class));
720 priv = GET_PRIV (class);
721
722 insert_vals_into_arrays (priv->inserts.pending.sub_pred_ids,
723 priv->inserts.pending.obj_graph_ids,
724 graph_id,
725 subject_id,
726 pred_id,
727 object_id);
728 }
729
730 void
731 tracker_class_add_delete_event (TrackerClass *class,
732 gint graph_id,
733 gint subject_id,
734 gint pred_id,
735 gint object_id)
736 {
737 TrackerClassPrivate *priv;
738
739 g_return_if_fail (TRACKER_IS_CLASS (class));
740 priv = GET_PRIV (class);
741
742 insert_vals_into_arrays (priv->deletes.pending.sub_pred_ids,
743 priv->deletes.pending.obj_graph_ids,
744 graph_id,
745 subject_id,
746 pred_id,
747 object_id);
748 }