第一部分是关于page的部分,设置了B+树的page的各个内容,主要由以下三个内容组成。
(1)b_plus_tree_page.h和b_plus_tree_page.cpp
(2) b_plus_tree_internal_page.h和b_plus_tree_internal_page.cpp
(3) b_plus_tree_leaf_page.h和b_plus_tree_leaf_page.cpp
一、b_plus_tree_page.h和b_plus_tree_page.cpp
首先是一些判断页类型和设置页类型的函数:
bool IsLeafPage() const;
bool IsRootPage() const;
void SetPageType(IndexPageType t);//t是所需要设定的页类型
然后是一些大小的获取、设置和增加函数:
int GetSize() const;
void SetSize(int s);//s是要设定的大小
void IncreaseSize(int a);//a是要增加的数额
接着是一些最大尺寸和最小尺寸的获取函数:
int GetMaxSize() const;
void SetMaxSize(int s);//s是要设定的最大大小的大小
int GetMinSize() const;
最后是一些节点和父节点的id获取和设置函数:
page_id_t GetParentPageId() const;
void SetParentPageId(page_id_t p);//p是要设置的父节点的页号
page_id_t GetPageId() const;
void SetPageId(page_id_t p);//p是当前页要设置的页号
b_plus_tree_page.h的完整代码:
/**
* b_plus_tree_page.h
*
* Both internal and leaf page are inherited from this page.
*
* It actually serves as a header part for each B+ tree page and
* contains information shared by both leaf page and internal page.
*
* Header format (size in byte, 20 bytes in total):
* ----------------------------------------------------------------------------
* | PageType (4) | LSN (4) | CurrentSize (4) | MaxSize (4) |
* ----------------------------------------------------------------------------
* | ParentPageId (4) | PageId(4) |
* ----------------------------------------------------------------------------
*/
#pragma once
#include <cassert>
#include <climits>
#include <cstdlib>
#include <string>
#include "buffer/buffer_pool_manager.h"
#include "index/generic_key.h"
namespace scudb {
#define MappingType std::pair<KeyType, ValueType>
#define INDEX_TEMPLATE_ARGUMENTS \
template <typename KeyType, typename ValueType, typename KeyComparator>
// define page type enum
enum class IndexPageType { INVALID_INDEX_PAGE = 0, LEAF_PAGE, INTERNAL_PAGE };
enum class OpType { READ = 0, INSERT, DELETE };
// Abstract class.
class BPlusTreePage {
public:
bool IsLeafPage() const;
bool IsRootPage() const;
void SetPageType(IndexPageType t);//t是所需要设定的页类型
int GetSize() const;
void SetSize(int s);//s是要设定的大小
void IncreaseSize(int a);//a是要增加的数额
int GetMaxSize() const;
void SetMaxSize(int s);//s是要设定的最大大小的大小
int GetMinSize() const;
page_id_t GetParentPageId() const;
void SetParentPageId(page_id_t p);//p是要设置的父节点的页号
page_id_t GetPageId() const;
void SetPageId(page_id_t p);//p是当前页要设置的页号
void SetLSN(lsn_t lsn = INVALID_LSN);
bool IsSafe(OpType op);
private:
// member variable, attributes that both internal and leaf page share
IndexPageType page_type_;
lsn_t lsn_;
int size_;
int max_size_;
page_id_t parent_page_id_;
page_id_t page_id_;
};
} // namespace scudb
这些函数的实现大部分比较简单,相当于辅助函数。以下是里面相对重要的一些函数:
其中的GetMinSize():
int BPlusTreePage::GetMinSize() const {
if (IsRootPage()) {//这里1表示只有一个指针,所以不用0来表示空
if (IsLeafPage()) return 1;
else return 2;//如果一个页既是根节点又是叶子节点,那么说明是空树,返回1。
//如果是根节点但不是叶子节点,那么至少有一个叶子节点,则返回2。
}
return (max_size_) / 2;//不然就返回最大规格的一半。
}
此外,还有个判断操作安全性的IsSafe函数,我也把它简化了一些:
bool BPlusTreePage::IsSafe(OpType op) {
int size = GetSize();
if (op == OpType::INSERT) {
if (size < GetMaxSize()) return true;//对于插入操作来说,size<GetMaxSize()的返回值max_size_才是合法的
else return false;
}
int minSize = GetMinSize() + 1;
if (op == OpType::DELETE) {
//return (IsLeafPage()) ? size >= minSize : size > minSize;
//上面是原来的写法,我用我自己的写法更简洁一些。
return size > minSize - int(IsLeafPage());
}
assert(false);//invalid area
}
b_plus_tree_page.cpp的完整代码:
/**
* b_plus_tree_page.cpp
*/
#include "page/b_plus_tree_page.h"
namespace scudb {
/*
* Helper methods to get/set page type
* Page type enum class is defined in b_plus_tree_page.h
*/
bool BPlusTreePage::IsLeafPage() const { if (page_type_ == IndexPageType::LEAF_PAGE) return true; return false; }
bool BPlusTreePage::IsRootPage() const { if (parent_page_id_ == INVALID_PAGE_ID) return true; return false; }
void BPlusTreePage::SetPageType(IndexPageType t) { page_type_ = t; }
/*
* Helper methods to get/set size (number of key/value pairs stored in that
* page)
*/
int BPlusTreePage::GetSize() const { return size_; }
void BPlusTreePage::SetSize(int s) { size_ = s; }
void BPlusTreePage::IncreaseSize(int a) { size_ += a; }
/*
* Helper methods to get/set max size (capacity) of the page
*/
int BPlusTreePage::GetMaxSize() const { return max_size_; }
void BPlusTreePage::SetMaxSize(int s) { max_size_ = s; }
/*
* Helper method to get min page size
* Generally, min page size == max page size / 2
* With n = 4 in our example B+-tree, each leaf must contain at least 2 values, and at most 3 values.
*/
int BPlusTreePage::GetMinSize() const {
if (IsRootPage()) {//这里1表示只有一个指针,所以不用0来表示空
if (IsLeafPage()) return 1;
else return 2;//如果一个页既是根节点又是叶子节点,那么说明是空树,返回1。
//如果是根节点但不是叶子节点,那么至少有一个叶子节点,则返回2。
}
return (max_size_) / 2;//不然就返回最大规格的一半。
}
/*
* Helper methods to get/set parent page id
*/
page_id_t BPlusTreePage::GetParentPageId() const { return parent_page_id_; }
void BPlusTreePage::SetParentPageId(page_id_t p) { parent_page_id_ = p; }
/*
* Helper methods to get/set self page id
*/
page_id_t BPlusTreePage::GetPageId() const { return page_id_; }
void BPlusTreePage::SetPageId(page_id_t p) { page_id_ = p; }
/*
* Helper methods to set lsn
*/
void BPlusTreePage::SetLSN(lsn_t lsn) { lsn_ = lsn; }
/* for concurrent index */
bool BPlusTreePage::IsSafe(OpType op) {
int size = GetSize();
if (op == OpType::INSERT) {
if (size < GetMaxSize()) return true;//对于插入操作来说,size<GetMaxSize()的返回值max_size_才是合法的
else return false;
}
int minSize = GetMinSize() + 1;
if (op == OpType::DELETE) {
//return (IsLeafPage()) ? size >= minSize : size > minSize;
//上面是原来的写法,我用我自己的写法更简洁一些。
return size > minSize - int(IsLeafPage());
}
assert(false);//invalid area
}
} // namespace scudb
二、b_plus_tree_internal_page.h和b_plus_tree_internal_page.cpp
第二部分主要是B+树的数据结构
这部分的内容比较困难,内容较多且具有较多的直接调用的别的一些函数。当然,我们也能够在阅读这些困难代码的过程中提升自己的代码能力。
首先是基本的设置和查询:
//基本的设置和查询
KeyType KeyAt(int i) const;
void SetKeyAt(int i, const KeyType &k);
int ValueIndex(const ValueType &v) const;
ValueType ValueAt(int i) const;
之后是遍历、插入新的节点、删除操作:
ValueType Lookup(const KeyType &k, const KeyComparator &com) const;
void PopulateNewRoot(const ValueType &ov, const KeyType &nk,
const ValueType &nv);//ov表示旧值,nk表示新的key,nv表示新值
int InsertNodeAfter(const ValueType &ov, const KeyType &nk,
const ValueType &nv);
void Remove(int id);
接着是移出一半、移出全部、将第一个移至结尾、将结尾移至开头函数。这些函数在B+树的增长过程和删除节点的过程中十分重要。
void MoveHalfTo(BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveAllTo(BPlusTreeInternalPage *r, int pi,
BufferPoolManager *buffer_pool_manager);
void MoveFirstToEndOf(BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveLastToFrontOf(BPlusTreeInternalPage *r,
int pi,
BufferPoolManager *buffer_pool_manager);
最后在定义的private中,还有复制一半、复制全部、复制开头、复制结尾的操作:
void CopyHalfFrom(MappingType *items, int size,
BufferPoolManager *buffer_pool_manager);
void CopyAllFrom(MappingType *items, int size,
BufferPoolManager *buffer_pool_manager);
void CopyLastFrom(const MappingType &pair,
BufferPoolManager *buffer_pool_manager);
void CopyFirstFrom(const MappingType &pair, int pi,
BufferPoolManager *buffer_pool_manager);
b_plus_tree_internal_page.h的完整代码:
/**
* b_plus_tree_internal_page.h
*
* Store n indexed keys and n+1 child pointers (page_id) within internal page.
* Pointer PAGE_ID(i) points to a subtree in which all keys K satisfy:
* K(i) <= K < K(i+1).
* NOTE: since the number of keys does not equal to number of child pointers,
* the first key always remains invalid. That is to say, any search/lookup
* should ignore the first key.
*
* Internal page format (keys are stored in increasing order):
* --------------------------------------------------------------------------
* | HEADER | KEY(1)+PAGE_ID(1) | KEY(2)+PAGE_ID(2) | ... | KEY(n)+PAGE_ID(n) |
* --------------------------------------------------------------------------
*/
#pragma once
#include <queue>
#include "page/b_plus_tree_page.h"
namespace scudb {
#define B_PLUS_TREE_INTERNAL_PAGE_TYPE \
BPlusTreeInternalPage<KeyType, ValueType, KeyComparator>
#define B_PLUS_TREE_INTERNAL_PAGE BPlusTreeInternalPage <KeyType, page_id_t, KeyComparator>
INDEX_TEMPLATE_ARGUMENTS
class BPlusTreeInternalPage : public BPlusTreePage {
public:
// must call initialize method after "create" a new node
void Init(page_id_t p, page_id_t par = INVALID_PAGE_ID);
//基本的设置和查询
KeyType KeyAt(int i) const;
void SetKeyAt(int i, const KeyType &k);
int ValueIndex(const ValueType &v) const;
ValueType ValueAt(int i) const;
ValueType Lookup(const KeyType &k, const KeyComparator &com) const;
void PopulateNewRoot(const ValueType &ov, const KeyType &nk,
const ValueType &nv);//ov表示旧值,nk表示新的key,nv表示新值
int InsertNodeAfter(const ValueType &ov, const KeyType &nk,
const ValueType &nv);
void Remove(int id);
ValueType RemoveAndReturnOnlyChild();
void MoveHalfTo(BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveAllTo(BPlusTreeInternalPage *r, int pi,
BufferPoolManager *buffer_pool_manager);
void MoveFirstToEndOf(BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveLastToFrontOf(BPlusTreeInternalPage *r,
int pi,
BufferPoolManager *buffer_pool_manager);
// DEUBG and PRINT
std::string ToString(bool verbose) const;
void QueueUpChildren(std::queue<BPlusTreePage *> *queue,
BufferPoolManager *buffer_pool_manager);
private:
void CopyHalfFrom(MappingType *items, int size,
BufferPoolManager *buffer_pool_manager);
void CopyAllFrom(MappingType *items, int size,
BufferPoolManager *buffer_pool_manager);
void CopyLastFrom(const MappingType &pair,
BufferPoolManager *buffer_pool_manager);
void CopyFirstFrom(const MappingType &pair, int pi,
BufferPoolManager *buffer_pool_manager);
MappingType array[0];
};
} // namespace scudb
之后是在cpp文件中一些比较重要的函数的实现:
初始化函数Init:
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::Init(page_id_t p,
page_id_t par) {//p表示当前页,par表示其父节点
SetPageType(IndexPageType::INTERNAL_PAGE); SetSize(0);
SetPageId(p); SetParentPageId(par);
SetMaxSize((PAGE_SIZE- sizeof(BPlusTreeInternalPage))/sizeof(MappingType) - 1); //minus 1 for first invalid key
}//这些都是在b_plus_tree_page中就已经设定过的函数,我们使用这些函数来完成初始化
ValueIndex函数使用的是遍历查找:
int B_PLUS_TREE_INTERNAL_PAGE_TYPE::ValueIndex(const ValueType &v) const {//v是要搜寻的值
for (int i = 0; i < GetSize(); i++) {//遍历查找
if (v == ValueAt(i)) return i;
}
return -1;//没找到返回-1
}
LookUp函数,采用二分查找来寻找对应的位置:
B_PLUS_TREE_INTERNAL_PAGE_TYPE::Lookup(const KeyType &k,
const KeyComparator &com) const {
assert(GetSize() > 1);
int l = 1;
int r = GetSize() - 1;
while (l <= r) { //这里使用二分查找,来找到小于等于输入的最后位置
int mid = (r - l) / 2 + l;
if (com(array[mid].first,k) > 0) r = mid - 1;
else l = mid + 1;
}
return array[l - 1].second;
}
InsertNodeAfter和Remove函数:
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_INTERNAL_PAGE_TYPE::InsertNodeAfter(
const ValueType &ov, const KeyType &nk,
const ValueType &nv) {
int idx = ValueIndex(ov) + 1;
assert(idx > 0);
IncreaseSize(1);
//int curSize = GetSize();
for (int i = GetSize() - 1; i > idx; i--) {//相当于把所有的值都往后推了一个
array[i].first = array[i - 1].first;
array[i].second = array[i - 1].second;
}
array[idx].first = nk;
array[idx].second = nv;
return GetSize();
}
/*****************************************************************************
* REMOVE
*****************************************************************************/
/*
* Remove the key & value pair in internal page according to input index(a.k.a
* array offset)
* NOTE: store key&value pair continuously after deletion
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::Remove(int id) {
if (id >= 0 && id < GetSize())
{
for (int i = id + 1; i < GetSize(); i++)//把删除的值之后的值依次前移一个,以完成删除
{
array[i - 1] = array[i];
}
IncreaseSize(-1);//大小减一
}
else assert(0);
}
接下来是比较困难的MoveHalfTo,MoveAllTo函数:
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveHalfTo(
BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager) {
assert(r != nullptr);
int total = GetMaxSize() + 1;
assert(GetSize() == total);
//copy last half
int copyIdx = (GetMaxSize() + 1) / 2;//max:4 x,1,2,3,4 -> 2,3,4
page_id_t recipPageId = r->GetPageId();
for (int i = (total) / 2; i < total; i++) {
r->array[i - (total) / 2].first = array[i].first;
r->array[i - (total) / 2].second = array[i].second;//这里就是把其中的一半数据依次复制到另外一半的存储空间上
//update children's parent page
//更新孩子节点的父节点
auto childRawPage = buffer_pool_manager->FetchPage(array[i].second);
BPlusTreePage *childTreePage = reinterpret_cast<BPlusTreePage *>(childRawPage->GetData());
childTreePage->SetParentPageId(recipPageId);
buffer_pool_manager->UnpinPage(array[i].second,true);
}
//set size,is odd, bigger is last part
SetSize(copyIdx);
r->SetSize(total - copyIdx);
}
/*****************************************************************************
* MERGE
*****************************************************************************/
/*
* Remove all of key & value pairs from this page to "recipient" page, then
* update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveAllTo(
BPlusTreeInternalPage* r, int pi,
BufferPoolManager* buffer_pool_manager) {
//首先需要找到父节点
Page* page = buffer_pool_manager->FetchPage(GetParentPageId());
if (page == nullptr) assert(0);
BPlusTreeInternalPage* parent = reinterpret_cast<BPlusTreeInternalPage*>(page->GetData());
int start = r->GetSize();
page_id_t rpId = r->GetPageId();
// the separation key from parent
SetKeyAt(0, parent->KeyAt(pi));
buffer_pool_manager->UnpinPage(parent->GetPageId(), false);
for (int i = 0; i < GetSize(); i++) {
//首先把数据复制过去
r->array[start + i].first = array[i].first;
r->array[start + i].second = array[i].second;
//然后更新父节点
auto childRawPage = buffer_pool_manager->FetchPage(array[i].second);
BPlusTreePage* childTreePage = reinterpret_cast<BPlusTreePage*>(childRawPage->GetData());
childTreePage->SetParentPageId(rpId);
buffer_pool_manager->UnpinPage(array[i].second, true);
}
//update relavent key & value pair in its parent page.
r->SetSize(start + GetSize());
assert(r->GetSize() <= GetMaxSize());
SetSize(0);
}
MoveFirstToEndOf函数:(CopyFirstFrom函数中有类似的思想)
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveFirstToEndOf(
BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager) {
MappingType pair{KeyAt(0), ValueAt(0)};
IncreaseSize(-1);
memmove(array, array + 1, static_cast<size_t>(GetSize()*sizeof(MappingType)));
r->CopyLastFrom(pair, buffer_pool_manager);//调用包含的CopyLastFrom函数
//page_id_t cI = pair.second;
Page *pg = buffer_pool_manager->FetchPage(pair.second);
if(pg == nullptr)assert(0);
BPlusTreePage *child = reinterpret_cast<BPlusTreePage *>(pg->GetData());
child->SetParentPageId(r->GetPageId());
if(child->GetParentPageId() != r->GetPageId()) assert(0);
buffer_pool_manager->UnpinPage(child->GetPageId(), true);
//以上用来更新父节点的id
pg = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE *parent = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE *>(pg->GetData());
parent->SetKeyAt(parent->ValueIndex(GetPageId()), array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
//以上用来更新父节点的键值和保存的值
}
b_plus_tree_internal_page.cpp的完整代码:
/**
* b_plus_tree_internal_page.cpp
*/
#include <iostream>
#include <sstream>
#include "common/exception.h"
#include "page/b_plus_tree_internal_page.h"
namespace scudb {
/*****************************************************************************
* HELPER METHODS AND UTILITIES
*****************************************************************************/
/*
* Init method after creating a new internal page
* Including set page type, set current size, set page id, set parent id and set
* max page size
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::Init(page_id_t p,
page_id_t par) {//p表示当前页,par表示其父节点
SetPageType(IndexPageType::INTERNAL_PAGE); SetSize(0);
SetPageId(p); SetParentPageId(par);
SetMaxSize((PAGE_SIZE- sizeof(BPlusTreeInternalPage))/sizeof(MappingType) - 1); //minus 1 for first invalid key
}//这些都是在b_plus_tree_page中就已经设定过的函数,我们使用这些函数来完成初始化
/*
* Helper method to get/set the key associated with input "index"(a.k.a
* array offset)
*/
INDEX_TEMPLATE_ARGUMENTS
KeyType B_PLUS_TREE_INTERNAL_PAGE_TYPE::KeyAt(int i) const {//i表示索引
if(i < 0 || i >= GetSize())//判断是否合法
assert(0);
else
return array[i].first;
}//获取指针
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::SetKeyAt(int i, const KeyType &k) {//i表示索引,k表示键的位置
if (i < 0 || i >= GetSize())//判断是否合法
assert(0);
else
array[i].first = k;
}//设置指针位置
/*
* Helper method to find and return array index(or offset), so that its value
* equals to input "value"
*/
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_INTERNAL_PAGE_TYPE::ValueIndex(const ValueType &v) const {//v是要搜寻的值
for (int i = 0; i < GetSize(); i++) {//遍历查找
if (v == ValueAt(i)) return i;
}
return -1;//没找到返回-1
}
/*
* Helper method to get the value associated with input "index"(a.k.a array
* offset)
*/
INDEX_TEMPLATE_ARGUMENTS
ValueType B_PLUS_TREE_INTERNAL_PAGE_TYPE::ValueAt(int i) const {
if (i < 0 || i >= GetSize())//判断是否合法
assert(0);
else
return array[i].second;
}
/*****************************************************************************
* LOOKUP
*****************************************************************************/
/*
* Find and return the child pointer(page_id) which points to the child page
* that contains input "key"
* Start the search from the second key(the first key should always be invalid)
*/
INDEX_TEMPLATE_ARGUMENTS
ValueType
B_PLUS_TREE_INTERNAL_PAGE_TYPE::Lookup(const KeyType &k,
const KeyComparator &com) const {
assert(GetSize() > 1);
int l = 1;
int r = GetSize() - 1;
while (l <= r) { //这里使用二分查找,来找到小于等于输入的最后位置
int mid = (r - l) / 2 + l;
if (com(array[mid].first,k) > 0) r = mid - 1;
else l = mid + 1;
}
return array[l - 1].second;
}
/*****************************************************************************
* INSERTION
*****************************************************************************/
/*
* Populate new root page with old_value + new_key & new_value
* When the insertion cause overflow from leaf page all the way upto the root
* page, you should create a new root page and populate its elements.
* NOTE: This method is only called within InsertIntoParent()(b_plus_tree.cpp)
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::PopulateNewRoot(
const ValueType &ov, const KeyType &nk,
const ValueType &nv) {
array[0].second = ov;
array[1].first = nk;
array[1].second = nv;
SetSize(2);
}
/*
* Insert new_key & new_value pair right after the pair with its value ==
* old_value
* @return: new size after insertion
*/
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_INTERNAL_PAGE_TYPE::InsertNodeAfter(
const ValueType &ov, const KeyType &nk,
const ValueType &nv) {
int idx = ValueIndex(ov) + 1;
assert(idx > 0);
IncreaseSize(1);
//int curSize = GetSize();
for (int i = GetSize() - 1; i > idx; i--) {//相当于把所有的值都往后推了一个
array[i].first = array[i - 1].first;
array[i].second = array[i - 1].second;
}
array[idx].first = nk;
array[idx].second = nv;
return GetSize();
}
/*****************************************************************************
* REMOVE
*****************************************************************************/
/*
* Remove the key & value pair in internal page according to input index(a.k.a
* array offset)
* NOTE: store key&value pair continuously after deletion
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::Remove(int id) {
if (id >= 0 && id < GetSize())
{
for (int i = id + 1; i < GetSize(); i++)//把删除的值之后的值依次前移一个,以完成删除
{
array[i - 1] = array[i];
}
IncreaseSize(-1);//大小减一
}
else assert(0);
}
/*****************************************************************************
* SPLIT
*****************************************************************************/
/*
* Remove half of key & value pairs from this page to "recipient" page
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveHalfTo(
BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager) {
assert(r != nullptr);
int total = GetMaxSize() + 1;
assert(GetSize() == total);
//copy last half
int copyIdx = (GetMaxSize() + 1) / 2;//max:4 x,1,2,3,4 -> 2,3,4
page_id_t recipPageId = r->GetPageId();
for (int i = (total) / 2; i < total; i++) {
r->array[i - (total) / 2].first = array[i].first;
r->array[i - (total) / 2].second = array[i].second;//这里就是把其中的一半数据依次复制到另外一半的存储空间上
//update children's parent page
//更新孩子节点的父节点
auto childRawPage = buffer_pool_manager->FetchPage(array[i].second);
BPlusTreePage *childTreePage = reinterpret_cast<BPlusTreePage *>(childRawPage->GetData());
childTreePage->SetParentPageId(recipPageId);
buffer_pool_manager->UnpinPage(array[i].second,true);
}
//set size,is odd, bigger is last part
SetSize(copyIdx);
r->SetSize(total - copyIdx);
}
/*****************************************************************************
* MERGE
*****************************************************************************/
/*
* Remove all of key & value pairs from this page to "recipient" page, then
* update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveAllTo(
BPlusTreeInternalPage* r, int pi,
BufferPoolManager* buffer_pool_manager) {
//首先需要找到父节点
Page* page = buffer_pool_manager->FetchPage(GetParentPageId());
if (page == nullptr) assert(0);
BPlusTreeInternalPage* parent = reinterpret_cast<BPlusTreeInternalPage*>(page->GetData());
int start = r->GetSize();
page_id_t rpId = r->GetPageId();
// the separation key from parent
SetKeyAt(0, parent->KeyAt(pi));
buffer_pool_manager->UnpinPage(parent->GetPageId(), false);
for (int i = 0; i < GetSize(); i++) {
//首先把数据复制过去
r->array[start + i].first = array[i].first;
r->array[start + i].second = array[i].second;
//然后更新父节点
auto childRawPage = buffer_pool_manager->FetchPage(array[i].second);
BPlusTreePage* childTreePage = reinterpret_cast<BPlusTreePage*>(childRawPage->GetData());
childTreePage->SetParentPageId(rpId);
buffer_pool_manager->UnpinPage(array[i].second, true);
}
//update relavent key & value pair in its parent page.
r->SetSize(start + GetSize());
assert(r->GetSize() <= GetMaxSize());
SetSize(0);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::CopyHalfFrom(
MappingType *items, int size, BufferPoolManager *buffer_pool_manager) {}
/*
* Remove the only key & value pair in internal page and return the value
* NOTE: only call this method within AdjustRoot()(in b_plus_tree.cpp)
*/
INDEX_TEMPLATE_ARGUMENTS
ValueType B_PLUS_TREE_INTERNAL_PAGE_TYPE::RemoveAndReturnOnlyChild() {
ValueType ret = ValueAt(0);
IncreaseSize(-1);
if(GetSize()) assert(0);
return ret;
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::CopyAllFrom(
MappingType *items, int size, BufferPoolManager *buffer_pool_manager) {
}
/*****************************************************************************
* REDISTRIBUTE
*****************************************************************************/
/*
* Remove the first key & value pair from this page to tail of "recipient"
* page, then update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveFirstToEndOf(
BPlusTreeInternalPage *r,
BufferPoolManager *buffer_pool_manager) {
MappingType pair{KeyAt(0), ValueAt(0)};
IncreaseSize(-1);
memmove(array, array + 1, static_cast<size_t>(GetSize()*sizeof(MappingType)));
r->CopyLastFrom(pair, buffer_pool_manager);//调用包含的CopyLastFrom函数
//page_id_t cI = pair.second;
Page *pg = buffer_pool_manager->FetchPage(pair.second);
if(pg == nullptr)assert(0);
BPlusTreePage *child = reinterpret_cast<BPlusTreePage *>(pg->GetData());
child->SetParentPageId(r->GetPageId());
if(child->GetParentPageId() != r->GetPageId()) assert(0);
buffer_pool_manager->UnpinPage(child->GetPageId(), true);
//以上用来更新父节点的id
pg = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE *parent = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE *>(pg->GetData());
parent->SetKeyAt(parent->ValueIndex(GetPageId()), array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
//以上用来更新父节点的键值和保存的值
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::CopyLastFrom(
const MappingType &pair, BufferPoolManager *buffer_pool_manager)
{
assert(GetSize() + 1 <= GetMaxSize());
array[GetSize()] = pair;
IncreaseSize(1);
}
/*
* Remove the last key & value pair from this page to head of "recipient"
* page, then update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::MoveLastToFrontOf(
BPlusTreeInternalPage *r, int pi,
BufferPoolManager *buffer_pool_manager) {
MappingType pair {KeyAt(GetSize() - 1),ValueAt(GetSize() - 1)};
IncreaseSize(-1);
r->CopyFirstFrom(pair, pi, buffer_pool_manager);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::CopyFirstFrom(
const MappingType &pair, int pi,
BufferPoolManager *buffer_pool_manager) {
assert(GetSize() < GetMaxSize()-1);
memmove(array + 1, array, GetSize()*sizeof(MappingType));
IncreaseSize(1);
array[0] = pair;
//以上完成了简单的复制进来的操作,后面需要更新相关参数
// 以下是跟MoveFirstToEndOf函数中类似的操作
// update child parent page id
Page *pg = buffer_pool_manager->FetchPage(pair.second);
if(pg == nullptr) assert(0);
BPlusTreePage *child = reinterpret_cast<BPlusTreePage *>(pg->GetData());
child->SetParentPageId(GetPageId());
assert(child->GetParentPageId() == GetPageId());
buffer_pool_manager->UnpinPage(child->GetPageId(), true);
//update relavent key & value pair in its parent page.
pg = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE *parent = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE *>(pg->GetData());
parent->SetKeyAt(pi, array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
}
/*****************************************************************************
* DEBUG
*****************************************************************************/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_INTERNAL_PAGE_TYPE::QueueUpChildren(
std::queue<BPlusTreePage *> *queue,
BufferPoolManager *buffer_pool_manager) {
for (int i = 0; i < GetSize(); i++) {
auto *page = buffer_pool_manager->FetchPage(array[i].second);
if (page == nullptr)
throw Exception(EXCEPTION_TYPE_INDEX,
"all page are pinned while printing");
BPlusTreePage *node =
reinterpret_cast<BPlusTreePage *>(page->GetData());
queue->push(node);
}
}
INDEX_TEMPLATE_ARGUMENTS
std::string B_PLUS_TREE_INTERNAL_PAGE_TYPE::ToString(bool verbose) const {
if (GetSize() == 0) {
return "";
}
std::ostringstream os;
if (verbose) {
os << "[pageId: " << GetPageId() << " parentId: " << GetParentPageId()
<< "]<" << GetSize() << "> ";
}
int entry = verbose ? 0 : 1;
int end = GetSize();
bool first = true;
while (entry < end) {
if (first) {
first = false;
} else {
os << " ";
}
os << std::dec << array[entry].first.ToString();
if (verbose) {
os << "(" << array[entry].second << ")";
}
++entry;
}
return os.str();
}
// valuetype for internalNode should be page id_t
template class BPlusTreeInternalPage<GenericKey<4>, page_id_t,
GenericComparator<4>>;
template class BPlusTreeInternalPage<GenericKey<8>, page_id_t,
GenericComparator<8>>;
template class BPlusTreeInternalPage<GenericKey<16>, page_id_t,
GenericComparator<16>>;
template class BPlusTreeInternalPage<GenericKey<32>, page_id_t,
GenericComparator<32>>;
template class BPlusTreeInternalPage<GenericKey<64>, page_id_t,
GenericComparator<64>>;
} // namespace scudb
三、b_plus_tree_leaf_page.h和b_plus_tree_leaf_page.cpp
b_plus_tree_leaf_page.h和b_plus_tree_leaf_page.cpp和之前的b_plus_tree_internal_page.h和b_plus_tree_internal_page.cpp里面有很多相似的地方。比如可以使用二分查找来查找位置,但这部分使用了很多存储空间的操作,memmove函数使用的较多。
基础的获得和设置函数:
page_id_t GetNextPageId() const;
void SetNextPageId(page_id_t next_page_id);
KeyType KeyAt(int i) const;
int KeyIndex(const KeyType &k, const KeyComparator &com) const;
插入、查找和删除操作:
int Insert(const KeyType &k, const ValueType &v,
const KeyComparator &com);
bool Lookup(const KeyType &key, ValueType &value,
const KeyComparator &comparator) const;
int RemoveAndDeleteRecord(const KeyType &k,
const KeyComparator &com);
接着是移出一半、移出全部、将第一个移至结尾、将结尾移至开头函数。
void MoveHalfTo(BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager /* Unused */);
void MoveAllTo(BPlusTreeLeafPage *r, int /* Unused */,
BufferPoolManager * /* Unused */);
void MoveFirstToEndOf(BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveLastToFrontOf(BPlusTreeLeafPage *r, int pI,
BufferPoolManager *buffer_pool_manager);
然后是private里面的复制一半、复制全部、复制开头、复制结尾的操作:
void CopyHalfFrom(MappingType *items, int size);
void CopyAllFrom(MappingType *items, int size);
void CopyLastFrom(const MappingType &it);
void CopyFirstFrom(const MappingType &it, int pI,
BufferPoolManager *buffer_pool_manager);
b_plus_tree_leaf_page.h的完整代码:
/**
* b_plus_tree_leaf_page.h
*
* Store indexed key and record id(record id = page id combined with slot id,
* see include/common/rid.h for detailed implementation) together within leaf
* page. Only support unique key.
* Leaf page format (keys are stored in order):
* ----------------------------------------------------------------------
* | HEADER | KEY(1) + RID(1) | KEY(2) + RID(2) | ... | KEY(n) + RID(n)
* ----------------------------------------------------------------------
*
* Header format (size in byte, 24 bytes in total):
* ---------------------------------------------------------------------
* | PageType (4) | CurrentSize (4) | MaxSize (4) | ParentPageId (4) |
* ---------------------------------------------------------------------
* ------------------------------
* | PageId (4) | NextPageId (4)
* ------------------------------
*/
#pragma once
#include <utility>
#include <vector>
#include "page/b_plus_tree_page.h"
namespace scudb {
#define B_PLUS_TREE_LEAF_PAGE_TYPE \
BPlusTreeLeafPage<KeyType, ValueType, KeyComparator>
INDEX_TEMPLATE_ARGUMENTS
class BPlusTreeLeafPage : public BPlusTreePage {
public:
// After creating a new leaf page from buffer pool, must call initialize
// method to set default values
void Init(page_id_t pi, page_id_t pari = INVALID_PAGE_ID);
// helper methods
page_id_t GetNextPageId() const;
void SetNextPageId(page_id_t next_page_id);
KeyType KeyAt(int i) const;
int KeyIndex(const KeyType &k, const KeyComparator &com) const;
const MappingType &GetItem(int index);
// insert and delete methods
int Insert(const KeyType &k, const ValueType &v,
const KeyComparator &com);
bool Lookup(const KeyType &key, ValueType &value,
const KeyComparator &comparator) const;
int RemoveAndDeleteRecord(const KeyType &k,
const KeyComparator &com);
// Split and Merge utility methods
void MoveHalfTo(BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager /* Unused */);
void MoveAllTo(BPlusTreeLeafPage *r, int /* Unused */,
BufferPoolManager * /* Unused */);
void MoveFirstToEndOf(BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager);
void MoveLastToFrontOf(BPlusTreeLeafPage *r, int pI,
BufferPoolManager *buffer_pool_manager);
// Debug
std::string ToString(bool verbose = false) const;
private:
void CopyHalfFrom(MappingType *items, int size);
void CopyAllFrom(MappingType *items, int size);
void CopyLastFrom(const MappingType &it);
void CopyFirstFrom(const MappingType &it, int pI,
BufferPoolManager *buffer_pool_manager);
page_id_t next_page_id_;
MappingType array[0];
};
} // namespace scudb
KeyIndex函数:
//跟之前的b_plus_tree_internal_page中的函数一样,利用二分查找来寻找位置
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_LEAF_PAGE_TYPE::KeyIndex(
const KeyType &k, const KeyComparator &com) const {
if(GetSize() < 0) assert(0);
int l = 0, r = GetSize() - 1;
while (l <= r) { //find the last key in array <= input
int mid = (r - l) / 2 + l;
if (com(array[mid].first,k) < 0) l = mid + 1;
else r = mid - 1;
}
return r + 1;
}
Insert函数:
//和b_plus_tree_internal_page的InsertNodeAfter函数类似
int B_PLUS_TREE_LEAF_PAGE_TYPE::Insert(const KeyType &k,
const ValueType &v,
const KeyComparator &com) {
int idx = KeyIndex(k,com); //first larger than key
if(idx < 0) assert(0);
IncreaseSize(1);//增加一份空间
int curSize = GetSize();
for (int i = GetSize() - 1; i > idx; i--) {//挨个往后复制一个
array[i].first = array[i - 1].first;
array[i].second = array[i - 1].second;
}
//把要插入的放进来
array[idx].first = k;
array[idx].second = v;
return curSize;
}
MoveHalfTo函数:
INDEX_TEMPLATE_ARGUMENTS
//跟之前b_plus_tree_internal_page中的MoveHalfTo函数非常相似
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveHalfTo(
BPlusTreeLeafPage *r,
__attribute__((unused)) BufferPoolManager *buffer_pool_manager) {
if(r == nullptr) assert(0);
int total = GetMaxSize() + 1;
assert(GetSize() == total);
//copy last half
int copyIdx = (total)/2;//7 is 4,5,6,7; 8 is 4,5,6,7,8
for (int i = (total) / 2; i < total; i++) {
r->array[i - copyIdx].first = array[i].first;
r->array[i - copyIdx].second = array[i].second;
}
//set pointer
r->SetNextPageId(GetNextPageId());
SetNextPageId(r->GetPageId());
//set size, is odd, bigger is last part
SetSize(copyIdx);
r->SetSize(total - copyIdx);
}
MoveFirstToEndOf和CopyFirstFrom函数相对困难:
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveFirstToEndOf(
BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager) {
MappingType p = GetItem(0);
IncreaseSize(-1);
memmove(array, array + 1, static_cast<size_t>(GetSize()*sizeof(MappingType)));//用存储空间的移动完成剩余的
r->CopyLastFrom(p);
//在父节点更新键和值
Page *pg = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE *par = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE *>(pg->GetData());
par->SetKeyAt(par->ValueIndex(GetPageId()), array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CopyFirstFrom(
const MappingType& it, int pI,
BufferPoolManager* buffer_pool_manager) {
if(GetSize() + 1 >= GetMaxSize()) assert(0);
memmove(array + 1, array, GetSize() * sizeof(MappingType));//还是使用内存的移动来完成剩余的移动
IncreaseSize(1);
array[0] = it;
Page* p = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE* par = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE*>(p->GetData());
par->SetKeyAt(pI, array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
}
b_plus_tree_leaf_page.cpp的完整代码:
/**
* b_plus_tree_leaf_page.cpp
*/
#include <sstream>
#include <include/page/b_plus_tree_internal_page.h>
#include "common/exception.h"
#include "common/rid.h"
#include "page/b_plus_tree_leaf_page.h"
namespace scudb {
/*****************************************************************************
* HELPER METHODS AND UTILITIES
*****************************************************************************/
/**
* Init method after creating a new leaf page
* Including set page type, set current size to zero, set page id/parent id, set
* next page id and set max size
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::Init(page_id_t pi, page_id_t pari) {//初始化,pi表示当前设置的页码,pari表示父节点页码
SetPageType(IndexPageType::LEAF_PAGE);SetSize(0);
if(sizeof(BPlusTreeLeafPage) != 28) assert(0);
SetPageId(pi);SetParentPageId(pari);
SetNextPageId(INVALID_PAGE_ID);
SetMaxSize((PAGE_SIZE - sizeof(BPlusTreeLeafPage))/sizeof(MappingType) - 1); //minus 1 for insert first then split
}
/**
* Helper methods to set/get next page id
*/
//以下是获取和设置id操作
INDEX_TEMPLATE_ARGUMENTS
page_id_t B_PLUS_TREE_LEAF_PAGE_TYPE::GetNextPageId() const {
return next_page_id_;
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::SetNextPageId(page_id_t next_page_id) {next_page_id_ = next_page_id;}
/**
* Helper method to find the first index i so that array[i].first >= key
* NOTE: This method is only used when generating index iterator
*/
//跟之前的b_plus_tree_internal_page中的函数一样,利用二分查找来寻找位置
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_LEAF_PAGE_TYPE::KeyIndex(
const KeyType &k, const KeyComparator &com) const {
if(GetSize() < 0) assert(0);
int l = 0, r = GetSize() - 1;
while (l <= r) { //find the last key in array <= input
int mid = (r - l) / 2 + l;
if (com(array[mid].first,k) < 0) l = mid + 1;
else r = mid - 1;
}
return r + 1;
}
/*
* Helper method to find and return the key associated with input "index"(a.k.a
* array offset)
*/
INDEX_TEMPLATE_ARGUMENTS
KeyType B_PLUS_TREE_LEAF_PAGE_TYPE::KeyAt(int i) const {
if (i < 0 || i >= GetSize())//判断是否合法
assert(0);
else
return array[i].first;
}
/*
* Helper method to find and return the key & value pair associated with input
* "index"(a.k.a array offset)
*/
INDEX_TEMPLATE_ARGUMENTS
const MappingType& B_PLUS_TREE_LEAF_PAGE_TYPE::GetItem(int index) {
assert(index >= 0 && index < GetSize());
return array[index];
}
/*****************************************************************************
* INSERTION
*****************************************************************************/
/*
* Insert key & value pair into leaf page ordered by key
* @return page size after insertion
*/
INDEX_TEMPLATE_ARGUMENTS
//和b_plus_tree_internal_page的InsertNodeAfter函数类似
int B_PLUS_TREE_LEAF_PAGE_TYPE::Insert(const KeyType &k,
const ValueType &v,
const KeyComparator &com) {
int idx = KeyIndex(k,com); //first larger than key
if(idx < 0) assert(0);
IncreaseSize(1);//增加一份空间
int curSize = GetSize();
for (int i = GetSize() - 1; i > idx; i--) {//挨个往后复制一个
array[i].first = array[i - 1].first;
array[i].second = array[i - 1].second;
}
//把要插入的放进来
array[idx].first = k;
array[idx].second = v;
return curSize;
}
/*****************************************************************************
* SPLIT
*****************************************************************************/
/*
* Remove half of key & value pairs from this page to "recipient" page
*/
INDEX_TEMPLATE_ARGUMENTS
//跟之前b_plus_tree_internal_page中的MoveHalfTo函数非常相似
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveHalfTo(
BPlusTreeLeafPage *r,
__attribute__((unused)) BufferPoolManager *buffer_pool_manager) {
if(r == nullptr) assert(0);
int total = GetMaxSize() + 1;
assert(GetSize() == total);
//copy last half
int copyIdx = (total)/2;//7 is 4,5,6,7; 8 is 4,5,6,7,8
for (int i = (total) / 2; i < total; i++) {
r->array[i - copyIdx].first = array[i].first;
r->array[i - copyIdx].second = array[i].second;
}
//set pointer
r->SetNextPageId(GetNextPageId());
SetNextPageId(r->GetPageId());
//set size, is odd, bigger is last part
SetSize(copyIdx);
r->SetSize(total - copyIdx);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CopyHalfFrom(MappingType *items, int size) {}
/*****************************************************************************
* LOOKUP
*****************************************************************************/
/*
* For the given key, check to see whether it exists in the leaf page. If it
* does, then store its corresponding value in input "value" and return true.
* If the key does not exist, then return false
*/
INDEX_TEMPLATE_ARGUMENTS
bool B_PLUS_TREE_LEAF_PAGE_TYPE::Lookup(const KeyType &k, ValueType &v,
const KeyComparator &com) const {
int idx = KeyIndex(k,com);
if (idx >= GetSize() || com(array[idx].first, k) != 0) {
return false;
}
v = array[idx].second;
return true;
}
/*****************************************************************************
* REMOVE
*****************************************************************************/
/*
* First look through leaf page to see whether delete key exist or not. If
* exist, perform deletion, otherwise return immdiately.
* NOTE: store key&value pair continuously after deletion
* @return page size after deletion
*/
INDEX_TEMPLATE_ARGUMENTS
int B_PLUS_TREE_LEAF_PAGE_TYPE::RemoveAndDeleteRecord(
const KeyType &k, const KeyComparator &com) {
int f = KeyIndex(k,com);
if (f >= GetSize() || com(k,KeyAt(f)) != 0) {
return GetSize();
}
//quick deletion
memmove(array + f, array + f + 1,
static_cast<size_t>((GetSize() - f - 1)*sizeof(MappingType)));//直接使用memmove变换存储空间即可
IncreaseSize(-1);
return GetSize();
}
/*****************************************************************************
* MERGE
*****************************************************************************/
/*
* Remove all of key & value pairs from this page to "recipient" page, then
* update next page id
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveAllTo(BPlusTreeLeafPage *r,
int, BufferPoolManager *) {
if(r == nullptr) assert(0);
//copy last half
int st = r->GetSize();//7 is 4,5,6,7; 8 is 4,5,6,7,8
for (int i = 0; i < GetSize(); i++) {
r->array[st + i].first = array[i].first;
r->array[st + i].second = array[i].second;
}
//设置指针
r->SetNextPageId(GetNextPageId());
//增加存储大小
r->IncreaseSize(GetSize());
SetSize(0);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CopyAllFrom(MappingType *items, int size) {}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CopyLastFrom(const MappingType& it) {
assert(GetSize() + 1 <= GetMaxSize());
array[GetSize()] = it;
IncreaseSize(1);
}
/*****************************************************************************
* REDISTRIBUTE
*****************************************************************************/
/*
* Remove the first key & value pair from this page to "recipient" page, then
* update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveFirstToEndOf(
BPlusTreeLeafPage *r,
BufferPoolManager *buffer_pool_manager) {
MappingType p = GetItem(0);
IncreaseSize(-1);
memmove(array, array + 1, static_cast<size_t>(GetSize()*sizeof(MappingType)));//用存储空间的移动完成剩余的
r->CopyLastFrom(p);
//在父节点更新键和值
Page *pg = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE *par = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE *>(pg->GetData());
par->SetKeyAt(par->ValueIndex(GetPageId()), array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
}
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::CopyFirstFrom(
const MappingType& it, int pI,
BufferPoolManager* buffer_pool_manager) {
if(GetSize() + 1 >= GetMaxSize()) assert(0);
memmove(array + 1, array, GetSize() * sizeof(MappingType));//还是使用内存的移动来完成剩余的移动
IncreaseSize(1);
array[0] = it;
Page* p = buffer_pool_manager->FetchPage(GetParentPageId());
B_PLUS_TREE_INTERNAL_PAGE* par = reinterpret_cast<B_PLUS_TREE_INTERNAL_PAGE*>(p->GetData());
par->SetKeyAt(pI, array[0].first);
buffer_pool_manager->UnpinPage(GetParentPageId(), true);
}
/*
* Remove the last key & value pair from this page to "recipient" page, then
* update relavent key & value pair in its parent page.
*/
INDEX_TEMPLATE_ARGUMENTS
void B_PLUS_TREE_LEAF_PAGE_TYPE::MoveLastToFrontOf(
BPlusTreeLeafPage *r, int pI,
BufferPoolManager *buffer_pool_manager) {
MappingType p = GetItem(GetSize() - 1);
IncreaseSize(-1);
r->CopyFirstFrom(p, pI, buffer_pool_manager);//调用CopyFirstFrom函数
}
/*****************************************************************************
* DEBUG
*****************************************************************************/
INDEX_TEMPLATE_ARGUMENTS
std::string B_PLUS_TREE_LEAF_PAGE_TYPE::ToString(bool verbose) const {
if (GetSize() == 0) {
return "";
}
std::ostringstream stream;
if (verbose) {
stream << "[pageId: " << GetPageId() << " parentId: " << GetParentPageId()
<< "]<" << GetSize() << "> ";
}
int entry = 0;
int end = GetSize();
bool first = true;
while (entry < end) {
if (first) {
first = false;
} else {
stream << " ";
}
stream << std::dec << array[entry].first;
if (verbose) {
stream << "(" << array[entry].second << ")";
}
++entry;
}
return stream.str();
}
template class BPlusTreeLeafPage<GenericKey<4>, RID,
GenericComparator<4>>;
template class BPlusTreeLeafPage<GenericKey<8>, RID,
GenericComparator<8>>;
template class BPlusTreeLeafPage<GenericKey<16>, RID,
GenericComparator<16>>;
template class BPlusTreeLeafPage<GenericKey<32>, RID,
GenericComparator<32>>;
template class BPlusTreeLeafPage<GenericKey<64>, RID,
GenericComparator<64>>;
} // namespace scudb