/**
 * del_search:
 * search for the first node that matches the value val.
 * It is assumed that this function will be called with a lock on root held
 * If del_search() finds the required node it grabs the lock on the node and 
 * returns.
 * If it doesn't find the node it releases all the locks and returns
 */
FG_BST_Node* del_search(int val, FG_BST_Node* root, int thread_num)
{
	if(val == root->value) {
		/*
		 * We will come in here if we want to delete the root node.
		 * No need to lock the root because it is already locked by
		 * the caller.
		 */
		return root; 
	} else if (val < root->value) {
		if (root->left == NULL) {
			pthread_mutex_unlock(&root->lock);
			return NULL;
		} else {
			pthread_mutex_lock(&root->left->lock);
			if (val == root->left->value) {
				return root->left;
			} else {
				pthread_mutex_unlock(&root->lock);
				return del_search(val, root->left, thread_num);
			}
		}
	} else {
		if (root->right == NULL) {
			/*
			 * Could not find the node, unlock current root and return
			 */
			pthread_mutex_unlock(&root->lock);
			return NULL;
		} else {
			pthread_mutex_lock(&root->right->lock);
			if (val == root->right->value) {
				return root->right;
			} else {
				pthread_mutex_unlock(&root->lock);
				return del_search(val, root->right, thread_num);
			}
		}
	}

	return NULL;
}	
Exemple #2
0
void delete_tree(tree** t, const void* key,
                 int (*compare_keys)(const void* key1, const void* key2)) {
    /* key with key to delete */
    tree** d = del_search(t, key, compare_keys);
    if(d == NULL) /*not found*/
        return;

    tree* p = NULL; /*key to be physically deleted */

    if((*d)->parent == NULL)  /*d is the root */
        p = delete_root(d); /*fiiled if root has at least 1 child*/

    else {  /* not root */
        if(((*d)->left == NULL) || ((*d)->right == NULL))  /*0 or 1 children*/
            repoint_child(d);
        else  /*2 children*/
            p = (tree*)successor_descendant(*d);
    }

    /*move child up to replace parent and delete child*/
    if(p != NULL)
        update_node(d, p, compare_keys);
}
int remove(int val, FG_BST_Node *root, int thread_num)
{
	FG_BST_Node *to_be_deleted, *parent, *successor_parent, *successor;
	FG_BST_Node *predecessor, *predecessor_parent;

	pthread_mutex_lock(&tree_lock);
	if (g_root == NULL) {
		pthread_mutex_unlock(&tree_lock);
		return -EINVAL;
	}

	root = g_root;
	pthread_mutex_lock(&root->lock);
	/*
	 * Check if we are deleting the root and that the root is the only node 
	 * in the tree
	 */
	if (val == root->value && root->left == NULL && root->right == NULL) {
		/*
		 * free the root node,
		 * set the tree's global root as NULL,
		 * unlock the treelock and return
		 */
		free(root);
		g_root = NULL;
		pthread_mutex_unlock(&tree_lock);
		return 0;
	}

	to_be_deleted = del_search(val, root, thread_num);
	if (to_be_deleted == NULL) {
		/*
		 * if del_search() returns NULL we can be sure that it is not
		 * holding any locks. So we can just return from here.
		 */
		printf("Could not find the item (%d) to be deleted\n", val);
		pthread_mutex_unlock(&tree_lock);
		return 0;
	}

	/*
	 * If we found the node to be deleted we can be sure that we have a lock
	 * on the node to be deleted and its parent (if parent exists)
	 */

	// store the parent
	parent = to_be_deleted->parent;

	/*
	 * Because we use the data swapping mechanism we need the lock on parent only 
	 * if the node to be deleted is a leaf node. Because that is the only case 
	 * where we need to update to_be_deleted's parent's pointer to NULL
	 */
	if (to_be_deleted->left == NULL && to_be_deleted->right == NULL &&
	    parent == NULL) {
		free(to_be_deleted);
		g_root = NULL;
		pthread_mutex_unlock(&tree_lock);
		return 0;
	}

	pthread_mutex_unlock(&tree_lock);
	// Leaf node to be deleted
	if (to_be_deleted->left == NULL && to_be_deleted->right == NULL) {
		if (to_be_deleted->value < parent->value) {
			// node to be deleted is the left child of its parent
			/*
			 * Unlock to_be_deleted. We can safely unlock here because we hold 
			 * a lock on the parent and nobody else can come and modify to_be_deleted
			 */
			// free the node
			free(to_be_deleted);
			// set parent's left child as NULL
			parent->left = NULL;
			// unlock the parent and return
			pthread_mutex_unlock(&parent->lock);
			return 0;
		} else {
			// node to be deleted is the right child of its parent
			// Follow the same procedure as above
			free(to_be_deleted);
			parent->right = NULL;
			pthread_mutex_unlock(&parent->lock);
			return 0;
		}
	}

	/*
	 * At this point, we are either deleting the root or an internal node.
	 * If deleting an internal node, then unlock the parent.
	 */
	if (parent != NULL) {
		pthread_mutex_unlock(&parent->lock);
	}

	/*
	 * Find inorder successor or inorder predecessor (whichever exists) for the 
	 * node to be deleted
	 */
	if (to_be_deleted->right != NULL) {
		// perform pre-emptive check
		pthread_mutex_lock(&to_be_deleted->right->lock);
		if (to_be_deleted->right->left == NULL) {
			/*
			 * The right node is the successor,
			 * copy the value,
			 * lock successor's right --- we had not discussed this. But this is needed
			 * update pointers,
			 * unlock successor's right,
			 * unlock successor,
			 * free successor,
			 * unlock to_be_deleted and return.
			 */
			successor = to_be_deleted->right;

			if (successor->right != NULL) {
				pthread_mutex_lock(&successor->right->lock);
				to_be_deleted->value = successor->value;
				to_be_deleted->right = successor->right;
				successor->right->parent = to_be_deleted;
				pthread_mutex_unlock(&successor->right->lock);
			} else {
				to_be_deleted->value = successor->value;
				to_be_deleted->right = NULL;
			}
			//pthread_mutex_unlock(&successor->lock);
			free(successor);
			pthread_mutex_unlock(&to_be_deleted->lock);
			return 0;
		}

		/*
		 * Else,
		 * Find the successor,
		 * copy the value,
		 * update successor's parent AND successor->right,
		 * unlock successor,
		 * free successor,
		 * unlock successor's parent,
		 * unlock to_be_deleted and return
		 */

		successor = get_inorder_successor(to_be_deleted);
		successor_parent = successor->parent;

		if (successor->right != NULL) {
			pthread_mutex_lock(&successor->right->lock);
			// the successor will always be the left child of it's parent
			successor_parent->left = successor->right;
			successor->right->parent = successor_parent;
			to_be_deleted->value = successor->value;
			pthread_mutex_unlock(&successor->right->lock);
		} else {
			to_be_deleted->value = successor->value;
			successor_parent->left = NULL;
		}

		free(successor);
		pthread_mutex_unlock(&successor_parent->lock);
		pthread_mutex_unlock(&to_be_deleted->lock);
		return 0;
	}

	/*
	 * The node to be deleted doesn't have a successor. We need to find 
	 * its predecessor.
	 * Very similar logic to finding successor.
	 */

	if (to_be_deleted->left != NULL) {
		pthread_mutex_lock(&to_be_deleted->left->lock);
		// perform pre-emptive check
		if (to_be_deleted->left->right == NULL) {
			/*
			 * The left node is the predecessor.
			 * copy the value,
			 * lock predecessor's left ---- We had discussed this but it is needed
			 * update pointers,
			 * unlock predecessor,
			 * free predecessor,
			 * unlock to_be_deleted and return.
			 */
			predecessor = to_be_deleted->left;

			if (predecessor->left != NULL) {
				pthread_mutex_lock(&predecessor->left->lock);
				to_be_deleted->value = predecessor->value;
				to_be_deleted->left = predecessor->left;
				predecessor->left->parent = to_be_deleted;
				pthread_mutex_unlock(&predecessor->left->lock);
			} else {
				to_be_deleted->value = predecessor->value;
				to_be_deleted->left = NULL;
			}

			free(predecessor);
			pthread_mutex_unlock(&to_be_deleted->lock);
			return 0;
		}

		/*
		 * Else,
		 * Find the predecessor,
		 * Copy the value,
		 * Update predecessor's parent AND predecessor->left,
		 * unlock predecessor,
		 * free predecessor,
		 * unlock predecessor's parent,
		 * unlock to_be_deleted and return.
		 */

		predecessor = get_inorder_predecessor(to_be_deleted);
		predecessor_parent = predecessor->parent;

		if (predecessor->left != NULL) {
			pthread_mutex_lock(&predecessor->left->lock);
			// predecessor will always be the right child of its parent
			predecessor_parent->right = predecessor->left;
			predecessor->left->parent = predecessor_parent;
			to_be_deleted->value = predecessor->value;
			pthread_mutex_unlock(&predecessor->left->lock);
		} else {
			to_be_deleted->value = predecessor->value;
			predecessor_parent->right = NULL;
		}
		free(predecessor);
		pthread_mutex_unlock(&predecessor_parent->lock);
		pthread_mutex_unlock(&to_be_deleted->lock);
		return 0;
	}

	return -1;
}