[anjuta] symbol-db: light speed given on population. Symbol table now memory mapped.
- From: Massimo Cora' <mcora src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta] symbol-db: light speed given on population. Symbol table now memory mapped.
- Date: Fri, 4 Jun 2010 23:01:08 +0000 (UTC)
commit efe42d331994f49acc2c5e7cb2496a60825db78d
Author: Massimo Corà <mcora src gnome org>
Date: Sat Jun 5 00:58:39 2010 +0200
symbol-db: light speed given on population. Symbol table now memory mapped.
0.000085 sec/sym on average insertion. This kicks every previous 'record'. Best one
was 0.0011 sec/sym. Population of entire Anjuta db (~1k files, 28k symbols) takes
here around 10 seconds. Most of the time is spent while flushing on db the records,
but I think that with a thread wrapper the gui freeze can be avoided.
plugins/symbol-db/symbol-db-engine-core.c | 391 ++++++++++++++++++++++++++++-
plugins/symbol-db/symbol-db-engine-priv.h | 4 +
2 files changed, 385 insertions(+), 10 deletions(-)
---
diff --git a/plugins/symbol-db/symbol-db-engine-core.c b/plugins/symbol-db/symbol-db-engine-core.c
index 9109d33..96f495e 100644
--- a/plugins/symbol-db/symbol-db-engine-core.c
+++ b/plugins/symbol-db/symbol-db-engine-core.c
@@ -167,6 +167,24 @@ typedef struct _TableMapTmpHeritage {
} TableMapTmpHeritage;
+typedef struct _TableMapSymbol {
+ gint symbol_id;
+ gint file_defined_id;
+ gchar *name;
+ gint file_position;
+ gint is_file_scope;
+ gchar *signature;
+ gchar *returntype;
+ gint scope_definition_id;
+ gint scope_id;
+ gint type_id;
+ gint kind_id;
+ gint access_kind_id;
+ gint implementation_kind_id;
+ gint update_flag;
+
+} TableMapSymbol;
+
/*
* utility macros
*/
@@ -259,6 +277,9 @@ sdb_engine_tablemap_db_flush_sym_type (SymbolDBEngine * dbe);
static void
sdb_engine_tablemap_db_flush_scope_def (SymbolDBEngine * dbe);
+static void
+sdb_engine_tablemap_db_flush_symbol (SymbolDBEngine * dbe);
+
void
sdb_engine_dyn_child_query_node_destroy (gpointer data);
@@ -316,7 +337,18 @@ sdb_engine_insert_cache (GHashTable* hash_table, const gchar* key,
}
static void
-sdb_engine_table_map_tmp_heritage_destroy (TableMapTmpHeritage *node)
+sdb_engine_tablemap_symbol_destroy (gpointer data)
+{
+ TableMapSymbol *node = (TableMapSymbol *)data;
+ g_free (node->signature);
+ g_free (node->returntype);
+ g_free (node->name);
+
+ g_slice_free (TableMapSymbol, node);
+}
+
+static void
+sdb_engine_tablemap_tmp_heritage_destroy (TableMapTmpHeritage *node)
{
g_free (node->field_inherits);
g_free (node->field_struct);
@@ -338,7 +370,7 @@ sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
TableMapTmpHeritage *node;
while ((node = g_queue_pop_head (priv->tmp_heritage_tablemap)) != NULL)
{
- sdb_engine_table_map_tmp_heritage_destroy (node);
+ sdb_engine_tablemap_tmp_heritage_destroy (node);
}
/* queue should be void. Free it */
@@ -379,6 +411,22 @@ sdb_engine_clear_tablemaps (SymbolDBEngine *dbe)
}
priv->scope_def_tablemap_id = 1;
+
+ if (priv->symbol_tablemap_queue)
+ {
+ g_queue_clear (priv->symbol_tablemap_queue);
+ g_queue_free (priv->symbol_tablemap_queue);
+ priv->symbol_tablemap_queue = NULL;
+ }
+
+ if (priv->symbol_tablemap_hash)
+ {
+ g_hash_table_destroy (priv->symbol_tablemap_hash);
+ priv->symbol_tablemap_hash = NULL;
+ }
+
+ priv->symbol_tablemap_id = 1;
+
}
static void
@@ -420,6 +468,14 @@ sdb_engine_init_table_maps (SymbolDBEngine *dbe)
NULL);
priv->scope_def_tablemap_queue = g_queue_new ();
priv->scope_def_tablemap_id = 1;
+
+ /* symbol_tablemap */
+ priv->symbol_tablemap_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ sdb_engine_tablemap_symbol_destroy);
+ priv->symbol_tablemap_queue = g_queue_new ();
+ priv->symbol_tablemap_id = 1;
}
static void
@@ -4203,7 +4259,7 @@ sdb_engine_tablemap_db_flush_sym_type (SymbolDBEngine * dbe)
if (error)
{
g_warning (error->message);
- g_object_unref (error);
+ g_error_free (error);
error = NULL;
}
@@ -4256,7 +4312,7 @@ sdb_engine_tablemap_db_flush_sym_type (SymbolDBEngine * dbe)
if (error)
{
g_warning (error->message);
- g_object_unref (error);
+ g_error_free (error);
error = NULL;
}
@@ -4265,7 +4321,9 @@ sdb_engine_tablemap_db_flush_sym_type (SymbolDBEngine * dbe)
DEBUG_PRINT ("===== elapsed using GDA TRANSACTION: %f", elapsed_DEBUG);
g_timer_destroy (sym_timer_DEBUG);
#endif
-
+
+ /* free also all the keys/values on hashtable */
+ g_hash_table_remove_all (priv->sym_type_tablemap_hash);
}
/* ### Thread note: this function inherits the mutex lock ### */
@@ -4829,7 +4887,7 @@ sdb_engine_tablemap_db_flush_scope_def (SymbolDBEngine * dbe)
if (error)
{
g_warning (error->message);
- g_object_unref (error);
+ g_error_free (error);
error = NULL;
}
@@ -4884,7 +4942,7 @@ sdb_engine_tablemap_db_flush_scope_def (SymbolDBEngine * dbe)
if (error)
{
g_warning (error->message);
- g_object_unref (error);
+ g_error_free (error);
error = NULL;
}
@@ -4893,7 +4951,9 @@ sdb_engine_tablemap_db_flush_scope_def (SymbolDBEngine * dbe)
DEBUG_PRINT ("===== elapsed using GDA TRANSACTION: %f", elapsed_DEBUG);
g_timer_destroy (sym_timer_DEBUG);
#endif
-
+
+ /* free also all the keys/values on hashtable */
+ g_hash_table_remove_all (priv->scope_def_tablemap_hash);
}
static gint
@@ -5325,7 +5385,7 @@ sdb_engine_second_pass_update_scope (SymbolDBEngine * dbe)
}
else
{
- sdb_engine_table_map_tmp_heritage_destroy (node);
+ sdb_engine_tablemap_tmp_heritage_destroy (node);
}
}
@@ -5365,7 +5425,7 @@ sdb_engine_second_pass_update_heritage (SymbolDBEngine * dbe)
{
g_warning ("Inherits was NULL on sym_referer id %d",
node->symbol_referer_id);
- sdb_engine_table_map_tmp_heritage_destroy (node);
+ sdb_engine_tablemap_tmp_heritage_destroy (node);
continue;
}
@@ -5528,6 +5588,7 @@ sdb_engine_second_pass_do (SymbolDBEngine * dbe)
{
sdb_engine_tablemap_db_flush_sym_type (dbe);
sdb_engine_tablemap_db_flush_scope_def (dbe);
+ sdb_engine_tablemap_db_flush_symbol (dbe);
}
@@ -5539,6 +5600,303 @@ sdb_engine_second_pass_do (SymbolDBEngine * dbe)
}
}
+
+static void
+sdb_engine_tablemap_db_flush_symbol (SymbolDBEngine * dbe)
+{
+ SymbolDBEnginePriv *priv;
+ gint i;
+ gint queue_length;
+ const GdaSet *plist;
+ const GdaStatement *stmt;
+ GdaHolder *param;
+ GValue *ret_value;
+ gboolean ret_bool;
+ GError *error = NULL;
+
+ priv = dbe->priv;
+ DEBUG_PRINT ("Preparing SYMBOL flush on db");
+#ifdef DEBUG
+ GTimer *sym_timer_DEBUG = g_timer_new ();
+#endif
+ queue_length = g_queue_get_length (priv->symbol_tablemap_queue);
+
+ gda_connection_begin_transaction (priv->db_connection, "symboltrans",
+ GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED, &error);
+
+ if (error)
+ {
+ g_warning (error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+ if ((stmt = sdb_engine_get_statement_by_query_id (dbe, PREP_QUERY_SYMBOL_NEW))
+ == NULL)
+ {
+ g_warning ("query is null");
+ return;
+ }
+
+ plist = sdb_engine_get_query_parameters_list (dbe, PREP_QUERY_SYMBOL_NEW);
+
+ for (i = 0; i < queue_length; i++)
+ {
+ TableMapSymbol * node;
+ node = (TableMapSymbol *)g_queue_pop_head (priv->symbol_tablemap_queue);
+
+ /* filedefid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "filedefid")) == NULL)
+ {
+ g_warning ("param filedefid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->file_defined_id, ret_bool, ret_value);
+
+ /* name parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "name")) == NULL)
+ {
+ g_warning ("param name is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_STR(priv, param, node->name, ret_bool, ret_value);
+
+ /* typeid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "typeid")) == NULL)
+ {
+ g_warning ("param typeid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->type_id, ret_bool, ret_value);
+
+ /* common params */
+
+ /* fileposition parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "fileposition")) == NULL)
+ {
+ g_warning ("param fileposition is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->file_position, ret_bool, ret_value);
+
+ /* isfilescope parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "isfilescope")) == NULL)
+ {
+ g_warning ("param isfilescope is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->is_file_scope, ret_bool, ret_value);
+
+ /* signature parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "signature")) == NULL)
+ {
+ g_warning ("param signature is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_STR(priv, param, node->signature, ret_bool, ret_value);
+
+ /* returntype parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "returntype")) == NULL)
+ {
+ g_warning ("param returntype is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_STR(priv, param, node->returntype, ret_bool, ret_value);
+
+ /* scopedefinitionid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "scopedefinitionid")) == NULL)
+ {
+ g_warning ("param scopedefinitionid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->scope_definition_id, ret_bool, ret_value);
+
+ /* scopeid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "scopeid")) == NULL)
+ {
+ g_warning ("param scopeid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->scope_id, ret_bool, ret_value);
+
+ /* kindid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "kindid")) == NULL)
+ {
+ g_warning ("param kindid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->kind_id, ret_bool, ret_value);
+
+ /* accesskindid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "accesskindid")) == NULL)
+ {
+ g_warning ("param accesskindid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->access_kind_id, ret_bool, ret_value);
+
+ /* implementationkindid parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "implementationkindid")) == NULL)
+ {
+ g_warning ("param implementationkindid is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->implementation_kind_id, ret_bool, ret_value);
+
+ /* updateflag parameter */
+ if ((param = gda_set_get_holder ((GdaSet*)plist, "updateflag")) == NULL)
+ {
+ g_warning ("param updateflag is NULL from pquery!");
+ return;
+ }
+
+ MP_SET_HOLDER_BATCH_INT(priv, param, node->update_flag, ret_bool, ret_value);
+
+
+ /* execute the query with parametes just set */
+ gda_connection_statement_execute_non_select (priv->db_connection,
+ (GdaStatement*)stmt,
+ (GdaSet*)plist, NULL,
+ NULL);
+
+ /* no need to free value, it'll be freed when associated value
+ * on hashtable'll be freed
+ */
+
+ MP_RESET_PLIST(plist);
+ }
+
+ gda_connection_commit_transaction (priv->db_connection, "symboltrans", &error);
+
+ if (error)
+ {
+ g_warning (error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+
+#ifdef DEBUG
+ gdouble elapsed_DEBUG = g_timer_elapsed (sym_timer_DEBUG, NULL);
+ DEBUG_PRINT ("===== elapsed using GDA TRANSACTION: %f", elapsed_DEBUG);
+ g_timer_destroy (sym_timer_DEBUG);
+#endif
+
+ /* free also all the keys/values on hashtable */
+ g_hash_table_remove_all (priv->symbol_tablemap_hash);
+}
+
+/**
+ * ### Thread note: this function inherits the mutex lock ###
+ *
+ * A specific function to perform a fast 1st insertion of symbols on db.
+ * This function avoids over-complex logic on an already complex
+ * sdb_engine_add_new_symbol (). Here we won't use update case but we'll consider
+ * just a plain insertion on tablemaps, of course, and a flush_on_db later.
+ *
+ */
+static gint
+sdb_engine_add_new_symbol_1st (SymbolDBEngine *dbe, const tagEntry *tag_entry,
+ gint file_defined_id)
+{
+ SymbolDBEnginePriv *priv;
+ gint table_id = -1;
+ const gchar* name;
+ gint file_position = 0;
+ gint is_file_scope = 0;
+ const gchar *signature;
+ const gchar *returntype;
+ gint scope_definition_id = 0;
+ gint scope_id = 0;
+ gint type_id = 0;
+ gint kind_id = 0;
+ gint access_kind_id = 0;
+ gint implementation_kind_id = 0;
+ gchar *key_to_find;
+ gpointer value;
+
+ g_return_val_if_fail (dbe != NULL, -1);
+ g_return_val_if_fail (tag_entry != NULL, -1);
+
+ priv = dbe->priv;
+
+ /* parse the entry name */
+ name = tag_entry->name;
+ file_position = tag_entry->address.lineNumber;
+ is_file_scope = tag_entry->fileScope;
+ signature = tagsField (tag_entry, "signature");
+ returntype = tagsField (tag_entry, "returntype");
+
+ type_id = sdb_engine_add_new_sym_type (dbe, tag_entry);
+ scope_definition_id = sdb_engine_add_new_scope_definition (dbe, tag_entry,
+ type_id);
+ scope_id = 0;
+
+ kind_id = sdb_engine_add_new_sym_kind (dbe, tag_entry);
+ access_kind_id = sdb_engine_add_new_sym_access (dbe, tag_entry);
+ implementation_kind_id = sdb_engine_add_new_sym_implementation (dbe, tag_entry);
+
+ key_to_find = g_strdup_printf ("%s|%d|%d", name, file_defined_id, file_position);
+
+ /* use a check-first, insert later pattern. Have a look at the hashtable if
+ * we find the correct key
+ */
+ value = g_hash_table_lookup (priv->symbol_tablemap_hash, key_to_find);
+
+ if (value == NULL)
+ {
+ TableMapSymbol *node;
+ gint new_id;
+
+ new_id = priv->symbol_tablemap_id++;
+
+ node = g_slice_new0 (TableMapSymbol);
+ node->symbol_id = new_id;
+ node->access_kind_id = access_kind_id;
+ node->file_defined_id = file_defined_id;
+ node->file_position = file_position;
+ node->implementation_kind_id = implementation_kind_id;
+ node->is_file_scope = is_file_scope;
+ node->kind_id = kind_id;
+ node->name = g_strdup (name); /* to be freed */
+ node->returntype = g_strdup (returntype); /* to be freed */
+ node->scope_definition_id = scope_definition_id;
+ node->scope_id = scope_id;
+ node->signature = g_strdup (signature); /* to be freed */
+ node->type_id = type_id;
+ node->update_flag = 0;
+
+ /* no value has been found, proceed with insertion */
+ g_hash_table_insert (priv->symbol_tablemap_hash, key_to_find, node);
+
+ /* insert the node also in the queue. */
+ g_queue_push_tail (priv->symbol_tablemap_queue, node);
+
+ table_id = new_id;
+ }
+ else
+ {
+ /* fine, return the id found */
+ table_id = GPOINTER_TO_INT (value);
+
+ g_free (key_to_find);
+ }
+
+ return table_id;
+}
+
+
/**
* ### Thread note: this function inherits the mutex lock ###
*
@@ -5595,6 +5953,15 @@ sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
g_return_val_if_fail (dbe != NULL, -1);
priv = dbe->priv;
+ if (priv->is_first_population == TRUE)
+ {
+ table_id = sdb_engine_add_new_symbol_1st (dbe, tag_entry, file_defined_id);
+ if (table_id > 0)
+ sdb_engine_add_new_tmp_heritage_scope (dbe, tag_entry, table_id);
+
+ return table_id;
+ }
+
/* keep it at 0 if sym_update == false */
if (sym_update == FALSE)
update_flag = 0;
@@ -5705,6 +6072,7 @@ sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
sym_list);
}
}
+
/* ok then, parse the symbol id value */
if (symbol_id <= 0)
{
@@ -5882,6 +6250,7 @@ sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
/* execute the query with parametes just set */
gint nrows;
+
nrows = gda_connection_statement_execute_non_select (priv->db_connection,
(GdaStatement*)stmt,
(GdaSet*)plist, &last_inserted,
@@ -5924,6 +6293,8 @@ sdb_engine_add_new_symbol (SymbolDBEngine * dbe, const tagEntry * tag_entry,
if (last_inserted)
g_object_unref (last_inserted);
+
+ /* post population phase */
/* before returning the table_id we have to fill some infoz on temporary tables
* so that in a second pass we can parse also the heritage and scope fields.
diff --git a/plugins/symbol-db/symbol-db-engine-priv.h b/plugins/symbol-db/symbol-db-engine-priv.h
index 4346667..cf6a53c 100644
--- a/plugins/symbol-db/symbol-db-engine-priv.h
+++ b/plugins/symbol-db/symbol-db-engine-priv.h
@@ -323,6 +323,10 @@ struct _SymbolDBEnginePriv
GHashTable *scope_def_tablemap_hash;
GQueue *scope_def_tablemap_queue;
guint scope_def_tablemap_id;
+
+ GHashTable *symbol_tablemap_hash;
+ GQueue *symbol_tablemap_queue;
+ guint symbol_tablemap_id;
GTree *file_symbols_cache;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]