[tracker/wip/carlosg/update-perf: 19/43] core: Refactor buffering of database updates
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/wip/carlosg/update-perf: 19/43] core: Refactor buffering of database updates
- Date: Wed, 24 Aug 2022 00:49:49 +0000 (UTC)
commit dfcaa2632813e56c1650794a4517c417e442d972
Author: Carlos Garnacho <carlosg gnome org>
Date: Mon Aug 15 20:46:34 2022 +0200
core: Refactor buffering of database updates
Currently, our caching of triples does have a number of nested structures:
- In the buffer there is a struct for each graph
- In the graph struct there is a set of changed resource
- In the resource struct there is a set of modified tables
- In the table struct there is a set of modified properties
- In the property struct there is a list of values
This incurs in a maintenance cost that is higher than desired, adding and
removing elements here becomes a fair chunk of the time spent in updates,
since there is a number of allocations and list/hashtable updates
performed for batches that deal with a fair amount of different resources
(i.e. most of them).
In order to improve this, keep use two arrays to buffer this data:
- A "properties" array, that keeps individual predicate/object pairs. This
is used to store the values of properties being inserted or deleted for
single-valued and multivalued properties. This struct is "linked" with
(i.e. references) other elements in the array, so that e.g. class updates
may reference multiple properties/values being updated.
- An "update log" array, containing structs that are a event_type/graph/
subject tuple, plus optionally a link to one of the properties in the
previous array, all other properties are fetched through iterating through
the linked properties. These log entries are valid for class table updates
(i.e. single-valued properties) or multi-valued property tables.
These arrays make allocating the buffer a one-time operation (buffer size
is fixed, and the arrays are reused during the processing of a TrackerBatch)
and insertions into the log largely O(1) as opposed to a number of
array/hashtable lookups and inserts.
But we still want to coalesce updates to a same class table (e.g. changes to
several single-valued properties in the same table), for that there is an
additional hashtable set that uses these log entries as keys themselves,
with special hash/equal functions, lookups for prior events modifying the
same TrackerClass is also quite fast.
Overall, this makes the maintenance of this buffer less expensive in the
big picture. Even though there are still some remnants of the previous
caching for graphs and resources, this plays less of a role.
Since this changes the ordering of updates, some tests that rely on implicit
ordering (DESCRIBE ones) had to be adapted for this change.
src/libtracker-sparql/core/tracker-data-update.c | 911 +++++++++++++----------
tests/core/describe/describe-multiple.out | 10 +-
2 files changed, 510 insertions(+), 411 deletions(-)
---
diff --git a/src/libtracker-sparql/core/tracker-data-update.c
b/src/libtracker-sparql/core/tracker-data-update.c
index be283ac5f..a42f7e56d 100644
--- a/src/libtracker-sparql/core/tracker-data-update.c
+++ b/src/libtracker-sparql/core/tracker-data-update.c
@@ -44,12 +44,45 @@
typedef struct _TrackerDataUpdateBuffer TrackerDataUpdateBuffer;
typedef struct _TrackerDataUpdateBufferGraph TrackerDataUpdateBufferGraph;
typedef struct _TrackerDataUpdateBufferResource TrackerDataUpdateBufferResource;
-typedef struct _TrackerDataUpdateBufferProperty TrackerDataUpdateBufferProperty;
-typedef struct _TrackerDataUpdateBufferTable TrackerDataUpdateBufferTable;
typedef struct _TrackerDataBlankBuffer TrackerDataBlankBuffer;
typedef struct _TrackerStatementDelegate TrackerStatementDelegate;
typedef struct _TrackerCommitDelegate TrackerCommitDelegate;
+#define UPDATE_LOG_SIZE 64
+
+typedef enum {
+ TRACKER_LOG_CLASS_INSERT,
+ TRACKER_LOG_CLASS_UPDATE,
+ TRACKER_LOG_CLASS_DELETE,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_INSERT,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR,
+} TrackerDataLogEntryType;
+
+typedef struct {
+ gint prev;
+ TrackerProperty *property;
+ GValue value;
+} TrackerDataPropertyEntry;
+
+typedef struct {
+ TrackerDataLogEntryType type;
+ const TrackerDataUpdateBufferGraph *graph;
+ TrackerRowid id;
+ union {
+ struct {
+ TrackerClass *class;
+ gint last_property_idx; /* Index in properties_ptr array */
+ } class;
+ struct {
+ TrackerProperty *property;
+ gint change_idx; /* Index in properties_ptr array */
+ } multivalued;
+ GObject *any;
+ } table;
+ GArray *properties_ptr;
+} TrackerDataLogEntry;
+
struct _TrackerDataUpdateBuffer {
/* string -> ID */
GHashTable *resource_cache;
@@ -59,6 +92,15 @@ struct _TrackerDataUpdateBuffer {
GPtrArray *graphs;
/* Statement to insert in Resource table */
TrackerDBStatement *insert_resource;
+
+ /* Array of TrackerDataPropertyEntry */
+ GArray *properties;
+ /* Array of TrackerDataLogEntry */
+ GArray *update_log;
+ /* Set of TrackerDataLogEntry. Used for class events lookups in order to
+ * coalesce single-valued property changes.
+ */
+ GHashTable *class_updates;
};
struct _TrackerDataUpdateBufferGraph {
@@ -79,32 +121,14 @@ struct _TrackerDataUpdateBufferResource {
TrackerRowid id;
gboolean create;
gboolean modified;
- /* TrackerProperty -> GArray */
+ /* TrackerProperty -> GArray of GValue */
GHashTable *predicates;
- /* string -> TrackerDataUpdateBufferTable */
- GHashTable *tables;
/* TrackerClass */
GPtrArray *types;
gboolean fts_updated;
};
-struct _TrackerDataUpdateBufferProperty {
- TrackerProperty *property;
- GValue value;
- guint delete_all_values : 1;
- guint delete_value : 1;
-};
-
-struct _TrackerDataUpdateBufferTable {
- gboolean insert;
- gboolean delete_row;
- gboolean multiple_values;
- TrackerClass *class;
- /* TrackerDataUpdateBufferProperty */
- GArray *properties;
-};
-
struct _TrackerStatementDelegate {
TrackerStatementCallback callback;
gpointer user_data;
@@ -148,10 +172,6 @@ enum {
G_DEFINE_TYPE (TrackerData, tracker_data, G_TYPE_OBJECT)
-static void cache_insert_value (TrackerData *data,
- TrackerClass *class,
- TrackerProperty *property,
- const GValue *value);
static GArray *get_property_values (TrackerData *data,
TrackerProperty *property,
GError **error);
@@ -180,6 +200,26 @@ static void tracker_data_insert_statement_with_string (TrackerData *data,
const GValue *object,
GError **error);
+static guint
+tracker_data_log_entry_hash (gconstpointer value)
+{
+ const TrackerDataLogEntry *entry = value;
+
+ return (g_direct_hash (entry->graph) ^
+ tracker_rowid_hash (&entry->id) ^
+ g_direct_hash (entry->table.any));
+}
+
+static gboolean
+tracker_data_log_entry_equal (gconstpointer value1,
+ gconstpointer value2)
+{
+ const TrackerDataLogEntry *entry1 = value1, *entry2 = value2;
+
+ return (entry1->graph == entry2->graph &&
+ entry1->id == entry2->id &&
+ entry1->table.any == entry2->table.any);
+}
void
tracker_data_add_commit_statement_callback (TrackerData *data,
@@ -499,6 +539,9 @@ tracker_data_finalize (GObject *object)
g_clear_pointer (&data->update_buffer.graphs, g_ptr_array_unref);
g_clear_pointer (&data->update_buffer.new_resources, g_hash_table_unref);
g_clear_pointer (&data->update_buffer.resource_cache, g_hash_table_unref);
+ g_clear_pointer (&data->update_buffer.properties, g_array_unref);
+ g_clear_pointer (&data->update_buffer.update_log, g_array_unref);
+ g_clear_pointer (&data->update_buffer.class_updates, g_hash_table_unref);
g_clear_object (&data->update_buffer.insert_resource);
g_clear_pointer (&data->insert_callbacks, g_ptr_array_unref);
@@ -547,151 +590,105 @@ get_transaction_modseq (TrackerData *data)
return data->transaction_modseq;
}
-static TrackerDataUpdateBufferTable *
-cache_table_new (gboolean multiple_values)
-{
- TrackerDataUpdateBufferTable *table;
-
- table = g_slice_new0 (TrackerDataUpdateBufferTable);
- table->multiple_values = multiple_values;
- table->properties = g_array_sized_new (FALSE, FALSE, sizeof (TrackerDataUpdateBufferProperty), 4);
-
- return table;
-}
-
static void
-cache_table_free (TrackerDataUpdateBufferTable *table)
-{
- TrackerDataUpdateBufferProperty *property;
- guint i;
-
- for (i = 0; i < table->properties->len; i++) {
- property = &g_array_index (table->properties, TrackerDataUpdateBufferProperty, i);
- g_value_unset (&property->value);
- }
-
- g_array_free (table->properties, TRUE);
- g_slice_free (TrackerDataUpdateBufferTable, table);
-}
-
-static TrackerDataUpdateBufferTable *
-cache_ensure_table (TrackerData *data,
- const gchar *table_name,
- gboolean multiple_values)
+log_entry_for_multi_value_property (TrackerData *data,
+ TrackerDataLogEntryType type,
+ TrackerProperty *property,
+ const GValue *value)
{
- TrackerDataUpdateBufferTable *table;
+ TrackerDataLogEntry entry = { 0, };
+ TrackerDataPropertyEntry prop = { 0, };
+ guint prop_idx;
- if (!data->resource_buffer->modified) {
- /* first modification of this particular resource, update nrl:modified */
- TrackerOntologies *ontologies;
- TrackerProperty *modified;
- GValue gvalue = { 0 };
-
- data->resource_buffer->modified = TRUE;
- ontologies = tracker_data_manager_get_ontologies (data->manager);
- modified = tracker_ontologies_get_property_by_uri (ontologies,
- TRACKER_PREFIX_NRL "modified");
-
- g_value_init (&gvalue, G_TYPE_INT64);
- g_value_set_int64 (&gvalue, get_transaction_modseq (data));
- cache_insert_value (data, NULL, modified, &gvalue);
- }
+ prop.property = property;
+ prop.prev = -1;
- table = g_hash_table_lookup (data->resource_buffer->tables, table_name);
- if (table == NULL) {
- table = cache_table_new (multiple_values);
- g_hash_table_insert (data->resource_buffer->tables, g_strdup (table_name), table);
- table->insert = multiple_values;
+ if (type != TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR) {
+ g_value_init (&prop.value, G_VALUE_TYPE (value));
+ g_value_copy (value, &prop.value);
}
- return table;
-}
+ g_array_append_val (data->update_buffer.properties, prop);
+ prop_idx = data->update_buffer.properties->len - 1;
-static void
-cache_insert_row (TrackerData *data,
- TrackerClass *class)
-{
- TrackerDataUpdateBufferTable *table;
-
- table = cache_ensure_table (data, tracker_class_get_name (class), FALSE);
- table->class = class;
- table->insert = TRUE;
+ entry.type = type;
+ entry.graph = data->resource_buffer->graph;
+ entry.id = data->resource_buffer->id;
+ entry.table.multivalued.property = property;
+ entry.table.multivalued.change_idx = prop_idx;
+ entry.properties_ptr = data->update_buffer.properties;
+ g_array_append_val (data->update_buffer.update_log, entry);
}
static void
-cache_insert_value (TrackerData *data,
- TrackerClass *class,
- TrackerProperty *prop,
- const GValue *value)
+log_entry_for_single_value_property (TrackerData *data,
+ TrackerClass *class,
+ TrackerProperty *property,
+ const GValue *value)
{
- TrackerDataUpdateBufferTable *table;
- TrackerDataUpdateBufferProperty property = { 0 };
- const gchar *table_name;
+ TrackerDataLogEntry entry = { 0, }, *entry_ptr;
+ TrackerDataPropertyEntry prop = { 0, };
+ guint prop_idx;
- property.property = prop;
- g_value_init (&property.value, G_VALUE_TYPE (value));
- g_value_copy (value, &property.value);
+ entry.type = TRACKER_LOG_CLASS_UPDATE;
+ entry.graph = data->resource_buffer->graph;
+ entry.id = data->resource_buffer->id;
+ entry.table.class.class = class;
+ entry.table.class.last_property_idx = -1;
+ entry.properties_ptr = data->update_buffer.properties;
- if (!class || tracker_property_get_multiple_values (prop))
- table_name = tracker_property_get_table_name (prop);
- else
- table_name = tracker_class_get_name (class);
+ entry_ptr = g_hash_table_lookup (data->update_buffer.class_updates, &entry);
- table = cache_ensure_table (data, table_name,
- tracker_property_get_multiple_values (prop));
- g_array_append_val (table->properties, property);
-}
+ if (!entry_ptr) {
+ g_array_append_val (data->update_buffer.update_log, entry);
+ entry_ptr = &g_array_index (data->update_buffer.update_log,
+ TrackerDataLogEntry,
+ data->update_buffer.update_log->len - 1);
+ g_hash_table_add (data->update_buffer.class_updates, entry_ptr);
+ }
-static void
-cache_delete_row (TrackerData *data,
- TrackerClass *class)
-{
- TrackerDataUpdateBufferTable *table;
+ prop.property = property;
+ prop.prev = entry_ptr->table.class.last_property_idx;
+ if (value) {
+ g_value_init (&prop.value, G_VALUE_TYPE (value));
+ g_value_copy (value, &prop.value);
+ }
+ g_array_append_val (data->update_buffer.properties, prop);
+ prop_idx = data->update_buffer.properties->len - 1;
- table = cache_ensure_table (data, tracker_class_get_name (class), FALSE);
- table->class = class;
- table->delete_row = TRUE;
+ entry_ptr->table.class.last_property_idx = prop_idx;
}
-/* Use only for multi-valued properties */
static void
-cache_delete_all_values (TrackerData *data,
- TrackerProperty *prop)
+log_entry_for_class (TrackerData *data,
+ TrackerDataLogEntryType type,
+ TrackerClass *class)
{
- TrackerDataUpdateBufferTable *table;
- TrackerDataUpdateBufferProperty property = { 0 };
+ TrackerDataLogEntry entry = { 0, }, *entry_ptr;
- property.property = prop;
- property.delete_all_values = TRUE;
+ entry.type = type;
+ entry.graph = data->resource_buffer->graph;
+ entry.id = data->resource_buffer->id;
+ entry.table.class.class = class;
+ entry.table.class.last_property_idx = -1;
+ entry.properties_ptr = data->update_buffer.properties;
- table = cache_ensure_table (data, tracker_property_get_table_name (prop), TRUE);
- g_array_append_val (table->properties, property);
-}
+ entry_ptr = g_hash_table_lookup (data->update_buffer.class_updates, &entry);
-static void
-cache_delete_value (TrackerData *data,
- TrackerClass *class,
- TrackerProperty *prop,
- const GValue *value)
-{
- TrackerDataUpdateBufferTable *table;
- TrackerDataUpdateBufferProperty property = { 0 };
- const gchar *table_name;
+ if (entry_ptr && entry_ptr->type == type)
+ return;
- property.property = prop;
- property.delete_value = TRUE;
+ entry.properties_ptr = data->update_buffer.properties;
+ g_array_append_val (data->update_buffer.update_log, entry);
- g_value_init (&property.value, G_VALUE_TYPE (value));
- g_value_copy (value, &property.value);
+ entry_ptr = &g_array_index (data->update_buffer.update_log,
+ TrackerDataLogEntry,
+ data->update_buffer.update_log->len - 1);
- if (!class || tracker_property_get_multiple_values (prop))
- table_name = tracker_property_get_table_name (prop);
+ if (type == TRACKER_LOG_CLASS_DELETE)
+ g_hash_table_remove (data->update_buffer.class_updates, entry_ptr);
else
- table_name = tracker_class_get_name (class);
-
- table = cache_ensure_table (data, table_name,
- tracker_property_get_multiple_values (prop));
- g_array_append_val (table->properties, property);
+ g_hash_table_add (data->update_buffer.class_updates, entry_ptr);
}
static TrackerRowid
@@ -869,254 +866,193 @@ statement_bind_gvalue (TrackerDBStatement *stmt,
}
}
-static void
-tracker_data_resource_buffer_flush (TrackerData *data,
- TrackerDataUpdateBufferResource *resource,
- GError **error)
-{
- TrackerDBInterface *iface;
- TrackerDBStatement *stmt;
- TrackerDataUpdateBufferTable *table;
- TrackerDataUpdateBufferProperty *property;
- GHashTableIter iter;
- const gchar *table_name, *database, *property_name;
- guint i;
- gint param;
- GError *actual_error = NULL;
+static gboolean
+tracker_data_flush_log (TrackerData *data,
+ GError **error)
+{
+ TrackerDBInterface *iface;
+ TrackerDBStatement *stmt = NULL;
+ TrackerDataPropertyEntry *property_entry;
+ guint i;
+ GError *inner_error = NULL;
iface = tracker_data_manager_get_writable_db_interface (data->manager);
- database = resource->graph->graph ? resource->graph->graph : "main";
-
- if (resource->fts_updated && !resource->create) {
- TrackerProperty *prop;
- GArray *values;
- GPtrArray *properties;
- gboolean retval;
- properties = NULL;
- g_hash_table_iter_init (&iter, resource->predicates);
+ for (i = 0; i < data->update_buffer.update_log->len; i++) {
+ TrackerDataLogEntry *entry;
+ const gchar *database;
- while (g_hash_table_iter_next (&iter, (gpointer*) &prop, (gpointer*) &values)) {
- if (tracker_property_get_fulltext_indexed (prop)) {
- if (!properties)
- properties = g_ptr_array_new ();
-
- g_ptr_array_add (properties, (gpointer) tracker_property_get_name (prop));
- }
- }
+ entry = &g_array_index (data->update_buffer.update_log,
+ TrackerDataLogEntry, i);
+ database = entry->graph->graph ? entry->graph->graph : "main";
- if (properties) {
- g_ptr_array_add (properties, NULL);
-
- retval = tracker_db_interface_sqlite_fts_delete_text (iface,
- database,
- resource->id,
- (const gchar **)
properties->pdata,
- error);
- g_ptr_array_free (properties, TRUE);
-
- if (!retval)
- return;
- }
- }
-
- g_hash_table_iter_init (&iter, resource->tables);
- while (g_hash_table_iter_next (&iter, (gpointer*) &table_name, (gpointer*) &table)) {
- if (table->multiple_values) {
- for (i = 0; i < table->properties->len; i++) {
- property = &g_array_index (table->properties,
TrackerDataUpdateBufferProperty, i);
- property_name = tracker_property_get_name (property->property);
-
- if (property->delete_all_values) {
- stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- "DELETE FROM
\"%s\".\"%s\" WHERE ID = ?",
- database,
- table_name);
- } else if (property->delete_value) {
- /* delete rows for multiple value properties */
- stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- "DELETE FROM
\"%s\".\"%s\" WHERE ID = ? AND \"%s\" = ?",
- database,
- table_name,
- property_name);
- } else {
- stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- "INSERT OR IGNORE INTO
\"%s\".\"%s\" (ID, \"%s\") VALUES (?, ?)",
- database,
- table_name,
- property_name);
- }
-
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
-
- param = 0;
+ if (entry->type == TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR) {
+ stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ "DELETE FROM \"%s\".\"%s\" WHERE ID =
?",
+ database,
+ tracker_property_get_table_name
(entry->table.multivalued.property));
+ if (!stmt)
+ return FALSE;
- tracker_db_statement_bind_int (stmt, param++, resource->id);
+ tracker_db_statement_bind_int (stmt, 0, entry->id);
+ } else if (entry->type == TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE) {
+ stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ "DELETE FROM \"%s\".\"%s\" WHERE ID =
? AND \"%s\" = ?",
+ database,
+ tracker_property_get_table_name
(entry->table.multivalued.property),
+ tracker_property_get_name
(entry->table.multivalued.property));
+ if (!stmt)
+ return FALSE;
- if (!property->delete_all_values)
- statement_bind_gvalue (stmt, param++, &property->value);
+ tracker_db_statement_bind_int (stmt, 0, entry->id);
+
+ property_entry = &g_array_index (entry->properties_ptr,
+ TrackerDataPropertyEntry,
+ entry->table.multivalued.change_idx);
+ statement_bind_gvalue (stmt, 1, &property_entry->value);
+ } else if (entry->type == TRACKER_LOG_MULTIVALUED_PROPERTY_INSERT) {
+ stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ "INSERT OR IGNORE INTO \"%s\".\"%s\"
(ID, \"%s\") VALUES (?, ?)",
+ database,
+ tracker_property_get_table_name
(entry->table.multivalued.property),
+ tracker_property_get_name
(entry->table.multivalued.property));
+ if (!stmt)
+ return FALSE;
- tracker_db_statement_execute (stmt, &actual_error);
- g_object_unref (stmt);
+ tracker_db_statement_bind_int (stmt, 0, entry->id);
+
+ property_entry = &g_array_index (entry->properties_ptr,
+ TrackerDataPropertyEntry,
+ entry->table.multivalued.change_idx);
+ statement_bind_gvalue (stmt, 1, &property_entry->value);
+ } else if (entry->type == TRACKER_LOG_CLASS_DELETE) {
+ stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ "DELETE FROM \"%s\".\"%s\" WHERE ID =
?",
+ database,
+ tracker_class_get_name
(entry->table.class.class));
+ if (!stmt)
+ return FALSE;
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
- }
+ tracker_db_statement_bind_int (stmt, 0, entry->id);
} else {
- if (table->delete_row) {
- /* remove row from class table */
- stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- "DELETE FROM \"%s\".\"%s\"
WHERE ID = ?",
- database, table_name);
-
- if (stmt) {
- tracker_db_statement_bind_int (stmt, 0, resource->id);
- tracker_db_statement_execute (stmt, &actual_error);
- g_object_unref (stmt);
- }
+ GHashTable *visited_properties;
+ gint param, property_idx;
+ GString *sql;
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
- } else {
- GHashTable *visited_properties;
- GString *sql;
- gint n;
+ sql = g_string_new (NULL);
+ visited_properties = g_hash_table_new (NULL, NULL);
+ param = 2;
- sql = g_string_new (NULL);
- visited_properties = g_hash_table_new (NULL, NULL);
- param = 1;
-
- if (table->insert) {
- GString *values_sql;
-
- g_string_append_printf (sql,
- "INSERT INTO \"%s\".\"%s\" (ID",
- database, table_name);
- values_sql = g_string_new ("VALUES (?1");
-
- for (n = table->properties->len - 1; n >= 0; n--) {
- property = &g_array_index (table->properties,
TrackerDataUpdateBufferProperty, n);
- property_name = tracker_property_get_name
(property->property);
-
- if (g_hash_table_contains (visited_properties,
property->property))
- continue;
-
- g_string_append_printf (sql, ", \"%s\"", property_name);
- g_string_append_printf (values_sql, ", ?%d", ++param);
- g_hash_table_add (visited_properties, property->property);
- }
+ if (entry->type == TRACKER_LOG_CLASS_INSERT) {
+ GString *values_sql;
- g_string_append (sql, ")");
- g_string_append (values_sql, ")");
+ g_string_append_printf (sql,
+ "INSERT INTO \"%s\".\"%s\" (ID",
+ database,
+ tracker_class_get_name (entry->table.class.class));
+ values_sql = g_string_new ("VALUES (?1");
- stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- "%s %s", sql->str,
values_sql->str);
- g_string_free (sql, TRUE);
- g_string_free (values_sql, TRUE);
- } else {
- g_string_append_printf (sql,
- "UPDATE \"%s\".\"%s\" SET ",
- database, table_name);
+ property_idx = entry->table.class.last_property_idx;
- for (n = table->properties->len - 1; n >= 0; n--) {
- property = &g_array_index (table->properties,
TrackerDataUpdateBufferProperty, n);
- property_name = tracker_property_get_name
(property->property);
+ while (property_idx >= 0) {
+ property_entry = &g_array_index (entry->properties_ptr,
+ TrackerDataPropertyEntry,
+ property_idx);
+ property_idx = property_entry->prev;
- if (g_hash_table_contains (visited_properties,
property->property))
- continue;
+ if (g_hash_table_contains (visited_properties,
property_entry->property))
+ continue;
- if (n < (int) table->properties->len - 1) {
- g_string_append (sql, ", ");
- }
+ g_string_append_printf (sql, ", \"%s\"", tracker_property_get_name
(property_entry->property));
+ g_string_append_printf (values_sql, ", ?%d", param++);
+ g_hash_table_add (visited_properties, property_entry->property);
+ }
- g_string_append_printf (sql, "\"%s\" = ?%d", property_name,
++param);
- g_hash_table_add (visited_properties, property->property);
- }
+ g_string_append (sql, ")");
+ g_string_append (values_sql, ")");
+
+ stmt = tracker_db_interface_create_vstatement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ "%s %s", sql->str,
values_sql->str);
+ g_string_free (sql, TRUE);
+ g_string_free (values_sql, TRUE);
+ } else if (entry->type == TRACKER_LOG_CLASS_UPDATE) {
+ g_string_append_printf (sql,
+ "UPDATE \"%s\".\"%s\" SET ",
+ database,
+ tracker_class_get_name (entry->table.class.class));
+ property_idx = entry->table.class.last_property_idx;
+
+ while (property_idx >= 0) {
+ TrackerDataPropertyEntry *property_entry;
+
+ property_entry = &g_array_index (entry->properties_ptr,
+ TrackerDataPropertyEntry,
+ property_idx);
+ property_idx = property_entry->prev;
+
+ if (g_hash_table_contains (visited_properties,
property_entry->property))
+ continue;
- g_string_append (sql, " WHERE ID = ?1");
+ if (param > 2)
+ g_string_append (sql, ", ");
- stmt = tracker_db_interface_create_statement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, &actual_error,
- sql->str);
- g_string_free (sql, TRUE);
+ g_string_append_printf (sql, "\"%s\" = ?%d",
+ tracker_property_get_name
(property_entry->property),
+ param++);
+ g_hash_table_add (visited_properties, property_entry->property);
}
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
- }
+ g_string_append (sql, " WHERE ID = ?1");
- tracker_db_statement_bind_int (stmt, 0, resource->id);
- param = 1;
+ stmt = tracker_db_interface_create_statement (iface,
TRACKER_DB_STATEMENT_CACHE_TYPE_UPDATE, error,
+ sql->str);
+ g_string_free (sql, TRUE);
+ }
- g_hash_table_remove_all (visited_properties);
+ if (!stmt)
+ return FALSE;
- for (n = table->properties->len - 1; n >= 0; n--) {
- property = &g_array_index (table->properties,
TrackerDataUpdateBufferProperty, n);
+ tracker_db_statement_bind_int (stmt, 0, entry->id);
+ param = 1;
- if (g_hash_table_contains (visited_properties, property->property))
- continue;
+ g_hash_table_remove_all (visited_properties);
- if (property->delete_value) {
- /* just set value to NULL for single value properties */
- tracker_db_statement_bind_null (stmt, param++);
- } else {
- statement_bind_gvalue (stmt, param++, &property->value);
- }
+ property_idx = entry->table.class.last_property_idx;
- g_hash_table_add (visited_properties, property->property);
- }
+ while (property_idx >= 0) {
+ TrackerDataPropertyEntry *property_entry;
- g_hash_table_unref (visited_properties);
+ property_entry = &g_array_index (entry->properties_ptr,
+ TrackerDataPropertyEntry,
+ property_idx);
+ property_idx = property_entry->prev;
- tracker_db_statement_execute (stmt, &actual_error);
- g_object_unref (stmt);
+ if (g_hash_table_contains (visited_properties, property_entry->property))
+ continue;
- if (actual_error) {
- g_propagate_error (error, actual_error);
- return;
+ if (G_VALUE_TYPE (&property_entry->value) == G_TYPE_INVALID) {
+ /* just set value to NULL for single value properties */
+ tracker_db_statement_bind_null (stmt, param++);
+ } else {
+ statement_bind_gvalue (stmt, param++, &property_entry->value);
}
- }
- }
- }
-
- if (resource->fts_updated) {
- TrackerProperty *prop;
- GArray *values;
- GPtrArray *properties;
- gboolean retval;
- properties = NULL;
- g_hash_table_iter_init (&iter, resource->predicates);
- while (g_hash_table_iter_next (&iter, (gpointer*) &prop, (gpointer*) &values)) {
- if (tracker_property_get_fulltext_indexed (prop)) {
- if (!properties)
- properties = g_ptr_array_new ();
-
- g_ptr_array_add (properties, (gpointer) tracker_property_get_name (prop));
+ g_hash_table_add (visited_properties, property_entry->property);
}
- }
- if (properties) {
- g_ptr_array_add (properties, NULL);
+ g_hash_table_unref (visited_properties);
+ }
- retval = tracker_db_interface_sqlite_fts_update_text (iface,
- database,
- resource->id,
- (const gchar **)
properties->pdata,
- error);
- g_ptr_array_free (properties, TRUE);
+ tracker_db_statement_execute (stmt, &inner_error);
+ g_object_unref (stmt);
- if (!retval)
- return;
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
}
}
+
+ return TRUE;
}
static void
@@ -1301,7 +1237,6 @@ graph_buffer_free (TrackerDataUpdateBufferGraph *graph)
static void resource_buffer_free (TrackerDataUpdateBufferResource *resource)
{
g_hash_table_unref (resource->predicates);
- g_hash_table_unref (resource->tables);
g_ptr_array_free (resource->types, TRUE);
resource->types = NULL;
@@ -1315,19 +1250,98 @@ tracker_data_update_buffer_flush (TrackerData *data,
{
TrackerDataUpdateBufferGraph *graph;
TrackerDataUpdateBufferResource *resource;
+ TrackerDBInterface *iface;
GHashTableIter iter;
GError *actual_error = NULL;
+ const gchar *database;
guint i;
+ if (data->update_buffer.update_log->len == 0)
+ return;
+
+ iface = tracker_data_manager_get_writable_db_interface (data->manager);
+
for (i = 0; i < data->update_buffer.graphs->len; i++) {
graph = g_ptr_array_index (data->update_buffer.graphs, i);
g_hash_table_iter_init (&iter, graph->resources);
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &resource)) {
- tracker_data_resource_buffer_flush (data, resource, &actual_error);
- if (actual_error) {
- g_propagate_error (error, actual_error);
- goto out;
+ if (resource->fts_updated && !resource->create) {
+ TrackerProperty *prop;
+ GArray *values;
+ GHashTableIter prop_iter;
+ GPtrArray *properties;
+ gboolean retval;
+
+ properties = NULL;
+ database = resource->graph->graph ? resource->graph->graph : "main";
+ g_hash_table_iter_init (&prop_iter, resource->predicates);
+ while (g_hash_table_iter_next (&prop_iter, (gpointer*) &prop, (gpointer*)
&values)) {
+ if (tracker_property_get_fulltext_indexed (prop)) {
+ if (!properties)
+ properties = g_ptr_array_new ();
+
+ g_ptr_array_add (properties, (gpointer)
tracker_property_get_name (prop));
+ }
+ }
+
+ if (properties) {
+ g_ptr_array_add (properties, NULL);
+
+ retval = tracker_db_interface_sqlite_fts_delete_text (iface,
+ database,
+ resource->id,
+ (const gchar
**) properties->pdata,
+ error);
+ g_ptr_array_free (properties, TRUE);
+
+ if (!retval)
+ goto out;
+ }
+ }
+ }
+ }
+
+ if (!tracker_data_flush_log (data, error))
+ goto out;
+
+ for (i = 0; i < data->update_buffer.graphs->len; i++) {
+ graph = g_ptr_array_index (data->update_buffer.graphs, i);
+ g_hash_table_iter_init (&iter, graph->resources);
+
+ while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &resource)) {
+ if (resource->fts_updated) {
+ TrackerProperty *prop;
+ GArray *values;
+ GHashTableIter prop_iter;
+ GPtrArray *properties;
+ gboolean retval;
+
+ properties = NULL;
+ database = resource->graph->graph ? resource->graph->graph : "main";
+ g_hash_table_iter_init (&prop_iter, resource->predicates);
+ while (g_hash_table_iter_next (&prop_iter, (gpointer*) &prop, (gpointer*)
&values)) {
+ if (tracker_property_get_fulltext_indexed (prop)) {
+ if (!properties)
+ properties = g_ptr_array_new ();
+
+ g_ptr_array_add (properties, (gpointer)
tracker_property_get_name (prop));
+ }
+ }
+
+ if (properties) {
+ g_ptr_array_add (properties, NULL);
+
+ retval = tracker_db_interface_sqlite_fts_update_text (iface,
+ database,
+ resource->id,
+ (const gchar
**) properties->pdata,
+ error);
+ g_ptr_array_free (properties, TRUE);
+
+ if (!retval)
+ goto out;
+ }
}
}
@@ -1343,6 +1357,9 @@ tracker_data_update_buffer_flush (TrackerData *data,
out:
g_hash_table_remove_all (data->update_buffer.new_resources);
+ g_hash_table_remove_all (data->update_buffer.class_updates);
+ g_array_set_size (data->update_buffer.properties, 0);
+ g_array_set_size (data->update_buffer.update_log, 0);
data->resource_buffer = NULL;
}
@@ -1350,18 +1367,8 @@ void
tracker_data_update_buffer_might_flush (TrackerData *data,
GError **error)
{
- TrackerDataUpdateBufferGraph *graph;
- guint i, count = 0;
-
- for (i = 0; i < data->update_buffer.graphs->len; i++) {
- graph = g_ptr_array_index (data->update_buffer.graphs, i);
- count += g_hash_table_size (graph->resources);
-
- if (count >= 50) {
- tracker_data_update_buffer_flush (data, error);
- break;
- }
- }
+ if (data->update_buffer.update_log->len > UPDATE_LOG_SIZE - 10)
+ tracker_data_update_buffer_flush (data, error);
}
static void
@@ -1378,6 +1385,9 @@ tracker_data_update_buffer_clear (TrackerData *data)
g_hash_table_remove_all (data->update_buffer.new_resources);
g_hash_table_remove_all (data->update_buffer.resource_cache);
+ g_hash_table_remove_all (data->update_buffer.class_updates);
+ g_array_set_size (data->update_buffer.properties, 0);
+ g_array_set_size (data->update_buffer.update_log, 0);
data->resource_buffer = NULL;
}
@@ -1410,20 +1420,39 @@ cache_create_service_decomposed (TrackerData *data,
g_ptr_array_add (data->resource_buffer->types, cl);
- g_value_init (&gvalue, G_TYPE_INT64);
-
- cache_insert_row (data, cl);
+ log_entry_for_class (data, TRACKER_LOG_CLASS_INSERT, cl);
tracker_data_resource_ref (data, data->resource_buffer->id, FALSE);
class_id = tracker_class_get_id (cl);
ontologies = tracker_data_manager_get_ontologies (data->manager);
+ g_value_init (&gvalue, G_TYPE_INT64);
g_value_set_int64 (&gvalue, class_id);
- cache_insert_value (data, NULL,
- tracker_ontologies_get_rdf_type (ontologies),
- &gvalue);
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_INSERT,
+ tracker_ontologies_get_rdf_type (ontologies),
+ &gvalue);
+
tracker_data_resource_ref (data, class_id, TRUE);
+ if (!data->resource_buffer->modified) {
+ /* first modification of this particular resource, update nrl:modified */
+ TrackerOntologies *ontologies;
+ TrackerProperty *modified;
+ GValue gvalue = { 0 };
+
+ data->resource_buffer->modified = TRUE;
+ ontologies = tracker_data_manager_get_ontologies (data->manager);
+ modified = tracker_ontologies_get_property_by_uri (ontologies,
+ TRACKER_PREFIX_NRL "modified");
+
+ g_value_init (&gvalue, G_TYPE_INT64);
+ g_value_set_int64 (&gvalue, get_transaction_modseq (data));
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (modified),
+ modified, &gvalue);
+ }
+
if (data->resource_buffer->create &&
strcmp (tracker_class_get_uri (cl), TRACKER_PREFIX_RDFS "Resource") == 0) {
/* Add nrl:added for the new rdfs:Resource */
@@ -1437,7 +1466,9 @@ cache_create_service_decomposed (TrackerData *data,
g_value_init (&gvalue, G_TYPE_INT64);
g_value_set_int64 (&gvalue, data->resource_time);
- cache_insert_value (data, NULL, added, &gvalue);
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (added),
+ added, &gvalue);
}
tracker_data_dispatch_insert_statement_callbacks (data,
@@ -1479,8 +1510,7 @@ cache_create_service_decomposed (TrackerData *data,
tracker_class_get_name (cl));
v = &g_array_index (old_values, GValue, 0);
-
- cache_insert_value (data, cl, *domain_indexes, v);
+ log_entry_for_single_value_property (data, cl, *domain_indexes, v);
}
domain_indexes++;
@@ -1719,10 +1749,10 @@ insert_property_domain_indexes (TrackerData *data,
domain_index_classes = tracker_property_get_domain_indexes (property);
while (*domain_index_classes) {
if (resource_in_domain_index_class (data, *domain_index_classes)) {
- cache_insert_value (data,
- *domain_index_classes,
- property,
- gvalue);
+ log_entry_for_single_value_property (data,
+ *domain_index_classes,
+ property,
+ gvalue);
}
domain_index_classes++;
}
@@ -1738,10 +1768,9 @@ delete_property_domain_indexes (TrackerData *data,
domain_index_classes = tracker_property_get_domain_indexes (property);
while (*domain_index_classes) {
if (resource_in_domain_index_class (data, *domain_index_classes)) {
- cache_delete_value (data,
- *domain_index_classes,
- property,
- gvalue);
+ log_entry_for_single_value_property (data,
+ *domain_index_classes,
+ property, NULL);
}
domain_index_classes++;
}
@@ -1915,10 +1944,33 @@ cache_insert_metadata_decomposed (TrackerData *data,
g_value_unset (&old_value);
g_value_unset (&new_value);
} else {
- cache_insert_value (data,
- NULL,
- property,
- object);
+ if (multiple_values) {
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_INSERT,
+ property, object);
+ } else {
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (property),
+ property, object);
+ }
+
+ if (!data->resource_buffer->modified) {
+ /* first modification of this particular resource, update nrl:modified */
+ TrackerOntologies *ontologies;
+ TrackerProperty *modified;
+ GValue gvalue = { 0 };
+
+ data->resource_buffer->modified = TRUE;
+ ontologies = tracker_data_manager_get_ontologies (data->manager);
+ modified = tracker_ontologies_get_property_by_uri (ontologies,
+ TRACKER_PREFIX_NRL "modified");
+
+ g_value_init (&gvalue, G_TYPE_INT64);
+ g_value_set_int64 (&gvalue, get_transaction_modseq (data));
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (modified),
+ modified, &gvalue);
+ }
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE)
tracker_data_resource_ref (data, g_value_get_int64 (object), multiple_values);
@@ -1960,7 +2012,16 @@ delete_metadata_decomposed (TrackerData *data,
if (!value_set_remove_value (old_values, object)) {
/* value not found */
} else {
- cache_delete_value (data, NULL, property, object);
+ if (multiple_values) {
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE,
+ property, object);
+ } else {
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (property),
+ property, NULL);
+ }
+
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE)
tracker_data_resource_unref (data, g_value_get_int64 (object), multiple_values);
@@ -2016,9 +2077,7 @@ cache_delete_resource_type_full (TrackerData *data,
data->resource_buffer->graph->graph : "main";
if (!single_type) {
- if (strcmp (tracker_class_get_uri (class), TRACKER_PREFIX_RDFS "Resource") == 0 &&
- g_hash_table_size (data->resource_buffer->tables) == 0) {
-
+ if (strcmp (tracker_class_get_uri (class), TRACKER_PREFIX_RDFS "Resource") == 0) {
/* skip subclass query when deleting whole resource
to improve performance */
@@ -2120,7 +2179,16 @@ cache_delete_resource_type_full (TrackerData *data,
g_value_copy (old_gvalue, ©);
value_set_remove_value (old_values, old_gvalue);
- cache_delete_value (data, NULL, prop, ©);
+
+ if (multiple_values) {
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE,
+ prop, ©);
+ } else {
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (prop),
+ prop, NULL);
+ }
if (tracker_property_get_data_type (prop) == TRACKER_PROPERTY_TYPE_RESOURCE)
tracker_data_resource_unref (data, g_value_get_int64 (©),
multiple_values);
@@ -2134,12 +2202,12 @@ cache_delete_resource_type_full (TrackerData *data,
g_value_init (&gvalue, G_TYPE_INT64);
g_value_set_int64 (&gvalue, tracker_class_get_id (class));
- cache_delete_value (data, NULL,
- tracker_ontologies_get_rdf_type (ontologies),
- &gvalue);
+ log_entry_for_multi_value_property (data, TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE,
+ tracker_ontologies_get_rdf_type (ontologies),
+ &gvalue);
tracker_data_resource_unref (data, tracker_class_get_id (class), TRUE);
- cache_delete_row (data, class);
+ log_entry_for_class (data, TRACKER_LOG_CLASS_DELETE, class);
tracker_data_resource_unref (data, data->resource_buffer->id, FALSE);
tracker_data_dispatch_delete_statement_callbacks (data,
@@ -2254,7 +2322,6 @@ resource_buffer_switch (TrackerData *data,
resource_buffer->types = rdf_types;
}
resource_buffer->predicates = g_hash_table_new_full (g_direct_hash, g_direct_equal,
g_object_unref, (GDestroyNotify) g_array_unref);
- resource_buffer->tables = g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
(GDestroyNotify) cache_table_free);
resource_buffer->graph = graph_buffer;
g_hash_table_insert (graph_buffer->resources, &resource_buffer->id, resource_buffer);
@@ -2332,7 +2399,9 @@ delete_all_helper (TrackerData *data,
if (subproperty == property) {
if (tracker_property_get_multiple_values (property)) {
- cache_delete_all_values (data, property);
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR,
+ property, NULL);
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
if (!tracker_data_resource_unref_all (data, property, error))
@@ -2340,7 +2409,9 @@ delete_all_helper (TrackerData *data,
}
} else {
value = &g_array_index (old_values, GValue, 0);
- cache_delete_value (data, NULL, property, value);
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (property),
+ property, NULL);
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE)
tracker_data_resource_unref (data, g_value_get_int64 (value), FALSE);
@@ -2356,7 +2427,15 @@ delete_all_helper (TrackerData *data,
if (!value_set_remove_value (super_old_values, value))
continue;
- cache_delete_value (data, NULL, property, value);
+ if (tracker_property_get_multiple_values (property)) {
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_DELETE,
+ property, value);
+ } else {
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (property),
+ property, NULL);
+ }
if (tracker_property_get_data_type (property) == TRACKER_PROPERTY_TYPE_RESOURCE) {
tracker_data_resource_unref (data, g_value_get_int64 (value),
@@ -2434,7 +2513,9 @@ delete_single_valued (TrackerData *data,
multiple_values = tracker_property_get_multiple_values (predicate);
if (super_is_single_valued && multiple_values) {
- cache_delete_all_values (data, predicate);
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR,
+ predicate, NULL);
if (tracker_property_get_data_type (predicate) == TRACKER_PROPERTY_TYPE_RESOURCE) {
if (!tracker_data_resource_unref_all (data, predicate, error))
@@ -2450,7 +2531,9 @@ delete_single_valued (TrackerData *data,
GValue *value;
value = &g_array_index (old_values, GValue, 0);
- cache_delete_value (data, NULL, predicate, value);
+ log_entry_for_single_value_property (data,
+ tracker_property_get_domain (predicate),
+ predicate, NULL);
if (tracker_property_get_data_type (predicate) == TRACKER_PROPERTY_TYPE_RESOURCE)
tracker_data_resource_unref (data, g_value_get_int64 (value),
multiple_values);
@@ -2641,7 +2724,9 @@ tracker_data_update_statement (TrackerData *data,
data->resource_buffer->fts_updated |=
tracker_property_get_fulltext_indexed (predicate);
- cache_delete_all_values (data, predicate);
+ log_entry_for_multi_value_property (data,
+ TRACKER_LOG_MULTIVALUED_PROPERTY_CLEAR,
+ predicate, NULL);
if (tracker_property_get_data_type (predicate) == TRACKER_PROPERTY_TYPE_RESOURCE) {
if (!tracker_data_resource_unref_all (data, predicate, error))
@@ -2678,6 +2763,14 @@ tracker_data_update_statement (TrackerData *data,
}
}
+static void
+clear_property (gpointer data)
+{
+ TrackerDataPropertyEntry *entry = data;
+
+ g_value_unset (&entry->value);
+}
+
void
tracker_data_begin_transaction (TrackerData *data,
GError **error)
@@ -2710,6 +2803,12 @@ tracker_data_begin_transaction (TrackerData *data,
(GDestroyNotify)
tracker_rowid_free, NULL);
/* used for normal transactions */
data->update_buffer.graphs = g_ptr_array_new_with_free_func ((GDestroyNotify)
graph_buffer_free);
+
+ data->update_buffer.properties = g_array_sized_new (FALSE, TRUE, sizeof
(TrackerDataPropertyEntry), UPDATE_LOG_SIZE);
+ g_array_set_clear_func (data->update_buffer.properties, clear_property);
+ data->update_buffer.update_log = g_array_sized_new (FALSE, TRUE, sizeof
(TrackerDataLogEntry), UPDATE_LOG_SIZE);
+ data->update_buffer.class_updates = g_hash_table_new (tracker_data_log_entry_hash,
+ tracker_data_log_entry_equal);
}
data->resource_buffer = NULL;
diff --git a/tests/core/describe/describe-multiple.out b/tests/core/describe/describe-multiple.out
index 8edc0fd45..156582543 100644
--- a/tests/core/describe/describe-multiple.out
+++ b/tests/core/describe/describe-multiple.out
@@ -1,8 +1,8 @@
"b" "http://example/relation" "z"
"c" "http://example/relation" "x"
"d" "http://example/relation" "z"
-"z" "http://example/title" "titleZ"
"x" "http://example/title" "titleX"
+"z" "http://example/title" "titleZ"
"b" "http://example/number" "73"
"c" "http://example/number" "113"
"b" "http://example/date" "2001-01-01T00:00:01Z"
@@ -10,13 +10,13 @@
"b" "http://example/name" "nameB"
"c" "http://example/name" "nameC"
"d" "http://example/name" "nameD"
-"z" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
-"z" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/B"
-"x" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
-"x" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/B"
"b" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
"b" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/A"
"c" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
"c" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/A"
"d" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
"d" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/A"
+"x" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
+"x" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/B"
+"z" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type"
"http://www.w3.org/2000/01/rdf-schema#Resource"
+"z" "http://www.w3.org/1999/02/22-rdf-syntax-ns#type" "http://example/B"
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]