Fixes to maintain consistency in the tree while versioning.
authorDana Jansens <danakj@orodu.net>
Fri, 30 Oct 2009 22:16:48 +0000 (18:16 -0400)
committerDana Jansens <danakj@orodu.net>
Thu, 12 Nov 2009 21:54:05 +0000 (16:54 -0500)
glib/gtree.c

index cd850b69333e69f1d4b5d5f280b1f539709054e1..59be18f53885ce64fc437630374d83837ca78af1 100644 (file)
@@ -500,6 +500,9 @@ static GTreeNode*
 g_tree_node_next_version (GTree     *tree,
                           GTreeNode *node)
 {
+  if (!node)
+    return NULL;
+
   g_assert(node->version(NOW) <= tree->version);
 
   if (node->version(NOW) == tree->version)
@@ -768,12 +771,16 @@ g_tree_insert_internal (GTree    *tree,
   while (node->parent(NOW) &&
          g_tree_priority (node) < g_tree_priority (node->parent(NOW)))
     {
-      GTreeNode *const sp = node->parent(NOW)->parent(NOW);
-      GTreeNode *const p = node->parent(NOW);
+      GTreeNode *sp, *p;
+
+      /* we'll be changing both of these nodes */
+      p = g_tree_node_next_version (tree, node->parent(NOW));
+      sp = g_tree_node_next_version (tree, p->parent(NOW));
+
       if (p->left(NOW) == node)
-        g_tree_node_rotate_right (tree, p);
+        node = g_tree_node_rotate_right (tree, p);
       else
-        g_tree_node_rotate_left (tree, p);
+        node = g_tree_node_rotate_left (tree, p);
 
       if (!sp)
         {
@@ -781,9 +788,9 @@ g_tree_insert_internal (GTree    *tree,
           tree->roots[0].root = node;
         }
       else if (sp->left(NOW) == p)
-        sp->left(NOW) = node;
+        sp->v[0].left = node;
       else
-        sp->right(NOW) = node;
+        sp->v[0].right = node;
     }
 }
 
@@ -897,6 +904,10 @@ g_tree_remove_internal (GTree         *tree,
   /* rotate the node down the tree, maintaining the heap property */
   while (node->left_child(NOW) || node->right_child(NOW))
     {
+      /* we're changing this node, make sure our pointer will stay valid
+         when we rotate it */
+      node = g_tree_node_next_version (tree, node);
+
       if (!node->left_child(NOW) ||
           (node->right_child(NOW) &&
            g_tree_priority (node->left(NOW)) >
@@ -964,16 +975,25 @@ g_tree_remove_internal (GTree         *tree,
           parent->v[0].right = node->right(NOW);
         }
     }
-  
-  if (!steal)
+
+  /* only really delete the node if it's in the current version, otherwise
+     it needs to be remembered */
+  if (node->nv == 1 && node->version(NOW) == tree->version)
     {
-      if (tree->key_destroy_func)
-        tree->key_destroy_func (node->data->key);
-      if (tree->value_destroy_func)
-        tree->value_destroy_func (node->data->value);
-    }
+      if (!steal)
+        {
+          if (tree->key_destroy_func)
+            tree->key_destroy_func (node->data->key);
+          if (tree->value_destroy_func)
+            tree->value_destroy_func (node->data->value);
+        }
 
-  g_slice_free (GTreeNode, node);
+      g_slice_free (GTreeNodeData, node->data);
+      g_slice_free1 (sizeof(GTreeNodeVersion) *
+                     (node->version(NOW) == 0 ? 1 : MAX_IN_DEGREE + 1),
+                     node->v);
+      g_slice_free (GTreeNode, node);
+    }
 
   tree->nnodes--;
 
@@ -1434,10 +1454,9 @@ g_tree_node_rotate_left (GTree     *tree,
 {
   GTreeNode *right;
 
-  right = node->right(NOW);
+  g_assert (node->version(NOW) == tree->version);
 
-  node = g_tree_node_next_version (tree, node);
-  right = g_tree_node_next_version (tree, right);
+  right = g_tree_node_next_version (tree, node->right(NOW));
 
   if (right->left_child(NOW))
     {
@@ -1463,10 +1482,9 @@ g_tree_node_rotate_right (GTree     *tree,
 {
   GTreeNode *left;
 
-  left = node->left(NOW);
+  g_assert (node->version(NOW) == tree->version);
 
-  node = g_tree_node_next_version (tree, node);
-  left = g_tree_node_next_version (tree, left);
+  left = g_tree_node_next_version (tree, node->left(NOW));
 
   if (left->right_child(NOW))
     {