📄 btree_insert.c
字号:
/** * Copyright (C) 2005-2007 Christoph Rupp (chris@crupp.de). * All rights reserved. See file LICENSE for licence and copyright * information. * * btree inserting * */#include <string.h>#include "db.h"#include "error.h"#include "keys.h"#include "page.h"#include "btree.h"#include "blob.h"#include "mem.h"#include "util.h"#include "btree_cursor.h"/* * the insert_scratchpad_t structure helps us to propagate return values * from the bottom of the tree to the root. */typedef struct{ /* * the backend pointer */ ham_btree_t *be; /* * the flags of the ham_insert()-call */ ham_u32_t flags; /* * the record which is inserted */ ham_record_t *record; /* * a key; this is used to propagate SMOs (structure modification * operations) from a child page to a parent page */ ham_key_t key; /* * a RID; this is used to propagate SMOs (structure modification * operations) from a child page to a parent page */ ham_offset_t rid; /* * a pointer to a cursor; if this is a valid pointer, then this * cursor will point to the new inserted item */ ham_bt_cursor_t *cursor;} insert_scratchpad_t;/* * return values */#define SPLIT 1/* * flags for my_insert_nosplit() */#define NOFLUSH 0x1000 /* avoid conflicts with public flags */#define OVERWRITE HAM_OVERWRITE/* * this is the function which does most of the work - traversing to a * leaf, inserting the key using my_insert_in_page() * and performing necessary SMOs. it works recursive. */static ham_status_tmy_insert_recursive(ham_page_t *page, ham_key_t *key, ham_offset_t rid, insert_scratchpad_t *scratchpad);/* * this function inserts a key in a page */static ham_status_tmy_insert_in_page(ham_page_t *page, ham_key_t *key, ham_offset_t rid, ham_u32_t flags, insert_scratchpad_t *scratchpad);/* * insert a key in a page; the page MUST have free slots */static ham_status_tmy_insert_nosplit(ham_page_t *page, ham_key_t *key, ham_offset_t rid, ham_record_t *record, ham_bt_cursor_t *cursor, ham_u32_t flags);/* * split a page and insert the new element */static ham_status_tmy_insert_split(ham_page_t *page, ham_key_t *key, ham_offset_t rid, ham_u32_t flags, insert_scratchpad_t *scratchpad);ham_status_tbtree_insert_cursor(ham_btree_t *be, ham_key_t *key, ham_record_t *record, ham_bt_cursor_t *cursor, ham_u32_t flags){ ham_status_t st; ham_page_t *root; ham_db_t *db=btree_get_db(be); insert_scratchpad_t scratchpad; /* * initialize the scratchpad */ memset(&scratchpad, 0, sizeof(scratchpad)); scratchpad.be=be; scratchpad.flags=flags; scratchpad.record=record; scratchpad.cursor=cursor; /* * get the root-page... */ ham_assert(btree_get_rootpage(be)!=0, ("btree has no root page")); root=db_fetch_page(db, btree_get_rootpage(be), 0); /* * ... and start the recursion */ st=my_insert_recursive(root, key, 0, &scratchpad); /* * 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; /* * allocate a new root page */ newroot=db_alloc_page(db, PAGE_TYPE_B_ROOT, 0); if (!newroot) return (db_get_error(db)); /* clear the node header */ memset(page_get_payload(newroot), 0, sizeof(btree_node_t)); /* * 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=my_insert_nosplit(newroot, &scratchpad.key, scratchpad.rid, scratchpad.record, scratchpad.cursor, flags|NOFLUSH); scratchpad.cursor=0; /* don't overwrite cursor if my_insert_nosplit is called again */ if (st) { if (scratchpad.key.data) ham_mem_free(db, scratchpad.key.data); return (st); } /* * set the new root page * * !! * do NOT delete the old root page - it's still in use! */ btree_set_rootpage(be, page_get_self(newroot)); btree_set_dirty(be, HAM_TRUE); db_set_dirty(db, 1); page_set_type(root, PAGE_TYPE_B_INDEX); } /* * release the scratchpad-memory and return to caller */ if (scratchpad.key.data) ham_mem_free(db, scratchpad.key.data); return (st);}ham_status_tbtree_insert(ham_btree_t *be, ham_key_t *key, ham_record_t *record, ham_u32_t flags){ return (btree_insert_cursor(be, key, record, 0, flags));}static ham_status_tmy_insert_recursive(ham_page_t *page, ham_key_t *key, ham_offset_t rid, insert_scratchpad_t *scratchpad){ ham_status_t st; ham_page_t *child; ham_db_t *db=page_get_owner(page); btree_node_t *node=ham_page_get_btree_node(page); /* * if we've reached a leaf: insert the key */ if (btree_node_is_leaf(node)) return (my_insert_in_page(page, key, rid, scratchpad->flags, scratchpad)); /* * otherwise traverse the root down to the leaf */ child=btree_traverse_tree(db, page, key, 0); if (!child) return (db_get_error(db)); /* * and call this function recursively */ st=my_insert_recursive(child, key, rid, scratchpad); switch (st) { /* * if we're done, we're done */ case HAM_SUCCESS: break; /* * if we tried to insert a duplicate key, we're done, too */ case HAM_DUPLICATE_KEY: break; /* * the child was split, and we have to insert a new (key/rid)-tuple. */ case SPLIT: st=my_insert_in_page(page, &scratchpad->key, scratchpad->rid, scratchpad->flags|HAM_OVERWRITE, scratchpad); break; /* * every other return value is unexpected and shouldn't happen */ default: db_set_error(db, st); break; } return (st);}static ham_status_tmy_insert_in_page(ham_page_t *page, ham_key_t *key, ham_offset_t rid, ham_u32_t flags, insert_scratchpad_t *scratchpad){ ham_size_t maxkeys=btree_get_maxkeys(scratchpad->be); btree_node_t *node=ham_page_get_btree_node(page); ham_assert(maxkeys>1, ("invalid result of db_get_maxkeys(): %d", maxkeys)); /* * if we can insert the new key without splitting the page: * my_insert_nosplit() will do the work for us */ if (btree_node_get_count(node)<maxkeys) { ham_status_t st=my_insert_nosplit(page, key, rid, scratchpad->record, scratchpad->cursor, flags); scratchpad->cursor=0; /* don't overwrite cursor if my_insert_nosplit is called again */ return (st); } /* * otherwise, we have to split the page. * but BEFORE we split, we check if the key already exists! */ if (btree_node_is_leaf(node)) { if (btree_node_search_by_key(page_get_owner(page), page, key)>=0) { if (flags&HAM_OVERWRITE) { ham_status_t st=my_insert_nosplit(page, key, rid, scratchpad->record, scratchpad->cursor, flags); /* don't overwrite cursor if my_insert_nosplit is called again */ scratchpad->cursor=0; return (st); } else return (HAM_DUPLICATE_KEY); } } return (my_insert_split(page, key, rid, flags, scratchpad));}static ham_status_tmy_insert_nosplit(ham_page_t *page, ham_key_t *key, ham_offset_t rid, ham_record_t *record, ham_bt_cursor_t *cursor, ham_u32_t flags){ int cmp; ham_status_t st; ham_bool_t overwrite=HAM_FALSE; ham_size_t i, count, keysize; int_key_t *bte=0; btree_node_t *node; ham_db_t *db=page_get_owner(page); ham_s32_t slot; ham_u32_t oldflags; node=ham_page_get_btree_node(page); count=btree_node_get_count(node); keysize=db_get_keysize(db); /* * uncouple all cursors */ st=db_uncouple_all_cursors(page); if (st) return (db_set_error(db, st)); if (btree_node_get_count(node)==0) slot=0; else { st=btree_get_slot(db, page, key, &slot); if (st) return (db_set_error(db, st)); /* insert the new key at the beginning? */ if (slot==-1) { slot++; bte=btree_node_get_key(db, node, slot); goto shift_elements; } cmp=key_compare_int_to_pub(page, (ham_u16_t)slot, key); if (db_get_error(db)) return (db_get_error(db)); bte=btree_node_get_key(db, node, slot); /* * key exists already */ if (cmp==0) { if (flags&HAM_OVERWRITE) { /* * no need to overwrite the key - it already exists! * however, we have to overwrite the data! */ if (btree_node_is_leaf(node)) overwrite=HAM_TRUE; else return (HAM_SUCCESS); } else return (HAM_DUPLICATE_KEY); } /* * otherwise, if the new key is < then the slot key, move to * the next slot */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -