[anjuta/symbol-db-model] symbol-db: Changed ref counting approach, added idle loop for ensure children
- From: Naba Kumar <naba src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [anjuta/symbol-db-model] symbol-db: Changed ref counting approach, added idle loop for ensure children
- Date: Sun, 14 Mar 2010 01:46:11 +0000 (UTC)
commit c7243be1be10ca181f2ec9d1e0eec8dad7bec784
Author: Naba Kumar <naba gnome org>
Date: Sun Mar 14 03:46:01 2010 +0200
symbol-db: Changed ref counting approach, added idle loop for ensure children
plugins/symbol-db/symbol-db-model-global.c | 2 +-
plugins/symbol-db/symbol-db-model.c | 339 +++++++++++++++-------------
2 files changed, 187 insertions(+), 154 deletions(-)
---
diff --git a/plugins/symbol-db/symbol-db-model-global.c b/plugins/symbol-db/symbol-db-model-global.c
index 4fe5f9a..602cc4a 100644
--- a/plugins/symbol-db/symbol-db-model-global.c
+++ b/plugins/symbol-db/symbol-db-model-global.c
@@ -107,7 +107,7 @@ symbol_db_model_global_get_children (SymbolDBModel *model, gint tree_level,
case 1:
symbol_id = g_value_get_int (&column_values[DATA_COL_SYMBOL_ID]);
iter = symbol_db_engine_get_scope_members_by_symbol_id
- (priv->dbe, symbol_id, offset, limit, SYMINFO_SIMPLE |
+ (priv->dbe, symbol_id, limit, offset, SYMINFO_SIMPLE |
SYMINFO_ACCESS | SYMINFO_TYPE | SYMINFO_FILE_PATH |
SYMINFO_KIND);
break;
diff --git a/plugins/symbol-db/symbol-db-model.c b/plugins/symbol-db/symbol-db-model.c
index fda5805..7074b24 100644
--- a/plugins/symbol-db/symbol-db-model.c
+++ b/plugins/symbol-db/symbol-db-model.c
@@ -30,11 +30,11 @@
/* Constants */
#define SYMBOL_DB_MODEL_PAGE_SIZE 100
+#define SYMBOL_DB_MODEL_ENSURE_CHILDREN_BATCH_SIZE 10
typedef struct _SymbolDBModelPage SymbolDBModelPage;
struct _SymbolDBModelPage
{
- gint ref_count;
gint begin_offset, end_offset;
SymbolDBModelPage *prev;
SymbolDBModelPage *next;
@@ -49,14 +49,18 @@ struct _SymbolDBModelNode {
*/
GValue *values;
- /* List of currently active (loaded) pages */
+ /* List of currently active (cached) pages */
SymbolDBModelPage *pages;
/* Data structure */
gint level;
SymbolDBModelNode *parent;
gint offset;
+
+ /* Children states */
+ gboolean children_ensured;
guint n_children;
+ gint children_ref_count;
SymbolDBModelNode **children;
};
@@ -66,21 +70,9 @@ typedef struct {
gint *query_columns; /* Corresponding GdaDataModel column */
gint node_id_column;
- /* Nodes currently references by others and already processed.
- * These are the nodes tracked and displayed by the view.
- */
- GHashTable *refed_nodes;
-
- /* Nodes referenced by others and queued for processing */
- GQueue *refed_nodes_queue;
-
- /* Internal temporary references. Some views could try to access
- * some nodes without holding reference to it first. A temporary
- * reference is created for it and potentially either eventually
- * refed by the view or released at some later time from my_ref
- * during a garbage collection rounds.
- */
- GHashTable *my_refed_nodes;
+ /* Idle child-ensure queue */
+ GQueue *ensure_children_queue;
+ guint ensure_children_idle_id;
SymbolDBModelNode *root;
} SymbolDBModelPriv;
@@ -96,6 +88,8 @@ static guint symbol_db_model_signals[LAST_SIGNAL] = { 0 };
/* Declarations */
+static void symbol_db_model_node_free (SymbolDBModelNode *node);
+
static void symbol_db_model_tree_model_init (GtkTreeModelIface *iface);
static gboolean symbol_db_model_get_query_value_at (SymbolDBModel *model,
@@ -118,8 +112,10 @@ static GdaDataModel* symbol_db_model_get_children (SymbolDBModel *model,
GValue column_values[],
gint offset, gint limit);
-static void symbol_db_model_ensure_node_children (SymbolDBModel *model,
- SymbolDBModelNode *parent);
+static void symbol_db_model_node_ensure_children (SymbolDBModel *model,
+ SymbolDBModelNode *parent,
+ gboolean queue_it,
+ gboolean emit_has_child);
/* Class definition */
G_DEFINE_TYPE_WITH_CODE (SymbolDBModel, symbol_db_model, G_TYPE_OBJECT,
@@ -127,12 +123,6 @@ G_DEFINE_TYPE_WITH_CODE (SymbolDBModel, symbol_db_model, G_TYPE_OBJECT,
symbol_db_model_tree_model_init))
/* Node */
-static void
-symbol_db_model_node_free (SymbolDBModelNode *node)
-{
- /* FIXME: */
-}
-
static inline SymbolDBModelNode*
symbol_db_model_node_get_child (SymbolDBModelNode *node, gint child_offset)
{
@@ -146,6 +136,58 @@ symbol_db_model_node_set_child (SymbolDBModelNode *node, gint child_offset,
node->children[child_offset] = val;
}
+static gboolean
+symbol_db_model_node_cleanse (SymbolDBModelNode *node)
+{
+ SymbolDBModelPage *page, *next;
+ gint i;
+
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ /* Can not cleanse a node if there are refed children */
+ g_return_val_if_fail (node->children_ref_count == 0, FALSE);
+
+ /* There should be no children with any ref. Children with ref count 0
+ * are floating children and can be destroyed.
+ */
+ for (i = 0; i < node->n_children; i++)
+ {
+ SymbolDBModelNode *child = symbol_db_model_node_get_child (node, i);
+ if (child)
+ {
+ /* Assert on nodes with ref count > 0 */
+ g_warn_if_fail (child->children_ref_count == 0);
+ symbol_db_model_node_free (child);
+ symbol_db_model_node_set_child (node, i, NULL);
+ }
+ }
+
+ /* Reset cached pages */
+ page = node->pages;
+ while (page)
+ {
+ next = page->next;
+ g_free (page);
+ page = next;
+ }
+ node->pages = NULL;
+
+ g_free (node->children);
+ node->children = NULL;
+
+ return TRUE;
+}
+
+static void
+symbol_db_model_node_free (SymbolDBModelNode *node)
+{
+ if (!symbol_db_model_node_cleanse (node))
+ return;
+
+ g_free (node->values);
+ g_free (node);
+}
+
static void
symbol_db_model_node_remove_page (SymbolDBModelNode *node,
SymbolDBModelPage *page)
@@ -210,74 +252,33 @@ symbol_db_model_node_find_child_page (SymbolDBModelNode *node,
}
static void
-symbol_db_model_node_page_ref (SymbolDBModelPage *page)
+symbol_db_model_node_ref_child (SymbolDBModelNode *node)
{
- page->ref_count++;
-}
-
-static void
-symbol_db_model_node_page_unref (SymbolDBModelNode *node,
- SymbolDBModelPage *page)
-{
- g_return_if_fail (page != NULL);
- g_return_if_fail (page->ref_count > 0);
-
- page->ref_count--;
- if (page->ref_count <= 0)
- {
- gint i;
- for (i = page->begin_offset; i < page->end_offset; i++)
- {
- symbol_db_model_node_free (symbol_db_model_node_get_child (node, i));
- symbol_db_model_node_set_child (node, i, NULL);
- }
- symbol_db_model_node_remove_page (node, page);
- g_free (page);
- }
-}
-
-static void
-symbol_db_model_node_ref (SymbolDBModelNode *node)
-{
- SymbolDBModelNode *parent;
- SymbolDBModelPage *page, *prev_page;
-
g_return_if_fail (node != NULL);
-
- /* Ref the page containing this node */
- parent = node->parent;
-
- if (!parent) /* Root not can not be reffed. It always exists */
- return;
-
- page = symbol_db_model_node_find_child_page (parent, node->offset,
- &prev_page);
-
- g_return_if_fail (page != NULL);
- symbol_db_model_node_page_ref (page);
-
- if (parent)
- symbol_db_model_node_ref (parent);
+ node->children_ref_count++;
}
static void
-symbol_db_model_node_unref (SymbolDBModelNode *node)
+symbol_db_model_node_unref_child (SymbolDBModelNode *node, gint child_offset)
{
- SymbolDBModelNode *parent;
- SymbolDBModelPage *page, *prev_page;
-
+ SymbolDBModelNode *parent_node;
+ gint node_offset;
g_return_if_fail (node != NULL);
+ g_return_if_fail (node->children_ref_count > 0);
- /* Ref the page containing this node */
- parent = node->parent;
- page = symbol_db_model_node_find_child_page (parent, node->offset,
- &prev_page);
-
- g_return_if_fail (page != NULL);
- symbol_db_model_node_page_unref (parent, page);
+ node->children_ref_count--;
+ parent_node = node->parent;
+ node_offset = node->offset;
+
+ /* If ref count reaches 0, cleanse this node */
+ if (node->children_ref_count <= 0)
+ {
+ symbol_db_model_node_cleanse (node);
+ }
- if (parent)
- symbol_db_model_node_unref (parent);
+ /* Reduce the associate ref count on parent also */
+ if (parent_node)
+ symbol_db_model_node_unref_child (parent_node, node_offset);
}
static SymbolDBModelNode *
@@ -436,6 +437,9 @@ symbol_db_model_get_iter (GtkTreeModel *tree_model,
g_return_val_if_fail (SYMBOL_DB_IS_MODEL(tree_model), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
g_return_val_if_fail (path != NULL, FALSE);
+
+ gchar *path_str = gtk_tree_path_to_string (path);
+ g_free (path_str);
depth = gtk_tree_path_get_depth (path);
g_return_val_if_fail (depth > 0, FALSE);
@@ -443,24 +447,18 @@ symbol_db_model_get_iter (GtkTreeModel *tree_model,
priv = GET_PRIV (tree_model);
indx = gtk_tree_path_get_indices (path);
- /* Ensure root expansion */
- if (priv->root->n_children == 0)
- symbol_db_model_ensure_node_children (SYMBOL_DB_MODEL (tree_model),
- priv->root);
- if (priv->root->n_children == 0)
- return FALSE;
-
parent_node = NULL;
node = priv->root;
for (i = 0; i < depth; i++)
{
parent_node = node;
+ if (!node->children_ensured)
+ symbol_db_model_node_ensure_children (SYMBOL_DB_MODEL (tree_model),
+ node, FALSE, FALSE);
if (node->children == NULL || node->n_children <= 0)
{
- /* No child available */
-
- /* FIXME: Do something more graceful like actually
- * expanding the node and proceeding further.
+ /* FIXME: No child available. View thinks there is child.
+ * It's an inconsistent state. Do something fancy to fix it.
*/
break;
}
@@ -501,11 +499,12 @@ symbol_db_model_get_path (GtkTreeModel *tree_model,
path = gtk_tree_path_new ();
node = (SymbolDBModelNode*)iter->user_data;
- offset = GPOINTER_TO_INT (iter->user_data);
+ offset = GPOINTER_TO_INT (iter->user_data2);
do {
gtk_tree_path_prepend_index (path, offset);
node = node->parent;
- offset = node->offset;
+ if (node)
+ offset = node->offset;
} while (node);
return path;
}
@@ -536,6 +535,15 @@ symbol_db_model_get_value (GtkTreeModel *tree_model,
node = symbol_db_model_node_get_child (parent_node, offset);
g_value_init (value, priv->column_types[column]);
g_return_if_fail (node != NULL);
+
+ /* View accessed the node, so update any pending has-child status */
+ if (!node->children_ensured)
+ symbol_db_model_node_ensure_children (SYMBOL_DB_MODEL (tree_model),
+ node, TRUE, TRUE);
+
+ /* FIXME: We should also refresh children status even if children was
+ * ensured already.
+ */
g_value_copy (&(node->values[column]), value);
}
@@ -619,20 +627,12 @@ symbol_db_model_iter_has_child (GtkTreeModel *tree_model,
parent_node = (SymbolDBModelNode*) iter->user_data;
offset = GPOINTER_TO_INT (iter->user_data2);
-
+
node = symbol_db_model_node_get_child (parent_node, offset);
- if (node == NULL)
- {
- symbol_db_model_page_fault (SYMBOL_DB_MODEL (tree_model),
- parent_node, offset);
- node = symbol_db_model_node_get_child (parent_node, offset);
- if (node == NULL)
- return FALSE;
- }
- if (node->n_children <= 0)
- symbol_db_model_ensure_node_children (SYMBOL_DB_MODEL (tree_model),
- node);
+ /* If node is not loaded, has-child is defered. See get_value() */
+ if (node == NULL)
+ return FALSE;
return (node->n_children > 0);
}
@@ -710,60 +710,29 @@ symbol_db_model_iter_parent (GtkTreeModel *tree_model,
static void
symbol_db_model_iter_ref (GtkTreeModel *tree_model, GtkTreeIter *iter)
{
- SymbolDBModelPriv *priv;
- SymbolDBModelNode *node, *parent_node;
+ SymbolDBModelNode *parent_node;
gint child_offset;
g_return_if_fail (symbol_db_model_iter_is_valid (tree_model, iter));
- priv = GET_PRIV(tree_model);
parent_node = (SymbolDBModelNode*) iter->user_data;
child_offset = GPOINTER_TO_INT (iter->user_data2);
- g_message ("Referencing node %p->%d", parent_node, child_offset);
-
- node = symbol_db_model_node_get_child (parent_node, child_offset);
-
- if (!node)
- {
- /* Page fault */
- g_warning ("Page fault occured without getting values first.");
- symbol_db_model_page_fault (SYMBOL_DB_MODEL (tree_model),
- parent_node, child_offset);
- }
- node = symbol_db_model_node_get_child (parent_node, child_offset);
- g_return_if_fail (node != NULL);
-
- /* If the node was already referenced internally, just pass it. */
- if (g_hash_table_lookup (priv->my_refed_nodes, node))
- g_hash_table_remove (priv->my_refed_nodes, node);
- else /* Otherwise make fresh reference */
- symbol_db_model_node_ref (node);
-
- /* Keep record of currently referenced nodes */
- if (g_hash_table_lookup (priv->refed_nodes, node))
- g_hash_table_insert (priv->refed_nodes, node, node);
+ symbol_db_model_node_ref_child (parent_node);
}
static void
symbol_db_model_iter_unref (GtkTreeModel *tree_model, GtkTreeIter *iter)
{
- SymbolDBModelPriv *priv;
- SymbolDBModelNode *node, *parent_node;
+ SymbolDBModelNode *parent_node;
gint child_offset;
g_return_if_fail (symbol_db_model_iter_is_valid (tree_model, iter));
- priv = GET_PRIV(tree_model);
parent_node = (SymbolDBModelNode*) iter->user_data;
child_offset = GPOINTER_TO_INT (iter->user_data2);
- g_message ("Unreferencing node %p->%d", parent_node, child_offset);
-
- node = symbol_db_model_node_get_child (parent_node, child_offset);
- g_return_if_fail (node != NULL);
-
- /* Check if the node is found anywhere as referenced */
+ symbol_db_model_node_unref_child (parent_node, child_offset);
}
static void
@@ -787,13 +756,56 @@ symbol_db_model_tree_model_init (GtkTreeModelIface *iface)
/* SymbolDBModel implementation */
+static gboolean
+on_symbol_db_ensure_children_idle (SymbolDBModel *model)
+{
+ gint count;
+ SymbolDBModelNode *node;
+ SymbolDBModelPriv *priv;
+
+ priv = GET_PRIV (model);
+
+ for (count = 0; count < SYMBOL_DB_MODEL_ENSURE_CHILDREN_BATCH_SIZE; count++)
+ {
+ node = g_queue_pop_head (priv->ensure_children_queue);
+ symbol_db_model_node_ensure_children (model, node, FALSE, TRUE);
+ if (g_queue_get_length (priv->ensure_children_queue) <= 0)
+ {
+ priv->ensure_children_idle_id = 0;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
static void
-symbol_db_model_ensure_node_children (SymbolDBModel *model,
- SymbolDBModelNode *potential_parent)
+symbol_db_model_node_ensure_children (SymbolDBModel *model,
+ SymbolDBModelNode *potential_parent,
+ gboolean queue_it,
+ gboolean emit_has_child)
{
+ SymbolDBModelPriv *priv;
+ gint old_n_children;
+
/* FIXME: Should we free (properly) existing children instead? */
g_return_if_fail (potential_parent->children == NULL);
- g_return_if_fail (potential_parent->n_children == 0);
+ g_return_if_fail (potential_parent->children_ensured == FALSE);
+
+ priv = GET_PRIV (model);
+ if (queue_it)
+ {
+ if (!g_queue_find (priv->ensure_children_queue, potential_parent))
+ {
+ g_queue_push_tail (priv->ensure_children_queue, potential_parent);
+ if (!priv->ensure_children_idle_id)
+ priv->ensure_children_idle_id =
+ g_idle_add ((GSourceFunc)on_symbol_db_ensure_children_idle,
+ model);
+ }
+ return;
+ }
+
+ old_n_children = potential_parent->n_children;
potential_parent->n_children =
symbol_db_model_get_n_children (model, potential_parent->level,
@@ -801,6 +813,23 @@ symbol_db_model_ensure_node_children (SymbolDBModel *model,
potential_parent->children = g_new0 (SymbolDBModelNode*,
potential_parent->n_children);
+
+ potential_parent->children_ensured = TRUE;
+ if (emit_has_child && potential_parent->n_children > 0)
+ {
+ GtkTreePath *path;
+ GtkTreeIter iter = {0};
+
+ iter.stamp = SYMBOL_DB_MODEL_STAMP;
+ iter.user_data = potential_parent->parent;
+ iter.user_data2 = GINT_TO_POINTER (potential_parent->offset);
+
+ path = symbol_db_model_get_path (GTK_TREE_MODEL (model), &iter);
+ gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model),
+ path, &iter);
+ gtk_tree_path_free (path);
+ }
+ /* g_warn_if_fail (potential_parent->n_children == old_n_children); */
}
static gboolean
@@ -904,9 +933,8 @@ symbol_db_model_get_children (SymbolDBModel *model, gint tree_level,
GValue column_values[], gint offset,
gint limit)
{
- return SYMBOL_DB_MODEL_GET_CLASS(model)->get_children (model, tree_level,
- column_values,
- offset, limit);
+ return SYMBOL_DB_MODEL_GET_CLASS(model)->
+ get_children (model, tree_level, column_values, offset, limit);
}
/* Object implementation */
@@ -914,7 +942,14 @@ symbol_db_model_get_children (SymbolDBModel *model, gint tree_level,
static void
symbol_db_model_finalize (GObject *object)
{
+ SymbolDBModelPriv *priv;
/* FIXME */
+
+ priv = GET_PRIV (object);
+ if (priv->ensure_children_idle_id)
+ g_source_remove (priv->ensure_children_idle_id);
+ g_queue_free (priv->ensure_children_queue);
+
G_OBJECT_CLASS (symbol_db_model_parent_class)->finalize (object);
}
@@ -952,8 +987,7 @@ symbol_db_model_init (SymbolDBModel *object)
priv->n_columns = 0;
priv->column_types = NULL;
priv->query_columns = NULL;
- priv->refed_nodes = g_hash_table_new (g_direct_hash, g_direct_equal);
- priv->my_refed_nodes = g_hash_table_new (g_direct_hash, g_direct_equal);
+ priv->ensure_children_queue = g_queue_new ();
}
static void
@@ -1066,4 +1100,3 @@ symbol_db_model_newv (gint n_columns, GType *types, gint *query_columns)
types, query_columns);
return model;
}
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]