extern "C" void fc_solve_dbm_store_offload_pre_cache( fcs_dbm_store_t store, fcs_pre_cache_t * pre_cache ) { leveldb::DB * db; #ifdef FCS_DBM_USE_LIBAVL struct avl_traverser trav; dict_key_t item; #else dnode_t * node; #endif dict_t * kaz_tree; int num_left_in_transaction = MAX_ITEMS_IN_TRANSACTION; leveldb::WriteBatch batch; fcs_pre_cache_key_val_pair_t * kv; db = (leveldb::DB *)store; kaz_tree = pre_cache->kaz_tree; #ifdef FCS_DBM_USE_LIBAVL avl_t_init(&trav, kaz_tree); #endif #ifdef FCS_DBM_USE_LIBAVL for ( item = avl_t_first(&trav, kaz_tree) ; item ; item = avl_t_next(&trav) ) #else for (node = fc_solve_kaz_tree_first(kaz_tree); node ; node = fc_solve_kaz_tree_next(kaz_tree, node) ) #define item (node->dict_key) #endif { kv = (fcs_pre_cache_key_val_pair_t *)(item); leveldb::Slice key((const char *)(kv->key.s+1),kv->key.s[0]); /* We add 1 to the parent and move's length because it includes the * trailing one-char move. * */ leveldb::Slice parent_and_move((const char *)(kv->parent_and_move.s+1),kv->parent_and_move.s[0]+1); batch.Put(key, parent_and_move); if ((--num_left_in_transaction) <= 0) { #define WRITE() assert(db->Write(leveldb::WriteOptions(), &batch).ok()) WRITE(); batch.Clear(); num_left_in_transaction = MAX_ITEMS_IN_TRANSACTION; } } WRITE(); #undef WRITE }
extern void fc_solve_dbm_store_offload_pre_cache( fcs_dbm_store store, fcs_pre_cache *const pre_cache) { fcs_dbm *const db = (fcs_dbm *)store; dict_t *const kaz_tree = pre_cache->kaz_tree; DB *const dbp = db->dbp; for (dnode_t *node = fc_solve_kaz_tree_first(kaz_tree); node; node = fc_solve_kaz_tree_next(kaz_tree, node)) { const_AUTO(kv, (pre_cache_key_val_pair *)(node->dict_key)); db->key.data = kv->key.s + 1; db->key.size = kv->key.s[0]; db->data.data = kv->parent.s + 1; db->data.size = kv->parent.s[0]; int ret; if ((ret = dbp->put(dbp, NULL, &(db->key), &(db->data), 0)) != 0) { dbp->err(dbp, ret, "DB->put"); my_close(dbp, ret); } } }
dnode_t *fc_solve_kaz_tree_delete(dict_t *dict, dnode_t *target) { dnode_t *nil = dict_nil(dict), *child, *delparent = target->parent; /* basic deletion */ assert (!dict_isempty(dict)); assert (dict_contains(dict, target)); /* * If the node being deleted has two children, then we replace it with its * successor (i.e. the leftmost node in the right subtree.) By doing this, * we avoid the traditional algorithm under which the successor's key and * value *only* move to the deleted node and the successor is spliced out * from the tree. We cannot use this approach because the user may hold * pointers to the successor, or nodes may be inextricably tied to some * other structures by way of embedding, etc. So we must splice out the * node we are given, not some other node, and must not move contents from * one node to another behind the user's back. */ if (target->left != nil && target->right != nil) { dnode_t *next = fc_solve_kaz_tree_next(dict, target); dnode_t *nextparent = next->parent; dnode_color_t nextcolor = next->color; assert (next != nil); assert (next->parent != nil); assert (next->left == nil); /* * First, splice out the successor from the tree completely, by * moving up its right child into its place. */ child = next->right; child->parent = nextparent; if (nextparent->left == next) { nextparent->left = child; } else { assert (nextparent->right == next); nextparent->right = child; } /* * Now that the successor has been extricated from the tree, install it * in place of the node that we want deleted. */ next->parent = delparent; next->left = target->left; next->right = target->right; next->left->parent = next; next->right->parent = next; next->color = target->color; target->color = nextcolor; if (delparent->left == target) { delparent->left = next; } else { assert (delparent->right == target); delparent->right = next; } } else { assert (target != nil); assert (target->left == nil || target->right == nil); child = (target->left != nil) ? target->left : target->right; child->parent = delparent = target->parent; if (target == delparent->left) { delparent->left = child; } else { assert (target == delparent->right); delparent->right = child; } } target->parent = NULL; target->right = NULL; target->left = NULL; #ifdef NO_FC_SOLVE dict->nodecount--; #endif assert (verify_bintree(dict)); /* red-black adjustments */ if (target->color == dnode_black) { dnode_t *parent, *sister; dict_root(dict)->color = dnode_red; while (child->color == dnode_black) { parent = child->parent; if (child == parent->left) { sister = parent->right; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_left(parent); sister = parent->right; assert (sister != nil); } if (sister->left->color == dnode_black && sister->right->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->right->color == dnode_black) { assert (sister->left->color == dnode_red); sister->left->color = dnode_black; sister->color = dnode_red; rotate_right(sister); sister = parent->right; assert (sister != nil); } sister->color = parent->color; sister->right->color = dnode_black; parent->color = dnode_black; rotate_left(parent); break; } } else { /* symmetric case: child == child->parent->right */ assert (child == parent->right); sister = parent->left; assert (sister != nil); if (sister->color == dnode_red) { sister->color = dnode_black; parent->color = dnode_red; rotate_right(parent); sister = parent->left; assert (sister != nil); } if (sister->right->color == dnode_black && sister->left->color == dnode_black) { sister->color = dnode_red; child = parent; } else { if (sister->left->color == dnode_black) { assert (sister->right->color == dnode_red); sister->right->color = dnode_black; sister->color = dnode_red; rotate_left(sister); sister = parent->left; assert (sister != nil); } sister->color = parent->color; sister->left->color = dnode_black; parent->color = dnode_black; rotate_right(parent); break; } } } child->color = dnode_black; dict_root(dict)->color = dnode_black; } assert (dict_verify(dict)); return target; }