DataBase作业3(1) 教师:N Yang

第一部分是关于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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值