/** * btree_insert_non_full * @access private * @param btree struct * @param btree node * @param key * @param data index * @return void * * inserts the node into the btree - either immediately if it's a leaf or find the branch, split * the child and call this recursively until a leaf is found */ static void btree_insert_non_full(btree_tree *t, btree_node *node, uint64_t key, uint32_t data_idx) { uint32_t i; btree_node *tmp_node; i = node->nr_of_keys; if (node->leaf) { while (i > 0 && key < node->keys[i - 1].key) { node->keys[i] = node->keys[i - 1]; i--; } node->keys[i].key = key; node->nr_of_keys++; /* Fetch data index, and set it to the idx element here too */ node->keys[i].idx = data_idx; /* Do administrative jobs */ dr_set_add(&(t->freelist), data_idx); t->header->item_count++; } else { tmp_node = btree_find_branch(t, node, key, &i); if (tmp_node->nr_of_keys == BTREE_T2(t) - 1) { btree_split_child(t, node, i, tmp_node); if (key > node->keys[i].key) { i++; } } btree_insert_non_full(t, btree_get_node(t, node->branch[i]), key, data_idx); } }
/** * btree_dump_node_dot * @access private * @param btree struct * @param btree node * @return void * * Outputs (using printf or php_printf) a physical representation * of the tree and it's data in a table format */ static void btree_dump_node_dot(btree_tree *t, btree_node *node) { int i; BTREE_PRINT("\n\"IDX%d\" [\nlabel=\"{{", node->idx); for (i = 0; i < node->nr_of_keys; i++) { BTREE_PRINT("%s%lu", i ? " | " : "", node->keys[i].key); } BTREE_PRINT("} "); if (!node->leaf) { BTREE_PRINT("| {"); for (i = 0; i < node->nr_of_keys + 1; i++) { BTREE_PRINT("%s<n%d>%d", i ? " | " : "", i, node->branch[i]); } BTREE_PRINT("}}\"\n];\n"); for (i = 0; i < node->nr_of_keys + 1; i++) { BTREE_PRINT("\"IDX%d\":n%d->\"IDX%d\";\n", node->idx, i, node->branch[i]); } for (i = 0; i < node->nr_of_keys + 1; i++) { btree_dump_node_dot(t, btree_get_node(t, node->branch[i])); } } else { BTREE_PRINT("}\"\n];\n"); } }
/** * btree_open * @access public * @param path to the file to use for mmap, must be absolute * @param error code for error handling on other side * @return struct with open btree * * This will attempt to open an existing btree * Must be unmapped and freed using btree_close after use */ BTREE_API btree_tree *btree_open(const char *path, int *error) { btree_tree *t; *error = 0; t = malloc(sizeof(btree_tree)); if (t == NULL) { *error = errno; return NULL; } *error = btree_open_file(t, path); if (*error != 0) { free(t); return NULL; } t->freelist.size = t->header->max_items; t->freelist.setinfo = t->mmap + BTREE_HEADER_SIZE; t->nodes = t->mmap + BTREE_HEADER_SIZE + BTREE_FREELIST_SIZE(t->header->max_items); t->data = t->mmap + BTREE_HEADER_SIZE + BTREE_FREELIST_SIZE(t->header->max_items) + (t->header->node_count * 4096); t->root = btree_get_node(t, t->header->root_node_idx); return t; }
/** * btree_find_branch * @access private * @param btree struct * @param btree node * @param key * @param i * @return void * * finds the branch for the node and calls btree_get_node */ static btree_node* btree_find_branch(btree_tree *t, btree_node *node, uint64_t key, uint32_t *i) { *i = node->nr_of_keys; while (*i > 0 && key < node->keys[(*i) - 1].key) { (*i)--; } return btree_get_node(t, node->branch[*i]); }
/** * btree_find_greatest * @access private * @param btree struct * @param btree node * @return btree node * * find greatest node in a branch */ static btree_node *btree_find_greatest(btree_tree *t, btree_node *node) { btree_node *ptr = node; while (!ptr->leaf) { ptr = btree_get_node(t, ptr->branch[ptr->nr_of_keys]); } return ptr; }
/** * btree_find_smallest * @access private * @param btree struct * @param btree node * @return btree node * * find smallest node in a branch */ static btree_node *btree_find_smallest(btree_tree *t, btree_node *node) { btree_node *ptr = node; while (!ptr->leaf) { ptr = btree_get_node(t, ptr->branch[0]); } return ptr; }
// Get a specific node from a tree btree_node *btree_get_node(btree *tree, int num){ btree_node *root; root = tree->root; if(root->num == num){ return root; } else { if(root->num < num){ if(root->right != NULL) { return btree_get_node((btree_node *)root->right, num); } else { return (btree_node*) NULL; } } else { if(root->left != NULL) { return btree_get_node(root->left, num); } else { return (btree_node*) NULL; } } } }
/** * btree_dump_node * @access private * @param btree struct * @return void * * Recursive helper for printing out the contents of a node, * used by btree_dump */ static void btree_dump_node(btree_tree *t, btree_node *node) { int i; BTREE_PRINT("\nIDX: %d\n", node->idx); for (i = 0; i < node->nr_of_keys; i++) { BTREE_PRINT("%9lu ", node->keys[i].key); } if (!node->leaf) { BTREE_PRINT("\n"); for (i = 0; i < node->nr_of_keys + 1; i++) { BTREE_PRINT("%9d ", node->branch[i]); } for (i = 0; i < node->nr_of_keys + 1; i++) { btree_dump_node(t, btree_get_node(t, node->branch[i])); } } }
/** * btree_dump_node_test * @access private * @param btree struct * @param btree node * @param level to output * @return void * * Recursive helper for printing out the contents of a node, * used by btree_dump_test - provides more information than the normal dump */ static void btree_dump_node_test(btree_tree *t, btree_node *node, int level) { int i; BTREE_PRINT("\n%*sIDX: %d: ", level * 2, "", node->idx); if (!node->leaf) { BTREE_PRINT("(%d) ", node->branch[0]); } for (i = 0; i < node->nr_of_keys; i++) { BTREE_PRINT("%lu ", node->keys[i].key); if (!node->leaf) { BTREE_PRINT("(%d) ", node->branch[i+1]); } } if (!node->leaf) { for (i = 0; i < node->nr_of_keys + 1; i++) { btree_dump_node_test(t, btree_get_node(t, node->branch[i]), level + 1); } } }
/** * btree_search_internal * @access private * @param btree struct * @param btree node * @param key * @param index to fill * @return 1 if found, 0 if not * * does the actual search of the tree to find an index location * can be called recursively as the nodes are walked */ static int btree_search_internal(btree_tree *t, btree_node *node, uint64_t key, uint32_t *idx) { int i = 0; while (i < node->nr_of_keys && key > node->keys[i].key) { i++; } if (i < node->nr_of_keys && key == node->keys[i].key) { if (idx) { *idx = node->keys[i].idx; } return 1; } if (node->leaf) { return 0; } else { btree_node *tmp_node = btree_get_node(t, node->branch[i]); return btree_search_internal(t, tmp_node, key, idx); } }
/** * btree_delete_internal * @access private * @param btree struct * @param btree node * @param key that was requested for deletion * @param current key * @param data index * @return int 1 on success, 0 on failure * * Removes a node at key from the btree * Locks the entire tree until complete */ static int btree_delete_internal(btree_tree *t, btree_node *node, uint64_t key_to_delete, uint64_t key, uint32_t *data_idx_to_free) { uint32_t idx; uint32_t data_idx; /* if x is a leaf then * if k is in x then * delete k from x and return true * else return false //k is not in subtree */ if (node->leaf) { if (btree_check_key_in_node(node, key, &idx, &data_idx)) { btree_delete_key_idx_from_node(node, idx); btree_delete_branch_idx_from_node(node, idx); if (key == key_to_delete) { *data_idx_to_free = data_idx; } return 1; } else { return 0; } } else { /* if k is in x then */ if (btree_check_key_in_node(node, key, &idx, &data_idx)) { btree_node *y, *node_with_prev_key; /* Record the data_idx for this key */ if (key == key_to_delete) { *data_idx_to_free = data_idx; } /* y = the child of x that precedes k * if y has at least t keys then * k' = the predecessor of k (use B-Tree-FindLargest) * Copy k' over k //i.e., replace k with k' * B-Tree-Delete(y, k') //Note: recursive call */ y = btree_get_node(t, node->branch[idx]); if (y->nr_of_keys >= BTREE_T(t)) { node_with_prev_key = btree_find_greatest(t, y); node->keys[idx] = node_with_prev_key->keys[y->nr_of_keys-1]; return btree_delete_internal(t, y, key_to_delete, node_with_prev_key->keys[y->nr_of_keys-1].key, data_idx_to_free); } else { btree_node *z, *node_with_next_key; /* else //y has t-1 keys * z = the child of x that follows k * if z has at least t keys then * k' = the successor of k * Copy k' over k //i.e., replace k with k' * B-Tree-Delete(z, k') //Note: recursive call */ z = btree_get_node(t, node->branch[idx + 1]); if (z->nr_of_keys >= BTREE_T(t)) { node_with_next_key = btree_find_smallest(t, z); node->keys[idx] = node_with_next_key->keys[0]; btree_delete_internal(t, z, key_to_delete, node_with_next_key->keys[0].key, data_idx_to_free); } else { /* else //both y and z have t-1 keys * merge k and all of z into y //y now contains 2t-1 keys. * //k and the pointer to z will be deleted from x. * B-Tree-Delete(y, k) //Note: recursive call */ btree_merge(t, y, node, idx, z); btree_delete_key_idx_from_node(node, idx); btree_delete_branch_idx_from_node(node, idx + 1); btree_delete_internal(t, y, key_to_delete, key, data_idx_to_free); if (t->root->nr_of_keys == 0 && !t->root->leaf) { t->root = btree_get_node(t, t->root->branch[0]); } } } } else { btree_node *c; uint32_t i; c = btree_find_branch(t, node, key, &i); if (c->nr_of_keys <= BTREE_T(t) - 1) { btree_node *z, *node_with_prev_key, *node_with_next_key; btree_key tmp_key; /* Is there a left sibling with T or more keys? */ if (i > 0) { /* otherwise there is no left sibling */ z = btree_get_node(t, node->branch[i - 1]); if (z->nr_of_keys > BTREE_T(t) - 1) { node_with_prev_key = btree_find_greatest(t, z); btree_node_insert_key(t, c, 0, node_with_prev_key->keys[z->nr_of_keys-1]); btree_delete_internal(t, z, key_to_delete, node_with_prev_key->keys[z->nr_of_keys-1].key, data_idx_to_free); /* Swap parent and first key in C */ tmp_key = node->keys[i-1]; node->keys[i-1] = c->keys[0]; c->keys[0] = tmp_key; goto proceed; } } /* Is there a left sibling with T or more keys? */ if (i < node->nr_of_keys) { /* otherwise there is no right sibling */ z = btree_get_node(t, node->branch[i + 1]); if (z->nr_of_keys > BTREE_T(t) - 1) { node_with_next_key = btree_find_smallest(t, z); btree_node_insert_key(t, c, c->nr_of_keys, node_with_next_key->keys[0]); btree_delete_internal(t, z, key_to_delete, node_with_next_key->keys[0].key, data_idx_to_free); /* Swap parent and last key in C */ tmp_key = node->keys[i]; node->keys[i] = c->keys[c->nr_of_keys - 1]; c->keys[c->nr_of_keys - 1] = tmp_key; goto proceed; } } /* No siblings, so we need to merge. */ /* Is there a left sibling? */ if (i > 0) { /* otherwise there is no left sibling */ z = btree_get_node(t, node->branch[i - 1]); btree_merge(t, z, node, i - 1, c); btree_delete_branch_idx_from_node(node, i); btree_delete_key_idx_from_node(node, i - 1); if (t->root->nr_of_keys == 0 && !t->root->leaf) { t->root = btree_get_node(t, t->root->branch[0]); } return btree_delete_internal(t, z, key_to_delete, key, data_idx_to_free); } /* Is there a right sibling? */ if (i < node->nr_of_keys) { /* otherwise there is no right sibling */ z = btree_get_node(t, node->branch[i + 1]); btree_merge(t, c, node, i, z); btree_delete_branch_idx_from_node(node, i + 1); btree_delete_key_idx_from_node(node, i); if (t->root->nr_of_keys == 0 && !t->root->leaf) { t->root = btree_get_node(t, t->root->branch[0]); } return btree_delete_internal(t, c, key_to_delete, key, data_idx_to_free); } } proceed: return btree_delete_internal(t, c, key_to_delete, key, data_idx_to_free); } } return 0; }