未验证 提交 02429ff7 编写于 作者: 羽飞's avatar 羽飞 提交者: GitHub

Merge pull request #31 from hnwyllmm/refactor/btree-1

再次重写B+树
...@@ -20,2439 +20,1925 @@ See the Mulan PSL v2 for more details. */ ...@@ -20,2439 +20,1925 @@ See the Mulan PSL v2 for more details. */
#define FIRST_INDEX_PAGE 1 #define FIRST_INDEX_PAGE 1
int float_compare(float f1, float f2) int calc_internal_page_capacity(int attr_length)
{
float result = f1 - f2;
if (-1e-6 < result && result < 1e-6) {
return 0;
}
return result > 0 ? 1 : -1;
}
int attribute_comp(const char *first, const char *second, AttrType attr_type, int attr_length)
{ // 简化
int i1, i2;
float f1, f2;
const char *s1, *s2;
switch (attr_type) {
case INTS: {
i1 = *(int *)first;
i2 = *(int *)second;
return i1 - i2;
} break;
case FLOATS: {
f1 = *(float *)first;
f2 = *(float *)second;
return float_compare(f1, f2);
} break;
case CHARS: {
s1 = first;
s2 = second;
return strncmp(s1, s2, attr_length);
} break;
default: {
LOG_PANIC("Unknown attr type: %d", attr_type);
}
}
return -2; // This means error happens
}
int key_compare(AttrType attr_type, int attr_length, const char *first, const char *second)
{
int result = attribute_comp(first, second, attr_type, attr_length);
if (0 != result) {
return result;
}
RID *rid1 = (RID *)(first + attr_length);
RID *rid2 = (RID *)(second + attr_length);
return RID::compare(rid1, rid2);
}
int lower_bound(AttrType attr_type, int attr_length, const char *data, const int item_length, const int item_num, const char *key, bool *_found = nullptr)
{
int left = 0;
int right = item_num;
int med = 0;
bool last_is_bigger = false;
bool found = false;
for ( ; left < right; ) {
med = (left + right) / 2;
const char *item = data + item_length * med;
int cmp_result = key_compare(attr_type, attr_length, key, item);
if (cmp_result == 0) {
last_is_bigger = false;
found = true;
break;
}
if (cmp_result > 0) {
last_is_bigger = true;
left = med + 1;
} else {
last_is_bigger = false;
right = med;
}
}
if (_found)
*_found = found;
if (last_is_bigger)
return med + 1;
return med;
}
int get_page_index_capacity(int attr_length)
{ {
int item_size = attr_length + sizeof(RID) + sizeof(PageNum);
int capacity = int capacity =
((int)BP_PAGE_DATA_SIZE - sizeof(IndexFileHeader) - sizeof(IndexNode)) / (attr_length + 2 * sizeof(RID)); ((int)BP_PAGE_DATA_SIZE - InternalIndexNode::HEADER_SIZE) / item_size;
// Here is some tricks
// 1. reserver one pair of kV for insert operation
// 2. make sure capacity % 2 == 0, otherwise it is likeyly to occur problem when split node
capacity = ((capacity - RECORD_RESERVER_PAIR_NUM) / 2) * 2;
return capacity; return capacity;
} }
IndexNode *BplusTreeHandler::get_index_node(char *page_data) const int calc_leaf_page_capacity(int attr_length)
{ {
IndexNode *node = (IndexNode *)(page_data + sizeof(IndexFileHeader)); int item_size = attr_length + sizeof(RID) + sizeof(RID);
node->keys = (char *)node + sizeof(IndexNode); int capacity =
node->rids = (RID *)(node->keys + (file_header_.order + RECORD_RESERVER_PAIR_NUM) * file_header_.key_length); ((int)BP_PAGE_DATA_SIZE - LeafIndexNode::HEADER_SIZE) / item_size;
return node; return capacity;
} }
RC BplusTreeHandler::sync() /////////////////////////////////////////////////////////////////////////////////
IndexNodeHandler::IndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
: header_(header), page_num_(page_handle.page_num()), node_((IndexNode *)page_handle.data())
{}
bool IndexNodeHandler::is_leaf() const
{ {
return disk_buffer_pool_->purge_all_pages(file_id_); return node_->is_leaf;
}
void IndexNodeHandler::init_empty(bool leaf)
{
node_->is_leaf = leaf;
node_->key_num = 0;
node_->parent = BP_INVALID_PAGE_NUM;
}
PageNum IndexNodeHandler::page_num() const
{
return page_num_;
} }
RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_length) int IndexNodeHandler::key_size() const
{ {
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool(); return header_.key_length;
RC rc = disk_buffer_pool->create_file(file_name); }
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to create file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
LOG_INFO("Successfully create index file:%s", file_name);
int file_id; int IndexNodeHandler::value_size() const
rc = disk_buffer_pool->open_file(file_name, &file_id); {
if (rc != RC::SUCCESS) { // return header_.value_size;
LOG_WARN("Failed to open file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); return sizeof(RID);
return rc; }
}
LOG_INFO("Successfully open index file %s.", file_name);
rc = disk_buffer_pool->allocate_page(file_id, &root_page_handle_); int IndexNodeHandler::item_size() const
if (rc != RC::SUCCESS) { {
LOG_WARN("Failed to allocate page. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); return key_size() + value_size();
disk_buffer_pool->close_file(file_id); }
return rc;
}
char *pdata; int IndexNodeHandler::size() const
rc = disk_buffer_pool->get_data(&root_page_handle_, &pdata); {
if (rc != RC::SUCCESS) { return node_->key_num;
LOG_WARN("Failed to get data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); }
disk_buffer_pool->close_file(file_id);
return rc;
}
PageNum page_num; void IndexNodeHandler::increase_size(int n)
rc = disk_buffer_pool->get_page_num(&root_page_handle_, &page_num); {
if (rc != RC::SUCCESS) { node_->key_num += n;
LOG_WARN("Failed to get page num. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); }
disk_buffer_pool->close_file(file_id);
return rc;
}
IndexFileHeader *file_header = (IndexFileHeader *)pdata; PageNum IndexNodeHandler::parent_page_num() const
file_header->attr_length = attr_length; {
file_header->key_length = attr_length + sizeof(RID); return node_->parent;
file_header->attr_type = attr_type; }
file_header->order = get_page_index_capacity(attr_length);
file_header->root_page = page_num;
root_node_ = get_index_node(pdata); void IndexNodeHandler::set_parent_page_num(PageNum page_num)
root_node_->init_empty(*file_header); {
this->node_->parent = page_num;
}
std::string to_string(const IndexNodeHandler &handler)
{
std::stringstream ss;
disk_buffer_pool->mark_dirty(&root_page_handle_); ss << "PageNum:" << handler.page_num()
<< ",is_leaf:" << handler.is_leaf() << ","
<< "key_num:" << handler.size() << ","
<< "parent:" << handler.parent_page_num() << ",";
disk_buffer_pool_ = disk_buffer_pool; return ss.str();
file_id_ = file_id; }
memcpy(&file_header_, pdata, sizeof(file_header_)); bool IndexNodeHandler::validate() const
header_dirty_ = false; {
if (parent_page_num() == BP_INVALID_PAGE_NUM) {
// this is a root page
if (size() < 1) {
LOG_WARN("root page has no item");
return false;
}
mem_pool_item_ = new common::MemPoolItem(file_name); if (!is_leaf() && size() < 2) {
if (mem_pool_item_->init(file_header->key_length) < 0) { LOG_WARN("root page internal node has less than 2 child. size=%d", size());
LOG_WARN("Failed to init memory pool for index %s", file_name); return false;
close(); }
return RC::NOMEM;
} }
return true;
LOG_INFO("Successfully create index %s", file_name);
return RC::SUCCESS;
} }
RC BplusTreeHandler::open(const char *file_name) /////////////////////////////////////////////////////////////////////////////////
LeafIndexNodeHandler::LeafIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
: IndexNodeHandler(header, page_handle), leaf_node_((LeafIndexNode *)page_handle.data())
{}
void LeafIndexNodeHandler::init_empty()
{ {
if (file_id_ > 0) { IndexNodeHandler::init_empty(true);
LOG_WARN("%s has been opened before index.open.", file_name); leaf_node_->prev_brother = BP_INVALID_PAGE_NUM;
return RC::RECORD_OPENNED; leaf_node_->next_brother = BP_INVALID_PAGE_NUM;
} }
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool(); void LeafIndexNodeHandler::set_next_page(PageNum page_num)
int file_id = 0; {
RC rc = disk_buffer_pool->open_file(file_name, &file_id); leaf_node_->next_brother = page_num;
if (rc != RC::SUCCESS) { }
LOG_WARN("Failed to open file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
BPPageHandle page_handle; void LeafIndexNodeHandler::set_prev_page(PageNum page_num)
rc = disk_buffer_pool->get_this_page(file_id, FIRST_INDEX_PAGE, &page_handle); {
if (rc != RC::SUCCESS) { leaf_node_->prev_brother = page_num;
LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); }
disk_buffer_pool_->close_file(file_id); PageNum LeafIndexNodeHandler::next_page() const
return rc; {
} return leaf_node_->next_brother;
}
PageNum LeafIndexNodeHandler::prev_page() const
{
return leaf_node_->prev_brother;
}
char *pdata; char *LeafIndexNodeHandler::key_at(int index)
rc = disk_buffer_pool->get_data(&page_handle, &pdata); {
if (rc != RC::SUCCESS) { assert(index >= 0 && index < size());
LOG_WARN("Failed to get first page data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); return __key_at(index);
disk_buffer_pool_->close_file(file_id); }
return rc;
}
memcpy(&file_header_, pdata, sizeof(IndexFileHeader)); char *LeafIndexNodeHandler::value_at(int index)
header_dirty_ = false; {
disk_buffer_pool_ = disk_buffer_pool; assert(index >= 0 && index < size());
file_id_ = file_id; return __value_at(index);
}
mem_pool_item_ = new common::MemPoolItem(file_name); int LeafIndexNodeHandler::max_size() const
if (mem_pool_item_->init(file_header_.key_length) < 0) { {
LOG_WARN("Failed to init memory pool for index %s", file_name); return header_.leaf_max_size;
close(); }
return RC::NOMEM;
}
if (file_header_.root_page == FIRST_INDEX_PAGE) { int LeafIndexNodeHandler::min_size() const
root_node_ = get_index_node(pdata); {
root_page_handle_ = page_handle; return header_.leaf_max_size - header_.leaf_max_size / 2;
}
LOG_INFO("Successfully open index %s", file_name); int LeafIndexNodeHandler::lookup(const KeyComparator &comparator, const char *key, bool *found /* = nullptr */) const
return RC::SUCCESS; {
const int size = this->size();
int i = 0;
for ( ; i < size; i++) {
int result = comparator(key, __key_at(i));
if (0 == result) {
if (found) {
*found = true;
}
return i;
}
if (result < 0) {
break;
}
} }
if (found) {
// close old page_handle *found = false;
disk_buffer_pool->unpin_page(&page_handle);
LOG_INFO("Begin to load root page of index:%s, root_page:%d.", file_name, file_header_.root_page);
rc = disk_buffer_pool->get_this_page(file_id, file_header_.root_page, &root_page_handle_);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
return rc;
} }
return i;
}
rc = disk_buffer_pool->get_data(&root_page_handle_, &pdata); void LeafIndexNodeHandler::insert(int index, const char *key, const char *value)
if (rc != RC::SUCCESS) { {
LOG_WARN("Failed to get first page data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc)); if (index < size()) {
disk_buffer_pool_->close_file(file_id); memmove(__item_at(index + 1), __item_at(index), (size() - index) * item_size());
return rc; }
memcpy(__item_at(index), key, key_size());
memcpy(__item_at(index) + key_size(), value, value_size());
increase_size(1);
}
void LeafIndexNodeHandler::remove(int index)
{
assert(index >= 0 && index < size());
if (index < size() - 1) {
memmove(__item_at(index), __item_at(index + 1), (size() - index - 1) * item_size());
} }
root_node_ = get_index_node(pdata); increase_size(-1);
}
LOG_INFO("Successfully open index %s", file_name); int LeafIndexNodeHandler::remove(const char *key, const KeyComparator &comparator)
return RC::SUCCESS; {
bool found = false;
int index = lookup(comparator, key, &found);
if (found) {
this->remove(index);
return 1;
}
return 0;
} }
RC BplusTreeHandler::close() RC LeafIndexNodeHandler::move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
{ {
if (file_id_ != -1) { const int size = this->size();
disk_buffer_pool_->unpin_page(&root_page_handle_); const int move_index = size / 2;
root_node_ = nullptr;
disk_buffer_pool_->close_file(file_id_); memcpy(other.__item_at(0), this->__item_at(move_index), item_size() * (size - move_index));
file_id_ = -1; other.increase_size(size - move_index);
this->increase_size(- ( size - move_index));
return RC::SUCCESS;
}
RC LeafIndexNodeHandler::move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
{
other.append(__item_at(0));
delete mem_pool_item_; if (size() >= 1) {
mem_pool_item_ = nullptr; memmove(__item_at(0), __item_at(1), (size() - 1) * item_size() );
} }
increase_size(-1);
disk_buffer_pool_ = nullptr;
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::print_node(IndexNode *node, PageNum page_num) RC LeafIndexNodeHandler::move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
{ {
LOG_INFO("PageNum:%d, node {%s}\n", page_num, node->to_string(file_header_).c_str()); other.preappend(__item_at(size() - 1));
if (node->is_leaf == false) { increase_size(-1);
for (int i = 0; i <= node->key_num; i++) { return RC::SUCCESS;
PageNum child_page_num = node->rids[i].page_num; }
BPPageHandle page_handle; /**
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page_num, &page_handle); * move all items to left page
if (rc != RC::SUCCESS) { */
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, child_page_num); RC LeafIndexNodeHandler::move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
continue; {
} memcpy(other.__item_at(other.size()), this->__item_at(0), this->size() * item_size());
other.increase_size(this->size());
this->increase_size(- this->size());
char *pdata; other.set_next_page(this->next_page());
disk_buffer_pool_->get_data(&page_handle, &pdata);
IndexNode *child = get_index_node(pdata); PageNum next_right_page_num = this->next_page();
print_node(child, child_page_num); if (next_right_page_num != BP_INVALID_PAGE_NUM) {
disk_buffer_pool_->unpin_page(&page_handle); BPPageHandle next_right_page_handle;
RC rc = bp->get_this_page(file_id, next_right_page_num, &next_right_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next right page. page number:%d. rc=%d:%s", next_right_page_num, rc, strrc(rc));
return rc;
} }
}
LeafIndexNodeHandler next_right_node(header_, next_right_page_handle);
next_right_node.set_prev_page(other.page_num());
next_right_page_handle.mark_dirty();
bp->unpin_page(&next_right_page_handle);
}
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::print_tree() void LeafIndexNodeHandler::append(const char *item)
{ {
if (file_id_ < 0) { memcpy(__item_at(size()), item, item_size());
LOG_WARN("Index hasn't been created or opened, fail to print"); increase_size(1);
return RC::SUCCESS; }
}
int page_count; void LeafIndexNodeHandler::preappend(const char *item)
RC rc = disk_buffer_pool_->get_page_count(file_id_, &page_count); {
if (rc != RC::SUCCESS) { if (size() > 0) {
LOG_WARN("Failed to get page count of index %d", file_id_); memmove(__item_at(1), __item_at(0), size() * item_size());
return rc;
} }
memcpy(__item_at(0), item, item_size());
increase_size(1);
}
LOG_INFO("\n\n\n !!!! Begin to print index %s:%d, page_count:%d, file_header:%s\n\n\n", char *LeafIndexNodeHandler::__item_at(int index) const
mem_pool_item_->get_name().c_str(), {
file_id_, return leaf_node_->array + (index * item_size());
page_count, }
file_header_.to_string().c_str()); char *LeafIndexNodeHandler::__key_at(int index) const
{
return __item_at(index);
}
char *LeafIndexNodeHandler::__value_at(int index) const
{
return __item_at(index) + key_size();
}
print_node(root_node_, file_header_.root_page); std::string to_string(const LeafIndexNodeHandler &handler, const KeyPrinter &printer)
return RC::SUCCESS; {
std::stringstream ss;
ss << to_string((const IndexNodeHandler &)handler)
<< ",prev page:" << handler.prev_page()
<< ",next page:" << handler.next_page();
ss << ",values=[" << printer(handler.__key_at(0)) ;
for (int i = 1; i < handler.size(); i++) {
ss << "," << printer(handler.__key_at(i));
}
ss << "]";
return ss.str();
} }
RC BplusTreeHandler::print_leafs() bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const
{ {
PageNum page_num; bool result = IndexNodeHandler::validate();
get_first_leaf_page(&page_num); if (false == result) {
return false;
}
IndexNode *node; const int node_size = size();
BPPageHandle page_handle; for (int i = 1; i < node_size; i++) {
RC rc; if (comparator(__key_at(i - 1), __key_at(i)) >= 0) {
while (page_num != -1) { LOG_WARN("page number = %d, invalid key order. id1=%d,id2=%d, this=%s",
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle); page_num(), i-1, i, to_string(*this).c_str());
if (rc != RC::SUCCESS) { return false;
LOG_WARN("Failed to print leafs, due to failed to load. ");
return rc;
} }
char *pdata;
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
LOG_INFO("Page:%d, Node:%s", page_num, node->to_string(file_header_).c_str());
page_num = node->next_brother;
disk_buffer_pool_->unpin_page(&page_handle);
} }
return RC::SUCCESS; PageNum parent_page_num = this->parent_page_num();
} if (parent_page_num == BP_INVALID_PAGE_NUM) {
return true;
}
bool BplusTreeHandler::validate_node(IndexNode *node) BPPageHandle parent_page_handle;
{ RC rc = bp->get_this_page(file_id, parent_page_num, &parent_page_handle);
if (node->key_num > file_header_.order) { if (rc != RC::SUCCESS) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str()); LOG_WARN("failed to fetch parent page. page num=%d, rc=%d:%s",
parent_page_num, rc, strrc(rc));
return false;
}
InternalIndexNodeHandler parent_node(header_, parent_page_handle);
int index_in_parent = parent_node.value_index(this->page_num());
if (index_in_parent < 0) {
LOG_WARN("invalid leaf node. cannot find index in parent. this page num=%d, parent page num=%d",
this->page_num(), parent_page_num);
bp->unpin_page(&parent_page_handle);
return false; return false;
} }
if (node->parent != -1) {
if (node->key_num < file_header_.order / 2) { if (0 != index_in_parent) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str()); int cmp_result = comparator(__key_at(0), parent_node.key_at(index_in_parent));
if (cmp_result < 0) {
LOG_WARN("invalid leaf node. first item should be greate than or equal to parent item. " \
"this page num=%d, parent page num=%d, index in parent=%d",
this->page_num(), parent_node.page_num(), index_in_parent);
bp->unpin_page(&parent_page_handle);
return false; return false;
} }
} else { }
// node is root
if (node->is_leaf == false) {
if (node->key_num < 1) { if (index_in_parent < parent_node.size() - 1) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str()); int cmp_result = comparator(__key_at(size() - 1), parent_node.key_at(index_in_parent + 1));
return false; if (cmp_result >= 0) {
} LOG_WARN("invalid leaf node. last item should be less than the item at the first after item in parent." \
"this page num=%d, parent page num=%d, parent item to compare=%d",
this->page_num(), parent_node.page_num(), index_in_parent + 1);
bp->unpin_page(&parent_page_handle);
return false;
} }
} }
bp->unpin_page(&parent_page_handle);
return true;
}
if (node->is_leaf && node->prev_brother != -1) { /////////////////////////////////////////////////////////////////////////////////
char *first_key = node->keys; InternalIndexNodeHandler::InternalIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
bool found = false; : IndexNodeHandler(header, page_handle), internal_node_((InternalIndexNode *)page_handle.data())
{}
PageNum parent_page = node->parent;
while (parent_page != -1) {
BPPageHandle parent_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &parent_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to check parent's keys, file_id:%d", file_id_);
return false; std::string to_string(const InternalIndexNodeHandler &node, const KeyPrinter &printer)
} {
std::stringstream ss;
ss << to_string((const IndexNodeHandler &)node);
ss << ",children:["
<< "{key:" << printer(node.__key_at(0)) << ","
<< "value:" << *(PageNum *)node.__value_at(0) << "}";
for (int i = 1; i < node.size(); i++) {
ss << ",{key:" << printer(node.__key_at(i))
<< ",value:"<< *(PageNum *)node.__value_at(i) << "}";
}
ss << "]";
return ss.str();
}
char *pdata; void InternalIndexNodeHandler::init_empty()
disk_buffer_pool_->get_data(&parent_handle, &pdata); {
IndexNode *parent = get_index_node(pdata); IndexNodeHandler::init_empty(false);
for (int i = 0; i < parent->key_num; i++) { }
char *cur_key = parent->keys + i * file_header_.key_length; void InternalIndexNodeHandler::create_new_root(PageNum first_page_num, const char *key, PageNum page_num)
int tmp = key_compare(file_header_.attr_type, file_header_.attr_length, first_key, cur_key); {
if (tmp == 0) { memset(__key_at(0), 0, key_size());
found = true; memcpy(__value_at(0), &first_page_num, value_size());
memcpy(__item_at(1), key, key_size());
break; memcpy(__value_at(1), &page_num, value_size());
} else if (tmp < 0) { increase_size(2);
break; }
}
}
disk_buffer_pool_->unpin_page(&parent_handle);
if (found == true) {
break;
}
parent_page = parent->parent; /**
} * insert one entry
* the entry to be inserted will never at the first slot.
* the right child page after split will always have bigger keys.
*/
void InternalIndexNodeHandler::insert(const char *key, PageNum page_num, const KeyComparator &comparator)
{
int insert_position = -1;
lookup(comparator, key, nullptr, &insert_position);
if (insert_position < size()) {
memmove(__item_at(insert_position + 1), __item_at(insert_position), (size() - insert_position) * item_size());
}
memcpy(__item_at(insert_position), key, key_size());
memcpy(__value_at(insert_position), &page_num, value_size());
increase_size(1);
}
if (found == false) { RC InternalIndexNodeHandler::move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
LOG_WARN("Failed to find leaf's first key in internal node. leaf:%s, file_id:%d", {
node->to_string(file_header_).c_str(), const int size = this->size();
file_id_); const int move_index = size / 2;
return false; RC rc = other.copy_from(this->__item_at(move_index), size - move_index, bp, file_id);
} if (rc != RC::SUCCESS) {
LOG_WARN("failed to copy item to new node. rc=%d:%s", rc, strrc(rc));
return rc;
} }
bool ret = false; increase_size(- (size - move_index));
char *last_key = node->keys; return rc;
char *cur_key; }
for (int i = 0; i < node->key_num; i++) {
int tmp;
cur_key = node->keys + i * file_header_.key_length;
if (i > 0) {
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, last_key);
if (tmp < 0) {
LOG_WARN("NODE %s 's key sequence is wrong", node->to_string(file_header_).c_str());
return false;
}
}
last_key = cur_key;
if (node->is_leaf) {
continue;
}
PageNum child_page = node->rids[i].page_num; int InternalIndexNodeHandler::max_size() const
BPPageHandle child_handle; {
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page, &child_handle); return header_.internal_max_size;
if (rc != RC::SUCCESS) { }
LOG_WARN(
"Failed to validte node's child %d, file_id:%d, node:%s", i, file_id_, node->to_string(file_header_).c_str());
continue;
}
char *pdata;
disk_buffer_pool_->get_data(&child_handle, &pdata);
IndexNode *child = get_index_node(pdata);
char *child_last_key = child->keys + (child->key_num - 1) * file_header_.key_length;
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, child_last_key);
if (tmp <= 0) {
LOG_WARN("Child's last key is bigger than current key, child:%s, current:%s, file_id:%d",
child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
ret = validate_node(child); int InternalIndexNodeHandler::min_size() const
if (ret == false) { {
disk_buffer_pool_->unpin_page(&child_handle); return header_.internal_max_size - header_.internal_max_size / 2;
return false; }
}
BPPageHandle next_child_handle; /**
PageNum next_child_page = node->rids[i + 1].page_num; * lookup the first item which key <= item
rc = disk_buffer_pool_->get_this_page(file_id_, next_child_page, &next_child_handle); * @return unlike the leafNode, the return value is not the insert position,
if (rc != RC::SUCCESS) { * but only the index of child to find.
LOG_WARN( */
"Failed to validte node's child %d, file_id:%d, node:%s", i, file_id_, node->to_string(file_header_).c_str()); int InternalIndexNodeHandler::lookup(const KeyComparator &comparator, const char *key,
disk_buffer_pool_->unpin_page(&child_handle); bool *found /* = nullptr */, int *insert_position /*= nullptr */) const
continue; {
} int i = 1;
disk_buffer_pool_->get_data(&next_child_handle, &pdata); const int size = this->size();
IndexNode *next_child = get_index_node(pdata); for ( ; i < size; i++) {
int result = comparator(key, __key_at(i));
char *first_next_child_key = next_child->keys; if (result == 0) {
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, first_next_child_key); if (found) {
if (next_child->is_leaf) { *found = true;
if (tmp != 0) {
LOG_WARN("Next child's first key isn't equal current key, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
} }
} else { if (insert_position) {
if (tmp >= 0) { *insert_position = i;
LOG_WARN("Next child's first key isn't equal current key, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
} }
return i;
} }
if (result < 0) {
if (i == node->key_num - 1) { if (found) {
ret = validate_node(next_child); *found = false;
if (ret == false) {
LOG_WARN("Next child is invalid, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
} }
} if (insert_position) {
if (child->is_leaf) { *insert_position = i;
if (child->next_brother != next_child_page || next_child->prev_brother != child_page) {
LOG_WARN("The child 's next brother or the next child's previous brother isn't correct, child:%s, "
"next_child:%s, file_id:%d",
child->to_string(file_header_).c_str(),
next_child->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
} }
return i - 1;
} }
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
} }
if (found) {
*found = false;
}
if (insert_position) {
*insert_position = size;
}
return size - 1;
}
return true; char *InternalIndexNodeHandler::key_at(int index)
{
assert(index >= 0 && index < size());
return __key_at(index);
}
void InternalIndexNodeHandler::set_key_at(int index, const char *key)
{
assert(index >= 0 && index < size());
memcpy(__key_at(index), key, key_size());
}
PageNum InternalIndexNodeHandler::value_at(int index)
{
assert(index >= 0 && index < size());
return *(PageNum *)__value_at(index);
}
int InternalIndexNodeHandler::value_index(PageNum page_num)
{
for (int i = 0; i < size(); i++) {
if (page_num == *(PageNum*)__value_at(i)) {
return i;
}
}
return -1;
}
void InternalIndexNodeHandler::remove(int index)
{
assert(index >= 0 && index < size());
if (index < size() - 1) {
memmove(__item_at(index), __item_at(index + 1), (size() - index - 1) * item_size());
}
increase_size(-1);
}
RC InternalIndexNodeHandler::move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
{
RC rc = other.copy_from(__item_at(0), size(), disk_buffer_pool, file_id);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to copy items to other node. rc=%d:%s", rc, strrc(rc));
return rc;
}
increase_size(- this->size());
return RC::SUCCESS;
} }
bool BplusTreeHandler::validate_leaf_link() RC InternalIndexNodeHandler::move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
{ {
BPPageHandle first_leaf_handle; RC rc = other.append(__item_at(0), disk_buffer_pool, file_id);
IndexNode *first_leaf = root_node_; if (rc != RC::SUCCESS) {
PageNum first_page; LOG_WARN("failed to append item to others.");
RC rc; return rc;
while (first_leaf->is_leaf == false) {
if (first_leaf_handle.open) {
disk_buffer_pool_->unpin_page(&first_leaf_handle);
}
first_page = first_leaf->rids[0].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, first_page, &first_leaf_handle);
if (rc != RC::SUCCESS) {
return false;
}
char *pdata;
disk_buffer_pool_->get_data(&first_leaf_handle, &pdata);
first_leaf = get_index_node(pdata);
} }
if (first_leaf_handle.open == false) { if (size() >= 1) {
// only root node memmove(__item_at(0), __item_at(1), (size() - 1) * item_size() );
if (first_leaf->prev_brother != -1 || first_leaf->next_brother != -1) {
LOG_WARN("root node is the only node, but either root node's previous brother or next brother is wrong, root:%s, "
"file_id:%s",
first_leaf->to_string(file_header_).c_str(),
file_id_);
return false;
}
return true;
} }
increase_size(-1);
return rc;
}
if (first_leaf->prev_brother != -1 || first_leaf->next_brother == -1) { RC InternalIndexNodeHandler::move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
LOG_WARN("First leaf is invalid, node:%s, file_id:%d", first_leaf->to_string(file_header_).c_str(), file_id_); {
disk_buffer_pool_->unpin_page(&first_leaf_handle); RC rc = other.preappend(__item_at(size() - 1), bp, file_id);
return false; if (rc != RC::SUCCESS) {
LOG_WARN("failed to preappend to others");
return rc;
} }
BPPageHandle last_leaf_handle; increase_size(-1);
IndexNode *last_leaf = root_node_; return rc;
PageNum last_page = -1; }
/**
* copy items from other node to self's right
*/
RC InternalIndexNodeHandler::copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool, int file_id)
{
memcpy(__item_at(this->size()), items, num * item_size());
while (last_leaf->is_leaf == false) { RC rc = RC::SUCCESS;
if (last_leaf_handle.open) { PageNum this_page_num = this->page_num();
disk_buffer_pool_->unpin_page(&last_leaf_handle); BPPageHandle page_handle;
} for (int i = 0; i < num; i++) {
last_page = last_leaf->rids[last_leaf->key_num].page_num; const PageNum page_num = *(const PageNum *)((items + i * item_size()) + key_size());
rc = disk_buffer_pool_->get_this_page(file_id_, last_page, &last_leaf_handle); rc = disk_buffer_pool->get_this_page(file_id, page_num, &page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&first_leaf_handle); LOG_WARN("failed to set child's page num. child page num:%d, this page num=%d, rc=%d:%s",
return false; page_num, this_page_num, rc, strrc(rc));
return rc;
} }
IndexNodeHandler child_node(header_, page_handle);
char *pdata; child_node.set_parent_page_num(this_page_num);
disk_buffer_pool_->get_data(&last_leaf_handle, &pdata); page_handle.mark_dirty();
last_leaf = get_index_node(pdata); disk_buffer_pool->unpin_page(&page_handle);
} }
increase_size(num);
return rc;
}
if (last_page == -1) { RC InternalIndexNodeHandler::append(const char *item, DiskBufferPool *bp, int file_id)
LOG_WARN("The last leaf is invalid, last leaf is root:%s, file_id:%d", {
last_leaf->to_string(file_header_).c_str(), return this->copy_from(item, 1, bp, file_id);
file_id_); }
disk_buffer_pool_->unpin_page(&first_leaf_handle);
return false;
}
if (last_leaf->next_brother != -1 || last_leaf->prev_brother == -1) { RC InternalIndexNodeHandler::preappend(const char *item, DiskBufferPool *bp, int file_id)
LOG_WARN( {
"The last leaf is invalid, last leaf:%s, file_id:%d", last_leaf->to_string(file_header_).c_str(), file_id_); PageNum child_page_num = *(PageNum *)(item + key_size());
disk_buffer_pool_->unpin_page(&first_leaf_handle); BPPageHandle page_handle;
disk_buffer_pool_->unpin_page(&last_leaf_handle); RC rc = bp->get_this_page(file_id, child_page_num, &page_handle);
return false; if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page. rc=%d:%s", rc, strrc(rc));
return rc;
} }
std::set<PageNum> leaf_pages; IndexNodeHandler child_node(header_, page_handle);
leaf_pages.insert(first_page); child_node.set_parent_page_num(this->page_num());
BPPageHandle current_handle; page_handle.mark_dirty();
IndexNode *cur_node = first_leaf; bp->unpin_page(&page_handle);
PageNum cur_page = first_page;
BPPageHandle next_handle; if (this->size() > 0) {
IndexNode *next_node = nullptr; memmove(__item_at(1), __item_at(0), this->size() * item_size());
PageNum next_page = cur_node->next_brother; }
bool found = false; memcpy(__item_at(0), item, item_size());
bool ret = false; increase_size(1);
return RC::SUCCESS;
}
while (next_page != -1) { char *InternalIndexNodeHandler::__item_at(int index) const
rc = disk_buffer_pool_->get_this_page(file_id_, next_page, &next_handle); {
if (rc != RC::SUCCESS) { return internal_node_->array + (index * item_size());
LOG_WARN("Failed to check leaf link "); }
goto cleanup;
}
char *pdata; char *InternalIndexNodeHandler::__key_at(int index) const
disk_buffer_pool_->get_data(&next_handle, &pdata); {
next_node = get_index_node(pdata); return __item_at(index);
}
if (cur_node->next_brother != next_page || next_node->prev_brother != cur_page) {
LOG_WARN("The leaf 's next brother or the next leaf's previous brother isn't correct, child:%s, next_child:%s, "
"file_id:%d",
cur_node->to_string(file_header_).c_str(),
next_node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_handle);
goto cleanup;
}
if (next_page == last_page) { char *InternalIndexNodeHandler::__value_at(int index) const
found = true; {
disk_buffer_pool_->unpin_page(&next_handle); return __item_at(index) + key_size();
break; }
}
if (leaf_pages.find(next_page) != leaf_pages.end()) { int InternalIndexNodeHandler::value_size() const
LOG_WARN( {
"Leaf links occur loop, current node:%s, file_id:%d", cur_node->to_string(file_header_).c_str(), file_id_); return sizeof(PageNum);
disk_buffer_pool_->unpin_page(&next_handle); }
goto cleanup;
} else {
leaf_pages.insert(next_page);
}
if (current_handle.open) { int InternalIndexNodeHandler::item_size() const
disk_buffer_pool_->unpin_page(&current_handle); {
} return key_size() + this->value_size();
current_handle = next_handle; }
cur_node = next_node;
cur_page = next_page;
next_page = cur_node->next_brother;
}
if (found == true) { bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const
ret = true; {
bool result = IndexNodeHandler::validate();
if (false == result) {
return false;
} }
cleanup: const int node_size = size();
if (first_leaf_handle.open) { for (int i = 2; i < node_size; i++) {
disk_buffer_pool_->unpin_page(&first_leaf_handle); if (comparator(__key_at(i - 1), __key_at(i)) >= 0) {
LOG_WARN("page number = %d, invalid key order. id1=%d,id2=%d, this=%s",
page_num(), i-1, i, to_string(*this).c_str());
return false;
}
} }
if (last_leaf_handle.open) { for (int i = 0; result && i < node_size; i++) {
disk_buffer_pool_->unpin_page(&last_leaf_handle); PageNum page_num = *(PageNum *)__value_at(i);
if (page_num < 0) {
LOG_WARN("this page num=%d, got invalid child page. page num=%d", this->page_num(), page_num);
} else {
BPPageHandle child_page_handle;
RC rc = bp->get_this_page(file_id, page_num, &child_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page while validate internal page. page num=%d, rc=%d:%s",
page_num, rc, strrc(rc));
} else {
IndexNodeHandler child_node(header_, child_page_handle);
if (child_node.parent_page_num() != this->page_num()) {
LOG_WARN("child's parent page num is invalid. child page num=%d, parent page num=%d, this page num=%d",
child_node.page_num(), child_node.parent_page_num(), this->page_num());
result = false;
}
bp->unpin_page(&child_page_handle);
}
}
} }
if (current_handle.open) { if (!result) {
disk_buffer_pool_->unpin_page(&current_handle); return result;
} }
return ret; const PageNum parent_page_num = this->parent_page_num();
} if (parent_page_num == BP_INVALID_PAGE_NUM) {
return result;
}
bool BplusTreeHandler::validate_tree() BPPageHandle parent_page_handle;
{ RC rc = bp->get_this_page(file_id, parent_page_num, &parent_page_handle);
IndexNode *node = root_node_; if (rc != RC::SUCCESS) {
if (validate_node(node) == false || validate_leaf_link() == false) { LOG_WARN("failed to fetch parent page. page num=%d, rc=%d:%s", parent_page_num, rc, strrc(rc));
LOG_WARN("Current B+ Tree is invalid");
print_tree();
return false; return false;
} }
return true;
}
RC BplusTreeHandler::find_leaf(const char *pkey, PageNum *leaf_page) InternalIndexNodeHandler parent_node(header_, parent_page_handle);
{ int index_in_parent = parent_node.value_index(this->page_num());
BPPageHandle page_handle; if (index_in_parent < 0) {
IndexNode *node = root_node_; LOG_WARN("invalid internal node. cannot find index in parent. this page num=%d, parent page num=%d",
while (false == node->is_leaf) { this->page_num(), parent_page_num);
char *pdata; bp->unpin_page(&parent_page_handle);
int i; return false;
//for (i = 0; i < node->key_num; i++) { }
// int tmp =
// key_compare(file_header_.attr_type, file_header_.attr_length, pkey, node->keys + i * file_header_.key_length);
// if (tmp < 0)
// break;
//}
i = lower_bound(file_header_.attr_type, file_header_.attr_length, node->keys, file_header_.key_length, node->key_num, pkey);
if (page_handle.open == true) {
disk_buffer_pool_->unpin_page(&page_handle);
}
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[i].page_num, &page_handle); if (0 != index_in_parent) {
if (rc != RC::SUCCESS) { int cmp_result = comparator(__key_at(1), parent_node.key_at(index_in_parent));
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, node->rids[i].page_num); if (cmp_result < 0) {
return rc; LOG_WARN("invalid internal node. the second item should be greate than or equal to parent item. " \
"this page num=%d, parent page num=%d, index in parent=%d",
this->page_num(), parent_node.page_num(), index_in_parent);
bp->unpin_page(&parent_page_handle);
return false;
} }
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
} }
if (page_handle.open == false) { if (index_in_parent < parent_node.size() - 1) {
*leaf_page = file_header_.root_page; int cmp_result = comparator(__key_at(size() - 1), parent_node.key_at(index_in_parent + 1));
return RC::SUCCESS; if (cmp_result >= 0) {
LOG_WARN("invalid internal node. last item should be less than the item at the first after item in parent." \
"this page num=%d, parent page num=%d, parent item to compare=%d",
this->page_num(), parent_node.page_num(), index_in_parent + 1);
bp->unpin_page(&parent_page_handle);
return false;
}
} }
bp->unpin_page(&parent_page_handle);
disk_buffer_pool_->get_page_num(&page_handle, leaf_page); return result;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
} }
RC BplusTreeHandler::insert_entry_into_node(IndexNode *node, const char *pkey, const RID *rid, PageNum left_page) /////////////////////////////////////////////////////////////////////////////////
{
int insert_pos = 0, tmp;
//for (; insert_pos < node->key_num; insert_pos++) {
// tmp = key_compare(
// file_header_.attr_type, file_header_.attr_length, pkey, node->keys + insert_pos * file_header_.key_length);
// if (tmp == 0) {
// LOG_TRACE("Insert into %d occur duplicated key, rid:%s.", file_id_, node->rids[insert_pos].to_string().c_str());
// return RC::RECORD_DUPLICATE_KEY;
// }
// if (tmp < 0)
// break;
//}
bool found = false;
insert_pos = lower_bound(file_header_.attr_type, file_header_.attr_length, node->keys, file_header_.key_length,
node->key_num, pkey, &found);
if (found) {
LOG_TRACE("Insert into %d occur duplicated key, rid:%s.", file_id_, node->rids[insert_pos].to_string().c_str());
return RC::RECORD_DUPLICATE_KEY;
}
char *from = node->keys + insert_pos * file_header_.key_length;
char *to = from + file_header_.key_length;
int len = (node->key_num - insert_pos) * file_header_.key_length;
memmove(to, from, len);
memcpy(node->keys + insert_pos * file_header_.key_length, pkey, file_header_.key_length);
if (node->is_leaf) {
len = (node->key_num - insert_pos) * sizeof(RID);
memmove(node->rids + insert_pos + 1, node->rids + insert_pos, len);
memcpy(node->rids + insert_pos, rid, sizeof(RID));
change_leaf_parent_key_insert(node, insert_pos, left_page);
} else {
len = (node->key_num - insert_pos) * sizeof(RID);
memmove(node->rids + insert_pos + 2, node->rids + insert_pos + 1, len);
memcpy(node->rids + insert_pos + 1, rid, sizeof(RID));
}
node->key_num++; //叶子结点增加一条记录 RC BplusTreeHandler::sync()
return RC::SUCCESS; {
return disk_buffer_pool_->purge_all_pages(file_id_);
} }
RC BplusTreeHandler::split_leaf(BPPageHandle &leaf_page_handle) RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_length,
int internal_max_size /* = -1*/, int leaf_max_size /* = -1 */)
{ {
PageNum leaf_page; DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
disk_buffer_pool_->get_page_num(&leaf_page_handle, &leaf_page); RC rc = disk_buffer_pool->create_file(file_name);
char *pdata;
RC rc = disk_buffer_pool_->get_data(&leaf_page_handle, &pdata);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to create file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc; return rc;
} }
IndexNode *old_node = get_index_node(pdata); LOG_INFO("Successfully create index file:%s", file_name);
char *new_parent_key = (char *)mem_pool_item_->alloc();
if (new_parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for new key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
// add a new node int file_id;
BPPageHandle page_handle2; rc = disk_buffer_pool->open_file(file_name, &file_id);
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle2);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to split index page due to failed to allocate page, file_id:%d ", file_id_); LOG_WARN("Failed to open file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc; return rc;
} }
PageNum new_page; LOG_INFO("Successfully open index file %s.", file_name);
disk_buffer_pool_->get_page_num(&page_handle2, &new_page);
disk_buffer_pool_->get_data(&page_handle2, &pdata); BPPageHandle header_page_handle;
IndexNode *new_node = get_index_node(pdata); rc = disk_buffer_pool->allocate_page(file_id, &header_page_handle);
new_node->init_empty(file_header_);
new_node->parent = old_node->parent;
new_node->prev_brother = leaf_page;
new_node->next_brother = old_node->next_brother;
old_node->next_brother = new_page;
// begin to move data from leaf_node to new_node
split_node(old_node, new_node, leaf_page, new_page, new_parent_key);
disk_buffer_pool_->mark_dirty(&leaf_page_handle);
disk_buffer_pool_->mark_dirty(&page_handle2);
PageNum parent_page = old_node->parent;
rc = insert_into_parent(parent_page, leaf_page_handle, new_parent_key, page_handle2);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert into parent of index %d", file_id_); LOG_WARN("failed to allocate header page for bplus tree. rc=%d:%s", rc, strrc(rc));
// restore status before insert into parent disk_buffer_pool->close_file(file_id);
// merge_nodes function will move left node into right node
merge_nodes(old_node, new_node, new_page, new_parent_key);
copy_node(old_node, new_node);
change_insert_leaf_link(old_node, new_node, leaf_page);
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&page_handle2);
disk_buffer_pool_->dispose_page(file_id_, new_page);
return rc; return rc;
} }
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&page_handle2);
return RC::SUCCESS;
}
RC BplusTreeHandler::insert_intern_node(
BPPageHandle &parent_page_handle, BPPageHandle &left_page_handle, BPPageHandle &right_page_handle, const char *pkey)
{
PageNum left_page;
disk_buffer_pool_->get_page_num(&left_page_handle, &left_page);
PageNum right_page; if (header_page_handle.page_num() != FIRST_INDEX_PAGE) {
disk_buffer_pool_->get_page_num(&right_page_handle, &right_page); LOG_WARN("header page num should be %d but got %d. is it a new file : %s",
FIRST_INDEX_PAGE, header_page_handle.page_num(), file_name);
disk_buffer_pool->close_file(file_id);
return RC::INTERNAL;
}
char *pdata; if (internal_max_size < 0) {
RC rc = disk_buffer_pool_->get_data(&parent_page_handle, &pdata); internal_max_size = calc_internal_page_capacity(attr_length);
if (rc != RC::SUCCESS) {
return rc;
} }
if (leaf_max_size < 0) {
leaf_max_size = calc_leaf_page_capacity(attr_length);
}
char *pdata = header_page_handle.data();
IndexFileHeader *file_header = (IndexFileHeader *)pdata;
file_header->attr_length = attr_length;
file_header->key_length = attr_length + sizeof(RID);
file_header->attr_type = attr_type;
file_header->internal_max_size = internal_max_size;
file_header->leaf_max_size = leaf_max_size;
file_header->root_page = BP_INVALID_PAGE_NUM;
IndexNode *node = get_index_node(pdata); header_page_handle.mark_dirty();
disk_buffer_pool->unpin_page(&header_page_handle);
RID rid; disk_buffer_pool_ = disk_buffer_pool;
rid.page_num = right_page; file_id_ = file_id;
rid.slot_num = BP_INVALID_PAGE_NUM; // change to invalid page num
insert_entry_into_node(node, pkey, &rid, right_page); memcpy(&file_header_, pdata, sizeof(file_header_));
header_dirty_ = false;
disk_buffer_pool_->mark_dirty(&parent_page_handle); mem_pool_item_ = new common::MemPoolItem(file_name);
if (mem_pool_item_->init(file_header->key_length) < 0) {
LOG_WARN("Failed to init memory pool for index %s", file_name);
close();
return RC::NOMEM;
}
key_comparator_.init(file_header->attr_type, file_header->attr_length);
key_printer_.init(file_header->attr_type, file_header->attr_length);
LOG_INFO("Successfully create index %s", file_name);
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::split_intern_node(BPPageHandle &inter_page_handle, const char *pkey) RC BplusTreeHandler::open(const char *file_name)
{ {
PageNum inter_page_num; if (file_id_ >= 0) {
disk_buffer_pool_->get_page_num(&inter_page_handle, &inter_page_num); LOG_WARN("%s has been opened before index.open.", file_name);
return RC::RECORD_OPENNED;
}
char *pdata; DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
RC rc = disk_buffer_pool_->get_data(&inter_page_handle, &pdata); int file_id = 0;
RC rc = disk_buffer_pool->open_file(file_name, &file_id);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc; return rc;
} }
IndexNode *inter_node = get_index_node(pdata); BPPageHandle page_handle;
rc = disk_buffer_pool->get_this_page(file_id, FIRST_INDEX_PAGE, &page_handle);
char *new_parent_key = (char *)mem_pool_item_->alloc();
if (new_parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for new key when split intern node index %d", file_id_);
return RC::NOMEM;
}
// add a new node
BPPageHandle new_page_handle;
rc = disk_buffer_pool_->allocate_page(file_id_, &new_page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Faild to alloc new page when split inter node of index, file_id:%d", file_id_); LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
mem_pool_item_->free(new_parent_key); disk_buffer_pool_->close_file(file_id);
return rc; return rc;
} }
disk_buffer_pool_->get_data(&new_page_handle, &pdata);
PageNum new_page;
disk_buffer_pool_->get_page_num(&new_page_handle, &new_page);
IndexNode *new_node = get_index_node(pdata);
new_node->init_empty(file_header_);
new_node->is_leaf = false;
new_node->parent = inter_node->parent;
split_node(inter_node, new_node, inter_page_num, new_page, new_parent_key);
disk_buffer_pool_->mark_dirty(&inter_page_handle); char *pdata = page_handle.data();
disk_buffer_pool_->mark_dirty(&new_page_handle); memcpy(&file_header_, pdata, sizeof(IndexFileHeader));
header_dirty_ = false;
disk_buffer_pool_ = disk_buffer_pool;
file_id_ = file_id;
// print(); mem_pool_item_ = new common::MemPoolItem(file_name);
PageNum parent_page = inter_node->parent; if (mem_pool_item_->init(file_header_.key_length) < 0) {
rc = insert_into_parent(parent_page, inter_page_handle, new_parent_key, new_page_handle); LOG_WARN("Failed to init memory pool for index %s", file_name);
if (rc != RC::SUCCESS) { close();
LOG_WARN("Failed to insert key to parents, file_id:%d", file_id_); return RC::NOMEM;
merge_nodes(inter_node, new_node, new_page, new_parent_key); }
copy_node(inter_node, new_node);
change_children_parent(inter_node->rids, inter_node->key_num + 1, inter_page_num);
mem_pool_item_->free(new_parent_key); // close old page_handle
disk_buffer_pool_->unpin_page(&new_page_handle); disk_buffer_pool->unpin_page(&page_handle);
disk_buffer_pool_->dispose_page(file_id_, new_page);
return rc; key_comparator_.init(file_header_.attr_type, file_header_.attr_length);
} LOG_INFO("Successfully open index %s", file_name);
mem_pool_item_->free(new_parent_key); return RC::SUCCESS;
disk_buffer_pool_->unpin_page(&new_page_handle);
return rc;
} }
RC BplusTreeHandler::insert_into_parent( RC BplusTreeHandler::close()
PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle)
{ {
if (parent_page == -1) { if (file_id_ != -1) {
return insert_into_new_root(left_page_handle, pkey, right_page_handle);
}
BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get parent page file_id:%d, page:%d", file_id_, parent_page);
return rc;
}
char *pdata; disk_buffer_pool_->close_file(file_id_);
disk_buffer_pool_->get_data(&page_handle, &pdata); file_id_ = -1;
IndexNode *node = get_index_node(pdata);
rc = insert_intern_node(page_handle, left_page_handle, right_page_handle, pkey); delete mem_pool_item_;
if (rc != RC::SUCCESS) { mem_pool_item_ = nullptr;
LOG_WARN("Failed to insert intern node of index :%d", file_id_);
return rc;
}
if (node->key_num > file_header_.order) {
rc = split_intern_node(page_handle, pkey);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to split intern node of index %d", file_id_);
int delete_index;
delete_entry_from_node(node, pkey, delete_index);
}
} }
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_ = nullptr;
return rc; return RC::SUCCESS;
} }
void BplusTreeHandler::swith_root(BPPageHandle &new_root_page_handle, IndexNode *root, PageNum root_page) RC BplusTreeHandler::print_leaf(BPPageHandle &page_handle)
{ {
//@@@ TODO here should add lock LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LOG_INFO("leaf node: %s", to_string(leaf_node, key_printer_).c_str());
disk_buffer_pool_->unpin_page(&root_page_handle_); disk_buffer_pool_->unpin_page(&page_handle);
root_page_handle_ = new_root_page_handle; return RC::SUCCESS;
root_node_ = root;
file_header_.root_page = root_page;
header_dirty_ = true;
} }
/** RC BplusTreeHandler::print_internal_node_recursive(BPPageHandle &page_handle)
* Create one new root node
* @param left_page_handle
* @param pkey
* @param right_page_handle
* @return
*/
RC BplusTreeHandler::insert_into_new_root(
BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle)
{ {
BPPageHandle new_root_page_handle; RC rc = RC::SUCCESS;
RC rc = disk_buffer_pool_->allocate_page(file_id_, &new_root_page_handle); LOG_INFO("bplus tree. file header: %s", file_header_.to_string().c_str());
if (rc != RC::SUCCESS) { InternalIndexNodeHandler internal_node(file_header_, page_handle);
LOG_WARN("Failed to alloc new page for the new root node of index, file_id:%d", file_id_); LOG_INFO("internal node: %s", to_string(internal_node, key_printer_).c_str());
return rc;
} int node_size = internal_node.size();
for (int i = 0; i < node_size; i++) {
PageNum root_page; PageNum page_num = internal_node.value_at(i);
disk_buffer_pool_->get_page_num(&new_root_page_handle, &root_page); BPPageHandle child_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
// modify the left node if (rc != RC::SUCCESS) {
PageNum left_page; LOG_WARN("failed to fetch child page. page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
char *pdata; disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->get_page_num(&left_page_handle, &left_page); return rc;
disk_buffer_pool_->get_data(&left_page_handle, &pdata); }
IndexNode *left = get_index_node(pdata);
left->parent = root_page;
disk_buffer_pool_->mark_dirty(&left_page_handle);
// modify the right node
PageNum right_page;
disk_buffer_pool_->get_page_num(&right_page_handle, &right_page);
disk_buffer_pool_->get_data(&right_page_handle, &pdata);
IndexNode *right = get_index_node(pdata);
right->parent = root_page;
disk_buffer_pool_->mark_dirty(&right_page_handle);
// handle the root node
disk_buffer_pool_->get_data(&new_root_page_handle, &pdata);
IndexNode *root = get_index_node(pdata);
root->init_empty(file_header_);
root->is_leaf = false;
root->key_num = 1;
memcpy(root->keys, pkey, file_header_.key_length);
RID rid;
rid.page_num = left_page;
rid.slot_num = EMPTY_RID_SLOT_NUM;
memcpy(root->rids, &rid, sizeof(RID));
rid.page_num = right_page;
rid.slot_num = EMPTY_RID_SLOT_NUM;
memcpy(root->rids + root->key_num, &rid, sizeof(RID));
disk_buffer_pool_->mark_dirty(&new_root_page_handle); IndexNodeHandler node(file_header_, child_page_handle);
swith_root(new_root_page_handle, root, root_page); if (node.is_leaf()) {
rc = print_leaf(child_page_handle);
} else {
rc = print_internal_node_recursive(child_page_handle);
}
if (rc != RC::SUCCESS) {
LOG_WARN("failed to print node. page id=%d, rc=%d:%s", child_page_handle.page_num(), rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
return rc;
}
}
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::insert_entry(const char *pkey, const RID *rid) RC BplusTreeHandler::print_tree()
{ {
if (file_id_ < 0) { if (file_id_ < 0) {
LOG_WARN("Index isn't ready!"); LOG_WARN("Index hasn't been created or opened, fail to print");
return RC::RECORD_CLOSED; return RC::SUCCESS;
} }
if (is_empty()) {
if (pkey == nullptr || rid == nullptr) { LOG_INFO("tree is empty");
LOG_WARN("Invalid arguments, key is empty or rid is empty"); return RC::SUCCESS;
return RC::INVALID_ARGUMENT;
} }
char *key = (char *)mem_pool_item_->alloc(); BPPageHandle page_handle;
if (key == nullptr) { PageNum page_num = file_header_.root_page;
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_); RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
return RC::NOMEM; if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch page. page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
return rc;
}
IndexNodeHandler node(file_header_, page_handle);
if (node.is_leaf()) {
rc = print_leaf(page_handle);
} else {
rc = print_internal_node_recursive(page_handle);
} }
memcpy(key, pkey, file_header_.attr_length); return rc;
memcpy(key + file_header_.attr_length, rid, sizeof(*rid)); }
PageNum leaf_page; RC BplusTreeHandler::print_leafs()
RC rc = find_leaf(key, &leaf_page); {
if (rc != RC::SUCCESS) { if (is_empty()) {
LOG_WARN("Failed to find leaf file_id:%d, %s", file_id_, rid->to_string().c_str()); LOG_INFO("empty tree");
mem_pool_item_->free(key); return RC::SUCCESS;
return rc;
} }
BPPageHandle page_handle; BPPageHandle page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle);
RC rc = left_most_page(page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load leaf file_id:%d, page_num:%d", file_id_, leaf_page); LOG_WARN("failed to get left most page. rc=%d:%s", rc, strrc(rc));
mem_pool_item_->free(key);
return rc; return rc;
} }
char *pdata; while (page_handle.page_num() != BP_INVALID_PAGE_NUM) {
disk_buffer_pool_->get_data(&page_handle, &pdata); LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LOG_INFO("leaf info: %s", to_string(leaf_node, key_printer_).c_str());
IndexNode *leaf = get_index_node(pdata); PageNum next_page_num = leaf_node.next_page();
rc = insert_entry_into_node(leaf, key, rid, leaf_page);
if (rc != RC::SUCCESS) {
LOG_TRACE("Failed to insert into leaf of index %d, rid:%s", file_id_, rid->to_string().c_str());
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return rc;
}
disk_buffer_pool_->mark_dirty(&page_handle);
if (leaf->key_num > file_header_.order) { if (next_page_num == BP_INVALID_PAGE_NUM) {
break;
}
rc = split_leaf(page_handle); rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert index of %d, failed to split for rid:%s", file_id_, rid->to_string().c_str()); LOG_WARN("failed to get next page. page id=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
int delete_index = 0;
delete_entry_from_node(leaf, key, delete_index);
disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return rc; return rc;
} }
} }
return rc;
disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return RC::SUCCESS;
} }
void BplusTreeHandler::get_entry_from_leaf( bool BplusTreeHandler::validate_node_recursive(BPPageHandle &page_handle)
IndexNode *node, const char *pkey, std::list<RID> &rids, bool &continue_check)
{ {
for (int i = node->key_num - 1; i >= 0; i--) { bool result = true;
int tmp = attribute_comp( IndexNodeHandler node(file_header_, page_handle);
pkey, node->keys + (i * file_header_.key_length), file_header_.attr_type, file_header_.attr_length); if (node.is_leaf()) {
if (tmp < 0) { LeafIndexNodeHandler leaf_node(file_header_, page_handle);
if (continue_check == true) { result = leaf_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
LOG_WARN("Something is wrong, the sequence is wrong."); } else {
print_tree(); InternalIndexNodeHandler internal_node(file_header_, page_handle);
continue_check = false; result = internal_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
for (int i = 0; result && i < internal_node.size(); i++) {
PageNum page_num = internal_node.value_at(i);
BPPageHandle child_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page.page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
result = false;
break; break;
} else {
continue;
} }
} else if (tmp == 0) {
rids.push_back(node->rids[i]); result = validate_node_recursive(child_page_handle);
continue_check = true;
} else {
continue_check = false;
break;
} }
} }
disk_buffer_pool_->unpin_page(&page_handle);
return result;
} }
RC BplusTreeHandler::get_entry(const char *pkey, std::list<RID> &rids) bool BplusTreeHandler::validate_leaf_link()
{ {
if (file_id_ < 0) { if (is_empty()) {
LOG_WARN("Index isn't ready!"); return true;
return RC::RECORD_CLOSED;
} }
char *key = (char *)mem_pool_item_->alloc(); BPPageHandle page_handle;
if (key == nullptr) { RC rc = left_most_page(page_handle);
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length); if (rc != RC::SUCCESS) {
return RC::NOMEM; LOG_WARN("failed to fetch left most page. rc=%d:%s", rc, strrc(rc));
return false;
} }
memcpy(key, pkey, file_header_.attr_length);
RC rc; PageNum prev_page_num = BP_INVALID_PAGE_NUM;
BPPageHandle page_handle; LeafIndexNodeHandler leaf_node(file_header_, page_handle);
char *pdata; if (leaf_node.prev_page() != prev_page_num) {
IndexNode *node = root_node_; LOG_WARN("invalid page. current_page_num=%d, prev page num should be %d but got %d",
while (false == node->is_leaf) { page_handle.page_num(), prev_page_num, leaf_node.prev_page());
return false;
int i; }
for (i = 0; i < node->key_num; i++) { PageNum next_page_num = leaf_node.next_page();
int tmp = attribute_comp(
pkey, node->keys + i * file_header_.key_length, file_header_.attr_type, file_header_.attr_length);
if (tmp < 0)
break;
}
if (page_handle.open == true) { prev_page_num = page_handle.page_num();
disk_buffer_pool_->unpin_page(&page_handle); char *prev_key = (char *)mem_pool_item_->alloc();
} memcpy(prev_key, leaf_node.key_at(leaf_node.size() - 1), file_header_.key_length);
disk_buffer_pool_->unpin_page(&page_handle);
rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[i].page_num, &page_handle); bool result = true;
while (result && next_page_num != BP_INVALID_PAGE_NUM) {
rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, node->rids[i].page_num); LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc; return false;
} }
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata); LeafIndexNodeHandler leaf_node(file_header_, page_handle);
} if (leaf_node.prev_page() != prev_page_num) {
LOG_WARN("invalid page. current_page_num=%d, prev page num should be %d but got %d",
bool continue_check = false; page_handle.page_num(), prev_page_num, leaf_node.prev_page());
get_entry_from_leaf(node, key, rids, continue_check); result = false;
while (continue_check == true) {
PageNum prev_brother = node->prev_brother;
if (prev_brother == EMPTY_RID_PAGE_NUM) {
break;
} }
if (page_handle.open) { if (key_comparator_(prev_key, leaf_node.key_at(0)) >= 0) {
disk_buffer_pool_->unpin_page(&page_handle); LOG_WARN("invalid page. current first key is not bigger than last");
} result = false;
rc = disk_buffer_pool_->get_this_page(file_id_, prev_brother, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Skip load the previous page, file_id:%d", file_id_);
break;
} }
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
get_entry_from_leaf(node, key, rids, continue_check);
}
if (page_handle.open) { next_page_num = leaf_node.next_page();
memcpy(prev_key, leaf_node.key_at(leaf_node.size() - 1), file_header_.key_length);
prev_page_num = page_handle.page_num();
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_->unpin_page(&page_handle);
} }
mem_pool_item_->free(key);
return RC::SUCCESS; free_key(prev_key);
// can do more things
return result;
} }
void BplusTreeHandler::delete_entry_from_node(IndexNode *node, const int delete_index) bool BplusTreeHandler::validate_tree()
{ {
char *from = node->keys + (delete_index + 1) * file_header_.key_length; if (is_empty()) {
char *to = from - file_header_.key_length; return true;
int len = (node->key_num - delete_index - 1) * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = node->rids + (delete_index + 1);
RID *to_rid = from_rid - 1;
len = (node->key_num - delete_index - 1) * sizeof(RID);
if (node->is_leaf == false) {
len += sizeof(RID);
} }
memmove(to_rid, from_rid, len);
node->key_num--;
}
RC BplusTreeHandler::get_parent_changed_index( BPPageHandle page_handle;
BPPageHandle &parent_handle, IndexNode *&parent, IndexNode *node, PageNum page_num, int &changed_index) RC rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
{
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->parent, &parent_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get pareent page, file_id:%d, parent_page:%d", LOG_WARN("failed to fetch root page. page id=%d, rc=%d:%s", file_header_.root_page, rc, strrc(rc));
file_id_,
node->parent);
return rc; return rc;
} }
char *pdata;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
while (changed_index <= parent->key_num) {
if ((parent->rids[changed_index].page_num) == page_num)
break;
changed_index++;
}
if (changed_index == parent->key_num + 1) { if (!validate_node_recursive(page_handle) || !validate_leaf_link()) {
LOG_WARN("Something is wrong, failed to find the target page %d in parent, node:%s file_id:%d", LOG_WARN("Current B+ Tree is invalid");
page_num,
node->to_string(file_header_).c_str(),
file_id_);
print_tree(); print_tree();
return RC::RECORD_CLOSED; return false;
} }
return RC::SUCCESS; LOG_INFO("great! current tree is valid");
return true;
} }
RC BplusTreeHandler::change_leaf_parent_key_insert(IndexNode *node, int changed_indx, PageNum page_num) bool BplusTreeHandler::is_empty() const
{ {
if (changed_indx != 0) { return file_header_.root_page == BP_INVALID_PAGE_NUM;
return RC::SUCCESS; }
}
if (node->is_leaf == false) {
return RC::SUCCESS;
}
if (node->parent == -1) {
return RC::SUCCESS;
}
if (node->key_num == 0) {
return RC::SUCCESS;
}
if (node->prev_brother == -1) {
return RC::SUCCESS;
}
int parent_changed_index = 0;
BPPageHandle parent_handle;
IndexNode *parent = nullptr;
RC rc = get_parent_changed_index(parent_handle, parent, node, page_num, parent_changed_index); RC BplusTreeHandler::find_leaf(const char *key, BPPageHandle &page_handle)
if (rc != RC::SUCCESS) { {
LOG_WARN("Failed to get parent's delete index, file_id:%d, child's page_num:%d", file_id_, page_num); return find_leaf_internal(
if (parent_handle.open) { [&](InternalIndexNodeHandler &internal_node) {
disk_buffer_pool_->unpin_page(&parent_handle); return internal_node.value_at(internal_node.lookup(key_comparator_, key));
return rc; },
} page_handle);
} }
if (parent_changed_index > 0) {
memcpy(parent->keys + (parent_changed_index - 1) * file_header_.key_length, node->keys, file_header_.key_length);
}
disk_buffer_pool_->unpin_page(&parent_handle); RC BplusTreeHandler::left_most_page(BPPageHandle &page_handle)
return RC::SUCCESS; {
return find_leaf_internal(
[&](InternalIndexNodeHandler &internal_node) {
return internal_node.value_at(0);
},
page_handle
);
} }
RC BplusTreeHandler::change_leaf_parent_key_delete(IndexNode *leaf, int delete_indx, const char *old_first_key) RC BplusTreeHandler::right_most_page(BPPageHandle &page_handle)
{ {
if (delete_indx != 0) { return find_leaf_internal(
return RC::SUCCESS; [&](InternalIndexNodeHandler &internal_node) {
} return internal_node.value_at(internal_node.size() - 1);
},
if (leaf->is_leaf == false) { page_handle
return RC::SUCCESS; );
} }
if (leaf->parent == -1) { RC BplusTreeHandler::find_leaf_internal(const std::function<PageNum(InternalIndexNodeHandler &)> &child_page_getter,
return RC::SUCCESS; BPPageHandle &page_handle)
{
if (is_empty()) {
return RC::EMPTY;
} }
if (leaf->prev_brother == -1) { RC rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
return RC::SUCCESS; if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch root page. page id=%d, rc=%d:%s", file_header_.root_page, rc, strrc(rc));
return rc;
} }
if (leaf->key_num == 0) { IndexNode *node = (IndexNode *)page_handle.data();
return RC::SUCCESS; while (false == node->is_leaf) {
} InternalIndexNodeHandler internal_node(file_header_, page_handle);
PageNum page_num = child_page_getter(internal_node);
IndexNode *node = leaf; disk_buffer_pool_->unpin_page(&page_handle);
bool found = false;
while (node->parent != -1) {
int index = 0;
BPPageHandle parent_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->parent, &parent_handle); rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get pareent page, file_id:%d, parent_page:%d", LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, page_num);
file_id_,
node->parent);
return rc; return rc;
} }
char *pdata; node = (IndexNode *)page_handle.data();
disk_buffer_pool_->get_data(&parent_handle, &pdata);
node = get_index_node(pdata);
int tmp = 0;
while (index < node->key_num) {
tmp = key_compare(file_header_.attr_type,
file_header_.attr_length,
old_first_key,
node->keys + index * file_header_.key_length);
if (tmp == 0) {
found = true;
memcpy(node->keys + index * file_header_.key_length, leaf->keys, file_header_.key_length);
break;
} else if (tmp > 0) {
index++;
continue;
} else {
break;
}
}
disk_buffer_pool_->unpin_page(&parent_handle);
if (found == true) {
return RC::SUCCESS;
}
} }
if (found == false) {
LOG_INFO("The old fist key has been changed, leaf:%s", leaf->to_string(file_header_).c_str());
print_tree();
}
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::delete_entry_from_node(IndexNode *node, const char *pkey, int &node_delete_index)
{
int delete_index, tmp; RC BplusTreeHandler::insert_entry_into_leaf_node(BPPageHandle &page_handle, const char *key, const RID *rid)
for (delete_index = 0; delete_index < node->key_num; delete_index++) { {
tmp = key_compare( LeafIndexNodeHandler leaf_node(file_header_, page_handle);
file_header_.attr_type, file_header_.attr_length, pkey, node->keys + delete_index * file_header_.key_length); bool exists = false;
if (tmp == 0) { int insert_position = leaf_node.lookup(key_comparator_, key, &exists);
node_delete_index = delete_index; if (exists) {
break; LOG_TRACE("entry exists");
} return RC::RECORD_DUPLICATE_KEY;
}
if (delete_index >= node->key_num) {
// LOG_WARN("Failed to delete index of %d", file_id_);
return RC::RECORD_INVALID_KEY;
} }
delete_entry_from_node(node, delete_index); if (leaf_node.size() < leaf_node.max_size()) {
leaf_node.insert(insert_position, key, (const char *)rid);
// change parent's key page_handle.mark_dirty();
change_leaf_parent_key_delete(node, delete_index, pkey); disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
RC BplusTreeHandler::change_insert_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page)
{
if (left->is_leaf == false) {
return RC::SUCCESS; return RC::SUCCESS;
} }
if (right->next_brother != -1) { BPPageHandle new_page_handle;
PageNum next_right_page = right->next_brother; RC rc = split<LeafIndexNodeHandler>(page_handle, new_page_handle);
BPPageHandle next_right_handle; if (rc != RC::SUCCESS) {
RC rc = disk_buffer_pool_->get_this_page(file_id_, next_right_page, &next_right_handle); LOG_WARN("failed to split leaf node. rc=%d:%s", rc, strrc(rc));
if (rc != RC::SUCCESS) { return rc;
LOG_WARN("Failed to set link for leaf for node %s, file_id:%d", file_id_, right->to_string(file_header_).c_str());
return rc;
}
char *pdata;
disk_buffer_pool_->get_data(&next_right_handle, &pdata);
IndexNode *next_right = get_index_node(pdata);
next_right->prev_brother = right_page;
disk_buffer_pool_->mark_dirty(&next_right_handle);
disk_buffer_pool_->unpin_page(&next_right_handle);
} }
return RC::SUCCESS; LeafIndexNodeHandler new_index_node(file_header_, new_page_handle);
} new_index_node.set_prev_page(page_handle.page_num());
new_index_node.set_next_page(leaf_node.next_page());
RC BplusTreeHandler::change_delete_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page) new_index_node.set_parent_page_num(leaf_node.parent_page_num());
{ leaf_node.set_next_page(new_page_handle.page_num());
if (left->is_leaf == false) {
return RC::SUCCESS;
}
right->prev_brother = left->prev_brother; PageNum next_page_num = new_index_node.next_page();
if (left->prev_brother != -1) { if (next_page_num != BP_INVALID_PAGE_NUM) {
PageNum prev_left_page = left->prev_brother; BPPageHandle next_page_handle;
BPPageHandle prev_left_handle; rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &next_page_handle);
RC rc = disk_buffer_pool_->get_this_page(file_id_, prev_left_page, &prev_left_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to set link for leaf for node %s, file_id:%d", file_id_, right->to_string(file_header_).c_str()); LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc; return rc;
} }
char *pdata; LeafIndexNodeHandler next_node(file_header_, next_page_handle);
disk_buffer_pool_->get_data(&prev_left_handle, &pdata); next_node.set_prev_page(new_page_handle.page_num());
IndexNode *prev_left = get_index_node(pdata); disk_buffer_pool_->unpin_page(&next_page_handle);
prev_left->next_brother = right_page;
disk_buffer_pool_->mark_dirty(&prev_left_handle);
disk_buffer_pool_->unpin_page(&prev_left_handle);
}
return RC::SUCCESS;
}
/**
* merge left node into right node.
* @param parent_handle
* @param left_handle
* @param right_handle
* @param delete_index
* @return
*/
RC BplusTreeHandler::coalesce_node(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle,
int delete_index, bool check_change_leaf_key, int node_delete_index, const char *pkey)
{
PageNum left_page, right_page, parent_page;
IndexNode *left, *right, *parent;
char *pdata, *parent_key;
RC rc;
disk_buffer_pool_->get_page_num(&left_handle, &left_page);
disk_buffer_pool_->get_data(&left_handle, &pdata);
left = get_index_node(pdata);
disk_buffer_pool_->get_page_num(&right_handle, &right_page);
disk_buffer_pool_->get_data(&right_handle, &pdata);
right = get_index_node(pdata);
parent_page = left->parent;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
parent_key = (char *)mem_pool_item_->alloc();
if (parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(parent_key, parent->keys + delete_index * file_header_.key_length, file_header_.key_length);
merge_nodes(left, right, right_page, parent_key);
disk_buffer_pool_->mark_dirty(&left_handle);
disk_buffer_pool_->mark_dirty(&right_handle);
change_delete_leaf_link(left, right, right_page);
if (check_change_leaf_key) {
change_leaf_parent_key_delete(right, node_delete_index, pkey);
} }
rc = delete_entry_internal(parent_page, parent_key); if (insert_position < leaf_node.size()) {
if (rc != RC::SUCCESS) { leaf_node.insert(insert_position, key, (const char *)rid);
LOG_WARN("Failed to delete internal entry of index ", file_id_); } else {
new_index_node.insert(insert_position - leaf_node.size(), key, (const char *)rid);
// restore status
copy_node(left, right);
right->key_num = 0;
split_node(left, right, left_page, right_page, parent_key);
change_delete_leaf_link(left, right, left_page);
left->next_brother = right_page;
right->prev_brother = left_page;
mem_pool_item_->free(parent_key);
return rc;
} }
mem_pool_item_->free(parent_key); return insert_entry_into_parent(page_handle, new_page_handle, new_index_node.key_at(0));
return RC::SUCCESS;
} }
void BplusTreeHandler::change_children_parent(RID *rids, int rid_len, PageNum new_parent_page) RC BplusTreeHandler::insert_entry_into_parent(BPPageHandle &page_handle, BPPageHandle &new_page_handle, const char *key)
{ {
for (int i = 0; i < rid_len; i++) { RC rc = RC::SUCCESS;
RID rid = rids[i];
PageNum page_num = rid.page_num; IndexNodeHandler node_handler(file_header_, page_handle);
IndexNodeHandler new_node_handler(file_header_, new_page_handle);
PageNum parent_page_num = node_handler.parent_page_num();
BPPageHandle child_page_handle; if (parent_page_num == BP_INVALID_PAGE_NUM) {
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
// create new root page
BPPageHandle root_page;
rc = disk_buffer_pool_->allocate_page(file_id_, &root_page);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load child page %d of index %d when change child's parent.", file_id_, page_num); LOG_WARN("failed to allocate new root page. rc=%d:%s", rc, strrc(rc));
continue; return rc;
} }
char *pdata; InternalIndexNodeHandler root_node(file_header_, root_page);
disk_buffer_pool_->get_data(&child_page_handle, &pdata); root_node.init_empty();
root_node.create_new_root(page_handle.page_num(), key, new_page_handle.page_num());
node_handler.set_parent_page_num(root_page.page_num());
new_node_handler.set_parent_page_num(root_page.page_num());
IndexNode *child_node = get_index_node(pdata); page_handle.mark_dirty();
child_node->parent = new_parent_page; new_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->mark_dirty(&child_page_handle); file_header_.root_page = root_page.page_num();
disk_buffer_pool_->unpin_page(&child_page_handle); update_root_page_num(); // TODO
} root_page.mark_dirty();
} disk_buffer_pool_->unpin_page(&root_page);
/** return RC::SUCCESS;
* merge left node into right node;
*
* This function is contrary to split_node
*/
void BplusTreeHandler::merge_nodes(IndexNode *left_node, IndexNode *right_node, PageNum right_page, char *parent_key)
{
bool is_leaf = left_node->is_leaf;
int old_left_key_num = left_node->key_num;
int old_right_key_num = right_node->key_num;
int new_left_key_num = 0;
int new_right_key_num = old_left_key_num + old_right_key_num;
if (is_leaf == false) {
new_right_key_num++;
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
if (is_leaf) {
int delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = right_node->rids;
RID *to_rid = right_node->rids + delta;
len = old_right_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
from = left_node->keys;
to = right_node->keys;
len = old_left_key_num * file_header_.key_length;
memmove(to, from, len);
from_rid = left_node->rids;
to_rid = right_node->rids;
len = old_left_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
} else { } else {
int delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = right_node->rids; BPPageHandle parent_page_handle;
RID *to_rid = right_node->rids + delta; rc = disk_buffer_pool_->get_this_page(file_id_, parent_page_num, &parent_page_handle);
len = (old_right_key_num + 1) * sizeof(RID); if (rc != RC::SUCCESS) {
memmove(to_rid, from_rid, len); LOG_WARN("failed to insert entry into leaf. rc=%d:%s", rc, strrc(rc));
// should do more things to recover
return rc;
}
InternalIndexNodeHandler node(file_header_, parent_page_handle);
memcpy(right_node->keys + (delta - 1) * file_header_.key_length, parent_key, file_header_.key_length); /// current node is not in full mode, insert the entry and return
if (node.size() < node.max_size()) {
node.insert(key, new_page_handle.page_num(), key_comparator_);
new_node_handler.set_parent_page_num(parent_page_num);
from = left_node->keys; page_handle.mark_dirty();
to = right_node->keys; new_page_handle.mark_dirty();
len = old_left_key_num * file_header_.key_length; parent_page_handle.mark_dirty();
memmove(to, from, len); disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
from_rid = left_node->rids; } else {
to_rid = right_node->rids;
len = (old_left_key_num + 1) * sizeof(RID);
memmove(to_rid, from_rid, len);
change_children_parent(to_rid, len / sizeof(RID), right_page); // we should split the node and insert the entry and then insert new entry to current node's parent
BPPageHandle new_parent_page_handle;
rc = split<InternalIndexNodeHandler>(parent_page_handle, new_parent_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to split internal node. rc=%d:%s", rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
} else {
// insert into left or right ? decide by key compare result
InternalIndexNodeHandler new_node(file_header_, new_parent_page_handle);
if (key_comparator_(key, new_node.key_at(0)) > 0) {
new_node.insert(key, new_page_handle.page_num(), key_comparator_);
new_node_handler.set_parent_page_num(new_node.page_num());
} else {
node.insert(key, new_page_handle.page_num(), key_comparator_);
new_node_handler.set_parent_page_num(node.page_num());
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
rc = insert_entry_into_parent(parent_page_handle, new_parent_page_handle, new_node.key_at(0));
}
}
} }
return rc;
} }
/** /**
* split left node to two node * split one full node into two
* This function is contrary to merge_node * @param page_handle[inout] the node to split
* @param new_page_handle[out] the new node after split
* @param intert_position the intert position of new key
*/ */
void BplusTreeHandler::split_node( template <typename IndexNodeHandlerType>
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_parent_key) RC BplusTreeHandler::split(BPPageHandle &page_handle, BPPageHandle &new_page_handle)
{ {
bool is_leaf = left_node->is_leaf; IndexNodeHandlerType old_node(file_header_, page_handle);
int old_left_key_num = left_node->key_num;
int old_right_key_num = right_node->key_num; // right_node->key_num should be zero
int total_key_num = left_node->key_num + right_node->key_num;
int mid, new_left_key_num, new_right_key_num;
/**
* if node is leaf, all key will be distributed both in left and right node
* if node is intern node, all keys except the middle key will be distributed both in the left and the right node
*/
if (is_leaf == true) {
new_left_key_num = total_key_num / 2;
mid = new_left_key_num;
new_right_key_num = total_key_num - mid;
} else {
new_left_key_num = (total_key_num - 1) / 2;
mid = new_left_key_num + 1;
new_right_key_num = (total_key_num - mid);
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
if (is_leaf) { char *new_parent_key = (char *)mem_pool_item_->alloc();
memcpy(new_parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length); if (new_parent_key == nullptr) {
} else { LOG_WARN("Failed to alloc memory for new key. size=%d", file_header_.key_length);
memmove(new_parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length); return RC::NOMEM;
} }
char *from = left_node->keys + mid * file_header_.key_length; // add a new node
char *to = right_node->keys; RC rc = disk_buffer_pool_->allocate_page(file_id_, &new_page_handle);
int len = new_right_key_num * file_header_.key_length; if (rc != RC::SUCCESS) {
memmove(to, from, len); LOG_WARN("Failed to split index page due to failed to allocate page, file_id:%d. rc=%d:%s", file_id_, rc, strrc(rc));
return rc;
RID *from_rid = left_node->rids + mid; }
RID *to_rid = right_node->rids;
len = new_right_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
// handle the last rid IndexNodeHandlerType new_node(file_header_, new_page_handle);
if (is_leaf == false) { new_node.init_empty();
new_node.set_parent_page_num(old_node.parent_page_num());
RID *changed_rids = to_rid; old_node.move_half_to(new_node, disk_buffer_pool_, file_id_);
int changed_rids_len = len;
PageNum changed_page = right_page;
if (old_right_key_num == 0) { page_handle.mark_dirty();
memmove(right_node->rids + new_right_key_num, left_node->rids + old_left_key_num, sizeof(RID)); new_page_handle.mark_dirty();
changed_rids_len += sizeof(RID); return RC::SUCCESS;
} }
change_children_parent(changed_rids, changed_rids_len / sizeof(RID), changed_page); RC BplusTreeHandler::update_root_page_num()
} else { {
change_insert_leaf_link(left_node, right_node, right_page); BPPageHandle header_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, FIRST_INDEX_PAGE, &header_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch header page. rc=%d:%s", rc, strrc(rc));
return rc;
} }
return; IndexFileHeader *header = (IndexFileHeader *)header_page_handle.data();
header->root_page = file_header_.root_page;
header_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&header_page_handle);
return rc;
} }
void BplusTreeHandler::copy_node(IndexNode *to, IndexNode *from)
{
memcpy(to->keys, from->keys, from->key_num * file_header_.key_length);
memcpy(to->rids, from->rids, (from->key_num + 1) * sizeof(RID));
memcpy(to, from, sizeof(IndexNode));
}
void BplusTreeHandler::redistribute_nodes( RC BplusTreeHandler::create_new_tree(const char *key, const RID *rid)
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *parent_key)
{ {
bool is_leaf = left_node->is_leaf; RC rc = RC::SUCCESS;
int old_left_key_num = left_node->key_num; if (file_header_.root_page != BP_INVALID_PAGE_NUM) {
int old_right_key_num = right_node->key_num; rc = RC::INTERNAL;
int total_key_num = left_node->key_num + right_node->key_num; LOG_WARN("cannot create new tree while root page is valid. root page id=%d", file_header_.root_page);
if (is_leaf == false) { return rc;
total_key_num++;
} }
// mid represent the parent key's position BPPageHandle page_handle;
int mid, new_left_key_num, new_right_key_num; rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle);
if (rc != RC::SUCCESS) {
/** LOG_WARN("failed to allocate root page. rc=%d:%s", rc, strrc(rc));
* if node is leaf, all key will be distributed both in left and right node return rc;
* if node is intern node, all keys except the middle key will be distributed both in the left and the right node
*/
if (is_leaf == true) {
new_left_key_num = total_key_num / 2;
mid = new_left_key_num;
new_right_key_num = total_key_num - mid;
} else {
new_left_key_num = (total_key_num - 1) / 2;
mid = new_left_key_num + 1;
new_right_key_num = (total_key_num - mid);
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
RID *changed_rids = nullptr;
int changed_rids_len = 0;
PageNum changed_page = 0;
int delta = old_left_key_num - new_left_key_num;
if (delta == 0) {
return;
} else if (delta > 0) {
// move kv from left to right
delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = right_node->rids;
RID *to_rid = right_node->rids + delta;
len = old_right_key_num * sizeof(RID);
if (left_node->is_leaf == false) {
len += sizeof(RID);
}
memmove(to_rid, from_rid, len);
if (is_leaf == false) {
memcpy(left_node->keys + old_left_key_num * file_header_.key_length, parent_key, file_header_.key_length);
}
delta = old_left_key_num - new_left_key_num;
from = left_node->keys + mid * file_header_.key_length;
to = right_node->keys;
len = delta * file_header_.key_length;
memmove(to, from, len);
from_rid = left_node->rids + mid;
to_rid = right_node->rids;
len = delta * sizeof(RID);
memmove(to_rid, from_rid, len);
changed_rids = to_rid;
changed_rids_len = len;
changed_page = right_page;
if (is_leaf) {
memcpy(parent_key, right_node->keys, file_header_.key_length);
} else {
memmove(parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length);
}
} else {
// move kv from right to left
if (is_leaf == false) {
memcpy(left_node->keys + old_left_key_num * file_header_.key_length, parent_key, file_header_.key_length);
}
int start_pos = old_left_key_num;
int len = (new_left_key_num - old_left_key_num);
if (is_leaf == false) {
start_pos++;
len--;
}
char *from = right_node->keys;
char *to = left_node->keys + start_pos * file_header_.key_length;
memmove(to, from, len * file_header_.key_length);
RID *from_rid = right_node->rids;
RID *to_rid = left_node->rids + start_pos;
memmove(to_rid, from_rid, len * sizeof(RID));
changed_rids = to_rid;
changed_rids_len = (new_left_key_num - old_left_key_num) * sizeof(RID);
changed_page = left_page;
if (is_leaf == false) {
memcpy(parent_key, right_node->keys + len * file_header_.key_length, file_header_.key_length);
memcpy(left_node->rids + new_left_key_num, right_node->rids + len, sizeof(RID));
} else {
memcpy(parent_key, right_node->keys + len * file_header_.key_length, file_header_.key_length);
}
delta = old_right_key_num - new_right_key_num;
from = right_node->keys + delta * file_header_.key_length;
to = right_node->keys;
len = new_right_key_num * file_header_.key_length;
memmove(to, from, len);
from_rid = right_node->rids + delta;
to_rid = right_node->rids;
len = new_right_key_num * sizeof(RID);
if (left_node->is_leaf == false) {
len += sizeof(RID);
}
memmove(to_rid, from_rid, len);
} }
// handle the last rid LeafIndexNodeHandler leaf_node(file_header_, page_handle);
if (left_node->is_leaf == false) { leaf_node.init_empty();
change_children_parent(changed_rids, changed_rids_len / sizeof(RID), changed_page); leaf_node.insert(0, key, (const char *)rid);
} file_header_.root_page = page_handle.page_num();
page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
return; rc = update_root_page_num();
// disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return rc;
} }
RC BplusTreeHandler::redistribute_nodes( char *BplusTreeHandler::make_key(const char *user_key, const RID &rid)
BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle)
{ {
char *key = (char *)mem_pool_item_->alloc();
if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_);
return nullptr;
}
memcpy(key, user_key, file_header_.attr_length);
memcpy(key + file_header_.attr_length, &rid, sizeof(rid));
return key;
}
PageNum left_page, right_page; void BplusTreeHandler::free_key(char *key)
IndexNode *left, *right, *parent; {
char *pdata; mem_pool_item_->free(key);
}
disk_buffer_pool_->get_page_num(&left_handle, &left_page);
disk_buffer_pool_->get_data(&left_handle, &pdata);
left = get_index_node(pdata);
disk_buffer_pool_->get_page_num(&right_handle, &right_page);
disk_buffer_pool_->get_data(&right_handle, &pdata);
right = get_index_node(pdata);
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
int parent_change_pos = -1;
for (int k = 0; k < parent->key_num; k++) {
if (parent->rids[k].page_num == left_page) { RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid)
parent_change_pos = k; {
break; if (file_id_ < 0) {
} LOG_WARN("Index isn't ready!");
return RC::RECORD_CLOSED;
} }
if (parent_change_pos == -1) { if (user_key == nullptr || rid == nullptr) {
LOG_WARN("Failed to find the parent pos during redistribute node"); LOG_WARN("Invalid arguments, key is empty or rid is empty");
return RC::RECORD_INVALID_KEY; return RC::INVALID_ARGUMENT;
} }
char *parent_key = parent->keys + parent_change_pos * file_header_.key_length; char *key = make_key(user_key, *rid);
redistribute_nodes(left, right, left_page, right_page, parent_key); if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_);
disk_buffer_pool_->mark_dirty(&left_handle); return RC::NOMEM;
disk_buffer_pool_->mark_dirty(&right_handle); }
disk_buffer_pool_->mark_dirty(&parent_handle);
return RC::SUCCESS;
}
RC BplusTreeHandler::clean_root_after_delete(IndexNode *old_root) if (is_empty()) {
{ return create_new_tree(key, rid);
if (old_root->key_num > 0) {
return RC::SUCCESS;
} }
BPPageHandle root_handle; BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, old_root->rids[0].page_num, &root_handle); RC rc = find_leaf(key, page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get new root page %d of index %d", old_root->rids[0].page_num, file_id_); LOG_WARN("Failed to find leaf file_id:%d, %s. rc=%d:%s", file_id_, rid->to_string().c_str(), rc, strrc(rc));
mem_pool_item_->free(key);
return rc; return rc;
} }
char *pdata; rc = insert_entry_into_leaf_node(page_handle, key, rid);
disk_buffer_pool_->get_data(&root_handle, &pdata);
IndexNode *root = get_index_node(pdata);
root->parent = -1;
disk_buffer_pool_->mark_dirty(&root_handle);
swith_root(root_handle, root, old_root->rids[0].page_num);
return RC::SUCCESS;
}
RC BplusTreeHandler::can_merge_with_other(BPPageHandle *page_handle, PageNum page_num, bool *can_merge)
{
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get page of current delete page, file_id:%d, page:%d", LOG_TRACE("Failed to insert into leaf of index %d, rid:%s", file_id_, rid->to_string().c_str());
file_id_, disk_buffer_pool_->unpin_page(&page_handle);
page_num); mem_pool_item_->free(key);
// disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return rc; return rc;
} }
char *pdata;
disk_buffer_pool_->get_data(page_handle, &pdata);
IndexNode *node = get_index_node(pdata);
*can_merge = node->key_num > (file_header_.order / 2);
mem_pool_item_->free(key);
LOG_TRACE("insert entry success");
// disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeHandler::delete_entry_internal(PageNum page_num, const char *pkey) RC BplusTreeHandler::get_entry(const char *user_key, std::list<RID> &rids)
{ {
BPPageHandle page_handle; if (file_id_ < 0) {
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle); LOG_WARN("Index isn't ready!");
if (rc != RC::SUCCESS) { return RC::RECORD_CLOSED;
LOG_WARN(
"Failed to delete entry in index node, due to failed to get page!, file_id:%d, page:%d", file_id_, page_num);
return rc;
} }
char *pdata; LOG_INFO("before get entry");
rc = disk_buffer_pool_->get_data(&page_handle, &pdata); disk_buffer_pool_->check_all_pages_unpinned(file_id_);
BplusTreeScanner scanner(*this);
RC rc = scanner.open(user_key, true/*left_inclusive*/, user_key, true/*right_inclusive*/);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("failed to open scanner. rc=%d:%s", rc, strrc(rc));
return rc; return rc;
} }
IndexNode *node = get_index_node(pdata);
int node_delete_index = -1; RID rid;
rc = delete_entry_from_node(node, pkey, node_delete_index); while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
if (rc != RC::SUCCESS) { rids.push_back(rid);
LOG_WARN("Failed to delete index %d", file_id_);
return rc;
} }
disk_buffer_pool_->mark_dirty(&page_handle); scanner.close();
if (rc != RC::RECORD_EOF) {
LOG_WARN("scanner return error. rc=%d:%s", rc, strrc(rc));
} else {
rc = RC::SUCCESS;
}
LOG_INFO("after get entry");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return rc;
}
int min_key = file_header_.order / 2; RC BplusTreeHandler::adjust_root(BPPageHandle &root_page_handle)
if (node->key_num >= min_key) { {
disk_buffer_pool_->unpin_page(&page_handle); IndexNodeHandler root_node(file_header_, root_page_handle);
if (root_node.is_leaf() && root_node.size() > 0) {
root_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&root_page_handle);
return RC::SUCCESS; return RC::SUCCESS;
} }
if (node->parent == -1) { if (root_node.is_leaf()) {
if (node->key_num == 0 && node->is_leaf == false) { // this is a leaf and an empty node
rc = clean_root_after_delete(node); file_header_.root_page = BP_INVALID_PAGE_NUM;
if (rc != RC::SUCCESS) { } else {
LOG_WARN("Failed to clean root after delete all entry in the root, file_id:%d", file_id_); // this is an internal node and has only one child node
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num); InternalIndexNodeHandler internal_node(file_header_, root_page_handle);
disk_buffer_pool_->unpin_page(&page_handle);
return rc;
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->dispose_page(file_id_, page_num);
return RC::SUCCESS; const PageNum child_page_num = internal_node.value_at(0);
BPPageHandle child_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page_num, &child_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page. page num=%d, rc=%d:%s", child_page_num, rc, strrc(rc));
return rc;
} }
disk_buffer_pool_->unpin_page(&page_handle); IndexNodeHandler child_node(file_header_, child_page_handle);
return RC::SUCCESS; child_node.set_parent_page_num(BP_INVALID_PAGE_NUM);
disk_buffer_pool_->unpin_page(&child_page_handle);
file_header_.root_page = child_page_num;
} }
int delete_index = 0; update_root_page_num();
BPPageHandle parent_handle;
IndexNode *parent = nullptr;
rc = get_parent_changed_index(parent_handle, parent, node, page_num, delete_index); PageNum old_root_page_num = root_page_handle.page_num();
if (rc != RC::SUCCESS) { disk_buffer_pool_->unpin_page(&root_page_handle);
LOG_WARN("Failed to get parent delete index"); disk_buffer_pool_->dispose_page(file_id_, old_root_page_num);
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num); return RC::SUCCESS;
}
template <typename IndexNodeHandlerType>
RC BplusTreeHandler::coalesce_or_redistribute(BPPageHandle &page_handle)
{
IndexNodeHandlerType index_node(file_header_, page_handle);
if (index_node.size() >= index_node.min_size()) {
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_->unpin_page(&page_handle);
return rc; return RC::SUCCESS;
} }
bool can_merge_with_right = false; const PageNum parent_page_num = index_node.parent_page_num();
bool force_collapse_with_right = false; if (BP_INVALID_PAGE_NUM == parent_page_num) {
bool can_merge_with_left = false; // this is the root page
// bool force_collapse_with_left = false; if (index_node.size() > 1) {
PageNum left_page = 0, right_page = 0;
BPPageHandle right_handle, left_handle;
if (delete_index == 0) {
right_page = parent->rids[delete_index + 1].page_num;
rc = can_merge_with_other(&right_handle, right_page, &can_merge_with_right);
if (rc != RC::SUCCESS) {
goto cleanup;
}
if (can_merge_with_right == false) {
force_collapse_with_right = true;
}
} else {
left_page = parent->rids[delete_index - 1].page_num;
rc = can_merge_with_other(&left_handle, left_page, &can_merge_with_left);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed delete index, due to failed to get page, file_id:%d, page:%d", file_id_, left_page);
goto cleanup;
}
if (can_merge_with_left == false) {
// begin to merge with right
// force_collapse_with_left = true;
if (delete_index < parent->key_num) {
right_page = parent->rids[delete_index + 1].page_num;
rc = can_merge_with_other(&right_handle, right_page, &can_merge_with_right);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get right page of current delete page, file_id:%d, "
"right_page:$d",
file_id_,
right_page);
goto cleanup;
}
} // delete_index < parent->key_num - 1
} // if can_merge_with_left = false
} // delete_index = 0
if (can_merge_with_left) {
rc = redistribute_nodes(parent_handle, left_handle, page_handle);
} else if (can_merge_with_right) {
rc = redistribute_nodes(parent_handle, page_handle, right_handle);
change_leaf_parent_key_delete(node, node_delete_index, pkey);
} else if (force_collapse_with_right) {
rc = coalesce_node(parent_handle, page_handle, right_handle, delete_index, true, node_delete_index, pkey);
if (rc == RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->dispose_page(file_id_, page_num); } else {
page_handle.open = false; // adjust the root node
} adjust_root(page_handle);
} else {
rc = coalesce_node(parent_handle, left_handle, page_handle, delete_index - 1, false, node_delete_index, pkey);
if (rc == RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&left_handle);
disk_buffer_pool_->dispose_page(file_id_, left_page);
left_handle.open = false;
} }
return RC::SUCCESS;
} }
cleanup: BPPageHandle parent_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page_num, &parent_page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num); LOG_WARN("failed to fetch parent page. page id=%d, rc=%d:%s", parent_page_num, rc, strrc(rc));
}
if (right_handle.open) {
disk_buffer_pool_->unpin_page(&right_handle);
}
if (left_handle.open) {
disk_buffer_pool_->unpin_page(&left_handle);
}
disk_buffer_pool_->unpin_page(&parent_handle);
if (page_handle.open) {
disk_buffer_pool_->unpin_page(&page_handle); disk_buffer_pool_->unpin_page(&page_handle);
return rc;
} }
return rc; InternalIndexNodeHandler parent_index_node(file_header_, parent_page_handle);
} int index = parent_index_node.lookup(key_comparator_, index_node.key_at(index_node.size() - 1));
if (parent_index_node.value_at(index) != page_handle.page_num()) {
RC BplusTreeHandler::delete_entry(const char *data, const RID *rid) LOG_ERROR("lookup return an invalid value. index=%d, this page num=%d, but got %d",
{ index, page_handle.page_num(), parent_index_node.value_at(index));
if (file_id_ < 0) {
LOG_WARN("Failed to delete index entry, due to index is't ready");
return RC::RECORD_CLOSED;
} }
PageNum neighbor_page_num;
char *pkey = (char *)mem_pool_item_->alloc(); if (index == 0) {
if (nullptr == pkey) { neighbor_page_num = parent_index_node.value_at(1);
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length); } else {
return RC::NOMEM; neighbor_page_num = parent_index_node.value_at(index - 1);
} }
memcpy(pkey, data, file_header_.attr_length);
memcpy(pkey + file_header_.attr_length, rid, sizeof(*rid));
PageNum leaf_page; BPPageHandle neighbor_page_handle;
RC rc = find_leaf(pkey, &leaf_page); rc = disk_buffer_pool_->get_this_page(file_id_, neighbor_page_num, &neighbor_page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
mem_pool_item_->free(pkey); LOG_WARN("failed to fetch neighbor page. page id=%d, rc=%d:%s", neighbor_page_num, rc, strrc(rc));
// TODO do more thing to release resource
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
return rc; return rc;
} }
rc = delete_entry_internal(leaf_page, pkey);
if (rc != RC::SUCCESS) { IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
LOG_WARN("Failed to delete index %d", file_id_); if (index_node.size() + neighbor_node.size() > index_node.max_size()) {
mem_pool_item_->free(pkey); rc = redistribute<IndexNodeHandlerType>(neighbor_page_handle, page_handle, parent_page_handle, index);
return rc; } else {
rc = coalesce<IndexNodeHandlerType>(neighbor_page_handle, page_handle, parent_page_handle, index);
} }
mem_pool_item_->free(pkey); return rc;
return RC::SUCCESS;
} }
RC BplusTreeHandler::find_first_index_satisfied(CompOp compop, const char *key, PageNum *page_num, int *rididx) template <typename IndexNodeHandlerType>
RC BplusTreeHandler::coalesce(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index)
{ {
BPPageHandle page_handle; IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
IndexNode *node; IndexNodeHandlerType node(file_header_, page_handle);
PageNum leaf_page, next;
char *pdata, *pkey; InternalIndexNodeHandler parent_node(file_header_, parent_page_handle);
RC rc;
int i, tmp; BPPageHandle *left_page_handle = nullptr;
RID rid; BPPageHandle *right_page_handle = nullptr;
if (compop == LESS_THAN || compop == LESS_EQUAL || compop == NOT_EQUAL) { if (index == 0) {
rc = get_first_leaf_page(page_num); // neighbor node is at right
if (rc != RC::SUCCESS) { left_page_handle = &page_handle;
LOG_WARN("Failed to get first leaf page, index:%d", file_id_); right_page_handle = &neighbor_page_handle;
return rc; index++;
} } else {
*rididx = 0; left_page_handle = &neighbor_page_handle;
return RC::SUCCESS; right_page_handle = &page_handle;
} // neighbor is at left
rid.page_num = -1;
rid.slot_num = -1;
pkey = (char *)mem_pool_item_->alloc();
if (pkey == nullptr) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
} }
memcpy(pkey, key, file_header_.attr_length);
memcpy(pkey + file_header_.attr_length, &rid, sizeof(RID));
rc = find_leaf(pkey, &leaf_page); IndexNodeHandlerType left_node(file_header_, *left_page_handle);
IndexNodeHandlerType right_node(file_header_, *right_page_handle);
parent_node.remove(index);
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
RC rc = right_node.move_to(left_node, disk_buffer_pool_, file_id_);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to find leaf page of index %d", file_id_); LOG_WARN("failed to move right node to left. rc=%d:%s", rc, strrc(rc));
mem_pool_item_->free(pkey);
return rc; return rc;
} }
mem_pool_item_->free(pkey); // left_node.validate(key_comparator_);
next = leaf_page; if (left_node.is_leaf()) {
LeafIndexNodeHandler left_leaf_node(file_header_, *left_page_handle);
LeafIndexNodeHandler right_leaf_node(file_header_, *right_page_handle);
left_leaf_node.set_next_page(right_leaf_node.next_page());
while (next > 0) { PageNum next_right_page_num = right_leaf_node.next_page();
rc = disk_buffer_pool_->get_this_page(file_id_, next, &page_handle); if (next_right_page_num != BP_INVALID_PAGE_NUM) {
if (rc != RC::SUCCESS) { BPPageHandle next_right_page_handle;
LOG_WARN("Failed to scan index due to failed to load page %d of index %d", next, file_id_); rc = disk_buffer_pool_->get_this_page(file_id_, next_right_page_num, &next_right_page_handle);
return rc; if (rc != RC::SUCCESS) {
} LOG_WARN("failed to fetch next right page. page number:%d. rc=%d:%s", next_right_page_num, rc, strrc(rc));
disk_buffer_pool_->get_data(&page_handle, &pdata); disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&neighbor_page_handle);
node = get_index_node(pdata); disk_buffer_pool_->unpin_page(&parent_page_handle);
for (i = 0; i < node->key_num; i++) { return rc;
tmp = attribute_comp(
node->keys + i * file_header_.key_length, key, file_header_.attr_type, file_header_.attr_length);
if (compop == EQUAL_TO || compop == GREAT_EQUAL) {
if (tmp >= 0) {
disk_buffer_pool_->get_page_num(&page_handle, page_num);
*rididx = i;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
}
if (compop == GREAT_THAN) {
if (tmp > 0) {
disk_buffer_pool_->get_page_num(&page_handle, page_num);
*rididx = i;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
} }
LeafIndexNodeHandler next_right_node(file_header_, next_right_page_handle);
next_right_node.set_prev_page(left_node.page_num());
disk_buffer_pool_->unpin_page(&next_right_page_handle);
} }
next = node->next_brother;
} }
disk_buffer_pool_->unpin_page(&page_handle);
return RC::RECORD_EOF; PageNum right_page_num = right_page_handle->page_num();
disk_buffer_pool_->unpin_page(left_page_handle);
disk_buffer_pool_->unpin_page(right_page_handle);
disk_buffer_pool_->dispose_page(file_id_, right_page_num);
return coalesce_or_redistribute<InternalIndexNodeHandler>(parent_page_handle);
} }
RC BplusTreeHandler::get_first_leaf_page(PageNum *leaf_page) template <typename IndexNodeHandlerType>
RC BplusTreeHandler::redistribute(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index)
{ {
RC rc; InternalIndexNodeHandler parent_node(file_header_, parent_page_handle);
BPPageHandle page_handle; IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
PageNum page_num; IndexNodeHandlerType node(file_header_, page_handle);
IndexNode *node; if (neighbor_node.size() < node.size()) {
char *pdata; LOG_ERROR("got invalid nodes. neighbor node size %d, this node size %d",
neighbor_node.size(), node.size());
node = root_node_; }
if (index == 0) {
while (node->is_leaf == false) { // the neighbor is at right
page_num = node->rids[0].page_num; neighbor_node.move_first_to_end(node, disk_buffer_pool_, file_id_);
if (page_handle.open) { // neighbor_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
disk_buffer_pool_->unpin_page(&page_handle); // node.validate(key_comparator_, disk_buffer_pool_, file_id_);
} parent_node.set_key_at(index + 1, neighbor_node.key_at(0));
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
} else {
// the neighbor is at left
neighbor_node.move_last_to_front(node, disk_buffer_pool_, file_id_);
// neighbor_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
// node.validate(key_comparator_, disk_buffer_pool_, file_id_);
parent_node.set_key_at(index, node.key_at(0));
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
}
neighbor_page_handle.mark_dirty();
page_handle.mark_dirty();
parent_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&parent_page_handle);
disk_buffer_pool_->unpin_page(&neighbor_page_handle);
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle); RC BplusTreeHandler::delete_entry_internal(BPPageHandle &leaf_page_handle, const char *key)
if (rc != RC::SUCCESS) { {
LOG_WARN("Failed to load page %d of index %d", page_num, file_id_); LeafIndexNodeHandler leaf_index_node(file_header_, leaf_page_handle);
return rc;
}
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata); const int remove_count = leaf_index_node.remove(key, key_comparator_);
if (remove_count == 0) {
LOG_TRACE("no data to remove");
disk_buffer_pool_->unpin_page(&leaf_page_handle);
return RC::RECORD_RECORD_NOT_EXIST;
} }
if (page_handle.open) { // leaf_index_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
disk_buffer_pool_->get_page_num(&page_handle, leaf_page);
disk_buffer_pool_->unpin_page(&page_handle); leaf_page_handle.mark_dirty();
} else {
disk_buffer_pool_->get_page_num(&root_page_handle_, leaf_page); if (leaf_index_node.size() >= leaf_index_node.min_size()) {
disk_buffer_pool_->unpin_page(&leaf_page_handle);
return RC::SUCCESS;
} }
return RC::SUCCESS; return coalesce_or_redistribute<LeafIndexNodeHandler>(leaf_page_handle);
} }
BplusTreeScanner::BplusTreeScanner(BplusTreeHandler &index_handler) : index_handler_(index_handler) RC BplusTreeHandler::delete_entry(const char *user_key, const RID *rid)
{}
RC BplusTreeScanner::open(CompOp comp_op, const char *value)
{ {
RC rc; if (file_id_ < 0) {
if (opened_) { LOG_WARN("Failed to delete index entry, due to index is't ready");
return RC::RECORD_OPENNED; return RC::RECORD_CLOSED;
} }
comp_op_ = comp_op; char *key = (char *)mem_pool_item_->alloc();
if (nullptr == key) {
char *value_copy = (char *)malloc(index_handler_.file_header_.attr_length); LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
if (value_copy == nullptr) {
LOG_WARN("Failed to alloc memory for value. size=%d", index_handler_.file_header_.attr_length);
return RC::NOMEM; return RC::NOMEM;
} }
memcpy(value_copy, value, index_handler_.file_header_.attr_length); memcpy(key, user_key, file_header_.attr_length);
value_ = value_copy; // mem_pool_item_->free value_ memcpy(key + file_header_.attr_length, rid, sizeof(*rid));
rc = index_handler_.find_first_index_satisfied(comp_op, value, &next_page_num_, &index_in_node_);
LOG_INFO("before delete");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
BPPageHandle leaf_page_handle;
RC rc = find_leaf(key, leaf_page_handle);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
if (rc == RC::RECORD_EOF) { LOG_WARN("failed to find leaf page. rc =%d:%s", rc, strrc(rc));
next_page_num_ = -1; mem_pool_item_->free(key);
index_in_node_ = -1; return rc;
} else }
return rc; rc = delete_entry_internal(leaf_page_handle, key);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index %d", file_id_);
mem_pool_item_->free(key);
return rc;
} }
num_fixed_pages_ = 1; mem_pool_item_->free(key);
next_index_of_page_handle_ = 0; LOG_INFO("after delete");
pinned_page_count_ = 0; disk_buffer_pool_->check_all_pages_unpinned(file_id_);
opened_ = true;
return RC::SUCCESS; return RC::SUCCESS;
} }
RC BplusTreeScanner::close() BplusTreeScanner::BplusTreeScanner(BplusTreeHandler &tree_handler) : tree_handler_(tree_handler)
{}
BplusTreeScanner::~BplusTreeScanner()
{ {
if (!opened_) { close();
return RC::RECORD_SCANCLOSED;
}
free((void *)value_);
value_ = nullptr;
opened_ = false;
return RC::SUCCESS;
} }
RC BplusTreeScanner::next_entry(RID *rid) RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
const char *right_user_key, bool right_inclusive)
{ {
RC rc; RC rc = RC::SUCCESS;
if (!opened_) { if (inited_) {
return RC::RECORD_CLOSED; LOG_WARN("tree scanner has been inited");
return RC::INTERNAL;
} }
rc = get_next_idx_in_memory(rid); //和RM中一样,有可能有错误,一次只查当前页和当前页的下一页,有待确定
if (rc == RC::RECORD_NO_MORE_IDX_IN_MEM) { inited_ = true;
rc = find_idx_pages();
// 校验输入的键值是否是合法范围
if (left_user_key && right_user_key) {
const auto &attr_comparator = tree_handler_.key_comparator_.attr_comparator();
const int result = attr_comparator(left_user_key, right_user_key);
if (result > 0 || // left < right
// left == right but is (left,right)/[left,right) or (left,right]
(result == 0 && (left_inclusive == false || right_inclusive == false))) {
return RC::INVALID_ARGUMENT;
}
}
if (nullptr == left_user_key) {
rc = tree_handler_.left_most_page(left_page_handle_);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left most page. rc=%d:%s", rc, strrc(rc));
return rc; return rc;
} }
rc = get_next_idx_in_memory(rid);
if (rc == RC::RECORD_NO_MORE_IDX_IN_MEM) { iter_index_ = 0;
rc = RC::RECORD_EOF;
}
return rc;
} else { } else {
char *left_key = nullptr;
if (left_inclusive) {
left_key = tree_handler_.make_key(left_user_key, *RID::min());
} else {
left_key = tree_handler_.make_key(left_user_key, *RID::max());
}
rc = tree_handler_.find_leaf(left_key, left_page_handle_);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left page. rc=%d:%s", rc, strrc(rc));
tree_handler_.free_key(left_key);
return rc; return rc;
} }
} LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_page_handle_);
return RC::SUCCESS; int left_index = left_node.lookup(tree_handler_.key_comparator_, left_key);
} tree_handler_.free_key(left_key);
// lookup 返回的是适合插入的位置,还需要判断一下是否在合适的边界范围内
if (left_index >= left_node.size()) { // 超出了当前页,就需要向后移动一个位置
const PageNum next_page_num = left_node.next_page();
if (next_page_num == BP_INVALID_PAGE_NUM) { // 这里已经是最后一页,说明当前扫描,没有数据
return RC::SUCCESS;
}
RC BplusTreeScanner::find_idx_pages() tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
{ rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, next_page_num, &left_page_handle_);
RC rc;
if (!opened_) {
return RC::RECORD_CLOSED;
}
if (pinned_page_count_ > 0) {
for (int i = 0; i < pinned_page_count_; i++) {
rc = index_handler_.disk_buffer_pool_->unpin_page(page_handles_ + i);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
return rc; LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc;
} }
left_index = 0;
} }
iter_index_ = left_index;
} }
next_index_of_page_handle_ = 0;
pinned_page_count_ = 0;
for (int i = 0; i < num_fixed_pages_; i++) { // 没有指定右边界范围,那么就返回右边界最大值
if (next_page_num_ <= 0) if (nullptr == right_user_key) {
break; rc = tree_handler_.right_most_page(right_page_handle_);
rc = index_handler_.disk_buffer_pool_->get_this_page(index_handler_.file_id_, next_page_num_, page_handles_ + i);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch right most page. rc=%d:%s", rc, strrc(rc));
return rc; return rc;
} }
char *pdata;
rc = index_handler_.disk_buffer_pool_->get_data(page_handles_ + i, &pdata); LeafIndexNodeHandler node(tree_handler_.file_header_, right_page_handle_);
end_index_ = node.size() - 1;
} else {
char *right_key = nullptr;
if (right_inclusive) {
right_key = tree_handler_.make_key(right_user_key, *RID::max());
} else {
right_key = tree_handler_.make_key(right_user_key, *RID::min());
}
rc = tree_handler_.find_leaf(right_key, right_page_handle_);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left page. rc=%d:%s", rc, strrc(rc));
tree_handler_.free_key(right_key);
return rc; return rc;
} }
IndexNode *node = index_handler_.get_index_node(pdata); LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_page_handle_);
pinned_page_count_++; int right_index = right_node.lookup(tree_handler_.key_comparator_, right_key);
next_page_num_ = node->next_brother; tree_handler_.free_key(right_key);
// lookup 返回的是适合插入的位置,需要根据实际情况做调整
// 通常情况下需要找到上一个位置
if (right_index > 0) {
right_index--;
} else {
// 实际上,只有最左边的叶子节点查找时,lookup 才可能返回0
// 其它的叶子节点都不可能返回0,所以这段逻辑其实是可以简化的
const PageNum prev_page_num = right_node.prev_page();
if (prev_page_num == BP_INVALID_PAGE_NUM) {
end_index_ = -1;
return RC::SUCCESS;
}
tree_handler_.disk_buffer_pool_->unpin_page(&right_page_handle_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, prev_page_num, &right_page_handle_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch prev page num. page num=%d, rc=%d:%s", prev_page_num, rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler tmp_node(tree_handler_.file_header_, right_page_handle_);
right_index = tmp_node.size() - 1;
}
end_index_ = right_index;
}
// 判断是否左边界比右边界要靠后
// 两个边界最多会多一页
// 查找不存在的元素,或者不存在的范围数据时,可能会存在这个问题
if (left_page_handle_.page_num() == right_page_handle_.page_num() &&
iter_index_ > end_index_) {
end_index_ = -1;
} else {
LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_page_handle_);
LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_page_handle_);
if (left_node.prev_page() == right_node.page_num()) {
end_index_ = -1;
}
} }
if (pinned_page_count_ > 0) return RC::SUCCESS;
return RC::SUCCESS;
return RC::RECORD_EOF;
} }
RC BplusTreeScanner::get_next_idx_in_memory(RID *rid) RC BplusTreeScanner::next_entry(RID *rid)
{ {
char *pdata; if (-1 == end_index_) {
IndexNode *node; return RC::RECORD_EOF;
RC rc;
if (next_index_of_page_handle_ >= pinned_page_count_) {
return RC::RECORD_NO_MORE_IDX_IN_MEM;
} }
if (next_page_num_ == -1 && index_in_node_ == -1) { LeafIndexNodeHandler node(tree_handler_.file_header_, left_page_handle_);
return RC::RECORD_EOF; memcpy(rid, node.value_at(iter_index_), sizeof(*rid));
if (left_page_handle_.page_num() == right_page_handle_.page_num() &&
iter_index_ == end_index_) {
end_index_ = -1;
return RC::SUCCESS;
} }
for (; next_index_of_page_handle_ < pinned_page_count_; next_index_of_page_handle_++) { if (iter_index_ < node.size() - 1) {
rc = index_handler_.disk_buffer_pool_->get_data(page_handles_ + next_index_of_page_handle_, &pdata); ++iter_index_;
if (rc != RC::SUCCESS) { return RC::SUCCESS;
LOG_WARN("Failed to get data from disk buffer pool. rc=%s", strrc); }
return rc;
}
node = index_handler_.get_index_node(pdata); RC rc = RC::SUCCESS;
for (; index_in_node_ < node->key_num; index_in_node_++) { if (left_page_handle_.page_num() != right_page_handle_.page_num()) {
if (satisfy_condition(node->keys + index_in_node_ * index_handler_.file_header_.key_length)) { PageNum page_num = node.next_page();
memcpy(rid, node->rids + index_in_node_, sizeof(RID)); tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
index_in_node_++; if (page_num == BP_INVALID_PAGE_NUM) {
return RC::SUCCESS; LOG_WARN("got invalid next page. page num=%d", page_num);
rc = RC::INTERNAL;
} else {
rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, page_num, &left_page_handle_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", page_num, rc, strrc(rc));
return rc;
} }
}
index_in_node_ = 0; iter_index_ = 0;
}
} else if (end_index_ != -1) {
LOG_WARN("should have more pages but not. left page=%d, right page=%d",
left_page_handle_.page_num(), right_page_handle_.page_num());
rc = RC::INTERNAL;
} }
return RC::RECORD_NO_MORE_IDX_IN_MEM; return rc;
} }
bool BplusTreeScanner::satisfy_condition(const char *pkey)
{
int i1 = 0, i2 = 0;
float f1 = 0, f2 = 0;
const char *s1 = nullptr, *s2 = nullptr;
if (comp_op_ == NO_OP) { RC BplusTreeScanner::close()
return true; {
if (left_page_handle_.open) {
tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
} }
if (right_page_handle_.open) {
AttrType attr_type = index_handler_.file_header_.attr_type; tree_handler_.disk_buffer_pool_->unpin_page(&right_page_handle_);
switch (attr_type) {
case INTS:
i1 = *(int *)pkey;
i2 = *(int *)value_;
break;
case FLOATS:
f1 = *(float *)pkey;
f2 = *(float *)value_;
break;
case CHARS:
s1 = pkey;
s2 = value_;
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
bool flag = false;
int attr_length = index_handler_.file_header_.attr_length;
switch (comp_op_) {
case EQUAL_TO:
switch (attr_type) {
case INTS:
flag = (i1 == i2);
break;
case FLOATS:
flag = 0 == float_compare(f1, f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) == 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case LESS_THAN:
switch (attr_type) {
case INTS:
flag = (i1 < i2);
break;
case FLOATS:
flag = (f1 < f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) < 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case GREAT_THAN:
switch (attr_type) {
case INTS:
flag = (i1 > i2);
break;
case FLOATS:
flag = (f1 > f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) > 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case LESS_EQUAL:
switch (attr_type) {
case INTS:
flag = (i1 <= i2);
break;
case FLOATS:
flag = (f1 <= f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) <= 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case GREAT_EQUAL:
switch (attr_type) {
case INTS:
flag = (i1 >= i2);
break;
case FLOATS:
flag = (f1 >= f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) >= 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case NOT_EQUAL:
switch (attr_type) {
case INTS:
flag = (i1 != i2);
break;
case FLOATS:
flag = 0 != float_compare(f1, f2);
break;
case CHARS:
flag = (strncmp(s1, s2, attr_length) != 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
default:
LOG_PANIC("Unknown comp op: %d", comp_op_);
} }
return flag; end_index_ = -1;
inited_ = false;
LOG_INFO("bplus tree scanner closed");
return RC::SUCCESS;
} }
...@@ -17,6 +17,7 @@ See the Mulan PSL v2 for more details. */ ...@@ -17,6 +17,7 @@ See the Mulan PSL v2 for more details. */
#ifndef __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_ #ifndef __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#define __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_ #define __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#include <string.h>
#include <sstream> #include <sstream>
#include "record_manager.h" #include "record_manager.h"
...@@ -26,16 +27,151 @@ See the Mulan PSL v2 for more details. */ ...@@ -26,16 +27,151 @@ See the Mulan PSL v2 for more details. */
#define EMPTY_RID_PAGE_NUM -1 #define EMPTY_RID_PAGE_NUM -1
#define EMPTY_RID_SLOT_NUM -1 #define EMPTY_RID_SLOT_NUM -1
class AttrComparator
{
public:
void init(AttrType type, int length)
{
attr_type_ = type;
attr_length_ = length;
}
int attr_length() const {
return attr_length_;
}
int operator()(const char *v1, const char *v2) const {
switch (attr_type_) {
case INTS: {
return *(int *)v1 - *(int *)v2;
}
break;
case FLOATS: {
float result = *(float *)v1 - *(float *)v2;
if (-1e-6 < result && result < 1e-6) {
return 0;
}
return result > 0 ? 1 : -1;
}
case CHARS: {
return strncmp(v1, v2, attr_length_);
}
default:{
LOG_ERROR("unknown attr type. %d", attr_type_);
abort();
}
}
}
private:
AttrType attr_type_;
int attr_length_;
};
class KeyComparator
{
public:
void init(AttrType type, int length)
{
attr_comparator_.init(type, length);
}
const AttrComparator &attr_comparator() const {
return attr_comparator_;
}
int operator() (const char *v1, const char *v2) const {
int result = attr_comparator_(v1, v2);
if (result != 0) {
return result;
}
const RID *rid1 = (const RID *)(v1 + attr_comparator_.attr_length());
const RID *rid2 = (const RID *)(v2 + attr_comparator_.attr_length());
return RID::compare(rid1, rid2);
}
private:
AttrComparator attr_comparator_;
};
class AttrPrinter
{
public:
void init(AttrType type, int length)
{
attr_type_ = type;
attr_length_ = length;
}
int attr_length() const {
return attr_length_;
}
std::string operator()(const char *v) const {
switch (attr_type_) {
case INTS: {
return std::to_string(*(int*)v);
}
break;
case FLOATS: {
return std::to_string(*(float*)v);
}
case CHARS: {
return std::string(v, attr_length_);
}
default:{
LOG_ERROR("unknown attr type. %d", attr_type_);
abort();
}
}
}
private:
AttrType attr_type_;
int attr_length_;
};
class KeyPrinter
{
public:
void init(AttrType type, int length)
{
attr_printer_.init(type, length);
}
const AttrPrinter &attr_printer() const {
return attr_printer_;
}
std::string operator() (const char *v) const {
std::stringstream ss;
ss << "{key:" << attr_printer_(v) << ",";
const RID *rid = (const RID *)(v + attr_printer_.attr_length());
ss << "rid:{" << rid->to_string() << "}}";
return ss.str();
}
private:
AttrPrinter attr_printer_;
};
/**
* the meta information of bplus tree
* this is the first page of bplus tree.
* only one field can be supported, can you extend it to multi-fields?
*/
struct IndexFileHeader { struct IndexFileHeader {
IndexFileHeader() IndexFileHeader()
{ {
memset(this, 0, sizeof(IndexFileHeader)); memset(this, 0, sizeof(IndexFileHeader));
root_page = BP_INVALID_PAGE_NUM;
} }
int attr_length; PageNum root_page;
int key_length; int32_t internal_max_size;
int32_t leaf_max_size;
int32_t attr_length;
int32_t key_length; // attr length + sizeof(RID)
AttrType attr_type; AttrType attr_type;
PageNum root_page;
int order;
const std::string to_string() const std::string to_string()
{ {
...@@ -45,74 +181,197 @@ struct IndexFileHeader { ...@@ -45,74 +181,197 @@ struct IndexFileHeader {
<< "key_length:" << key_length << "," << "key_length:" << key_length << ","
<< "attr_type:" << attr_type << "," << "attr_type:" << attr_type << ","
<< "root_page:" << root_page << "," << "root_page:" << root_page << ","
<< "order:" << order << ";"; << "internal_max_size:" << internal_max_size << ","
<< "leaf_max_size:" << leaf_max_size << ";";
return ss.str(); return ss.str();
} }
}; };
#define RECORD_RESERVER_PAIR_NUM 2 #define RECORD_RESERVER_PAIR_NUM 2
/**
* the common part of page describtion of bplus tree
* storage format:
* | page type | item number | parent page id |
*/
struct IndexNode { struct IndexNode {
static constexpr int HEADER_SIZE = 12;
bool is_leaf; bool is_leaf;
int key_num; int key_num;
PageNum parent; PageNum parent;
PageNum prev_brother; // valid when is_leaf = true };
PageNum next_brother; // valid when is_leaf = true
/**
* leaf page of bplus tree
* storage format:
* | common header | prev page id | next page id |
* | key0, rid0 | key1, rid1 | ... | keyn, ridn |
*
* the key is in format: the key value of record and rid.
* so the key in leaf page must be unique.
* the value is rid.
* can you implenment a cluster index ?
*/
struct LeafIndexNode : public IndexNode {
static constexpr int HEADER_SIZE = IndexNode::HEADER_SIZE + 8;
PageNum prev_brother;
PageNum next_brother;
/** /**
* leaf can store order keys and rids at most * leaf can store order keys and rids at most
*/
char array[0];
};
/**
* internal page of bplus tree
* storage format:
* | common header |
* | key(0),page_id(0) | key(1), page_id(1) | ... | key(n), page_id(n) |
*
* the first key is ignored(key0).
* so it will waste space, can you fix this?
*/
struct InternalIndexNode : public IndexNode {
static constexpr int HEADER_SIZE = IndexNode::HEADER_SIZE;
/**
* internal node just store order -1 keys and order rids, the last rid is last rght child. * internal node just store order -1 keys and order rids, the last rid is last rght child.
*/ */
char *keys; char array[0];
};
class IndexNodeHandler {
public:
IndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
void init_empty(bool leaf);
bool is_leaf() const;
int key_size() const;
int value_size() const;
int item_size() const;
void increase_size(int n);
int size() const;
void set_parent_page_num(PageNum page_num);
PageNum parent_page_num() const;
PageNum page_num() const;
bool validate() const;
friend std::string to_string(const IndexNodeHandler &handler);
protected:
const IndexFileHeader &header_;
PageNum page_num_;
IndexNode *node_;
};
class LeafIndexNodeHandler : public IndexNodeHandler {
public:
LeafIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
void init_empty();
void set_next_page(PageNum page_num);
void set_prev_page(PageNum page_num);
PageNum next_page() const;
PageNum prev_page() const;
char *key_at(int index);
char *value_at(int index);
/**
* 查找指定key的插入位置(注意不是key本身)
* 如果key已经存在,会设置found的值
* NOTE: 当前lookup的实现效率非常低,你是否可以优化它?
*/
int lookup(const KeyComparator &comparator, const char *key, bool *found = nullptr) const;
void insert(int index, const char *key, const char *value);
void remove(int index);
int remove(const char *key, const KeyComparator &comparator);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
/** /**
* In the node which isn't leaf, the rids point to child's page, * move all items to left page
* rids[i] is keys[i]'s left child, rids[key_num] is the last right child.
* In the node which is leaf, the rids point to record's rid.
*/ */
RID *rids; RC move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
void init_empty(IndexFileHeader &file_header) int max_size() const;
{ int min_size() const;
is_leaf = true;
key_num = 0;
parent = -1;
prev_brother = -1;
next_brother = -1;
keys = (char *)(this + 1);
rids = (RID *)(keys + (file_header.order + RECORD_RESERVER_PAIR_NUM) * file_header.key_length);
}
std::string to_string(IndexFileHeader &file_header) bool validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const;
{
std::stringstream ss;
ss << "is_leaf:" << is_leaf << "," friend std::string to_string(const LeafIndexNodeHandler &handler, const KeyPrinter &printer);
<< "key_num:" << key_num << "," private:
<< "parent:" << parent << "," char *__item_at(int index) const;
<< "prev_brother:" << prev_brother << "," char *__key_at(int index) const;
<< "next_brother:" << next_brother << ","; char *__value_at(int index) const;
if (file_header.attr_type == INTS) { // CHARS, INTS, FLOATS
ss << "start_key:" << *(int *)(keys) << ","
<< "end_key:" << *(int *)(keys + (key_num - 1) * file_header.key_length) << ";";
} else if (file_header.attr_type == FLOATS) {
ss << "start_key:" << *(float *)(keys) << ","
<< "end_key:" << *(float *)(keys + (key_num - 1) * file_header.key_length) << ";";
} else if (file_header.attr_type == CHARS) {
char *temp = (char *)malloc(file_header.attr_length + 1);
memset(temp, 0, file_header.attr_length + 1);
memcpy(temp, keys, file_header.attr_length);
ss << "start_key:" << temp << ",";
memcpy(temp, keys + (key_num - 1) * file_header.key_length, file_header.attr_length);
ss << "end_key:" << temp << ";";
free(temp);
} else {
ss << "Unkown key range." << std::endl;
}
return ss.str(); void append(const char *item);
} void preappend(const char *item);
private:
LeafIndexNode *leaf_node_;
};
class InternalIndexNodeHandler : public IndexNodeHandler {
public:
InternalIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
void init_empty();
void create_new_root(PageNum first_page_num, const char *key, PageNum page_num);
void insert(const char *key, PageNum page_num, const KeyComparator &comparator);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
char *key_at(int index);
PageNum value_at(int index);
/**
* 返回指定子节点在当前节点中的索引
*/
int value_index(PageNum page_num);
void set_key_at(int index, const char *key);
void remove(int index);
/**
* 与Leaf节点不同,lookup返回指定key应该属于哪个子节点,返回这个子节点在当前节点中的索引
* 如果想要返回插入位置,就提供 `insert_position` 参数
* NOTE: 查找效率不高,你可以优化它吗?
*/
int lookup(const KeyComparator &comparator, const char *key,
bool *found = nullptr, int *insert_position = nullptr) const;
int max_size() const;
int min_size() const;
RC move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
bool validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const;
friend std::string to_string(const InternalIndexNodeHandler &handler, const KeyPrinter &printer);
private:
RC copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool, int file_id);
RC append(const char *item, DiskBufferPool *bp, int file_id);
RC preappend(const char *item, DiskBufferPool *bp, int file_id);
private:
char *__item_at(int index) const;
char *__key_at(int index) const;
char *__value_at(int index) const;
int value_size() const;
int item_size() const;
private:
InternalIndexNode *internal_node_;
}; };
class BplusTreeHandler { class BplusTreeHandler {
...@@ -121,7 +380,8 @@ public: ...@@ -121,7 +380,8 @@ public:
* 此函数创建一个名为fileName的索引。 * 此函数创建一个名为fileName的索引。
* attrType描述被索引属性的类型,attrLength描述被索引属性的长度 * attrType描述被索引属性的类型,attrLength描述被索引属性的长度
*/ */
RC create(const char *file_name, AttrType attr_type, int attr_length); RC create(const char *file_name, AttrType attr_type, int attr_length,
int internal_max_size = -1, int leaf_max_size = -1);
/** /**
* 打开名为fileName的索引文件。 * 打开名为fileName的索引文件。
...@@ -137,22 +397,24 @@ public: ...@@ -137,22 +397,24 @@ public:
/** /**
* 此函数向IndexHandle对应的索引中插入一个索引项。 * 此函数向IndexHandle对应的索引中插入一个索引项。
* 参数pData指向要插入的属性值,参数rid标识该索引项对应的元组, * 参数user_key指向要插入的属性值,参数rid标识该索引项对应的元组,
* 即向索引中插入一个值为(*pData,rid)的键值对 * 即向索引中插入一个值为(user_key,rid)的键值对
*/ */
RC insert_entry(const char *pkey, const RID *rid); RC insert_entry(const char *user_key, const RID *rid);
/** /**
* 从IndexHandle句柄对应的索引中删除一个值为(*pData,rid)的索引项 * 从IndexHandle句柄对应的索引中删除一个值为(*pData,rid)的索引项
* @return RECORD_INVALID_KEY 指定值不存在 * @return RECORD_INVALID_KEY 指定值不存在
*/ */
RC delete_entry(const char *pkey, const RID *rid); RC delete_entry(const char *user_key, const RID *rid);
bool is_empty() const;
/** /**
* 获取指定值的record * 获取指定值的record
* @param rid 返回值,记录记录所在的页面号和slot * @param rid 返回值,记录记录所在的页面号和slot
*/ */
RC get_entry(const char *pkey, std::list<RID> &rids); RC get_entry(const char *user_key, std::list<RID> &rids);
RC sync(); RC sync();
...@@ -170,65 +432,60 @@ public: ...@@ -170,65 +432,60 @@ public:
public: public:
RC print_tree(); RC print_tree();
RC print_node(IndexNode *node, PageNum page_num);
RC print_leafs(); RC print_leafs();
private:
RC print_leaf(BPPageHandle &page_handle);
RC print_internal_node_recursive(BPPageHandle &page_handle);
bool validate_node(IndexNode *node); bool validate_node(IndexNode *node);
bool validate_leaf_link(); bool validate_leaf_link();
bool validate_node_recursive(BPPageHandle &page_handle);
protected: protected:
RC find_leaf(const char *pkey, PageNum *leaf_page); RC find_leaf(const char *key, BPPageHandle &page_handle);
RC left_most_page(BPPageHandle &page_handle);
RC right_most_page(BPPageHandle &page_handle);
RC find_leaf_internal(const std::function<PageNum(InternalIndexNodeHandler &)> &child_page_getter,
BPPageHandle &page_handle);
RC insert_into_parent( RC insert_into_parent(
PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle); PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC insert_intern_node(BPPageHandle &parent_page_handle, BPPageHandle &left_page_handle,
BPPageHandle &right_page_handle, const char *pkey);
RC split_leaf(BPPageHandle &leaf_page_handle); RC split_leaf(BPPageHandle &leaf_page_handle);
RC split_intern_node(BPPageHandle &parent_page_handle, const char *pkey);
RC delete_entry_internal(PageNum page_num, const char *pkey); RC delete_entry_internal(BPPageHandle &leaf_page_handle, const char *key);
RC coalesce_node(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle, int delete_index,
bool check_change_leaf_key, int node_delete_index, const char *pkey);
RC insert_into_new_root(BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle); RC insert_into_new_root(BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC clean_root_after_delete(IndexNode *old_root);
RC insert_entry_into_node(IndexNode *node, const char *pkey, const RID *rid, PageNum left_page);
RC delete_entry_from_node(IndexNode *node, const char *pkey, int &node_delete_index);
void delete_entry_from_node(IndexNode *node, const int delete_index);
RC redistribute_nodes(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle);
void redistribute_nodes(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_key);
void merge_nodes(IndexNode *left_node, IndexNode *right_node, PageNum left_page, char *parent_key);
RC can_merge_with_other(BPPageHandle *page_handle, PageNum page_num, bool *can_merge);
void split_node(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_parent_key);
void copy_node(IndexNode *to, IndexNode *from);
void get_entry_from_leaf(IndexNode *node, const char *pkey, std::list<RID> &rids, bool &continue_check);
RC find_first_index_satisfied(CompOp comp_op, const char *pkey, PageNum *page_num, int *rididx);
RC get_first_leaf_page(PageNum *leaf_page);
IndexNode *get_index_node(char *page_data) const;
void swith_root(BPPageHandle &new_root_page_handle, IndexNode *root, PageNum root_page);
void change_children_parent(RID *rid, int rid_len, PageNum new_parent_page);
RC get_parent_changed_index(
BPPageHandle &parent_handle, IndexNode *&parent, IndexNode *node, PageNum page_num, int &changed_index);
RC change_leaf_parent_key_insert(IndexNode *node, int changed_indx, PageNum page_num);
RC change_leaf_parent_key_delete(IndexNode *leaf, int delete_indx, const char *old_first_key);
RC change_insert_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page);
RC change_delete_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page);
template <typename IndexNodeHandlerType>
RC split(BPPageHandle &page_handle, BPPageHandle &new_page_handle);
template <typename IndexNodeHandlerType>
RC coalesce_or_redistribute(BPPageHandle &page_handle);
template <typename IndexNodeHandlerType>
RC coalesce(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index);
template <typename IndexNodeHandlerType>
RC redistribute(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index);
RC insert_entry_into_parent(BPPageHandle &page_handle, BPPageHandle &new_page_handle, const char *key);
RC insert_entry_into_leaf_node(BPPageHandle &page_handle, const char *pkey, const RID *rid);
RC update_root_page_num();
RC create_new_tree(const char *key, const RID *rid);
RC adjust_root(BPPageHandle &root_page_handle);
private:
char *make_key(const char *user_key, const RID &rid);
void free_key(char *key);
protected: protected:
DiskBufferPool *disk_buffer_pool_ = nullptr; DiskBufferPool *disk_buffer_pool_ = nullptr;
int file_id_ = -1; int file_id_ = -1;
bool header_dirty_ = false; bool header_dirty_ = false;
IndexFileHeader file_header_; IndexFileHeader file_header_;
BPPageHandle root_page_handle_; KeyComparator key_comparator_;
IndexNode *root_node_ = nullptr; KeyPrinter key_printer_;
common::MemPoolItem *mem_pool_item_ = nullptr; common::MemPoolItem *mem_pool_item_ = nullptr;
...@@ -239,73 +496,33 @@ private: ...@@ -239,73 +496,33 @@ private:
class BplusTreeScanner { class BplusTreeScanner {
public: public:
BplusTreeScanner(BplusTreeHandler &index_handler); BplusTreeScanner(BplusTreeHandler &tree_handler);
~BplusTreeScanner();
/** /**
* 用于在indexHandle对应的索引上初始化一个基于条件的扫描。 * 扫描指定范围的数据
* compOp和*value指定比较符和比较值,indexScan为初始化后的索引扫描结构指针 * @param left_key 扫描范围的左边界,如果是null,则没有左边界
* 没有带两个边界的范围扫描 * @param left_inclusive 左边界的值是否包含在内
* @param right_key 扫描范围的右边界。如果是null,则没有右边界
* @param right_inclusive 右边界的值是否包含在内
*/ */
RC open(CompOp comp_op, const char *value); RC open(const char *left_user_key, bool left_inclusive,
const char *right_user_key, bool right_inclusive);
/**
* 用于继续索引扫描,获得下一个满足条件的索引项,
* 并返回该索引项对应的记录的ID
*/
RC next_entry(RID *rid); RC next_entry(RID *rid);
/**
* 关闭一个索引扫描,释放相应的资源
*/
RC close(); RC close();
/**
* 获取由fileName指定的B+树索引内容,返回指向B+树的指针。
* 此函数提供给测试程序调用,用于检查B+树索引内容的正确性
*/
// RC getIndexTree(char *fileName, Tree *index);
private:
RC get_next_idx_in_memory(RID *rid);
RC find_idx_pages();
bool satisfy_condition(const char *key);
private: private:
BplusTreeHandler &index_handler_; bool inited_ = false;
bool opened_ = false; BplusTreeHandler &tree_handler_;
CompOp comp_op_ = NO_OP; // 用于比较的操作符
const char *value_ = nullptr; // 与属性行比较的值 /// 使用左右叶子节点和位置来表示扫描的起始位置和终止位置
int num_fixed_pages_ = -1; // 固定在缓冲区中的页,与指定的页面固定策略有关 /// 起始位置和终止位置都是有效的数据
int pinned_page_count_ = 0; // 实际固定在缓冲区的页面数 BPPageHandle left_page_handle_;
BPPageHandle page_handles_[BP_BUFFER_SIZE]; // 固定在缓冲区页面所对应的页面操作列表 BPPageHandle right_page_handle_;
int next_index_of_page_handle_ = -1; // 当前被扫描页面的操作索引 int iter_index_ = -1;
int index_in_node_ = -1; // 当前B+ Tree页面上的key index int end_index_ = -1; // use -1 for end of scan
PageNum next_page_num_ = -1; // 下一个将要被读入的页面号
};
class BplusTreeTester {
public:
BplusTreeTester(BplusTreeHandler &index_handler) : index_handler_(index_handler)
{}
~BplusTreeTester() = default;
void set_order(int order)
{
if (order >= 2 && order % 2 == 0) {
index_handler_.file_header_.order = order;
LOG_INFO("Successfully set index %d's order as %d", index_handler_.file_id_, order);
} else {
LOG_INFO("Invalid input order argument %d", order);
}
}
const int get_oder()
{
return index_handler_.file_header_.order;
}
protected:
BplusTreeHandler &index_handler_;
}; };
#endif //__OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_ #endif //__OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
\ No newline at end of file
...@@ -100,17 +100,16 @@ RC BplusTreeIndex::delete_entry(const char *record, const RID *rid) ...@@ -100,17 +100,16 @@ RC BplusTreeIndex::delete_entry(const char *record, const RID *rid)
return index_handler_.delete_entry(record + field_meta_.offset(), rid); return index_handler_.delete_entry(record + field_meta_.offset(), rid);
} }
IndexScanner *BplusTreeIndex::create_scanner(CompOp comp_op, const char *value) IndexScanner *BplusTreeIndex::create_scanner(const char *left_key, bool left_inclusive,
const char *right_key, bool right_inclusive)
{ {
BplusTreeScanner *bplus_tree_scanner = new BplusTreeScanner(index_handler_); BplusTreeIndexScanner *index_scanner = new BplusTreeIndexScanner(index_handler_);
RC rc = bplus_tree_scanner->open(comp_op, value); RC rc = index_scanner->open(left_key, left_inclusive, right_key, right_inclusive);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open index scanner. file_id:%d, rc=%d:%s", index_handler_.get_file_id(), rc, strrc(rc)); LOG_WARN("failed to open index scanner. rc=%d:%s", rc, strrc(rc));
delete bplus_tree_scanner; delete index_scanner;
return nullptr; return nullptr;
} }
BplusTreeIndexScanner *index_scanner = new BplusTreeIndexScanner(bplus_tree_scanner);
return index_scanner; return index_scanner;
} }
...@@ -120,22 +119,26 @@ RC BplusTreeIndex::sync() ...@@ -120,22 +119,26 @@ RC BplusTreeIndex::sync()
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
BplusTreeIndexScanner::BplusTreeIndexScanner(BplusTreeScanner *tree_scanner) : tree_scanner_(tree_scanner) BplusTreeIndexScanner::BplusTreeIndexScanner(BplusTreeHandler &tree_handler) : tree_scanner_(tree_handler)
{} {}
BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept
{ {
tree_scanner_->close(); tree_scanner_.close();
delete tree_scanner_; }
RC BplusTreeIndexScanner::open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive)
{
return tree_scanner_.open(left_key, left_inclusive, right_key, right_inclusive);
} }
RC BplusTreeIndexScanner::next_entry(RID *rid) RC BplusTreeIndexScanner::next_entry(RID *rid)
{ {
return tree_scanner_->next_entry(rid); return tree_scanner_.next_entry(rid);
} }
RC BplusTreeIndexScanner::destroy() RC BplusTreeIndexScanner::destroy()
{ {
delete this; delete this;
return RC::SUCCESS; return RC::SUCCESS;
} }
\ No newline at end of file
...@@ -30,7 +30,11 @@ public: ...@@ -30,7 +30,11 @@ public:
RC insert_entry(const char *record, const RID *rid) override; RC insert_entry(const char *record, const RID *rid) override;
RC delete_entry(const char *record, const RID *rid) override; RC delete_entry(const char *record, const RID *rid) override;
IndexScanner *create_scanner(CompOp comp_op, const char *value) override; /**
* 扫描指定范围的数据
*/
IndexScanner *create_scanner(const char *left_key, bool left_inclusive,
const char *right_key, bool right_inclusive) override;
RC sync() override; RC sync() override;
...@@ -41,14 +45,15 @@ private: ...@@ -41,14 +45,15 @@ private:
class BplusTreeIndexScanner : public IndexScanner { class BplusTreeIndexScanner : public IndexScanner {
public: public:
BplusTreeIndexScanner(BplusTreeScanner *tree_scanner); BplusTreeIndexScanner(BplusTreeHandler &tree_handle);
~BplusTreeIndexScanner() noexcept override; ~BplusTreeIndexScanner() noexcept override;
RC next_entry(RID *rid) override; RC next_entry(RID *rid) override;
RC destroy() override; RC destroy() override;
RC open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive);
private: private:
BplusTreeScanner *tree_scanner_; BplusTreeScanner tree_scanner_;
}; };
#endif //__OBSERVER_STORAGE_COMMON_BPLUS_TREE_INDEX_H_ #endif //__OBSERVER_STORAGE_COMMON_BPLUS_TREE_INDEX_H_
...@@ -46,7 +46,8 @@ public: ...@@ -46,7 +46,8 @@ public:
virtual RC insert_entry(const char *record, const RID *rid) = 0; virtual RC insert_entry(const char *record, const RID *rid) = 0;
virtual RC delete_entry(const char *record, const RID *rid) = 0; virtual RC delete_entry(const char *record, const RID *rid) = 0;
virtual IndexScanner *create_scanner(CompOp comp_op, const char *value) = 0; virtual IndexScanner *create_scanner(const char *left_key, bool left_inclusive,
const char *right_key, bool right_inclusive) = 0;
virtual RC sync() = 0; virtual RC sync() = 0;
...@@ -63,8 +64,12 @@ public: ...@@ -63,8 +64,12 @@ public:
IndexScanner() = default; IndexScanner() = default;
virtual ~IndexScanner() = default; virtual ~IndexScanner() = default;
/**
* 遍历元素数据
* 如果没有更多的元素,返回RECORD_EOF
*/
virtual RC next_entry(RID *rid) = 0; virtual RC next_entry(RID *rid) = 0;
virtual RC destroy() = 0; virtual RC destroy() = 0;
}; };
#endif // __OBSERVER_STORAGE_COMMON_INDEX_H_ #endif // __OBSERVER_STORAGE_COMMON_INDEX_H_
\ No newline at end of file
...@@ -17,7 +17,7 @@ See the Mulan PSL v2 for more details. */ ...@@ -17,7 +17,7 @@ See the Mulan PSL v2 for more details. */
#include <sstream> #include <sstream>
#include "storage/default/disk_buffer_pool.h" #include "storage/default/disk_buffer_pool.h"
typedef int SlotNum; typedef int32_t SlotNum;
class ConditionFilter; class ConditionFilter;
...@@ -48,6 +48,11 @@ struct RID { ...@@ -48,6 +48,11 @@ struct RID {
return page_num == other.page_num && slot_num == other.slot_num; return page_num == other.page_num && slot_num == other.slot_num;
} }
bool operator!=(const RID &other) const
{
return !(*this == other);
}
static int compare(const RID *rid1, const RID *rid2) static int compare(const RID *rid1, const RID *rid2)
{ {
int page_diff = rid1->page_num - rid2->page_num; int page_diff = rid1->page_num - rid2->page_num;
...@@ -57,6 +62,22 @@ struct RID { ...@@ -57,6 +62,22 @@ struct RID {
return rid1->slot_num - rid2->slot_num; return rid1->slot_num - rid2->slot_num;
} }
} }
/**
* 返回一个不可能出现的最小的RID
* 虽然page num 0和slot num 0都是合法的,但是page num 0通常用于存放meta数据,所以对数据部分来说都是
* 不合法的. 这里在bplus tree中查找时会用到。
*/
static RID *min()
{
static RID rid{0, 0};
return &rid;
}
static RID *max()
{
static RID rid{std::numeric_limits<PageNum>::max(), std::numeric_limits<SlotNum>::max()};
return &rid;
}
}; };
class RidDigest { class RidDigest {
...@@ -222,4 +243,4 @@ private: ...@@ -222,4 +243,4 @@ private:
RecordPageHandler record_page_handler_; RecordPageHandler record_page_handler_;
}; };
#endif //__OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_ #endif //__OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_
\ No newline at end of file
...@@ -768,7 +768,43 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) ...@@ -768,7 +768,43 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter)
return nullptr; return nullptr;
} }
return index->create_scanner(filter.comp_op(), (const char *)value_cond_desc->value); const char *left_key = nullptr;
const char *right_key = nullptr;
bool left_inclusive = false;
bool right_inclusive = false;
switch (filter.comp_op()) {
case EQUAL_TO: {
left_key = (const char *)value_cond_desc->value;
right_key = (const char *)value_cond_desc->value;
left_inclusive = true;
right_inclusive = true;
}
break;
case LESS_EQUAL: {
right_key = (const char *)value_cond_desc->value;
right_inclusive = true;
}
break;
case GREAT_EQUAL: {
left_key = (const char *)value_cond_desc->value;
left_inclusive = true;
}
break;
case LESS_THAN: {
right_key = (const char *)value_cond_desc->value;
right_inclusive = false;
}
break;
case GREAT_THAN: {
left_key = (const char *)value_cond_desc->value;
left_inclusive = false;
}
break;
default: {
return nullptr;
}
}
return index->create_scanner(left_key, left_inclusive, right_key, right_inclusive);
} }
IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter)
......
...@@ -478,7 +478,7 @@ RC DiskBufferPool::purge_page(int file_id, PageNum page_num) ...@@ -478,7 +478,7 @@ RC DiskBufferPool::purge_page(int file_id, PageNum page_num)
RC DiskBufferPool::purge_page(Frame *buf) RC DiskBufferPool::purge_page(Frame *buf)
{ {
if (buf->pin_count > 0) { if (buf->pin_count > 0) {
LOG_INFO("Begin to free page %d of %d, but it's pinned, pin_count:%d.", LOG_INFO("Begin to free page %d of %d(file id), but it's pinned, pin_count:%d.",
buf->page.page_num, buf->page.page_num,
buf->file_desc, buf->file_desc,
buf->pin_count); buf->pin_count);
...@@ -488,12 +488,12 @@ RC DiskBufferPool::purge_page(Frame *buf) ...@@ -488,12 +488,12 @@ RC DiskBufferPool::purge_page(Frame *buf)
if (buf->dirty) { if (buf->dirty) {
RC rc = flush_page(buf); RC rc = flush_page(buf);
if (rc != RC::SUCCESS) { if (rc != RC::SUCCESS) {
LOG_WARN("Failed to flush page %d of %d during purge page.", buf->page.page_num, buf->file_desc); LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page.page_num, buf->file_desc);
return rc; return rc;
} }
} }
LOG_DEBUG("Successfully purge frame =%p, page %d of %d", buf, buf->page.page_num, buf->file_desc); LOG_DEBUG("Successfully purge frame =%p, page %d of %d(file desc)", buf, buf->page.page_num, buf->file_desc);
bp_manager_.free(buf); bp_manager_.free(buf);
return RC::SUCCESS; return RC::SUCCESS;
} }
...@@ -533,7 +533,8 @@ RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle) ...@@ -533,7 +533,8 @@ RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle)
for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) { for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
Frame *frame = *it; Frame *frame = *it;
if (frame->pin_count > 0) { if (frame->pin_count > 0) {
LOG_WARN("The page has been pinned, file_id:%d, pagenum:%d", frame->file_desc, frame->page.page_num); LOG_WARN("The page has been pinned, file_desc:%d, pagenum:%d, pin_count=%d",
frame->file_desc, frame->page.page_num, frame->pin_count);
continue; continue;
} }
if (frame->dirty) { if (frame->dirty) {
...@@ -548,6 +549,29 @@ RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle) ...@@ -548,6 +549,29 @@ RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle)
return RC::SUCCESS; return RC::SUCCESS;
} }
RC DiskBufferPool::check_all_pages_unpinned(int file_id)
{
RC rc = check_file_id(file_id);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush pages due to invalid file_id %d", file_id);
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
std::list<Frame *> frames = bp_manager_.find_list(file_handle->file_desc);
for (auto & frame : frames) {
if (frame->page.page_num == 0 && frame->pin_count > 1) {
LOG_WARN("This page has been pinned. file id=%d, page num:%d, pin count=%d",
file_id, frame->page.page_num, frame->pin_count);
} else if (frame->page.page_num != 0 && frame->pin_count > 0) {
LOG_WARN("This page has been pinned. file id=%d, page num:%d, pin count=%d",
file_id, frame->page.page_num, frame->pin_count);
}
}
LOG_INFO("all pages have been checked of file id %d", file_id);
return RC::SUCCESS;
}
RC DiskBufferPool::flush_page(Frame *frame) RC DiskBufferPool::flush_page(Frame *frame)
{ {
// The better way is use mmap the block into memory, // The better way is use mmap the block into memory,
......
...@@ -69,6 +69,16 @@ typedef struct BPPageHandle { ...@@ -69,6 +69,16 @@ typedef struct BPPageHandle {
BPPageHandle() : open(false), frame(nullptr) BPPageHandle() : open(false), frame(nullptr)
{} {}
PageNum page_num() const {
return frame->page.page_num;
}
void mark_dirty() {
this->frame->dirty = true;
}
char *data() {
return this->frame->page.data;
}
bool open; bool open;
Frame *frame; Frame *frame;
} BPPageHandle; } BPPageHandle;
...@@ -195,6 +205,8 @@ public: ...@@ -195,6 +205,8 @@ public:
RC purge_all_pages(int file_id); RC purge_all_pages(int file_id);
RC check_all_pages_unpinned(int file_id);
protected: protected:
RC allocate_page(Frame **buf); RC allocate_page(Frame **buf);
......
...@@ -40,6 +40,7 @@ int k = 0; ...@@ -40,6 +40,7 @@ int k = 0;
void test_insert() void test_insert()
{ {
RC rc = RC::SUCCESS;
for (int i = 0; i < insert_num; i++) { for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size; rid.page_num = i / page_size;
...@@ -51,10 +52,11 @@ void test_insert() ...@@ -51,10 +52,11 @@ void test_insert()
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str()); LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Insert %d", i); LOG_INFO("Insert %d. rid=%s", i, rid.to_string().c_str());
} }
RC rc = handler->insert_entry((const char *)&i, &rid); rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
handler->print_tree();
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
} }
} }
...@@ -71,10 +73,11 @@ void test_insert() ...@@ -71,10 +73,11 @@ void test_insert()
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str()); LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Insert %d", i); LOG_INFO("Insert %d. rid=%s", i, rid.to_string().c_str());
} }
RC rc = handler->insert_entry((const char *)&i, &rid); rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
handler->print_tree();
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
} }
} }
...@@ -91,9 +94,9 @@ void test_insert() ...@@ -91,9 +94,9 @@ void test_insert()
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str()); LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Insert %d", i); LOG_INFO("Insert %d. rid=%s", i, rid.to_string().c_str());
} }
RC rc = handler->insert_entry((const char *)&i, &rid); rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
} }
...@@ -114,11 +117,14 @@ void test_insert() ...@@ -114,11 +117,14 @@ void test_insert()
LOG_INFO("Begin to check duplicated insert the page's num %s", rid.to_string().c_str()); LOG_INFO("Begin to check duplicated insert the page's num %s", rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Check duplicate insert %d", i); LOG_INFO("check duplicate Insert %d. rid=%s. i%TIMES=%d", i, rid.to_string().c_str(), i%TIMES);
} }
RC rc = handler->insert_entry((const char *)&i, &rid); rc = handler->insert_entry((const char *)&i, &rid);
int t = i % TIMES; int t = i % TIMES;
if (t == 0 || t == 1 || t == 2) { if (t == 0 || t == 1 || t == 2) {
if (rc != RC::RECORD_DUPLICATE_KEY) {
LOG_WARN("insert duplicate key success");
}
ASSERT_EQ(RC::RECORD_DUPLICATE_KEY, rc); ASSERT_EQ(RC::RECORD_DUPLICATE_KEY, rc);
} else { } else {
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
...@@ -154,6 +160,7 @@ void test_get() ...@@ -154,6 +160,7 @@ void test_get()
void test_delete() void test_delete()
{ {
RC rc = RC::SUCCESS;
std::list<RID> rids; std::list<RID> rids;
for (int i = 0; i < insert_num / 2; i++) { for (int i = 0; i < insert_num / 2; i++) {
...@@ -164,16 +171,19 @@ void test_delete() ...@@ -164,16 +171,19 @@ void test_delete()
if (t == 0 || t == 1) { if (t == 0 || t == 1) {
if (insert_num > page_size) { if (insert_num > page_size) {
if (k++ % 100 == 0) { if (k++ % 100 == 0) {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to delete entry of index, i=%d rid: %s", i, rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to delete entry of index, i=%d, rid: %s", i, rid.to_string().c_str());
} }
RC rc = handler->delete_entry((const char *)&i, &rid); rc = handler->delete_entry((const char *)&i, &rid);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to delete entry. i=%d, rid=%s", i, rid.to_string().c_str());
}
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc);
} }
} }
...@@ -192,7 +202,7 @@ void test_delete() ...@@ -192,7 +202,7 @@ void test_delete()
} else { } else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
} }
RC rc = handler->delete_entry((const char *)&i, &rid); rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
...@@ -205,20 +215,26 @@ void test_delete() ...@@ -205,20 +215,26 @@ void test_delete()
rid.slot_num = i % page_size; rid.slot_num = i % page_size;
if (insert_num > page_size) { if (insert_num > page_size) {
if (k++ % 100 == 0) { if (k++ % 100 == 0) {
LOG_INFO("Begin to get entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to get entry of index, i=%d,rid: %s", i, rid.to_string().c_str());
} }
} else { } else {
LOG_INFO("Begin to get entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to get entry of index, i=%d, rid: %s", i, rid.to_string().c_str());
} }
rids.clear(); rids.clear();
RC rc = handler->get_entry((const char *)&i, rids); rc = handler->get_entry((const char *)&i, rids);
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
int t = i % TIMES; int t = i % TIMES;
if (t == 0 || t == 1) { if (t == 0 || t == 1) {
ASSERT_EQ(0, rids.size()); ASSERT_EQ(0, rids.size());
} else { } else {
if (rids.size() != 1) {
LOG_WARN("invalid. i=%d, rid=%s, check rid=%s", i, rid.to_string().c_str(), check_rid.to_string().c_str());
}
ASSERT_EQ(1, rids.size()); ASSERT_EQ(1, rids.size());
check_rid = rids.front(); check_rid = rids.front();
if (rid != check_rid) {
LOG_WARN("invalid. i=%d, rid=%s, check rid=%s", i, rid.to_string().c_str(), check_rid.to_string().c_str());
}
ASSERT_EQ(rid.page_num, check_rid.page_num); ASSERT_EQ(rid.page_num, check_rid.page_num);
ASSERT_EQ(rid.slot_num, check_rid.slot_num); ASSERT_EQ(rid.slot_num, check_rid.slot_num);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
...@@ -239,7 +255,7 @@ void test_delete() ...@@ -239,7 +255,7 @@ void test_delete()
} else { } else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
} }
RC rc = handler->delete_entry((const char *)&i, &rid); rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
...@@ -261,7 +277,7 @@ void test_delete() ...@@ -261,7 +277,7 @@ void test_delete()
} else { } else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
} }
RC rc = handler->delete_entry((const char *)&i, &rid); rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree()); ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
...@@ -280,7 +296,7 @@ void test_delete() ...@@ -280,7 +296,7 @@ void test_delete()
} else { } else {
LOG_INFO("Begin to insert entry of index, rid: %s", rid.to_string().c_str()); LOG_INFO("Begin to insert entry of index, rid: %s", rid.to_string().c_str());
} }
RC rc = handler->insert_entry((const char *)&i, &rid); rc = handler->insert_entry((const char *)&i, &rid);
int t = i % TIMES; int t = i % TIMES;
if (t == 0 || t == 1 || t == 2) { if (t == 0 || t == 1 || t == 2) {
ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(RC::SUCCESS, rc);
...@@ -292,6 +308,385 @@ void test_delete() ...@@ -292,6 +308,385 @@ void test_delete()
handler->print_tree(); handler->print_tree();
} }
TEST(test_bplus_tree, test_leaf_index_node_handle)
{
LoggerFactory::init_default("test.log");
IndexFileHeader index_file_header;
index_file_header.root_page = BP_INVALID_PAGE_NUM;
index_file_header.internal_max_size = 5;
index_file_header.leaf_max_size = 5;
index_file_header.attr_length = 4;
index_file_header.key_length = 4 + sizeof(RID);
index_file_header.attr_type = INTS;
Frame frame;
frame.dirty = false;
frame.pin_count = 0;
frame.acc_time = 0;
frame.file_desc = 0;
frame.page.page_num = 100;
BPPageHandle page_handle;
page_handle.open = true;
page_handle.frame = &frame;
KeyComparator key_comparator;
key_comparator.init(INTS, 4);
LeafIndexNodeHandler leaf_node(index_file_header, page_handle);
leaf_node.init_empty();
ASSERT_EQ(0, leaf_node.size());
bool found;
int index;
char key_mem[4 + sizeof(RID)];
int &key = *(int *)key_mem;
RID &rid = *(RID *)(key_mem + 4);
rid.page_num = 0;
rid.slot_num = 0;
for (int i = 0; i < 5; i++) {
key = i * 2 + 1;
index = leaf_node.lookup(key_comparator, key_mem, &found);
ASSERT_EQ(false, found);
leaf_node.insert(index, (const char *)&key, (const char *)&rid);
}
ASSERT_EQ(5, leaf_node.size());
for (int i = 0; i < 5; i++) {
key = i * 2;
index = leaf_node.lookup(key_comparator, key_mem, &found);
ASSERT_EQ(false, found);
ASSERT_EQ(i, index);
}
key = 12;
index = leaf_node.lookup(key_comparator, key_mem, &found);
ASSERT_EQ(false, found);
ASSERT_EQ(5, index);
for (int i = 0; i < 5; i++) {
key = i * 2 + 1;
index = leaf_node.lookup(key_comparator, key_mem, &found);
if (!found || i != index) {
printf("found=%d, index=%d, key=%d", found, index, key);
}
ASSERT_EQ(true, found);
ASSERT_EQ(i, index);
}
}
TEST(test_bplus_tree, test_internal_index_node_handle)
{
LoggerFactory::init_default("test.log");
IndexFileHeader index_file_header;
index_file_header.root_page = BP_INVALID_PAGE_NUM;
index_file_header.internal_max_size = 5;
index_file_header.leaf_max_size = 5;
index_file_header.attr_length = 4;
index_file_header.key_length = 4 + sizeof(RID);
index_file_header.attr_type = INTS;
Frame frame;
frame.dirty = false;
frame.pin_count = 0;
frame.acc_time = 0;
frame.file_desc = 0;
frame.page.page_num = 100;
BPPageHandle page_handle;
page_handle.open = true;
page_handle.frame = &frame;
KeyComparator key_comparator;
key_comparator.init(INTS, 4);
InternalIndexNodeHandler internal_node(index_file_header, page_handle);
internal_node.init_empty();
ASSERT_EQ(0, internal_node.size());
bool found;
int index;
int insert_position;
char key_mem[4 + sizeof(RID)];
int &key = *(int *)key_mem;
RID &rid = *(RID *)(key_mem + 4);
rid.page_num = 0;
rid.slot_num = 0;
key = 3;
internal_node.create_new_root(1, key_mem, key);
for (int i = 2; i < 5; i++) {
key = i * 2 + 1;
internal_node.insert((const char *)&key, (PageNum)key, key_comparator);
}
ASSERT_EQ(5, internal_node.size());
for (int i = 1; i < 5; i++) {
key = i * 2 + 1;
int real_key = *(int*)internal_node.key_at(i);
ASSERT_EQ(key, real_key);
}
key = 0;
index = internal_node.lookup(key_comparator, key_mem, &found, &insert_position);
ASSERT_EQ(false, found);
ASSERT_EQ(0, index);
ASSERT_EQ(1, insert_position);
key = 2;
index = internal_node.lookup(key_comparator, key_mem, &found, &insert_position);
ASSERT_EQ(false, found);
ASSERT_EQ(0, index);
ASSERT_EQ(1, insert_position);
key = 4;
index = internal_node.lookup(key_comparator, key_mem, &found, &insert_position);
ASSERT_EQ(false, found);
ASSERT_EQ(1, index);
ASSERT_EQ(2, insert_position);
key = 8;
index = internal_node.lookup(key_comparator, key_mem, &found, &insert_position);
ASSERT_EQ(false, found);
ASSERT_EQ(3, index);
ASSERT_EQ(4, insert_position);
key = 10;
index = internal_node.lookup(key_comparator, key_mem, &found, &insert_position);
ASSERT_EQ(false, found);
ASSERT_EQ(4, index);
ASSERT_EQ(5, insert_position);
key = 12;
index = internal_node.lookup(key_comparator, key_mem, &found);
ASSERT_EQ(false, found);
ASSERT_EQ(4, index);
ASSERT_EQ(5, insert_position);
for (int i = 1; i < 5; i++) {
key = i * 2 + 1;
index = internal_node.lookup(key_comparator, key_mem, &found);
if (!found || i != index) {
printf("found=%d, index=%d, key=%d", found, index, key);
}
ASSERT_EQ(true, found);
ASSERT_EQ(i, index);
}
}
TEST(test_bplus_tree, test_scanner)
{
LoggerFactory::init_default("test.log");
DiskBufferPool::set_pool_num(POOL_NUM);
const char *index_name = "scanner.btree";
::remove(index_name);
handler = new BplusTreeHandler();
handler->create(index_name, INTS, sizeof(int), ORDER, ORDER);
int count = 0;
RC rc = RC::SUCCESS;
RID rid;
for (int i = 0; i < 100; i++) {
int key = i * 2 + 1;
rid.page_num = 0;
rid.slot_num = key;
rc = handler->insert_entry((const char *)&key, &rid);
ASSERT_EQ(RC::SUCCESS, rc);
}
handler->print_tree();
BplusTreeScanner scanner(*handler);
int begin = -100;
int end = -20;
rc = scanner.open((const char *)&begin, false, (const char *)&end, false);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = -100;
end = 1;
rc = scanner.open((const char *)&begin, false, (const char *)&end, false);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = -100;
end = 1;
rc = scanner.open((const char *)&begin, false, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 1;
end = 3;
rc = scanner.open((const char *)&begin, false, (const char *)&end, false/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 1;
end = 3;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(2, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 0;
end = 3;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(2, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 11;
end = 21;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ((end - begin) / 2 + 1, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 11;
end = 91;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ((end - begin) / 2 + 1, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 191;
end = 199;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ((end - begin) / 2 + 1, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 191;
end = 201;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(5, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 200;
end = 301;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
rc = scanner.next_entry(&rid);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 300;
end = 201;
rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::INVALID_ARGUMENT, rc);
scanner.close();
begin = 300;
end = 201;
rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(100, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 300;
end = 10;
rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(5, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 190;
end = 10;
rc = scanner.open((const char *)&begin, true, nullptr, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(5, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
begin = 190;
end = 10;
rc = scanner.open(nullptr, true, nullptr, true/*inclusive*/);
ASSERT_EQ(RC::SUCCESS, rc);
count = 0;
while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) {
count++;
}
ASSERT_EQ(100, count);
ASSERT_EQ(RC::RECORD_EOF, rc);
scanner.close();
}
TEST(test_bplus_tree, test_bplus_tree_insert) TEST(test_bplus_tree, test_bplus_tree_insert)
{ {
...@@ -301,10 +696,7 @@ TEST(test_bplus_tree, test_bplus_tree_insert) ...@@ -301,10 +696,7 @@ TEST(test_bplus_tree, test_bplus_tree_insert)
::remove(index_name); ::remove(index_name);
handler = new BplusTreeHandler(); handler = new BplusTreeHandler();
handler->create(index_name, INTS, sizeof(int)); handler->create(index_name, INTS, sizeof(int), ORDER, ORDER);
BplusTreeTester bplus_tree_tester(*handler);
bplus_tree_tester.set_order(ORDER);
test_insert(); test_insert();
...@@ -329,4 +721,4 @@ int main(int argc, char **argv) ...@@ -329,4 +721,4 @@ int main(int argc, char **argv)
int rc = RUN_ALL_TESTS(); int rc = RUN_ALL_TESTS();
return rc; return rc;
} }
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册