/** * flush the backend * * @remark this function is called during ham_flush @note This is a B+-tree 'backend' method. */ static ham_status_t my_fun_flush(ham_btree_t *be) { ham_db_t *db=be_get_db(be); db_indexdata_t *indexdata=env_get_indexdata_ptr(db_get_env(db), db_get_indexdata_offset(db)); /* * nothing to do if the backend was not touched */ if (!be_is_dirty(be)) return (0); index_set_max_keys(indexdata, btree_get_maxkeys(be)); index_set_keysize(indexdata, be_get_keysize(be)); index_set_self(indexdata, btree_get_rootpage(be)); index_set_flags(indexdata, be_get_flags(be)); index_set_recno(indexdata, be_get_recno(be)); index_clear_reserved(indexdata); env_set_dirty(db_get_env(db)); be_set_dirty(be, HAM_FALSE); return (0); }
static ham_status_t __insert_cursor(ham_btree_t *be, ham_key_t *key, ham_record_t *record, ham_bt_cursor_t *cursor, insert_hints_t *hints) { ham_status_t st; ham_page_t *root; ham_db_t *db=be_get_db(be); ham_env_t *env = db_get_env(db); insert_scratchpad_t scratchpad; ham_assert(hints->force_append == HAM_FALSE, (0)); ham_assert(hints->force_prepend == HAM_FALSE, (0)); /* * initialize the scratchpad */ memset(&scratchpad, 0, sizeof(scratchpad)); scratchpad.be=be; scratchpad.record=record; scratchpad.cursor=cursor; /* * get the root-page... */ ham_assert(btree_get_rootpage(be)!=0, ("btree has no root page")); st=db_fetch_page(&root, db, btree_get_rootpage(be), 0); ham_assert(st ? root == NULL : 1, (0)); if (st) return st; /* * ... and start the recursion */ st=__insert_recursive(root, key, 0, &scratchpad, hints); /* * if the root page was split, we have to create a new * root page. */ if (st==SPLIT) { ham_page_t *newroot; btree_node_t *node; /* * the root-page will be changed... */ st=ham_log_add_page_before(root); if (st) return (st); /* * allocate a new root page */ st=db_alloc_page(&newroot, db, PAGE_TYPE_B_ROOT, 0); ham_assert(st ? newroot == NULL : 1, (0)); if (st) return (st); ham_assert(page_get_owner(newroot), ("")); /* clear the node header */ memset(page_get_payload(newroot), 0, sizeof(btree_node_t)); stats_page_is_nuked(db, root, HAM_TRUE); /* * insert the pivot element and the ptr_left */ node=ham_page_get_btree_node(newroot); btree_node_set_ptr_left(node, btree_get_rootpage(be)); st=__insert_nosplit(newroot, &scratchpad.key, scratchpad.rid, scratchpad.record, scratchpad.cursor, hints); ham_assert(!(scratchpad.key.flags & HAM_KEY_USER_ALLOC), (0)); scratchpad.cursor=0; /* don't overwrite cursor if __insert_nosplit is called again */ if (st) { ham_assert(!(scratchpad.key.flags & HAM_KEY_USER_ALLOC), (0)); if (scratchpad.key.data) allocator_free(env_get_allocator(env), scratchpad.key.data); return (st); } /* * set the new root page * * !! * do NOT delete the old root page - it's still in use! * * also don't forget to flush the backend - otherwise the header * page of the database will not contain the updated information. * The backend is flushed when the database is closed, but if * recovery is enabled then the flush here is critical. */ btree_set_rootpage(be, page_get_self(newroot)); be_set_dirty(be, HAM_TRUE); be->_fun_flush(be); /* * As we re-purpose a page, we will reset its pagecounter * as well to signal its first use as the new type assigned * here. */ if (env_get_cache(env) && (page_get_type(root)!=PAGE_TYPE_B_INDEX)) cache_update_page_access_counter(root, env_get_cache(env), 0); page_set_type(root, PAGE_TYPE_B_INDEX); page_set_dirty(root, env); page_set_dirty(newroot, env); /* the root page was modified (btree_set_rootpage) - make sure that * it's logged */ if (env_get_rt_flags(env)&HAM_ENABLE_RECOVERY) { st=txn_add_page(env_get_txn(env), env_get_header_page(env), HAM_TRUE); if (st) return (st); } } /* * release the scratchpad-memory and return to caller */ ham_assert(!(scratchpad.key.flags & HAM_KEY_USER_ALLOC), (0)); if (scratchpad.key.data) allocator_free(env_get_allocator(env), scratchpad.key.data); return (st); }
/** * create and initialize a new backend * * @remark this function is called after the @a ham_db_t structure * and the file were created * * the @a flags are stored in the database; only transfer * the persistent flags! * * @note This is a B+-tree 'backend' method. */ static ham_status_t my_fun_create(ham_btree_t *be, ham_u16_t keysize, ham_u32_t flags) { ham_status_t st; ham_page_t *root; ham_size_t maxkeys; ham_db_t *db=be_get_db(be); db_indexdata_t *indexdata=env_get_indexdata_ptr(db_get_env(db), db_get_indexdata_offset(db)); if (be_is_active(be)) { ham_trace(("backend has alread been initialized before!")); /* HAM_INTERNAL_ERROR -- not really, when keeping custom * backends in mind */ return HAM_ALREADY_INITIALIZED; } /* * prevent overflow - maxkeys only has 16 bit! */ maxkeys=btree_calc_maxkeys(env_get_pagesize(db_get_env(db)), keysize); if (maxkeys>MAX_KEYS_PER_NODE) { ham_trace(("keysize/pagesize ratio too high")); return HAM_INV_KEYSIZE; } else if (maxkeys==0) { ham_trace(("keysize too large for the current pagesize")); return HAM_INV_KEYSIZE; } /* * allocate a new root page */ st=db_alloc_page(&root, db, PAGE_TYPE_B_ROOT, PAGE_IGNORE_FREELIST); ham_assert(st ? root == NULL : 1, (0)); ham_assert(!st ? root != NULL : 1, (0)); if (!root) return st ? st : HAM_INTERNAL_ERROR; memset(page_get_raw_payload(root), 0, sizeof(btree_node_t)+sizeof(ham_perm_page_union_t)); /* * calculate the maximum number of keys for this page, * and make sure that this number is even */ btree_set_maxkeys(be, (ham_u16_t)maxkeys); be_set_dirty(be, HAM_TRUE); be_set_keysize(be, keysize); be_set_flags(be, flags); btree_set_rootpage(be, page_get_self(root)); index_clear_reserved(indexdata); index_set_max_keys(indexdata, (ham_u16_t)maxkeys); index_set_keysize(indexdata, keysize); index_set_self(indexdata, page_get_self(root)); index_set_flags(indexdata, flags); index_set_recno(indexdata, 0); index_clear_reserved(indexdata); env_set_dirty(db_get_env(db)); be_set_active(be, HAM_TRUE); return (0); }