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

重构buffer pool (#33)

重构disk buffer pool:
新增BufferPoolManager,管理所有的DiskBufferPool;
原有DiskBufferPool只处理一个文件,取消其中file_id的概念;
删除BPPageHandle,直接使用Frame;
BPManager更名BPFrameManager;
BPFileSubHeader改为BPFileHeader并直接放在DiskBufferPool中
上级 7ad72565
......@@ -36,6 +36,8 @@ See the Mulan PSL v2 for more details. */
#include "sql/query_cache/query_cache_stage.h"
#include "storage/default/default_storage_stage.h"
#include "storage/mem/mem_storage_stage.h"
#include "storage/default/disk_buffer_pool.h"
#include "storage/default/default_handler.h"
using namespace common;
......@@ -156,6 +158,33 @@ int prepare_init_seda()
return 0;
}
int init_global_objects()
{
BufferPoolManager *bpm = new BufferPoolManager();
BufferPoolManager::set_instance(bpm);
DefaultHandler *handler = new DefaultHandler();
DefaultHandler::set_default(handler);
return 0;
}
int uninit_global_objects()
{
DefaultHandler *default_handler = &DefaultHandler::get_default();
if (default_handler != nullptr) {
DefaultHandler::set_default(nullptr);
delete default_handler;
}
BufferPoolManager *bpm = &BufferPoolManager::instance();
if (bpm != nullptr) {
BufferPoolManager::set_instance(nullptr);
delete bpm;
}
return 0;
}
int init(ProcessParam *process_param)
{
......@@ -200,6 +229,12 @@ int init(ProcessParam *process_param)
get_properties()->to_string(conf_data);
LOG_INFO("Output configuration \n%s", conf_data.c_str());
rc = init_global_objects();
if (rc != 0) {
LOG_ERROR("failed to init global objects");
return rc;
}
// seda is used for backend async event handler
// the latency of seda is slow, it isn't used for critical latency
// environment.
......@@ -229,7 +264,8 @@ int init(ProcessParam *process_param)
void cleanup_util()
{
uninit_global_objects();
if (nullptr != get_properties()) {
delete get_properties();
get_properties() = nullptr;
......@@ -245,4 +281,6 @@ void cleanup_util()
}
void cleanup()
{}
{
cleanup_util();
}
......@@ -16,10 +16,10 @@ See the Mulan PSL v2 for more details. */
#include <string>
static const char *TABLE_META_SUFFIX = ".table";
static const char *TABLE_META_FILE_PATTERN = ".*\\.table$";
static const char *TABLE_DATA_SUFFIX = ".data";
static const char *TABLE_INDEX_SUFFIX = ".index";
static constexpr const char *TABLE_META_SUFFIX = ".table";
static constexpr const char *TABLE_META_FILE_PATTERN = ".*\\.table$";
static constexpr const char *TABLE_DATA_SUFFIX = ".data";
static constexpr const char *TABLE_INDEX_SUFFIX = ".index";
std::string table_meta_file(const char *base_dir, const char *table_name);
std::string table_data_file(const char *base_dir, const char *table_name);
......
......@@ -47,66 +47,54 @@ int page_header_size(int record_capacity)
return align8(page_fix_size() + bitmap_size);
}
////////////////////////////////////////////////////////////////////////////////
RecordPageHandler::RecordPageHandler()
: disk_buffer_pool_(nullptr), file_id_(-1), page_header_(nullptr), bitmap_(nullptr)
{
page_handle_.open = false;
page_handle_.frame = nullptr;
}
RecordPageHandler::~RecordPageHandler()
{
cleanup();
}
RC RecordPageHandler::init(DiskBufferPool &buffer_pool, int file_id, PageNum page_num)
RC RecordPageHandler::init(DiskBufferPool &buffer_pool, PageNum page_num)
{
if (disk_buffer_pool_ != nullptr) {
LOG_WARN("Disk buffer pool has been opened for file_id:page_num %d:%d.", file_id, page_num);
LOG_WARN("Disk buffer pool has been opened for page_num %d.", page_num);
return RC::RECORD_OPENNED;
}
RC ret = RC::SUCCESS;
if ((ret = buffer_pool.get_this_page(file_id, page_num, &page_handle_)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page handle from disk buffer pool. file_id:%d, ret=%d:%s", file_id, ret, strrc(ret));
if ((ret = buffer_pool.get_this_page(page_num, &frame_)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page handle from disk buffer pool. ret=%d:%s", ret, strrc(ret));
return ret;
}
char *data;
ret = buffer_pool.get_data(&page_handle_, &data);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to get page data. ret=%d:%s", ret, strrc(ret));
return ret;
}
char *data = frame_->data();
disk_buffer_pool_ = &buffer_pool;
file_id_ = file_id;
page_header_ = (PageHeader *)(data);
bitmap_ = data + page_fix_size();
LOG_TRACE("Successfully init file_id:page_num %d:%d.", file_id, page_num);
LOG_TRACE("Successfully init page_num %d.", page_num);
return ret;
}
RC RecordPageHandler::init_empty_page(DiskBufferPool &buffer_pool, int file_id, PageNum page_num, int record_size)
RC RecordPageHandler::init_empty_page(DiskBufferPool &buffer_pool, PageNum page_num, int record_size)
{
RC ret = init(buffer_pool, file_id, page_num);
RC ret = init(buffer_pool, page_num);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to init empty page file_id:page_num:record_size %d:%d:%d.", file_id, page_num, record_size);
LOG_ERROR("Failed to init empty page page_num:record_size %d:%d.", page_num, record_size);
return ret;
}
int page_size = sizeof(page_handle_.frame->page.data);
int page_size = BP_PAGE_DATA_SIZE;
int record_phy_size = align8(record_size);
page_header_->record_num = 0;
page_header_->record_capacity = page_record_capacity(page_size, record_phy_size);
page_header_->record_real_size = record_size;
page_header_->record_size = record_phy_size;
page_header_->first_record_offset = page_header_size(page_header_->record_capacity);
bitmap_ = page_handle_.frame->page.data + page_fix_size();
bitmap_ = frame_->data() + page_fix_size();
memset(bitmap_, 0, page_bitmap_size(page_header_->record_capacity));
disk_buffer_pool_->mark_dirty(&page_handle_);
frame_->mark_dirty();
return RC::SUCCESS;
}
......@@ -114,10 +102,8 @@ RC RecordPageHandler::init_empty_page(DiskBufferPool &buffer_pool, int file_id,
RC RecordPageHandler::cleanup()
{
if (disk_buffer_pool_ != nullptr) {
disk_buffer_pool_->unpin_page(&page_handle_);
disk_buffer_pool_->unpin_page(frame_);
disk_buffer_pool_ = nullptr;
// skip purge page,
// skip reset page_header & bitmap
}
return RC::SUCCESS;
......@@ -125,9 +111,8 @@ RC RecordPageHandler::cleanup()
RC RecordPageHandler::insert_record(const char *data, RID *rid)
{
if (page_header_->record_num == page_header_->record_capacity) {
LOG_WARN("Page is full, file_id:page_num %d:%d.", file_id_, page_handle_.frame->page.page_num);
LOG_WARN("Page is full, page_num %d:%d.", frame_->page_num());
return RC::RECORD_NOMEM;
}
......@@ -141,7 +126,7 @@ RC RecordPageHandler::insert_record(const char *data, RID *rid)
char *record_data = get_record_data(index);
memcpy(record_data, data, page_header_->record_real_size);
disk_buffer_pool_->mark_dirty(&page_handle_);
frame_->mark_dirty();
if (rid) {
rid->page_num = get_page_num();
......@@ -155,25 +140,21 @@ RC RecordPageHandler::insert_record(const char *data, RID *rid)
RC RecordPageHandler::update_record(const Record *rec)
{
if (rec->rid.slot_num >= page_header_->record_capacity) {
LOG_ERROR("Invalid slot_num %d, exceed page's record capacity, file_id:page_num %d:%d.",
rec->rid.slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num %d, exceed page's record capacity, page_num %d.",
rec->rid.slot_num, frame_->page_num());
return RC::INVALID_ARGUMENT;
}
Bitmap bitmap(bitmap_, page_header_->record_capacity);
if (!bitmap.get_bit(rec->rid.slot_num)) {
LOG_ERROR("Invalid slot_num %d, slot is empty, file_id:page_num %d:%d.",
rec->rid.slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num %d, slot is empty, page_num %d.",
rec->rid.slot_num, frame_->page_num());
return RC::RECORD_RECORD_NOT_EXIST;
} else {
char *record_data = get_record_data(rec->rid.slot_num);
memcpy(record_data, rec->data, page_header_->record_real_size);
bitmap.set_bit(rec->rid.slot_num);
disk_buffer_pool_->mark_dirty(&page_handle_);
frame_->mark_dirty();
// LOG_TRACE("Update record. file_id=%d, page num=%d,slot=%d", file_id_, rec->rid.page_num, rec->rid.slot_num);
return RC::SUCCESS;
}
......@@ -182,10 +163,8 @@ RC RecordPageHandler::update_record(const Record *rec)
RC RecordPageHandler::delete_record(const RID *rid)
{
if (rid->slot_num >= page_header_->record_capacity) {
LOG_ERROR("Invalid slot_num %d, exceed page's record capacity, file_id:page_num %d:%d.",
rid->slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num %d, exceed page's record capacity, page_num %d.",
rid->slot_num, frame_->page_num());
return RC::INVALID_ARGUMENT;
}
......@@ -193,21 +172,18 @@ RC RecordPageHandler::delete_record(const RID *rid)
if (bitmap.get_bit(rid->slot_num)) {
bitmap.clear_bit(rid->slot_num);
page_header_->record_num--;
disk_buffer_pool_->mark_dirty(&page_handle_);
frame_->mark_dirty();
if (page_header_->record_num == 0) {
DiskBufferPool *disk_buffer_pool = disk_buffer_pool_;
int file_id = file_id_;
PageNum page_num = get_page_num();
cleanup();
disk_buffer_pool->dispose_page(file_id, page_num);
disk_buffer_pool->dispose_page(page_num);
}
return RC::SUCCESS;
} else {
LOG_ERROR("Invalid slot_num %d, slot is empty, file_id:page_num %d:%d.",
rid->slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num %d, slot is empty, page_num %d.",
rid->slot_num, frame_->page_num());
return RC::RECORD_RECORD_NOT_EXIST;
}
}
......@@ -215,19 +191,15 @@ RC RecordPageHandler::delete_record(const RID *rid)
RC RecordPageHandler::get_record(const RID *rid, Record *rec)
{
if (rid->slot_num >= page_header_->record_capacity) {
LOG_ERROR("Invalid slot_num:%d, exceed page's record capacity, file_id:page_num %d:%d.",
rid->slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num:%d, exceed page's record capacity, page_num %d.",
rid->slot_num, frame_->page_num());
return RC::RECORD_INVALIDRID;
}
Bitmap bitmap(bitmap_, page_header_->record_capacity);
if (!bitmap.get_bit(rid->slot_num)) {
LOG_ERROR("Invalid slot_num:%d, slot is empty, file_id:page_num %d:%d.",
rid->slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num:%d, slot is empty, page_num %d.",
rid->slot_num, frame_->page_num());
return RC::RECORD_RECORD_NOT_EXIST;
}
......@@ -245,10 +217,8 @@ RC RecordPageHandler::get_first_record(Record *rec)
RC RecordPageHandler::get_next_record(Record *rec)
{
if (rec->rid.slot_num >= page_header_->record_capacity - 1) {
LOG_ERROR("Invalid slot_num:%d, exceed page's record capacity, file_id:page_num %d:%d.",
rec->rid.slot_num,
file_id_,
page_handle_.frame->page.page_num);
LOG_ERROR("Invalid slot_num:%d, exceed page's record capacity, page_num %d.",
rec->rid.slot_num, frame_->page_num());
return RC::RECORD_EOF;
}
......@@ -256,7 +226,7 @@ RC RecordPageHandler::get_next_record(Record *rec)
int index = bitmap.next_setted_bit(rec->rid.slot_num + 1);
if (index < 0) {
LOG_WARN("There is no empty slot on page -- file_id:%d, page_num:%d.", file_id_, page_handle_.frame->page.page_num);
LOG_WARN("There is no empty slot on page -- page_num:%d.", frame_->page_num());
return RC::RECORD_EOF;
}
......@@ -271,7 +241,7 @@ PageNum RecordPageHandler::get_page_num() const
if (nullptr == page_header_) {
return (PageNum)(-1);
}
return page_handle_.frame->page.page_num;
return frame_->page_num();
}
bool RecordPageHandler::is_full() const
......@@ -281,21 +251,16 @@ bool RecordPageHandler::is_full() const
////////////////////////////////////////////////////////////////////////////////
RecordFileHandler::RecordFileHandler() : disk_buffer_pool_(nullptr), file_id_(-1)
{}
RC RecordFileHandler::init(DiskBufferPool *buffer_pool, int file_id)
RC RecordFileHandler::init(DiskBufferPool *buffer_pool)
{
if (disk_buffer_pool_ != nullptr) {
LOG_ERROR("%d has been openned.", file_id);
LOG_ERROR("record file handler has been openned.");
return RC::RECORD_OPENNED;
}
disk_buffer_pool_ = buffer_pool;
file_id_ = file_id;
LOG_INFO("Successfully open %d.", file_id);
LOG_INFO("Successfully open record file handle");
return RC::SUCCESS;
}
......@@ -311,8 +276,8 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
RC ret = RC::SUCCESS;
// 找到没有填满的页面
int page_count = 0;
if ((ret = disk_buffer_pool_->get_page_count(file_id_, &page_count)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page count while inserting record, file_id:%d", this->file_id_);
if ((ret = disk_buffer_pool_->get_page_count(&page_count)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page count while inserting record");
return ret;
}
......@@ -321,8 +286,8 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
if (page_count >= 2) {
// 当前buffer pool 有页面时才尝试加载第一页
// 参考diskBufferPool,有效page的pageNum从1开始
if ((ret = record_page_handler_.init(*disk_buffer_pool_, file_id_, 1)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler, file_id:%d, ret=%d", file_id_, ret);
if ((ret = record_page_handler_.init(*disk_buffer_pool_, 1)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler, ret=%d", ret);
return ret;
}
current_page_num = record_page_handler_.get_page_num();
......@@ -339,10 +304,10 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
}
if (current_page_num != record_page_handler_.get_page_num()) {
record_page_handler_.cleanup();
ret = record_page_handler_.init(*disk_buffer_pool_, file_id_, current_page_num);
ret = record_page_handler_.init(*disk_buffer_pool_, current_page_num);
if (ret != RC::SUCCESS && ret != RC::BUFFERPOOL_INVALID_PAGE_NUM) {
LOG_ERROR(
"Failed to init record page handler. page number is %d. ret=%d:%s", current_page_num, ret, strrc(ret));
LOG_ERROR("Failed to init record page handler. page number is %d. ret=%d:%s",
current_page_num, ret, strrc(ret));
return ret;
}
}
......@@ -355,27 +320,24 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
// 找不到就分配一个新的页面
if (!page_found) {
BPPageHandle page_handle;
if ((ret = disk_buffer_pool_->allocate_page(file_id_, &page_handle)) != RC::SUCCESS) {
LOG_ERROR("Failed to allocate page while inserting record. file_it:%d, ret:%d", file_id_, ret);
Frame *frame = nullptr;
if ((ret = disk_buffer_pool_->allocate_page(&frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to allocate page while inserting record. ret:%d", ret);
return ret;
}
current_page_num = page_handle.frame->page.page_num;
current_page_num = frame->page_num();
record_page_handler_.cleanup();
ret = record_page_handler_.init_empty_page(*disk_buffer_pool_, file_id_, current_page_num, record_size);
ret = record_page_handler_.init_empty_page(*disk_buffer_pool_, current_page_num, record_size);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to init empty page. file_id:%d, ret:%d", file_id_, ret);
if (RC::SUCCESS != disk_buffer_pool_->unpin_page(&page_handle)) {
LOG_ERROR("Failed to unpin page. file_id:%d", file_id_);
LOG_ERROR("Failed to init empty page. ret:%d", ret);
if (RC::SUCCESS != disk_buffer_pool_->unpin_page(frame)) {
LOG_ERROR("Failed to unpin page. ");
}
return ret;
}
//@@@ TODO, remove unpin page here
// if (RC::SUCCESS != disk_buffer_pool_->unpin_page(&page_handle)) {
// LOG_ERROR("Failed to unpin page. file_id:%d", file_id_);
// }
disk_buffer_pool_->unpin_page(frame);
}
// 找到空闲位置
......@@ -390,8 +352,8 @@ RC RecordFileHandler::update_record(const Record *rec)
}
RC ret;
RecordPageHandler page_handler;
if ((ret = page_handler.init(*disk_buffer_pool_, file_id_, rec->rid.page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d, file_id=%d", rec->rid.page_num, file_id_);
if ((ret = page_handler.init(*disk_buffer_pool_, rec->rid.page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d", rec->rid.page_num);
return ret;
}
......@@ -406,8 +368,8 @@ RC RecordFileHandler::delete_record(const RID *rid)
RC ret = RC::SUCCESS;
RecordPageHandler page_handler;
if ((ret != page_handler.init(*disk_buffer_pool_, file_id_, rid->page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d, file_id:%d", rid->page_num, file_id_);
if ((ret != page_handler.init(*disk_buffer_pool_, rid->page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d", rid->page_num);
return ret;
}
return page_handler.delete_record(rid);
......@@ -427,8 +389,8 @@ RC RecordFileHandler::get_record(const RID *rid, Record *rec)
}
RecordPageHandler page_handler;
if ((ret != page_handler.init(*disk_buffer_pool_, file_id_, rid->page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d, file_id:%d", rid->page_num, file_id_);
if ((ret != page_handler.init(*disk_buffer_pool_, rid->page_num)) != RC::SUCCESS) {
LOG_ERROR("Failed to init record page handler.page number=%d", rid->page_num);
return ret;
}
......@@ -437,15 +399,11 @@ RC RecordFileHandler::get_record(const RID *rid, Record *rec)
////////////////////////////////////////////////////////////////////////////////
RecordFileScanner::RecordFileScanner() : disk_buffer_pool_(nullptr), file_id_(-1), condition_filter_(nullptr)
{}
RC RecordFileScanner::open_scan(DiskBufferPool &buffer_pool, int file_id, ConditionFilter *condition_filter)
RC RecordFileScanner::open_scan(DiskBufferPool &buffer_pool, ConditionFilter *condition_filter)
{
close_scan();
disk_buffer_pool_ = &buffer_pool;
file_id_ = file_id;
condition_filter_ = condition_filter;
return RC::SUCCESS;
......@@ -483,8 +441,8 @@ RC RecordFileScanner::get_next_record(Record *rec)
Record current_record = *rec;
int page_count = 0;
if ((ret = disk_buffer_pool_->get_page_count(file_id_, &page_count)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page count while getting next record. file id=%d", file_id_);
if ((ret = disk_buffer_pool_->get_page_count(&page_count)) != RC::SUCCESS) {
LOG_ERROR("Failed to get page count while getting next record.");
return RC::RECORD_EOF;
}
......@@ -496,7 +454,7 @@ RC RecordFileScanner::get_next_record(Record *rec)
if (current_record.rid.page_num != record_page_handler_.get_page_num()) {
record_page_handler_.cleanup();
ret = record_page_handler_.init(*disk_buffer_pool_, file_id_, current_record.rid.page_num);
ret = record_page_handler_.init(*disk_buffer_pool_, current_record.rid.page_num);
if (ret != RC::SUCCESS && ret != RC::BUFFERPOOL_INVALID_PAGE_NUM) {
LOG_ERROR("Failed to init record page handler. page num=%d", current_record.rid.page_num);
return ret;
......
......@@ -15,6 +15,7 @@ See the Mulan PSL v2 for more details. */
#define __OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_
#include <sstream>
#include <limits>
#include "storage/default/disk_buffer_pool.h"
typedef int32_t SlotNum;
......@@ -96,10 +97,10 @@ struct Record {
class RecordPageHandler {
public:
RecordPageHandler();
RecordPageHandler() = default;
~RecordPageHandler();
RC init(DiskBufferPool &buffer_pool, int file_id, PageNum page_num);
RC init_empty_page(DiskBufferPool &buffer_pool, int file_id, PageNum page_num, int record_size);
RC init(DiskBufferPool &buffer_pool, PageNum page_num);
RC init_empty_page(DiskBufferPool &buffer_pool, PageNum page_num, int record_size);
RC cleanup();
RC insert_record(const char *data, RID *rid);
......@@ -114,7 +115,7 @@ public:
return rc;
}
rc = updater(record);
disk_buffer_pool_->mark_dirty(&page_handle_);
frame_->mark_dirty();
return rc;
}
......@@ -131,51 +132,40 @@ public:
protected:
char *get_record_data(SlotNum slot_num)
{
return page_handle_.frame->page.data + page_header_->first_record_offset + (page_header_->record_size * slot_num);
return frame_->data() + page_header_->first_record_offset + (page_header_->record_size * slot_num);
}
protected:
DiskBufferPool *disk_buffer_pool_;
int file_id_;
BPPageHandle page_handle_;
PageHeader *page_header_;
char *bitmap_;
DiskBufferPool *disk_buffer_pool_ = nullptr;
Frame *frame_ = nullptr;
PageHeader *page_header_ = nullptr;
char *bitmap_ = nullptr;
};
class RecordFileHandler {
public:
RecordFileHandler();
RC init(DiskBufferPool *buffer_pool, int file_id);
RecordFileHandler() = default;
RC init(DiskBufferPool *buffer_pool);
void close();
/**
* 更新指定文件中的记录,rec指向的记录结构中的rid字段为要更新的记录的标识符,
* pData字段指向新的记录内容
* @param rec
* @return
*/
RC update_record(const Record *rec);
/**
* 从指定文件中删除标识符为rid的记录
* @param rid
* @return
*/
RC delete_record(const RID *rid);
/**
* 插入一个新的记录到指定文件中,pData为指向新纪录内容的指针,返回该记录的标识符rid
* @param data
* @param rid
* @return
*/
RC insert_record(const char *data, int record_size, RID *rid);
/**
* 获取指定文件中标识符为rid的记录内容到rec指向的记录结构中
* @param rid
* @param rec
* @return
*/
RC get_record(const RID *rid, Record *rec);
......@@ -185,7 +175,7 @@ public:
RC rc = RC::SUCCESS;
RecordPageHandler page_handler;
if ((rc != page_handler.init(*disk_buffer_pool_, file_id_, rid->page_num)) != RC::SUCCESS) {
if ((rc != page_handler.init(*disk_buffer_pool_, rid->page_num)) != RC::SUCCESS) {
return rc;
}
......@@ -193,15 +183,13 @@ public:
}
private:
DiskBufferPool *disk_buffer_pool_;
int file_id_; // 参考DiskBufferPool中的fileId
DiskBufferPool *disk_buffer_pool_ = nullptr;
RecordPageHandler record_page_handler_; // 目前只有insert record使用
};
class RecordFileScanner {
public:
RecordFileScanner();
RecordFileScanner() = default;
/**
* 打开一个文件扫描。
......@@ -210,13 +198,8 @@ public:
* 然后再调用GetNextRec函数来逐个返回文件中满足条件的记录。
* 如果条件数量conNum为0,则意味着检索文件中的所有记录。
* 如果条件不为空,则要对每条记录进行条件比较,只有满足所有条件的记录才被返回
* @param buffer_pool
* @param file_id
* @param condition_num
* @param conditions
* @return
*/
RC open_scan(DiskBufferPool &buffer_pool, int file_id, ConditionFilter *condition_filter);
RC open_scan(DiskBufferPool &buffer_pool, ConditionFilter *condition_filter);
/**
* 关闭一个文件扫描,释放相应的资源
......@@ -236,10 +219,9 @@ public:
RC get_next_record(Record *rec);
private:
DiskBufferPool *disk_buffer_pool_;
int file_id_; // 参考DiskBufferPool中的fileId
DiskBufferPool *disk_buffer_pool_ = nullptr;
ConditionFilter *condition_filter_;
ConditionFilter *condition_filter_ = nullptr;
RecordPageHandler record_page_handler_;
};
......
......@@ -29,9 +29,6 @@ See the Mulan PSL v2 for more details. */
#include "storage/index/bplus_tree_index.h"
#include "storage/trx/trx.h"
Table::Table() : data_buffer_pool_(nullptr), file_id_(-1), record_handler_(nullptr)
{}
Table::~Table()
{
if (record_handler_ != nullptr) {
......@@ -39,8 +36,8 @@ Table::~Table()
record_handler_ = nullptr;
}
if (data_buffer_pool_ != nullptr && file_id_ >= 0) {
data_buffer_pool_->close_file(file_id_);
if (data_buffer_pool_ != nullptr) {
data_buffer_pool_->close_file();
data_buffer_pool_ = nullptr;
}
......@@ -102,8 +99,8 @@ RC Table::create(
fs.close();
std::string data_file = table_data_file(base_dir, name);
data_buffer_pool_ = theGlobalDiskBufferPool();
rc = data_buffer_pool_->create_file(data_file.c_str());
BufferPoolManager &bpm = BufferPoolManager::instance();
rc = bpm.create_file(data_file.c_str());
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to create disk buffer pool of data file. file name=%s", data_file.c_str());
return rc;
......@@ -339,28 +336,24 @@ RC Table::make_record(int value_num, const Value *values, char *&record_out)
RC Table::init_record_handler(const char *base_dir)
{
std::string data_file = table_data_file(base_dir, table_meta_.name());
if (nullptr == data_buffer_pool_) {
data_buffer_pool_ = theGlobalDiskBufferPool();
}
int data_buffer_pool_file_id;
RC rc = data_buffer_pool_->open_file(data_file.c_str(), &data_buffer_pool_file_id);
RC rc = BufferPoolManager::instance().open_file(data_file.c_str(), data_buffer_pool_);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to open disk buffer pool for file:%s. rc=%d:%s", data_file.c_str(), rc, strrc(rc));
return rc;
}
record_handler_ = new RecordFileHandler();
rc = record_handler_->init(data_buffer_pool_, data_buffer_pool_file_id);
rc = record_handler_->init(data_buffer_pool_);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to init record handler. rc=%d:%s", rc, strrc(rc));
data_buffer_pool_->close_file(data_buffer_pool_file_id);
data_buffer_pool_->close_file();
data_buffer_pool_ = nullptr;
delete record_handler_;
record_handler_ = nullptr;
return rc;
}
file_id_ = data_buffer_pool_file_id;
return rc;
}
......@@ -419,9 +412,9 @@ RC Table::scan_record(
RC rc = RC::SUCCESS;
RecordFileScanner scanner;
rc = scanner.open_scan(*data_buffer_pool_, file_id_, filter);
rc = scanner.open_scan(*data_buffer_pool_, filter);
if (rc != RC::SUCCESS) {
LOG_ERROR("failed to open scanner. file id=%d. rc=%d:%s", file_id_, rc, strrc(rc));
LOG_ERROR("failed to open scanner. rc=%d:%s", rc, strrc(rc));
return rc;
}
......@@ -441,7 +434,7 @@ RC Table::scan_record(
if (RC::RECORD_EOF == rc) {
rc = RC::SUCCESS;
} else {
LOG_ERROR("failed to scan record. file id=%d, rc=%d:%s", file_id_, rc, strrc(rc));
LOG_ERROR("failed to scan record. rc=%d:%s", rc, strrc(rc));
}
scanner.close_scan();
return rc;
......@@ -834,7 +827,7 @@ IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter)
RC Table::sync()
{
RC rc = data_buffer_pool_->purge_all_pages(file_id_);
RC rc = data_buffer_pool_->purge_all_pages();
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush table's data pages. table=%s, rc=%d:%s", name(), rc, strrc(rc));
return rc;
......
......@@ -30,7 +30,7 @@ class Trx;
class Table {
public:
Table();
Table() = default;
~Table();
/**
......@@ -101,10 +101,9 @@ private:
private:
std::string base_dir_;
TableMeta table_meta_;
DiskBufferPool *data_buffer_pool_; /// 数据文件关联的buffer pool
int file_id_;
RecordFileHandler *record_handler_; /// 记录操作
DiskBufferPool *data_buffer_pool_ = nullptr; /// 数据文件关联的buffer pool
RecordFileHandler *record_handler_ = nullptr; /// 记录操作
std::vector<Index *> indexes_;
};
#endif // __OBSERVER_STORAGE_COMMON_TABLE_H__
\ No newline at end of file
#endif // __OBSERVER_STORAGE_COMMON_TABLE_H__
......@@ -24,10 +24,20 @@ See the Mulan PSL v2 for more details. */
#include "storage/common/table.h"
#include "storage/common/condition_filter.h"
static DefaultHandler *default_handler = nullptr;
void DefaultHandler::set_default(DefaultHandler *handler)
{
if (default_handler != nullptr && handler != nullptr) {
LOG_ERROR("default handler is setted");
abort();
}
default_handler = handler;
}
DefaultHandler &DefaultHandler::get_default()
{
static DefaultHandler handler;
return handler;
return *default_handler;
}
DefaultHandler::DefaultHandler()
......
......@@ -159,6 +159,7 @@ public:
RC sync();
public:
static void set_default(DefaultHandler *handler);
static DefaultHandler &get_default();
private:
......@@ -167,4 +168,4 @@ private:
std::map<std::string, Db *> opened_dbs_;
}; // class Handler
#endif // __OBSERVER_STORAGE_DEFAULT_ENGINE_H__
\ No newline at end of file
#endif // __OBSERVER_STORAGE_DEFAULT_ENGINE_H__
......@@ -21,7 +21,8 @@ See the Mulan PSL v2 for more details. */
using namespace common;
int DiskBufferPool::POOL_NUM = MAX_OPEN_FILE / 4;
static const PageNum BP_HEADER_PAGE = 0;
static const int MEM_POOL_ITEM_NUM = 50;
unsigned long current_time()
{
......@@ -30,20 +31,7 @@ unsigned long current_time()
return tp.tv_sec * 1000 * 1000 * 1000UL + tp.tv_nsec;
}
BPFileHandle::BPFileHandle()
{
memset((void *)this, 0, sizeof(*this));
}
BPFileHandle::~BPFileHandle()
{
if (file_name != nullptr) {
::free((void *)file_name);
file_name = nullptr;
}
}
BPManager::BPManager(const char *name) : MemPoolSimple<Frame>(name)
BPFrameManager::BPFrameManager(const char *name) : MemPoolSimple<Frame>(name)
{}
static bool match_purge(void *item, void *arg)
......@@ -52,7 +40,7 @@ static bool match_purge(void *item, void *arg)
return frame->can_purge();
}
Frame *BPManager::begin_purge()
Frame *BPFrameManager::begin_purge()
{
return MemPoolSimple<Frame>::find(match_purge, nullptr);
}
......@@ -72,13 +60,13 @@ static bool match_file_page(void *item, void *arg)
Frame *frame = (Frame *)item;
MatchFilePage *file_page = (MatchFilePage *)arg;
if (frame->file_desc == file_page->file_desc && frame->page.page_num == file_page->page_num)
if (frame->file_desc() == file_page->file_desc && frame->page_num() == file_page->page_num)
return true;
return false;
}
Frame *BPManager::get(int file_desc, PageNum page_num)
Frame *BPFrameManager::get(int file_desc, PageNum page_num)
{
MatchFilePage file_page(file_desc, page_num);
return MemPoolSimple<Frame>::find(match_file_page, &file_page);
......@@ -89,328 +77,194 @@ static bool match_file(void *item, void *arg)
Frame *frame = (Frame *)item;
int *file_desc = (int *)arg;
if (frame->file_desc == *file_desc)
if (frame->file_desc() == *file_desc)
return true;
return false;
}
std::list<Frame *> BPManager::find_list(int file_desc)
std::list<Frame *> BPFrameManager::find_list(int file_desc)
{
return find_all(match_file, &file_desc);
}
DiskBufferPool *theGlobalDiskBufferPool()
DiskBufferPool::DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager)
: bp_manager_(bp_manager), frame_manager_(frame_manager)
{
static DiskBufferPool *instance = DiskBufferPool::mk_instance();
return instance;
}
DiskBufferPool::DiskBufferPool() : bp_manager_("BPManager")
{
bp_manager_.init(false, DiskBufferPool::POOL_NUM, BP_BUFFER_SIZE);
};
DiskBufferPool::~DiskBufferPool()
{
for (int i = 0; i < MAX_OPEN_FILE; i++) {
BPFileHandle *file_handle = open_list_[i];
if (file_handle == nullptr) {
continue;
}
close_file(i);
open_list_[i] = nullptr;
}
bp_manager_.cleanup();
close_file();
LOG_INFO("Exit");
}
RC DiskBufferPool::create_file(const char *file_name)
RC DiskBufferPool::open_file(const char *file_name)
{
int fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
if (fd < 0) {
LOG_ERROR("Failed to create %s, due to %s.", file_name, strerror(errno));
return RC::SCHEMA_DB_EXIST;
}
close(fd);
/**
* Here don't care about the failure
*/
fd = open(file_name, O_RDWR);
if (fd < 0) {
LOG_ERROR("Failed to open for readwrite %s, due to %s.", file_name, strerror(errno));
return RC::IOERR_ACCESS;
}
Page page;
memset(&page, 0, sizeof(Page));
BPFileSubHeader *fileSubHeader;
fileSubHeader = (BPFileSubHeader *)page.data;
fileSubHeader->allocated_pages = 1;
fileSubHeader->page_count = 1;
char *bitmap = page.data + (int)BP_FILE_SUB_HDR_SIZE;
bitmap[0] |= 0x01;
if (lseek(fd, 0, SEEK_SET) == -1) {
LOG_ERROR("Failed to seek file %s to position 0, due to %s .", file_name, strerror(errno));
close(fd);
return RC::IOERR_SEEK;
}
if (write(fd, (char *)&page, sizeof(Page)) != sizeof(Page)) {
LOG_ERROR("Failed to write header to file %s, due to %s.", file_name, strerror(errno));
close(fd);
return RC::IOERR_WRITE;
}
close(fd);
LOG_INFO("Successfully create %s.", file_name);
return RC::SUCCESS;
}
RC DiskBufferPool::open_file(const char *file_name, int *file_id)
{
int fd, i, size = 0, empty_id = -1;
// This part isn't gentle, the better method is using LRU queue.
for (i = 0; i < MAX_OPEN_FILE; i++) {
if (open_list_[i]) {
size++;
if (!strcmp(open_list_[i]->file_name, file_name)) {
*file_id = i;
LOG_INFO("%s has already been opened.", file_name);
return RC::SUCCESS;
}
} else if (empty_id == -1) {
empty_id = i;
}
}
i = size;
if (i >= MAX_OPEN_FILE && open_list_[i - 1]) {
LOG_ERROR("Failed to open file %s, because too much files have been opened.", file_name);
return RC::BUFFERPOOL_OPEN_TOO_MANY_FILES;
}
int fd;
if ((fd = open(file_name, O_RDWR)) < 0) {
LOG_ERROR("Failed to open file %s, because %s.", file_name, strerror(errno));
return RC::IOERR_ACCESS;
}
LOG_INFO("Successfully open file %s.", file_name);
BPFileHandle *file_handle = new (std::nothrow) BPFileHandle();
if (file_handle == nullptr) {
LOG_ERROR("Failed to alloc memory of BPFileHandle for %s.", file_name);
close(fd);
return RC::NOMEM;
}
file_name_ = file_name;
file_desc_ = fd;
RC tmp = RC::SUCCESS;
file_handle->bopen = true;
file_handle->file_name = strdup(file_name);
file_handle->file_desc = fd;
if ((tmp = allocate_page(&file_handle->hdr_frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to allocate block for %s's BPFileHandle.", file_name);
delete file_handle;
RC rc = RC::SUCCESS;
rc = allocate_frame(&hdr_frame_);
if (rc != RC::SUCCESS) {
LOG_ERROR("failed to allocate frame for header. file name %s", file_name_.c_str());
close(fd);
return tmp;
file_desc_ = -1;
return rc;
}
file_handle->hdr_frame->dirty = false;
file_handle->hdr_frame->file_desc = fd;
file_handle->hdr_frame->pin_count = 1;
file_handle->hdr_frame->acc_time = current_time();
if ((tmp = load_page(0, file_handle, file_handle->hdr_frame)) != RC::SUCCESS) {
hdr_frame_->dirty_ = false;
hdr_frame_->file_desc_ = fd;
hdr_frame_->pin_count_ = 1;
hdr_frame_->acc_time_ = current_time();
if ((rc = load_page(BP_HEADER_PAGE, hdr_frame_)) != RC::SUCCESS) {
LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
file_handle->hdr_frame->pin_count = 0;
purge_page(file_handle->hdr_frame);
hdr_frame_->pin_count_ = 0;
purge_frame(hdr_frame_);
close(fd);
delete file_handle;
return tmp;
file_desc_ = -1;
return rc;
}
file_handle->hdr_page = &(file_handle->hdr_frame->page);
file_handle->bitmap = file_handle->hdr_page->data + BP_FILE_SUB_HDR_SIZE;
file_handle->file_sub_header = (BPFileSubHeader *)file_handle->hdr_page->data;
open_list_[empty_id] = file_handle;
*file_id = empty_id;
file_header_ = (BPFileHeader *)hdr_frame_->data();
LOG_INFO("Successfully open %s. file_id=%d, hdr_frame=%p", file_name, *file_id, file_handle->hdr_frame);
LOG_INFO("Successfully open %s. file_desc=%d, hdr_frame=%p", file_name, file_desc_, hdr_frame_);
return RC::SUCCESS;
}
RC DiskBufferPool::close_file(int file_id)
RC DiskBufferPool::close_file()
{
RC tmp;
if ((tmp = check_file_id(file_id)) != RC::SUCCESS) {
LOG_ERROR("Failed to close file, due to invalid fileId %d", file_id);
return tmp;
RC rc = RC::SUCCESS;
if (file_desc_ < 0) {
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
file_handle->hdr_frame->pin_count--;
if ((tmp = purge_all_pages(file_handle)) != RC::SUCCESS) {
file_handle->hdr_frame->pin_count++;
LOG_ERROR("Failed to close file %d:%s, due to failed to purge all pages.", file_id, file_handle->file_name);
return tmp;
hdr_frame_->pin_count_--;
if ((rc = purge_all_pages()) != RC::SUCCESS) {
hdr_frame_->pin_count_++;
LOG_ERROR("Failed to close %s, due to failed to purge all pages.", file_name_.c_str());
return rc;
}
disposed_pages.erase(file_handle->file_desc);
disposed_pages.clear();
if (close(file_handle->file_desc) < 0) {
LOG_ERROR("Failed to close fileId:%d, fileName:%s, error:%s", file_id, file_handle->file_name, strerror(errno));
if (close(file_desc_) < 0) {
LOG_ERROR("Failed to close fileId:%d, fileName:%s, error:%s", file_desc_, file_name_.c_str(), strerror(errno));
return RC::IOERR_CLOSE;
}
open_list_[file_id] = nullptr;
LOG_INFO("Successfully close file %d:%s.", file_id, file_handle->file_name);
delete file_handle;
LOG_INFO("Successfully close file %d:%s.", file_desc_, file_name_.c_str());
file_desc_ = -1;
bp_manager_.close_file(file_name_.c_str());
return RC::SUCCESS;
}
RC DiskBufferPool::get_this_page(int file_id, PageNum page_num, BPPageHandle *page_handle)
RC DiskBufferPool::get_this_page(PageNum page_num, Frame **frame)
{
RC tmp;
if ((tmp = check_file_id(file_id)) != RC::SUCCESS) {
LOG_ERROR("Failed to load page %d, due to invalid fileId %d", page_num, file_id);
return tmp;
}
BPFileHandle *file_handle = open_list_[file_id];
if ((tmp = check_page_num(page_num, file_handle)) != RC::SUCCESS) {
LOG_ERROR("Failed to load page %s:%d, due to invalid pageNum.", file_handle->file_name, page_num);
return tmp;
}
RC rc = RC::SUCCESS;
Frame *used_match_frame = bp_manager_.get(file_handle->file_desc, page_num);
Frame *used_match_frame = frame_manager_.get(file_desc_, page_num);
if (used_match_frame != nullptr) {
page_handle->frame = used_match_frame;
page_handle->frame->pin_count++;
page_handle->frame->acc_time = current_time();
page_handle->open = true;
used_match_frame->pin_count_++;
used_match_frame->acc_time_ = current_time();
bp_manager_.mark_modified(used_match_frame);
frame_manager_.mark_modified(used_match_frame);
*frame = used_match_frame;
return RC::SUCCESS;
}
// Allocate one page and load the data into this page
if ((tmp = allocate_page(&(page_handle->frame))) != RC::SUCCESS) {
LOG_ERROR("Failed to load page %s:%d, due to failed to alloc page.", file_handle->file_name, page_num);
return tmp;
}
page_handle->frame->dirty = false;
page_handle->frame->file_desc = file_handle->file_desc;
page_handle->frame->pin_count = 1;
page_handle->frame->acc_time = current_time();
if ((tmp = load_page(page_num, file_handle, page_handle->frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to load page %s:%d", file_handle->file_name, page_num);
page_handle->frame->pin_count = 0;
purge_page(page_handle->frame);
return tmp;
}
page_handle->open = true;
Frame *allocated_frame = nullptr;
if ((rc = allocate_frame(&allocated_frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to alloc frame %s:%d, due to failed to alloc page.", file_name_.c_str(), page_num);
return rc;
}
allocated_frame->dirty_ = false;
allocated_frame->file_desc_ = file_desc_;
allocated_frame->pin_count_ = 1;
allocated_frame->acc_time_ = current_time();
if ((rc = load_page(page_num, allocated_frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to load page %s:%d", file_name_.c_str(), page_num);
allocated_frame->pin_count_ = 0;
purge_frame(allocated_frame);
return rc;
}
*frame = allocated_frame;
return RC::SUCCESS;
}
RC DiskBufferPool::allocate_page(int file_id, BPPageHandle *page_handle)
RC DiskBufferPool::allocate_page(Frame **frame)
{
RC tmp;
if ((tmp = check_file_id(file_id)) != RC::SUCCESS) {
LOG_ERROR("Failed to alloc page, due to invalid fileId %d", file_id);
return tmp;
}
BPFileHandle *file_handle = open_list_[file_id];
RC rc = RC::SUCCESS;
int byte = 0, bit = 0;
if ((file_handle->file_sub_header->allocated_pages) < (file_handle->file_sub_header->page_count)) {
if ((file_header_->allocated_pages) < (file_header_->page_count)) {
// There is one free page
for (int i = 0; i < file_handle->file_sub_header->page_count; i++) {
for (int i = 0; i < file_header_->page_count; i++) {
byte = i / 8;
bit = i % 8;
if (((file_handle->bitmap[byte]) & (1 << bit)) == 0) {
(file_handle->file_sub_header->allocated_pages)++;
file_handle->bitmap[byte] |= (1 << bit);
if (((file_header_->bitmap[byte]) & (1 << bit)) == 0) {
(file_header_->allocated_pages)++;
file_header_->bitmap[byte] |= (1 << bit);
// TODO, do we need clean the loaded page's data?
return get_this_page(file_id, i, page_handle);
hdr_frame_->mark_dirty();
return get_this_page(i, frame);
}
}
}
if ((tmp = allocate_page(&(page_handle->frame))) != RC::SUCCESS) {
LOG_ERROR("Failed to allocate page %s, due to no free page.", file_handle->file_name);
return tmp;
Frame *allocated_frame = nullptr;
if ((rc = allocate_frame(&allocated_frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to allocate frame %s, due to no free page.", file_name_.c_str());
return rc;
}
PageNum page_num = file_handle->file_sub_header->page_count;
file_handle->file_sub_header->allocated_pages++;
file_handle->file_sub_header->page_count++;
PageNum page_num = file_header_->page_count;
file_header_->allocated_pages++;
file_header_->page_count++;
byte = page_num / 8;
bit = page_num % 8;
file_handle->bitmap[byte] |= (1 << bit);
file_handle->hdr_frame->dirty = true;
file_header_->bitmap[byte] |= (1 << bit);
hdr_frame_->mark_dirty();
page_handle->frame->dirty = false;
page_handle->frame->file_desc = file_handle->file_desc;
page_handle->frame->pin_count = 1;
page_handle->frame->acc_time = current_time();
memset(&(page_handle->frame->page), 0, sizeof(Page));
page_handle->frame->page.page_num = file_handle->file_sub_header->page_count - 1;
allocated_frame->dirty_ = false;
allocated_frame->file_desc_ = file_desc_;
allocated_frame->pin_count_ = 1;
allocated_frame->acc_time_ = current_time();
allocated_frame->clear_page();
allocated_frame->page_.page_num = file_header_->page_count - 1;
// Use flush operation to extension file
if ((tmp = flush_page(page_handle->frame)) != RC::SUCCESS) {
LOG_WARN("Failed to alloc page %s , due to failed to extend one page.", file_handle->file_name);
if ((rc = flush_page(*allocated_frame)) != RC::SUCCESS) {
LOG_WARN("Failed to alloc page %s , due to failed to extend one page.", file_name_.c_str());
// skip return false, delay flush the extended page
// return tmp;
}
page_handle->open = true;
*frame = allocated_frame;
return RC::SUCCESS;
}
RC DiskBufferPool::get_page_num(BPPageHandle *page_handle, PageNum *page_num)
RC DiskBufferPool::unpin_page(Frame *frame)
{
if (!page_handle->open)
return RC::BUFFERPOOL_CLOSED;
*page_num = page_handle->frame->page.page_num;
return RC::SUCCESS;
}
RC DiskBufferPool::get_data(BPPageHandle *page_handle, char **data)
{
if (!page_handle->open)
return RC::BUFFERPOOL_CLOSED;
*data = page_handle->frame->page.data;
return RC::SUCCESS;
}
RC DiskBufferPool::mark_dirty(BPPageHandle *page_handle)
{
page_handle->frame->dirty = true;
return RC::SUCCESS;
}
RC DiskBufferPool::unpin_page(BPPageHandle *page_handle)
{
page_handle->open = false;
if (--page_handle->frame->pin_count == 0) {
int file_desc = page_handle->frame->file_desc;
auto it = disposed_pages.find(file_desc);
if (it != disposed_pages.end()) {
BPDisposedPages &disposed_page = it->second;
PageNum page_num = page_handle->frame->page.page_num;
auto pages_it = disposed_page.pages.find(page_num);
if (pages_it != disposed_page.pages.end()) {
LOG_INFO("Dispose file_id:%d, page:%d", disposed_page.file_id, page_num);
dispose_page(disposed_page.file_id, page_num);
disposed_page.pages.erase(pages_it);
}
if (--frame->pin_count_ == 0) {
PageNum page_num = frame->page_num();
auto pages_it = disposed_pages.find(page_num);
if (pages_it != disposed_pages.end()) {
LOG_INFO("Dispose file_desc:%d, page:%d", file_desc_, page_num);
dispose_page(page_num);
disposed_pages.erase(pages_it);
}
}
......@@ -420,256 +274,314 @@ RC DiskBufferPool::unpin_page(BPPageHandle *page_handle)
/**
* dispose_page will delete the data of the page of pageNum, free the page both from buffer pool and data file.
* purge_page will purge the page of pageNum, free the page from buffer pool
* @param fileID
* @param pageNum
* @return
*/
RC DiskBufferPool::dispose_page(int file_id, PageNum page_num)
RC DiskBufferPool::dispose_page(PageNum page_num)
{
RC rc;
if ((rc = check_file_id(file_id)) != RC::SUCCESS) {
LOG_ERROR("Failed to alloc page, due to invalid fileId %d", file_id);
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
if ((rc = check_page_num(page_num, file_handle)) != RC::SUCCESS) {
LOG_ERROR("Failed to dispose page %s:%d, due to invalid pageNum", file_handle->file_name, page_num);
return rc;
}
rc = purge_page(file_handle, page_num);
RC rc = purge_page(page_num);
if (rc != RC::SUCCESS) {
LOG_INFO("Dispose page %s:%d later, due to this page is being used", file_handle->file_name, page_num);
auto it = disposed_pages.find(file_handle->file_desc);
if (it == disposed_pages.end()) {
BPDisposedPages disposed_page;
disposed_page.file_id = file_id;
disposed_page.pages.insert(page_num);
disposed_pages.insert(std::pair<int, BPDisposedPages>(file_handle->file_desc, disposed_page));
} else {
BPDisposedPages &disposed_page = it->second;
disposed_page.pages.insert(page_num);
}
LOG_INFO("Dispose page %s:%d later, due to this page is being used", file_name_.c_str(), page_num);
disposed_pages.insert(page_num);
return rc;
}
file_handle->hdr_frame->dirty = true;
file_handle->file_sub_header->allocated_pages--;
// file_handle->pFileSubHeader->pageCount--;
hdr_frame_->dirty_ = true;
file_header_->allocated_pages--;
char tmp = 1 << (page_num % 8);
file_handle->bitmap[page_num / 8] &= ~tmp;
file_header_->bitmap[page_num / 8] &= ~tmp;
return RC::SUCCESS;
}
RC DiskBufferPool::purge_page(int file_id, PageNum page_num)
RC DiskBufferPool::purge_frame(Frame *buf)
{
RC rc;
if ((rc = check_file_id(file_id)) != RC::SUCCESS) {
LOG_ERROR("Failed to alloc page, due to invalid fileId %d", file_id);
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
return purge_page(file_handle, page_num);
}
RC DiskBufferPool::purge_page(Frame *buf)
{
if (buf->pin_count > 0) {
if (buf->pin_count_ > 0) {
LOG_INFO("Begin to free page %d of %d(file id), but it's pinned, pin_count:%d.",
buf->page.page_num,
buf->file_desc,
buf->pin_count);
buf->page_num(), buf->file_desc_, buf->pin_count_);
return RC::LOCKED_UNLOCK;
}
if (buf->dirty) {
RC rc = flush_page(buf);
if (buf->dirty_) {
RC rc = flush_page(*buf);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page.page_num, buf->file_desc);
LOG_WARN("Failed to flush page %d of %d(file desc) during purge page.", buf->page_num(), buf->file_desc_);
return rc;
}
}
LOG_DEBUG("Successfully purge frame =%p, page %d of %d(file desc)", buf, buf->page.page_num, buf->file_desc);
bp_manager_.free(buf);
LOG_DEBUG("Successfully purge frame =%p, page %d of %d(file desc)", buf, buf->page_num(), buf->file_desc_);
frame_manager_.free(buf);
return RC::SUCCESS;
}
/**
* dispose_page will delete the data of the page of pageNum
* force_page will flush the page of pageNum
* @param fileHandle
* @param pageNum
* @return
*/
RC DiskBufferPool::purge_page(BPFileHandle *file_handle, PageNum page_num)
RC DiskBufferPool::purge_page(PageNum page_num)
{
Frame *used_frame = bp_manager_.get(file_handle->file_desc, page_num);
Frame *used_frame = frame_manager_.get(file_desc_, page_num);
if (used_frame != nullptr) {
return purge_page(used_frame);
return purge_frame(used_frame);
}
return RC::SUCCESS;
}
RC DiskBufferPool::purge_all_pages(int file_id)
{
RC rc = check_file_id(file_id);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush pages due to invalid file_id %d", file_id);
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
return purge_all_pages(file_handle);
}
RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle)
RC DiskBufferPool::purge_all_pages()
{
std::list<Frame *> used = bp_manager_.find_list(file_handle->file_desc);
std::list<Frame *> used = frame_manager_.find_list(file_desc_);
for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
Frame *frame = *it;
if (frame->pin_count > 0) {
if (frame->pin_count_ > 0) {
LOG_WARN("The page has been pinned, file_desc:%d, pagenum:%d, pin_count=%d",
frame->file_desc, frame->page.page_num, frame->pin_count);
frame->file_desc_, frame->page_.page_num, frame->pin_count_);
continue;
}
if (frame->dirty) {
RC rc = flush_page(frame);
if (frame->dirty_) {
RC rc = flush_page(*frame);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush all pages' of %s.", file_handle->file_name);
LOG_ERROR("Failed to flush all pages' of %s.", file_name_.c_str());
return rc;
}
}
bp_manager_.free(frame);
frame_manager_.free(frame);
}
return RC::SUCCESS;
}
RC DiskBufferPool::check_all_pages_unpinned(int file_id)
RC DiskBufferPool::check_all_pages_unpinned()
{
RC rc = check_file_id(file_id);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush pages due to invalid file_id %d", file_id);
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
std::list<Frame *> frames = bp_manager_.find_list(file_handle->file_desc);
std::list<Frame *> frames = frame_manager_.find_list(file_desc_);
for (auto & frame : frames) {
if (frame->page.page_num == 0 && frame->pin_count > 1) {
LOG_WARN("This page has been pinned. file id=%d, page num:%d, pin count=%d",
file_id, frame->page.page_num, frame->pin_count);
} else if (frame->page.page_num != 0 && frame->pin_count > 0) {
LOG_WARN("This page has been pinned. file id=%d, page num:%d, pin count=%d",
file_id, frame->page.page_num, frame->pin_count);
if (frame->page_num() == BP_HEADER_PAGE && frame->pin_count_ > 1) {
LOG_WARN("This page has been pinned. file desc=%d, page num:%d, pin count=%d",
file_desc_, frame->page_num(), frame->pin_count_);
} else if (frame->page_num() != BP_HEADER_PAGE && frame->pin_count_ > 0) {
LOG_WARN("This page has been pinned. file desc=%d, page num:%d, pin count=%d",
file_desc_, frame->page_num(), frame->pin_count_);
}
}
LOG_INFO("all pages have been checked of file id %d", file_id);
LOG_INFO("all pages have been checked of file desc %d", file_desc_);
return RC::SUCCESS;
}
RC DiskBufferPool::flush_page(Frame *frame)
RC DiskBufferPool::flush_page(Frame &frame)
{
// The better way is use mmap the block into memory,
// so it is easier to flush data to file.
s64_t offset = ((s64_t)frame->page.page_num) * sizeof(Page);
if (lseek(frame->file_desc, offset, SEEK_SET) == offset - 1) {
LOG_ERROR("Failed to flush page %lld of %d due to failed to seek %s.", offset, frame->file_desc, strerror(errno));
Page &page = frame.page_;
s64_t offset = ((s64_t)page.page_num) * sizeof(Page);
if (lseek(file_desc_, offset, SEEK_SET) == offset - 1) {
LOG_ERROR("Failed to flush page %lld of %d due to failed to seek %s.", offset, file_desc_, strerror(errno));
return RC::IOERR_SEEK;
}
if (write(frame->file_desc, &(frame->page), sizeof(Page)) != sizeof(Page)) {
LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, frame->file_desc, strerror(errno));
if (write(file_desc_, &page, sizeof(Page)) != sizeof(Page)) {
LOG_ERROR("Failed to flush page %lld of %d due to %s.", offset, file_desc_, strerror(errno));
return RC::IOERR_WRITE;
}
frame->dirty = false;
LOG_DEBUG("Flush block. file desc=%d, page num=%d", frame->file_desc, frame->page.page_num);
frame.dirty_ = false;
LOG_DEBUG("Flush block. file desc=%d, page num=%d", file_desc_, page.page_num);
return RC::SUCCESS;
}
RC DiskBufferPool::allocate_page(Frame **buffer)
RC DiskBufferPool::allocate_frame(Frame **buffer)
{
Frame *frame = bp_manager_.alloc();
Frame *frame = frame_manager_.alloc();
if (frame != nullptr) {
*buffer = frame;
return RC::SUCCESS;
}
frame = bp_manager_.begin_purge();
frame = frame_manager_.begin_purge();
if (frame == nullptr) {
LOG_ERROR("All pages have been used and pinned.");
return RC::NOMEM;
}
if (frame->dirty) {
RC rc = flush_page(frame);
if (frame->dirty_) {
RC rc = bp_manager_.flush_page(*frame);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to aclloc block due to failed to flush old block.");
return rc;
}
}
bp_manager_.mark_modified(frame);
frame_manager_.mark_modified(frame);
*buffer = frame;
return RC::SUCCESS;
}
RC DiskBufferPool::check_file_id(int file_id)
RC DiskBufferPool::check_page_num(PageNum page_num)
{
if (file_id < 0 || file_id >= MAX_OPEN_FILE) {
LOG_ERROR("Invalid fileId:%d.", file_id);
return RC::BUFFERPOOL_ILLEGAL_FILE_ID;
if (page_num >= file_header_->page_count) {
LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_name_.c_str());
return RC::BUFFERPOOL_INVALID_PAGE_NUM;
}
if (!open_list_[file_id]) {
LOG_ERROR("Invalid fileId:%d, it is empty.", file_id);
return RC::BUFFERPOOL_ILLEGAL_FILE_ID;
if ((file_header_->bitmap[page_num / 8] & (1 << (page_num % 8))) == 0) {
LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_name_.c_str());
return RC::BUFFERPOOL_INVALID_PAGE_NUM;
}
return RC::SUCCESS;
}
RC DiskBufferPool::get_page_count(int file_id, int *page_count)
RC DiskBufferPool::load_page(PageNum page_num, Frame *frame)
{
RC rc = RC::SUCCESS;
if ((rc = check_file_id(file_id)) != RC::SUCCESS) {
return rc;
s64_t offset = ((s64_t)page_num) * sizeof(Page);
if (lseek(file_desc_, offset, SEEK_SET) == -1) {
LOG_ERROR("Failed to load page %s:%d, due to failed to lseek:%s.",
file_name_.c_str(), page_num, strerror(errno));
return RC::IOERR_SEEK;
}
if (read(file_desc_, &(frame->page_), sizeof(Page)) != sizeof(Page)) {
LOG_ERROR("Failed to load page %s:%d, due to failed to read data:%s.",
file_name_.c_str(), page_num, strerror(errno));
return RC::IOERR_READ;
}
*page_count = open_list_[file_id]->file_sub_header->page_count;
return RC::SUCCESS;
}
RC DiskBufferPool::check_page_num(PageNum page_num, BPFileHandle *file_handle)
RC DiskBufferPool::get_page_count(int *page_count)
{
if (page_num >= file_handle->file_sub_header->page_count) {
LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_handle->file_name);
return RC::BUFFERPOOL_INVALID_PAGE_NUM;
*page_count = file_header_->allocated_pages;
return RC::SUCCESS;
}
int DiskBufferPool::file_desc() const
{
return file_desc_;
}
////////////////////////////////////////////////////////////////////////////////
BufferPoolManager::BufferPoolManager()
{
frame_manager_.init(true/*dynamic*/, MEM_POOL_ITEM_NUM);
}
BufferPoolManager::~BufferPoolManager()
{
std::unordered_map<std::string, DiskBufferPool *> tmp_bps;
tmp_bps.swap(buffer_pools_);
for (auto &iter : tmp_bps) {
delete iter.second;
}
if ((file_handle->bitmap[page_num / 8] & (1 << (page_num % 8))) == 0) {
LOG_ERROR("Invalid pageNum:%d, file's name:%s", page_num, file_handle->file_name);
return RC::BUFFERPOOL_INVALID_PAGE_NUM;
}
RC BufferPoolManager::create_file(const char *file_name)
{
int fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
if (fd < 0) {
LOG_ERROR("Failed to create %s, due to %s.", file_name, strerror(errno));
return RC::SCHEMA_DB_EXIST;
}
close(fd);
/**
* Here don't care about the failure
*/
fd = open(file_name, O_RDWR);
if (fd < 0) {
LOG_ERROR("Failed to open for readwrite %s, due to %s.", file_name, strerror(errno));
return RC::IOERR_ACCESS;
}
Page page;
memset(&page, 0, sizeof(Page));
BPFileHeader *file_header = (BPFileHeader *)page.data;
file_header->allocated_pages = 1;
file_header->page_count = 1;
char *bitmap = file_header->bitmap;
bitmap[0] |= 0x01;
if (lseek(fd, 0, SEEK_SET) == -1) {
LOG_ERROR("Failed to seek file %s to position 0, due to %s .", file_name, strerror(errno));
close(fd);
return RC::IOERR_SEEK;
}
if (write(fd, (char *)&page, sizeof(Page)) != sizeof(Page)) {
LOG_ERROR("Failed to write header to file %s, due to %s.", file_name, strerror(errno));
close(fd);
return RC::IOERR_WRITE;
}
close(fd);
LOG_INFO("Successfully create %s.", file_name);
return RC::SUCCESS;
}
RC DiskBufferPool::load_page(PageNum page_num, BPFileHandle *file_handle, Frame *frame)
RC BufferPoolManager::open_file(const char *_file_name, DiskBufferPool *& _bp)
{
s64_t offset = ((s64_t)page_num) * sizeof(Page);
if (lseek(file_handle->file_desc, offset, SEEK_SET) == -1) {
LOG_ERROR(
"Failed to load page %s:%d, due to failed to lseek:%s.", file_handle->file_name, page_num, strerror(errno));
std::string file_name(_file_name);
if (buffer_pools_.find(file_name) != buffer_pools_.end()) {
LOG_WARN("file already opened. file name=%s", _file_name);
return RC::BUFFERPOOL_OPEN;
}
return RC::IOERR_SEEK;
DiskBufferPool *bp = new DiskBufferPool(*this, frame_manager_);
RC rc = bp->open_file(_file_name);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to open file name");
delete bp;
return rc;
}
if (read(file_handle->file_desc, &(frame->page), sizeof(Page)) != sizeof(Page)) {
LOG_ERROR(
"Failed to load page %s:%d, due to failed to read data:%s.", file_handle->file_name, page_num, strerror(errno));
return RC::IOERR_READ;
buffer_pools_.insert(std::pair<std::string, DiskBufferPool *>(file_name, bp));
fd_buffer_pools_.insert(std::pair<int, DiskBufferPool *>(bp->file_desc(), bp));
_bp = bp;
return RC::SUCCESS;
}
RC BufferPoolManager::close_file(const char *_file_name)
{
std::string file_name(_file_name);
auto iter = buffer_pools_.find(file_name);
if (iter == buffer_pools_.end()) {
LOG_WARN("file has not opened: %s", _file_name);
return RC::INTERNAL;
}
int fd = iter->second->file_desc();
fd_buffer_pools_.erase(fd);
DiskBufferPool *bp = iter->second;
buffer_pools_.erase(iter);
delete bp;
return RC::SUCCESS;
}
RC BufferPoolManager::flush_page(Frame &frame)
{
int fd = frame.file_desc();
auto iter = fd_buffer_pools_.find(fd);
if (iter == fd_buffer_pools_.end()) {
LOG_WARN("unknown buffer pool of fd %d", fd);
return RC::INTERNAL;
}
DiskBufferPool *bp = iter->second;
return bp->flush_page(frame);
}
static BufferPoolManager *default_bpm = nullptr;
void BufferPoolManager::set_instance(BufferPoolManager *bpm)
{
if (default_bpm != nullptr && bpm != nullptr) {
LOG_ERROR("default buffer pool manager has been setted");
abort();
}
default_bpm = bpm;
}
BufferPoolManager &BufferPoolManager::instance()
{
return *default_bpm;
}
......@@ -14,19 +14,23 @@ See the Mulan PSL v2 for more details. */
#ifndef __OBSERVER_STORAGE_COMMON_PAGE_MANAGER_H_
#define __OBSERVER_STORAGE_COMMON_PAGE_MANAGER_H_
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <string>
#include <unordered_map>
#include "rc.h"
#include "common/mm/mem_pool.h"
typedef int PageNum;
typedef int32_t PageNum;
class BufferPoolManager;
class DiskBufferPool;
//
#define BP_INVALID_PAGE_NUM (-1)
......@@ -34,73 +38,82 @@ typedef int PageNum;
#define BP_PAGE_DATA_SIZE (BP_PAGE_SIZE - sizeof(PageNum))
#define BP_FILE_SUB_HDR_SIZE (sizeof(BPFileSubHeader))
#define BP_BUFFER_SIZE 256
#define MAX_OPEN_FILE 1024
typedef struct {
struct Page {
PageNum page_num;
char data[BP_PAGE_DATA_SIZE];
} Page;
};
// sizeof(Page) should be equal to BP_PAGE_SIZE
typedef struct {
PageNum page_count;
int allocated_pages;
} BPFileSubHeader;
typedef struct {
int file_id;
std::set<PageNum> pages;
} BPDisposedPages;
typedef struct Frame_ {
bool dirty;
unsigned int pin_count;
unsigned long acc_time;
int file_desc;
Page page;
/**
* BufferPool的文件第一个页面,存放一些元数据信息,包括了后面每页的分配信息。
* TODO 1. 当前的做法,只能分配比较少的页面,你可以扩展一下,支持更多的页面或无限多的页面吗?
* 可以参考Linux ext(n)和Windows NTFS等文件系统
* 2. 当前使用bitmap存放页面分配情况,但是这种方法在页面非常多的时候,查找空闲页面的
* 效率非常低,你有办法优化吗?
*/
struct BPFileHeader {
int32_t page_count; //! 当前文件一共有多少个页面
int32_t allocated_pages; //! 已经分配了多少个页面
char bitmap[0]; //! 页面分配位图, 第0个页面(就是当前页面),总是1
};
bool can_purge()
class Frame
{
public:
void clear_page()
{
return pin_count <= 0;
memset(&page_, 0, sizeof(page_));
}
} Frame;
typedef struct BPPageHandle {
BPPageHandle() : open(false), frame(nullptr)
{}
PageNum page_num() const
{
return page_.page_num;
}
PageNum page_num() const {
return frame->page.page_num;
void set_page_num(PageNum page_num)
{
page_.page_num = page_num;
}
/**
* 标记指定页面为“脏”页。如果修改了页面的内容,则应调用此函数,
* 以便该页面被淘汰出缓冲区时系统将新的页面数据写入磁盘文件
*/
void mark_dirty() {
this->frame->dirty = true;
dirty_ = true;
}
char *data() {
return this->frame->page.data;
return page_.data;
}
bool open;
Frame *frame;
} BPPageHandle;
class BPFileHandle {
public:
BPFileHandle();
~BPFileHandle();
int file_desc() const
{
return file_desc_;
}
public:
bool bopen;
const char *file_name;
int file_desc;
Frame *hdr_frame;
Page *hdr_page;
char *bitmap;
BPFileSubHeader *file_sub_header;
void set_file_desc(int fd)
{
file_desc_ = fd;
}
bool can_purge()
{
return pin_count_ <= 0;
}
private:
friend class DiskBufferPool;
bool dirty_ = false;
unsigned int pin_count_ = 0;
unsigned long acc_time_ = 0;
int file_desc_ = -1;
Page page_;
};
class BPManager : public common::MemPoolSimple<Frame> {
class BPFrameManager : public common::MemPoolSimple<Frame> {
public:
BPManager(const char *tag);
BPFrameManager(const char *tag);
Frame *get(int file_desc, PageNum page_num);
......@@ -111,26 +124,7 @@ public:
class DiskBufferPool {
public:
static DiskBufferPool *mk_instance()
{
return new DiskBufferPool();
}
static void set_pool_num(int pool_num)
{
if (pool_num > 0) {
POOL_NUM = pool_num;
LOG_INFO("Successfully set POOL_NUM as %d", pool_num);
} else {
LOG_INFO("Invalid input argument pool_num:%d", pool_num);
}
}
static const int get_pool_num()
{
return POOL_NUM;
}
DiskBufferPool(BufferPoolManager &bp_manager, BPFrameManager &frame_manager);
~DiskBufferPool();
/**
......@@ -142,53 +136,36 @@ public:
* 根据文件名打开一个分页文件,返回文件ID
* @return
*/
RC open_file(const char *file_name, int *file_id);
RC open_file(const char *file_name);
/**
* 关闭fileID对应的分页文件
* 关闭分页文件
*/
RC close_file(int file_id);
RC close_file();
/**
* 根据文件ID和页号获取指定页面到缓冲区,返回页面句柄指针。
* @return
*/
RC get_this_page(int file_id, PageNum page_num, BPPageHandle *page_handle);
RC get_this_page(PageNum page_num, Frame **frame);
/**
* 在指定文件中分配一个新的页面,并将其放入缓冲区,返回页面句柄指针。
* 分配页面时,如果文件中有空闲页,就直接分配一个空闲页;
* 如果文件中没有空闲页,则扩展文件规模来增加新的空闲页。
*/
RC allocate_page(int file_id, BPPageHandle *page_handle);
/**
* 根据页面句柄指针返回对应的页面号
*/
RC get_page_num(BPPageHandle *page_handle, PageNum *page_num);
/**
* 根据页面句柄指针返回对应的数据区指针
*/
RC get_data(BPPageHandle *page_handle, char **data);
RC allocate_page(Frame **frame);
/**
* 比purge_page多一个动作, 在磁盘上将对应的页数据删掉。
*/
RC dispose_page(int file_id, PageNum page_num);
RC dispose_page(PageNum page_num);
/**
* 释放指定文件关联的页的内存, 如果已经脏, 则刷到磁盘,除了pinned page
* @param file_handle
* @param page_num 如果不指定page_num 将刷新所有页
*/
RC purge_page(int file_id, PageNum page_num);
/**
* 标记指定页面为“脏”页。如果修改了页面的内容,则应调用此函数,
* 以便该页面被淘汰出缓冲区时系统将新的页面数据写入磁盘文件
*/
RC mark_dirty(BPPageHandle *page_handle);
RC purge_page(PageNum page_num);
RC purge_all_pages();
/**
* 此函数用于解除pageHandle对应页面的驻留缓冲区限制。
......@@ -196,44 +173,66 @@ public:
* 该页面被设置为驻留缓冲区状态,以防止其在处理过程中被置换出去,
* 因此在该页面使用完之后应调用此函数解除该限制,使得该页面此后可以正常地被淘汰出缓冲区
*/
RC unpin_page(BPPageHandle *page_handle);
RC unpin_page(Frame *frame);
/**
* 获取文件的总页数
*/
RC get_page_count(int file_id, int *page_count);
RC get_page_count(int *page_count);
RC check_all_pages_unpinned();
RC purge_all_pages(int file_id);
int file_desc() const;
RC check_all_pages_unpinned(int file_id);
/**
* 如果页面是脏的,就将数据刷新到磁盘
*/
RC flush_page(Frame &frame);
protected:
RC allocate_page(Frame **buf);
RC allocate_frame(Frame **buf);
/**
* 刷新指定文件关联的所有脏页到磁盘,除了pinned page
* @param file_handle
* @param page_num 如果不指定page_num 将刷新所有页
* 刷新指定页面到磁盘(flush),并且释放关联的Frame
*/
RC purge_page(BPFileHandle *file_handle, PageNum page_num);
RC purge_page(Frame *used_frame);
RC purge_all_pages(BPFileHandle *file_handle);
RC check_file_id(int file_id);
RC check_page_num(PageNum page_num, BPFileHandle *file_handle);
RC load_page(PageNum page_num, BPFileHandle *file_handle, Frame *frame);
RC flush_page(Frame *frame);
RC purge_frame(Frame *used_frame);
RC check_page_num(PageNum page_num);
private:
DiskBufferPool();
/**
* 加载指定页面的数据到内存中
*/
RC load_page(PageNum page_num, Frame *frame);
private:
BPManager bp_manager_;
BPFileHandle *open_list_[MAX_OPEN_FILE] = {nullptr};
std::map<int, BPDisposedPages> disposed_pages;
static int POOL_NUM;
BufferPoolManager &bp_manager_;
BPFrameManager & frame_manager_;
std::string file_name_;
int file_desc_ = -1;
Frame * hdr_frame_ = nullptr;
BPFileHeader * file_header_ = nullptr;
std::set<PageNum> disposed_pages;
};
DiskBufferPool *theGlobalDiskBufferPool();
class BufferPoolManager
{
public:
BufferPoolManager();
~BufferPoolManager();
RC create_file(const char *file_name);
RC open_file(const char *file_name, DiskBufferPool *&bp);
RC close_file(const char *file_name);
RC flush_page(Frame &frame);
public:
static void set_instance(BufferPoolManager *bpm);
static BufferPoolManager &instance();
private:
BPFrameManager frame_manager_{"BufPool"};
std::unordered_map<std::string, DiskBufferPool *> buffer_pools_;
std::unordered_map<int, DiskBufferPool *> fd_buffer_pools_;
};
#endif //__OBSERVER_STORAGE_COMMON_PAGE_MANAGER_H_
......@@ -38,8 +38,8 @@ int calc_leaf_page_capacity(int attr_length)
}
/////////////////////////////////////////////////////////////////////////////////
IndexNodeHandler::IndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
: header_(header), page_num_(page_handle.page_num()), node_((IndexNode *)page_handle.data())
IndexNodeHandler::IndexNodeHandler(const IndexFileHeader &header, Frame *frame)
: header_(header), page_num_(frame->page_num()), node_((IndexNode *)frame->data())
{}
bool IndexNodeHandler::is_leaf() const
......@@ -122,8 +122,8 @@ bool IndexNodeHandler::validate() const
}
/////////////////////////////////////////////////////////////////////////////////
LeafIndexNodeHandler::LeafIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
: IndexNodeHandler(header, page_handle), leaf_node_((LeafIndexNode *)page_handle.data())
LeafIndexNodeHandler::LeafIndexNodeHandler(const IndexFileHeader &header, Frame *frame)
: IndexNodeHandler(header, frame), leaf_node_((LeafIndexNode *)frame->data())
{}
void LeafIndexNodeHandler::init_empty()
......@@ -224,7 +224,7 @@ int LeafIndexNodeHandler::remove(const char *key, const KeyComparator &comparato
return 0;
}
RC LeafIndexNodeHandler::move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
RC LeafIndexNodeHandler::move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp)
{
const int size = this->size();
const int move_index = size / 2;
......@@ -234,7 +234,7 @@ RC LeafIndexNodeHandler::move_half_to(LeafIndexNodeHandler &other, DiskBufferPoo
this->increase_size(- ( size - move_index));
return RC::SUCCESS;
}
RC LeafIndexNodeHandler::move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
RC LeafIndexNodeHandler::move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool)
{
other.append(__item_at(0));
......@@ -245,7 +245,7 @@ RC LeafIndexNodeHandler::move_first_to_end(LeafIndexNodeHandler &other, DiskBuff
return RC::SUCCESS;
}
RC LeafIndexNodeHandler::move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
RC LeafIndexNodeHandler::move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp)
{
other.preappend(__item_at(size() - 1));
......@@ -255,7 +255,7 @@ RC LeafIndexNodeHandler::move_last_to_front(LeafIndexNodeHandler &other, DiskBuf
/**
* move all items to left page
*/
RC LeafIndexNodeHandler::move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
RC LeafIndexNodeHandler::move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp)
{
memcpy(other.__item_at(other.size()), this->__item_at(0), this->size() * item_size());
other.increase_size(this->size());
......@@ -265,17 +265,17 @@ RC LeafIndexNodeHandler::move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp
PageNum next_right_page_num = this->next_page();
if (next_right_page_num != BP_INVALID_PAGE_NUM) {
BPPageHandle next_right_page_handle;
RC rc = bp->get_this_page(file_id, next_right_page_num, &next_right_page_handle);
Frame *next_right_frame;
RC rc = bp->get_this_page(next_right_page_num, &next_right_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next right page. page number:%d. rc=%d:%s", next_right_page_num, rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler next_right_node(header_, next_right_page_handle);
LeafIndexNodeHandler next_right_node(header_, next_right_frame);
next_right_node.set_prev_page(other.page_num());
next_right_page_handle.mark_dirty();
bp->unpin_page(&next_right_page_handle);
next_right_frame->mark_dirty();
bp->unpin_page(next_right_frame);
}
return RC::SUCCESS;
}
......@@ -322,7 +322,7 @@ std::string to_string(const LeafIndexNodeHandler &handler, const KeyPrinter &pri
return ss.str();
}
bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const
bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp) const
{
bool result = IndexNodeHandler::validate();
if (false == result) {
......@@ -343,20 +343,20 @@ bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferP
return true;
}
BPPageHandle parent_page_handle;
RC rc = bp->get_this_page(file_id, parent_page_num, &parent_page_handle);
Frame *parent_frame;
RC rc = bp->get_this_page(parent_page_num, &parent_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch parent page. page num=%d, rc=%d:%s",
parent_page_num, rc, strrc(rc));
return false;
}
InternalIndexNodeHandler parent_node(header_, parent_page_handle);
InternalIndexNodeHandler parent_node(header_, parent_frame);
int index_in_parent = parent_node.value_index(this->page_num());
if (index_in_parent < 0) {
LOG_WARN("invalid leaf node. cannot find index in parent. this page num=%d, parent page num=%d",
this->page_num(), parent_page_num);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
......@@ -366,7 +366,7 @@ bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferP
LOG_WARN("invalid leaf node. first item should be greate than or equal to parent item. " \
"this page num=%d, parent page num=%d, index in parent=%d",
this->page_num(), parent_node.page_num(), index_in_parent);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
}
......@@ -377,17 +377,17 @@ bool LeafIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferP
LOG_WARN("invalid leaf node. last item should be less than the item at the first after item in parent." \
"this page num=%d, parent page num=%d, parent item to compare=%d",
this->page_num(), parent_node.page_num(), index_in_parent + 1);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
}
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return true;
}
/////////////////////////////////////////////////////////////////////////////////
InternalIndexNodeHandler::InternalIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle)
: IndexNodeHandler(header, page_handle), internal_node_((InternalIndexNode *)page_handle.data())
InternalIndexNodeHandler::InternalIndexNodeHandler(const IndexFileHeader &header, Frame *frame)
: IndexNodeHandler(header, frame), internal_node_((InternalIndexNode *)frame->data())
{}
std::string to_string(const InternalIndexNodeHandler &node, const KeyPrinter &printer)
......@@ -436,11 +436,11 @@ void InternalIndexNodeHandler::insert(const char *key, PageNum page_num, const K
increase_size(1);
}
RC InternalIndexNodeHandler::move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
RC InternalIndexNodeHandler::move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp)
{
const int size = this->size();
const int move_index = size / 2;
RC rc = other.copy_from(this->__item_at(move_index), size - move_index, bp, file_id);
RC rc = other.copy_from(this->__item_at(move_index), size - move_index, bp);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to copy item to new node. rc=%d:%s", rc, strrc(rc));
return rc;
......@@ -538,9 +538,9 @@ void InternalIndexNodeHandler::remove(int index)
increase_size(-1);
}
RC InternalIndexNodeHandler::move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
RC InternalIndexNodeHandler::move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool)
{
RC rc = other.copy_from(__item_at(0), size(), disk_buffer_pool, file_id);
RC rc = other.copy_from(__item_at(0), size(), disk_buffer_pool);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to copy items to other node. rc=%d:%s", rc, strrc(rc));
return rc;
......@@ -550,9 +550,9 @@ RC InternalIndexNodeHandler::move_to(InternalIndexNodeHandler &other, DiskBuffer
return RC::SUCCESS;
}
RC InternalIndexNodeHandler::move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id)
RC InternalIndexNodeHandler::move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool)
{
RC rc = other.append(__item_at(0), disk_buffer_pool, file_id);
RC rc = other.append(__item_at(0), disk_buffer_pool);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to append item to others.");
return rc;
......@@ -565,9 +565,9 @@ RC InternalIndexNodeHandler::move_first_to_end(InternalIndexNodeHandler &other,
return rc;
}
RC InternalIndexNodeHandler::move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id)
RC InternalIndexNodeHandler::move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp)
{
RC rc = other.preappend(__item_at(size() - 1), bp, file_id);
RC rc = other.preappend(__item_at(size() - 1), bp);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to preappend to others");
return rc;
......@@ -579,50 +579,50 @@ RC InternalIndexNodeHandler::move_last_to_front(InternalIndexNodeHandler &other,
/**
* copy items from other node to self's right
*/
RC InternalIndexNodeHandler::copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool, int file_id)
RC InternalIndexNodeHandler::copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool)
{
memcpy(__item_at(this->size()), items, num * item_size());
RC rc = RC::SUCCESS;
PageNum this_page_num = this->page_num();
BPPageHandle page_handle;
Frame *frame = nullptr;
for (int i = 0; i < num; i++) {
const PageNum page_num = *(const PageNum *)((items + i * item_size()) + key_size());
rc = disk_buffer_pool->get_this_page(file_id, page_num, &page_handle);
rc = disk_buffer_pool->get_this_page(page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to set child's page num. child page num:%d, this page num=%d, rc=%d:%s",
page_num, this_page_num, rc, strrc(rc));
return rc;
}
IndexNodeHandler child_node(header_, page_handle);
IndexNodeHandler child_node(header_, frame);
child_node.set_parent_page_num(this_page_num);
page_handle.mark_dirty();
disk_buffer_pool->unpin_page(&page_handle);
frame->mark_dirty();
disk_buffer_pool->unpin_page(frame);
}
increase_size(num);
return rc;
}
RC InternalIndexNodeHandler::append(const char *item, DiskBufferPool *bp, int file_id)
RC InternalIndexNodeHandler::append(const char *item, DiskBufferPool *bp)
{
return this->copy_from(item, 1, bp, file_id);
return this->copy_from(item, 1, bp);
}
RC InternalIndexNodeHandler::preappend(const char *item, DiskBufferPool *bp, int file_id)
RC InternalIndexNodeHandler::preappend(const char *item, DiskBufferPool *bp)
{
PageNum child_page_num = *(PageNum *)(item + key_size());
BPPageHandle page_handle;
RC rc = bp->get_this_page(file_id, child_page_num, &page_handle);
Frame *frame = nullptr;
RC rc = bp->get_this_page(child_page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page. rc=%d:%s", rc, strrc(rc));
return rc;
}
IndexNodeHandler child_node(header_, page_handle);
IndexNodeHandler child_node(header_, frame);
child_node.set_parent_page_num(this->page_num());
page_handle.mark_dirty();
bp->unpin_page(&page_handle);
frame->mark_dirty();
bp->unpin_page(frame);
if (this->size() > 0) {
memmove(__item_at(1), __item_at(0), this->size() * item_size());
......@@ -658,7 +658,7 @@ int InternalIndexNodeHandler::item_size() const
return key_size() + this->value_size();
}
bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const
bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBufferPool *bp) const
{
bool result = IndexNodeHandler::validate();
if (false == result) {
......@@ -679,19 +679,19 @@ bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBuf
if (page_num < 0) {
LOG_WARN("this page num=%d, got invalid child page. page num=%d", this->page_num(), page_num);
} else {
BPPageHandle child_page_handle;
RC rc = bp->get_this_page(file_id, page_num, &child_page_handle);
Frame *child_frame;
RC rc = bp->get_this_page(page_num, &child_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page while validate internal page. page num=%d, rc=%d:%s",
page_num, rc, strrc(rc));
} else {
IndexNodeHandler child_node(header_, child_page_handle);
IndexNodeHandler child_node(header_, child_frame);
if (child_node.parent_page_num() != this->page_num()) {
LOG_WARN("child's parent page num is invalid. child page num=%d, parent page num=%d, this page num=%d",
child_node.page_num(), child_node.parent_page_num(), this->page_num());
result = false;
}
bp->unpin_page(&child_page_handle);
bp->unpin_page(child_frame);
}
}
}
......@@ -705,19 +705,19 @@ bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBuf
return result;
}
BPPageHandle parent_page_handle;
RC rc = bp->get_this_page(file_id, parent_page_num, &parent_page_handle);
Frame *parent_frame;
RC rc = bp->get_this_page(parent_page_num, &parent_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch parent page. page num=%d, rc=%d:%s", parent_page_num, rc, strrc(rc));
return false;
}
InternalIndexNodeHandler parent_node(header_, parent_page_handle);
InternalIndexNodeHandler parent_node(header_, parent_frame);
int index_in_parent = parent_node.value_index(this->page_num());
if (index_in_parent < 0) {
LOG_WARN("invalid internal node. cannot find index in parent. this page num=%d, parent page num=%d",
this->page_num(), parent_page_num);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
......@@ -727,7 +727,7 @@ bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBuf
LOG_WARN("invalid internal node. the second item should be greate than or equal to parent item. " \
"this page num=%d, parent page num=%d, index in parent=%d",
this->page_num(), parent_node.page_num(), index_in_parent);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
}
......@@ -738,11 +738,11 @@ bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBuf
LOG_WARN("invalid internal node. last item should be less than the item at the first after item in parent." \
"this page num=%d, parent page num=%d, parent item to compare=%d",
this->page_num(), parent_node.page_num(), index_in_parent + 1);
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return false;
}
}
bp->unpin_page(&parent_page_handle);
bp->unpin_page(parent_frame);
return result;
}
......@@ -751,40 +751,40 @@ bool InternalIndexNodeHandler::validate(const KeyComparator &comparator, DiskBuf
RC BplusTreeHandler::sync()
{
return disk_buffer_pool_->purge_all_pages(file_id_);
return disk_buffer_pool_->purge_all_pages();
}
RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_length,
int internal_max_size /* = -1*/, int leaf_max_size /* = -1 */)
{
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
RC rc = disk_buffer_pool->create_file(file_name);
BufferPoolManager &bpm = BufferPoolManager::instance();
RC rc = bpm.create_file(file_name);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to create file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
LOG_INFO("Successfully create index file:%s", file_name);
int file_id;
rc = disk_buffer_pool->open_file(file_name, &file_id);
DiskBufferPool *bp = nullptr;
rc = bpm.open_file(file_name, bp);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
LOG_INFO("Successfully open index file %s.", file_name);
BPPageHandle header_page_handle;
rc = disk_buffer_pool->allocate_page(file_id, &header_page_handle);
Frame *header_frame;
rc = bp->allocate_page(&header_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to allocate header page for bplus tree. rc=%d:%s", rc, strrc(rc));
disk_buffer_pool->close_file(file_id);
bpm.close_file(file_name);
return rc;
}
if (header_page_handle.page_num() != FIRST_INDEX_PAGE) {
if (header_frame->page_num() != FIRST_INDEX_PAGE) {
LOG_WARN("header page num should be %d but got %d. is it a new file : %s",
FIRST_INDEX_PAGE, header_page_handle.page_num(), file_name);
disk_buffer_pool->close_file(file_id);
FIRST_INDEX_PAGE, header_frame->page_num(), file_name);
bpm.close_file(file_name);
return RC::INTERNAL;
}
......@@ -794,7 +794,8 @@ RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_
if (leaf_max_size < 0) {
leaf_max_size = calc_leaf_page_capacity(attr_length);
}
char *pdata = header_page_handle.data();
char *pdata = header_frame->data();
IndexFileHeader *file_header = (IndexFileHeader *)pdata;
file_header->attr_length = attr_length;
file_header->key_length = attr_length + sizeof(RID);
......@@ -803,14 +804,13 @@ RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_
file_header->leaf_max_size = leaf_max_size;
file_header->root_page = BP_INVALID_PAGE_NUM;
header_page_handle.mark_dirty();
disk_buffer_pool->unpin_page(&header_page_handle);
header_frame->mark_dirty();
disk_buffer_pool_ = disk_buffer_pool;
file_id_ = file_id;
disk_buffer_pool_ = bp;
memcpy(&file_header_, pdata, sizeof(file_header_));
header_dirty_ = false;
bp->unpin_page(header_frame);
mem_pool_item_ = new common::MemPoolItem(file_name);
if (mem_pool_item_->init(file_header->key_length) < 0) {
......@@ -827,32 +827,31 @@ RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_
RC BplusTreeHandler::open(const char *file_name)
{
if (file_id_ >= 0) {
if (disk_buffer_pool_ != nullptr) {
LOG_WARN("%s has been opened before index.open.", file_name);
return RC::RECORD_OPENNED;
}
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
int file_id = 0;
RC rc = disk_buffer_pool->open_file(file_name, &file_id);
BufferPoolManager &bpm = BufferPoolManager::instance();
DiskBufferPool *disk_buffer_pool;
RC rc = bpm.open_file(file_name, disk_buffer_pool);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
BPPageHandle page_handle;
rc = disk_buffer_pool->get_this_page(file_id, FIRST_INDEX_PAGE, &page_handle);
Frame *frame;
rc = disk_buffer_pool->get_this_page(FIRST_INDEX_PAGE, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
bpm.close_file(file_name);
return rc;
}
char *pdata = page_handle.data();
char *pdata = frame->data();
memcpy(&file_header_, pdata, sizeof(IndexFileHeader));
header_dirty_ = false;
disk_buffer_pool_ = disk_buffer_pool;
file_id_ = file_id;
mem_pool_item_ = new common::MemPoolItem(file_name);
if (mem_pool_item_->init(file_header_.key_length) < 0) {
......@@ -862,19 +861,19 @@ RC BplusTreeHandler::open(const char *file_name)
}
// close old page_handle
disk_buffer_pool->unpin_page(&page_handle);
disk_buffer_pool->unpin_page(frame);
key_comparator_.init(file_header_.attr_type, file_header_.attr_length);
key_printer_.init(file_header_.attr_type, file_header_.attr_length);
LOG_INFO("Successfully open index %s", file_name);
return RC::SUCCESS;
}
RC BplusTreeHandler::close()
{
if (file_id_ != -1) {
if (disk_buffer_pool_ != nullptr) {
disk_buffer_pool_->close_file(file_id_);
file_id_ = -1;
disk_buffer_pool_->close_file(); // TODO
delete mem_pool_item_;
mem_pool_item_ = nullptr;
......@@ -884,52 +883,52 @@ RC BplusTreeHandler::close()
return RC::SUCCESS;
}
RC BplusTreeHandler::print_leaf(BPPageHandle &page_handle)
RC BplusTreeHandler::print_leaf(Frame *frame)
{
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LeafIndexNodeHandler leaf_node(file_header_, frame);
LOG_INFO("leaf node: %s", to_string(leaf_node, key_printer_).c_str());
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return RC::SUCCESS;
}
RC BplusTreeHandler::print_internal_node_recursive(BPPageHandle &page_handle)
RC BplusTreeHandler::print_internal_node_recursive(Frame *frame)
{
RC rc = RC::SUCCESS;
LOG_INFO("bplus tree. file header: %s", file_header_.to_string().c_str());
InternalIndexNodeHandler internal_node(file_header_, page_handle);
InternalIndexNodeHandler internal_node(file_header_, frame);
LOG_INFO("internal node: %s", to_string(internal_node, key_printer_).c_str());
int node_size = internal_node.size();
for (int i = 0; i < node_size; i++) {
PageNum page_num = internal_node.value_at(i);
BPPageHandle child_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
Frame *child_frame;
rc = disk_buffer_pool_->get_this_page(page_num, &child_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page. page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return rc;
}
IndexNodeHandler node(file_header_, child_page_handle);
IndexNodeHandler node(file_header_, child_frame);
if (node.is_leaf()) {
rc = print_leaf(child_page_handle);
rc = print_leaf(child_frame);
} else {
rc = print_internal_node_recursive(child_page_handle);
rc = print_internal_node_recursive(child_frame);
}
if (rc != RC::SUCCESS) {
LOG_WARN("failed to print node. page id=%d, rc=%d:%s", child_page_handle.page_num(), rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
LOG_WARN("failed to print node. page id=%d, rc=%d:%s", child_frame->page_num(), rc, strrc(rc));
disk_buffer_pool_->unpin_page(frame);
return rc;
}
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return RC::SUCCESS;
}
RC BplusTreeHandler::print_tree()
{
if (file_id_ < 0) {
if (disk_buffer_pool_ == nullptr) {
LOG_WARN("Index hasn't been created or opened, fail to print");
return RC::SUCCESS;
}
......@@ -938,19 +937,19 @@ RC BplusTreeHandler::print_tree()
return RC::SUCCESS;
}
BPPageHandle page_handle;
Frame *frame;
PageNum page_num = file_header_.root_page;
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
RC rc = disk_buffer_pool_->get_this_page(page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch page. page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
return rc;
}
IndexNodeHandler node(file_header_, page_handle);
IndexNodeHandler node(file_header_, frame);
if (node.is_leaf()) {
rc = print_leaf(page_handle);
rc = print_leaf(frame);
} else {
rc = print_internal_node_recursive(page_handle);
rc = print_internal_node_recursive(frame);
}
return rc;
}
......@@ -962,26 +961,26 @@ RC BplusTreeHandler::print_leafs()
return RC::SUCCESS;
}
BPPageHandle page_handle;
Frame *frame;
RC rc = left_most_page(page_handle);
RC rc = left_most_page(frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to get left most page. rc=%d:%s", rc, strrc(rc));
return rc;
}
while (page_handle.page_num() != BP_INVALID_PAGE_NUM) {
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
while (frame->page_num() != BP_INVALID_PAGE_NUM) {
LeafIndexNodeHandler leaf_node(file_header_, frame);
LOG_INFO("leaf info: %s", to_string(leaf_node, key_printer_).c_str());
PageNum next_page_num = leaf_node.next_page();
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
if (next_page_num == BP_INVALID_PAGE_NUM) {
break;
}
rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &page_handle);
rc = disk_buffer_pool_->get_this_page(next_page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to get next page. page id=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc;
......@@ -990,31 +989,31 @@ RC BplusTreeHandler::print_leafs()
return rc;
}
bool BplusTreeHandler::validate_node_recursive(BPPageHandle &page_handle)
bool BplusTreeHandler::validate_node_recursive(Frame *frame)
{
bool result = true;
IndexNodeHandler node(file_header_, page_handle);
IndexNodeHandler node(file_header_, frame);
if (node.is_leaf()) {
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
result = leaf_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
LeafIndexNodeHandler leaf_node(file_header_, frame);
result = leaf_node.validate(key_comparator_, disk_buffer_pool_);
} else {
InternalIndexNodeHandler internal_node(file_header_, page_handle);
result = internal_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
InternalIndexNodeHandler internal_node(file_header_, frame);
result = internal_node.validate(key_comparator_, disk_buffer_pool_);
for (int i = 0; result && i < internal_node.size(); i++) {
PageNum page_num = internal_node.value_at(i);
BPPageHandle child_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
Frame *child_frame;
RC rc = disk_buffer_pool_->get_this_page(page_num, &child_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page.page id=%d, rc=%d:%s", page_num, rc, strrc(rc));
result = false;
break;
}
result = validate_node_recursive(child_page_handle);
result = validate_node_recursive(child_frame);
}
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return result;
}
......@@ -1024,8 +1023,8 @@ bool BplusTreeHandler::validate_leaf_link()
return true;
}
BPPageHandle page_handle;
RC rc = left_most_page(page_handle);
Frame *frame;
RC rc = left_most_page(frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch left most page. rc=%d:%s", rc, strrc(rc));
return false;
......@@ -1033,31 +1032,31 @@ bool BplusTreeHandler::validate_leaf_link()
PageNum prev_page_num = BP_INVALID_PAGE_NUM;
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LeafIndexNodeHandler leaf_node(file_header_, frame);
if (leaf_node.prev_page() != prev_page_num) {
LOG_WARN("invalid page. current_page_num=%d, prev page num should be %d but got %d",
page_handle.page_num(), prev_page_num, leaf_node.prev_page());
frame->page_num(), prev_page_num, leaf_node.prev_page());
return false;
}
PageNum next_page_num = leaf_node.next_page();
prev_page_num = page_handle.page_num();
prev_page_num = frame->page_num();
char *prev_key = (char *)mem_pool_item_->alloc();
memcpy(prev_key, leaf_node.key_at(leaf_node.size() - 1), file_header_.key_length);
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
bool result = true;
while (result && next_page_num != BP_INVALID_PAGE_NUM) {
rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &page_handle);
rc = disk_buffer_pool_->get_this_page(next_page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return false;
}
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LeafIndexNodeHandler leaf_node(file_header_, frame);
if (leaf_node.prev_page() != prev_page_num) {
LOG_WARN("invalid page. current_page_num=%d, prev page num should be %d but got %d",
page_handle.page_num(), prev_page_num, leaf_node.prev_page());
frame->page_num(), prev_page_num, leaf_node.prev_page());
result = false;
}
if (key_comparator_(prev_key, leaf_node.key_at(0)) >= 0) {
......@@ -1067,8 +1066,8 @@ bool BplusTreeHandler::validate_leaf_link()
next_page_num = leaf_node.next_page();
memcpy(prev_key, leaf_node.key_at(leaf_node.size() - 1), file_header_.key_length);
prev_page_num = page_handle.page_num();
disk_buffer_pool_->unpin_page(&page_handle);
prev_page_num = frame->page_num();
disk_buffer_pool_->unpin_page(frame);
}
free_key(prev_key);
......@@ -1082,14 +1081,14 @@ bool BplusTreeHandler::validate_tree()
return true;
}
BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
Frame *frame;
RC rc = disk_buffer_pool_->get_this_page(file_header_.root_page, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch root page. page id=%d, rc=%d:%s", file_header_.root_page, rc, strrc(rc));
return rc;
}
if (!validate_node_recursive(page_handle) || !validate_leaf_link()) {
if (!validate_node_recursive(frame) || !validate_leaf_link()) {
LOG_WARN("Current B+ Tree is invalid");
print_tree();
return false;
......@@ -1104,68 +1103,68 @@ bool BplusTreeHandler::is_empty() const
return file_header_.root_page == BP_INVALID_PAGE_NUM;
}
RC BplusTreeHandler::find_leaf(const char *key, BPPageHandle &page_handle)
RC BplusTreeHandler::find_leaf(const char *key, Frame *&frame)
{
return find_leaf_internal(
[&](InternalIndexNodeHandler &internal_node) {
return internal_node.value_at(internal_node.lookup(key_comparator_, key));
},
page_handle);
frame);
}
RC BplusTreeHandler::left_most_page(BPPageHandle &page_handle)
RC BplusTreeHandler::left_most_page(Frame *&frame)
{
return find_leaf_internal(
[&](InternalIndexNodeHandler &internal_node) {
return internal_node.value_at(0);
},
page_handle
frame
);
}
RC BplusTreeHandler::right_most_page(BPPageHandle &page_handle)
RC BplusTreeHandler::right_most_page(Frame *&frame)
{
return find_leaf_internal(
[&](InternalIndexNodeHandler &internal_node) {
return internal_node.value_at(internal_node.size() - 1);
},
page_handle
frame
);
}
RC BplusTreeHandler::find_leaf_internal(const std::function<PageNum(InternalIndexNodeHandler &)> &child_page_getter,
BPPageHandle &page_handle)
Frame *&frame)
{
if (is_empty()) {
return RC::EMPTY;
}
RC rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
RC rc = disk_buffer_pool_->get_this_page(file_header_.root_page, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch root page. page id=%d, rc=%d:%s", file_header_.root_page, rc, strrc(rc));
return rc;
}
IndexNode *node = (IndexNode *)page_handle.data();
IndexNode *node = (IndexNode *)frame->data();
while (false == node->is_leaf) {
InternalIndexNodeHandler internal_node(file_header_, page_handle);
InternalIndexNodeHandler internal_node(file_header_, frame);
PageNum page_num = child_page_getter(internal_node);
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
rc = disk_buffer_pool_->get_this_page(page_num, &frame);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, page_num);
LOG_WARN("Failed to load page page_num:%d", page_num);
return rc;
}
node = (IndexNode *)page_handle.data();
node = (IndexNode *)frame->data();
}
return RC::SUCCESS;
}
RC BplusTreeHandler::insert_entry_into_leaf_node(BPPageHandle &page_handle, const char *key, const RID *rid)
RC BplusTreeHandler::insert_entry_into_leaf_node(Frame *frame, const char *key, const RID *rid)
{
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LeafIndexNodeHandler leaf_node(file_header_, frame);
bool exists = false;
int insert_position = leaf_node.lookup(key_comparator_, key, &exists);
if (exists) {
......@@ -1175,36 +1174,36 @@ RC BplusTreeHandler::insert_entry_into_leaf_node(BPPageHandle &page_handle, cons
if (leaf_node.size() < leaf_node.max_size()) {
leaf_node.insert(insert_position, key, (const char *)rid);
page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
frame->mark_dirty();
disk_buffer_pool_->unpin_page(frame);
return RC::SUCCESS;
}
BPPageHandle new_page_handle;
RC rc = split<LeafIndexNodeHandler>(page_handle, new_page_handle);
Frame * new_frame = nullptr;
RC rc = split<LeafIndexNodeHandler>(frame, new_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to split leaf node. rc=%d:%s", rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler new_index_node(file_header_, new_page_handle);
new_index_node.set_prev_page(page_handle.page_num());
LeafIndexNodeHandler new_index_node(file_header_, new_frame);
new_index_node.set_prev_page(frame->page_num());
new_index_node.set_next_page(leaf_node.next_page());
new_index_node.set_parent_page_num(leaf_node.parent_page_num());
leaf_node.set_next_page(new_page_handle.page_num());
leaf_node.set_next_page(new_frame->page_num());
PageNum next_page_num = new_index_node.next_page();
if (next_page_num != BP_INVALID_PAGE_NUM) {
BPPageHandle next_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, next_page_num, &next_page_handle);
Frame * next_frame;
rc = disk_buffer_pool_->get_this_page(next_page_num, &next_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler next_node(file_header_, next_page_handle);
next_node.set_prev_page(new_page_handle.page_num());
disk_buffer_pool_->unpin_page(&next_page_handle);
LeafIndexNodeHandler next_node(file_header_, next_frame);
next_node.set_prev_page(new_frame->page_num());
disk_buffer_pool_->unpin_page(next_frame);
}
if (insert_position < leaf_node.size()) {
......@@ -1213,94 +1212,94 @@ RC BplusTreeHandler::insert_entry_into_leaf_node(BPPageHandle &page_handle, cons
new_index_node.insert(insert_position - leaf_node.size(), key, (const char *)rid);
}
return insert_entry_into_parent(page_handle, new_page_handle, new_index_node.key_at(0));
return insert_entry_into_parent(frame, new_frame, new_index_node.key_at(0));
}
RC BplusTreeHandler::insert_entry_into_parent(BPPageHandle &page_handle, BPPageHandle &new_page_handle, const char *key)
RC BplusTreeHandler::insert_entry_into_parent(Frame *frame, Frame *new_frame, const char *key)
{
RC rc = RC::SUCCESS;
IndexNodeHandler node_handler(file_header_, page_handle);
IndexNodeHandler new_node_handler(file_header_, new_page_handle);
IndexNodeHandler node_handler(file_header_, frame);
IndexNodeHandler new_node_handler(file_header_, new_frame);
PageNum parent_page_num = node_handler.parent_page_num();
if (parent_page_num == BP_INVALID_PAGE_NUM) {
// create new root page
BPPageHandle root_page;
rc = disk_buffer_pool_->allocate_page(file_id_, &root_page);
Frame *root_frame;
rc = disk_buffer_pool_->allocate_page(&root_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to allocate new root page. rc=%d:%s", rc, strrc(rc));
return rc;
}
InternalIndexNodeHandler root_node(file_header_, root_page);
InternalIndexNodeHandler root_node(file_header_, root_frame);
root_node.init_empty();
root_node.create_new_root(page_handle.page_num(), key, new_page_handle.page_num());
node_handler.set_parent_page_num(root_page.page_num());
new_node_handler.set_parent_page_num(root_page.page_num());
root_node.create_new_root(frame->page_num(), key, new_frame->page_num());
node_handler.set_parent_page_num(root_frame->page_num());
new_node_handler.set_parent_page_num(root_frame->page_num());
page_handle.mark_dirty();
new_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
frame->mark_dirty();
new_frame->mark_dirty();
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(new_frame);
file_header_.root_page = root_page.page_num();
file_header_.root_page = root_frame->page_num();
update_root_page_num(); // TODO
root_page.mark_dirty();
disk_buffer_pool_->unpin_page(&root_page);
root_frame->mark_dirty();
disk_buffer_pool_->unpin_page(root_frame);
return RC::SUCCESS;
} else {
BPPageHandle parent_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, parent_page_num, &parent_page_handle);
Frame *parent_frame;
rc = disk_buffer_pool_->get_this_page(parent_page_num, &parent_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to insert entry into leaf. rc=%d:%s", rc, strrc(rc));
// should do more things to recover
return rc;
}
InternalIndexNodeHandler node(file_header_, parent_page_handle);
InternalIndexNodeHandler node(file_header_, parent_frame);
/// current node is not in full mode, insert the entry and return
if (node.size() < node.max_size()) {
node.insert(key, new_page_handle.page_num(), key_comparator_);
node.insert(key, new_frame->page_num(), key_comparator_);
new_node_handler.set_parent_page_num(parent_page_num);
page_handle.mark_dirty();
new_page_handle.mark_dirty();
parent_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
frame->mark_dirty();
new_frame->mark_dirty();
parent_frame->mark_dirty();
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(new_frame);
disk_buffer_pool_->unpin_page(parent_frame);
} else {
// we should split the node and insert the entry and then insert new entry to current node's parent
BPPageHandle new_parent_page_handle;
rc = split<InternalIndexNodeHandler>(parent_page_handle, new_parent_page_handle);
Frame * new_parent_frame;
rc = split<InternalIndexNodeHandler>(parent_frame, new_parent_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to split internal node. rc=%d:%s", rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(new_frame);
disk_buffer_pool_->unpin_page(parent_frame);
} else {
// insert into left or right ? decide by key compare result
InternalIndexNodeHandler new_node(file_header_, new_parent_page_handle);
InternalIndexNodeHandler new_node(file_header_, new_parent_frame);
if (key_comparator_(key, new_node.key_at(0)) > 0) {
new_node.insert(key, new_page_handle.page_num(), key_comparator_);
new_node.insert(key, new_frame->page_num(), key_comparator_);
new_node_handler.set_parent_page_num(new_node.page_num());
} else {
node.insert(key, new_page_handle.page_num(), key_comparator_);
node.insert(key, new_frame->page_num(), key_comparator_);
new_node_handler.set_parent_page_num(node.page_num());
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(new_frame);
rc = insert_entry_into_parent(parent_page_handle, new_parent_page_handle, new_node.key_at(0));
rc = insert_entry_into_parent(parent_frame, new_parent_frame, new_node.key_at(0));
}
}
}
......@@ -1314,9 +1313,9 @@ RC BplusTreeHandler::insert_entry_into_parent(BPPageHandle &page_handle, BPPageH
* @param intert_position the intert position of new key
*/
template <typename IndexNodeHandlerType>
RC BplusTreeHandler::split(BPPageHandle &page_handle, BPPageHandle &new_page_handle)
RC BplusTreeHandler::split(Frame *frame, Frame *&new_frame)
{
IndexNodeHandlerType old_node(file_header_, page_handle);
IndexNodeHandlerType old_node(file_header_, frame);
char *new_parent_key = (char *)mem_pool_item_->alloc();
if (new_parent_key == nullptr) {
......@@ -1325,36 +1324,36 @@ RC BplusTreeHandler::split(BPPageHandle &page_handle, BPPageHandle &new_page_han
}
// add a new node
RC rc = disk_buffer_pool_->allocate_page(file_id_, &new_page_handle);
RC rc = disk_buffer_pool_->allocate_page(&new_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to split index page due to failed to allocate page, file_id:%d. rc=%d:%s", file_id_, rc, strrc(rc));
LOG_WARN("Failed to split index page due to failed to allocate page, rc=%d:%s", rc, strrc(rc));
return rc;
}
IndexNodeHandlerType new_node(file_header_, new_page_handle);
IndexNodeHandlerType new_node(file_header_, new_frame);
new_node.init_empty();
new_node.set_parent_page_num(old_node.parent_page_num());
old_node.move_half_to(new_node, disk_buffer_pool_, file_id_);
old_node.move_half_to(new_node, disk_buffer_pool_);
page_handle.mark_dirty();
new_page_handle.mark_dirty();
frame->mark_dirty();
new_frame->mark_dirty();
return RC::SUCCESS;
}
RC BplusTreeHandler::update_root_page_num()
{
BPPageHandle header_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, FIRST_INDEX_PAGE, &header_page_handle);
Frame * header_frame;
RC rc = disk_buffer_pool_->get_this_page(FIRST_INDEX_PAGE, &header_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch header page. rc=%d:%s", rc, strrc(rc));
return rc;
}
IndexFileHeader *header = (IndexFileHeader *)header_page_handle.data();
IndexFileHeader *header = (IndexFileHeader *)header_frame->data();
header->root_page = file_header_.root_page;
header_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&header_page_handle);
header_frame->mark_dirty();
disk_buffer_pool_->unpin_page(header_frame);
return rc;
}
......@@ -1368,19 +1367,19 @@ RC BplusTreeHandler::create_new_tree(const char *key, const RID *rid)
return rc;
}
BPPageHandle page_handle;
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle);
Frame *frame;
rc = disk_buffer_pool_->allocate_page(&frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to allocate root page. rc=%d:%s", rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler leaf_node(file_header_, page_handle);
LeafIndexNodeHandler leaf_node(file_header_, frame);
leaf_node.init_empty();
leaf_node.insert(0, key, (const char *)rid);
file_header_.root_page = page_handle.page_num();
page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&page_handle);
file_header_.root_page = frame->page_num();
frame->mark_dirty();
disk_buffer_pool_->unpin_page(frame);
rc = update_root_page_num();
// disk_buffer_pool_->check_all_pages_unpinned(file_id_);
......@@ -1391,7 +1390,7 @@ char *BplusTreeHandler::make_key(const char *user_key, const RID &rid)
{
char *key = (char *)mem_pool_item_->alloc();
if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_);
LOG_WARN("Failed to alloc memory for key.");
return nullptr;
}
memcpy(key, user_key, file_header_.attr_length);
......@@ -1406,11 +1405,6 @@ void BplusTreeHandler::free_key(char *key)
RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid)
{
if (file_id_ < 0) {
LOG_WARN("Index isn't ready!");
return RC::RECORD_CLOSED;
}
if (user_key == nullptr || rid == nullptr) {
LOG_WARN("Invalid arguments, key is empty or rid is empty");
return RC::INVALID_ARGUMENT;
......@@ -1418,7 +1412,7 @@ RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid)
char *key = make_key(user_key, *rid);
if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_);
LOG_WARN("Failed to alloc memory for key.");
return RC::NOMEM;
}
......@@ -1426,18 +1420,18 @@ RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid)
return create_new_tree(key, rid);
}
BPPageHandle page_handle;
RC rc = find_leaf(key, page_handle);
Frame *frame;
RC rc = find_leaf(key, frame);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to find leaf file_id:%d, %s. rc=%d:%s", file_id_, rid->to_string().c_str(), rc, strrc(rc));
LOG_WARN("Failed to find leaf %s. rc=%d:%s", rid->to_string().c_str(), rc, strrc(rc));
mem_pool_item_->free(key);
return rc;
}
rc = insert_entry_into_leaf_node(page_handle, key, rid);
rc = insert_entry_into_leaf_node(frame, key, rid);
if (rc != RC::SUCCESS) {
LOG_TRACE("Failed to insert into leaf of index %d, rid:%s", file_id_, rid->to_string().c_str());
disk_buffer_pool_->unpin_page(&page_handle);
LOG_TRACE("Failed to insert into leaf of index, rid:%s", rid->to_string().c_str());
disk_buffer_pool_->unpin_page(frame);
mem_pool_item_->free(key);
// disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return rc;
......@@ -1451,14 +1445,6 @@ RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid)
RC BplusTreeHandler::get_entry(const char *user_key, std::list<RID> &rids)
{
if (file_id_ < 0) {
LOG_WARN("Index isn't ready!");
return RC::RECORD_CLOSED;
}
LOG_INFO("before get entry");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
BplusTreeScanner scanner(*this);
RC rc = scanner.open(user_key, true/*left_inclusive*/, user_key, true/*right_inclusive*/);
if (rc != RC::SUCCESS) {
......@@ -1477,17 +1463,15 @@ RC BplusTreeHandler::get_entry(const char *user_key, std::list<RID> &rids)
} else {
rc = RC::SUCCESS;
}
LOG_INFO("after get entry");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return rc;
}
RC BplusTreeHandler::adjust_root(BPPageHandle &root_page_handle)
RC BplusTreeHandler::adjust_root(Frame *root_frame)
{
IndexNodeHandler root_node(file_header_, root_page_handle);
IndexNodeHandler root_node(file_header_, root_frame);
if (root_node.is_leaf() && root_node.size() > 0) {
root_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&root_page_handle);
root_frame->mark_dirty();
disk_buffer_pool_->unpin_page(root_frame);
return RC::SUCCESS;
}
......@@ -1496,36 +1480,36 @@ RC BplusTreeHandler::adjust_root(BPPageHandle &root_page_handle)
file_header_.root_page = BP_INVALID_PAGE_NUM;
} else {
// this is an internal node and has only one child node
InternalIndexNodeHandler internal_node(file_header_, root_page_handle);
InternalIndexNodeHandler internal_node(file_header_, root_frame);
const PageNum child_page_num = internal_node.value_at(0);
BPPageHandle child_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page_num, &child_page_handle);
Frame * child_frame;
RC rc = disk_buffer_pool_->get_this_page(child_page_num, &child_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch child page. page num=%d, rc=%d:%s", child_page_num, rc, strrc(rc));
return rc;
}
IndexNodeHandler child_node(file_header_, child_page_handle);
IndexNodeHandler child_node(file_header_, child_frame);
child_node.set_parent_page_num(BP_INVALID_PAGE_NUM);
disk_buffer_pool_->unpin_page(&child_page_handle);
disk_buffer_pool_->unpin_page(child_frame);
file_header_.root_page = child_page_num;
}
update_root_page_num();
PageNum old_root_page_num = root_page_handle.page_num();
disk_buffer_pool_->unpin_page(&root_page_handle);
disk_buffer_pool_->dispose_page(file_id_, old_root_page_num);
PageNum old_root_page_num = root_frame->page_num();
disk_buffer_pool_->unpin_page(root_frame);
disk_buffer_pool_->dispose_page(old_root_page_num);
return RC::SUCCESS;
}
template <typename IndexNodeHandlerType>
RC BplusTreeHandler::coalesce_or_redistribute(BPPageHandle &page_handle)
RC BplusTreeHandler::coalesce_or_redistribute(Frame *frame)
{
IndexNodeHandlerType index_node(file_header_, page_handle);
IndexNodeHandlerType index_node(file_header_, frame);
if (index_node.size() >= index_node.min_size()) {
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return RC::SUCCESS;
}
......@@ -1533,27 +1517,27 @@ RC BplusTreeHandler::coalesce_or_redistribute(BPPageHandle &page_handle)
if (BP_INVALID_PAGE_NUM == parent_page_num) {
// this is the root page
if (index_node.size() > 1) {
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
} else {
// adjust the root node
adjust_root(page_handle);
adjust_root(frame);
}
return RC::SUCCESS;
}
BPPageHandle parent_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page_num, &parent_page_handle);
Frame * parent_frame;
RC rc = disk_buffer_pool_->get_this_page(parent_page_num, &parent_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch parent page. page id=%d, rc=%d:%s", parent_page_num, rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(frame);
return rc;
}
InternalIndexNodeHandler parent_index_node(file_header_, parent_page_handle);
InternalIndexNodeHandler parent_index_node(file_header_, parent_frame);
int index = parent_index_node.lookup(key_comparator_, index_node.key_at(index_node.size() - 1));
if (parent_index_node.value_at(index) != page_handle.page_num()) {
if (parent_index_node.value_at(index) != frame->page_num()) {
LOG_ERROR("lookup return an invalid value. index=%d, this page num=%d, but got %d",
index, page_handle.page_num(), parent_index_node.value_at(index));
index, frame->page_num(), parent_index_node.value_at(index));
}
PageNum neighbor_page_num;
if (index == 0) {
......@@ -1562,53 +1546,52 @@ RC BplusTreeHandler::coalesce_or_redistribute(BPPageHandle &page_handle)
neighbor_page_num = parent_index_node.value_at(index - 1);
}
BPPageHandle neighbor_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, neighbor_page_num, &neighbor_page_handle);
Frame * neighbor_frame;
rc = disk_buffer_pool_->get_this_page(neighbor_page_num, &neighbor_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch neighbor page. page id=%d, rc=%d:%s", neighbor_page_num, rc, strrc(rc));
// TODO do more thing to release resource
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(parent_frame);
return rc;
}
IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
IndexNodeHandlerType neighbor_node(file_header_, neighbor_frame);
if (index_node.size() + neighbor_node.size() > index_node.max_size()) {
rc = redistribute<IndexNodeHandlerType>(neighbor_page_handle, page_handle, parent_page_handle, index);
rc = redistribute<IndexNodeHandlerType>(neighbor_frame, frame, parent_frame, index);
} else {
rc = coalesce<IndexNodeHandlerType>(neighbor_page_handle, page_handle, parent_page_handle, index);
rc = coalesce<IndexNodeHandlerType>(neighbor_frame, frame, parent_frame, index);
}
return rc;
}
template <typename IndexNodeHandlerType>
RC BplusTreeHandler::coalesce(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index)
RC BplusTreeHandler::coalesce(Frame *neighbor_frame, Frame *frame, Frame *parent_frame, int index)
{
IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
IndexNodeHandlerType node(file_header_, page_handle);
IndexNodeHandlerType neighbor_node(file_header_, neighbor_frame);
IndexNodeHandlerType node(file_header_, frame);
InternalIndexNodeHandler parent_node(file_header_, parent_page_handle);
InternalIndexNodeHandler parent_node(file_header_, parent_frame);
BPPageHandle *left_page_handle = nullptr;
BPPageHandle *right_page_handle = nullptr;
Frame *left_frame = nullptr;
Frame *right_frame = nullptr;
if (index == 0) {
// neighbor node is at right
left_page_handle = &page_handle;
right_page_handle = &neighbor_page_handle;
left_frame = frame;
right_frame = neighbor_frame;
index++;
} else {
left_page_handle = &neighbor_page_handle;
right_page_handle = &page_handle;
left_frame = neighbor_frame;
right_frame = frame;
// neighbor is at left
}
IndexNodeHandlerType left_node(file_header_, *left_page_handle);
IndexNodeHandlerType right_node(file_header_, *right_page_handle);
IndexNodeHandlerType left_node(file_header_, left_frame);
IndexNodeHandlerType right_node(file_header_, right_frame);
parent_node.remove(index);
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
RC rc = right_node.move_to(left_node, disk_buffer_pool_, file_id_);
RC rc = right_node.move_to(left_node, disk_buffer_pool_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to move right node to left. rc=%d:%s", rc, strrc(rc));
return rc;
......@@ -1616,101 +1599,95 @@ RC BplusTreeHandler::coalesce(BPPageHandle &neighbor_page_handle, BPPageHandle &
// left_node.validate(key_comparator_);
if (left_node.is_leaf()) {
LeafIndexNodeHandler left_leaf_node(file_header_, *left_page_handle);
LeafIndexNodeHandler right_leaf_node(file_header_, *right_page_handle);
LeafIndexNodeHandler left_leaf_node(file_header_, left_frame);
LeafIndexNodeHandler right_leaf_node(file_header_, right_frame);
left_leaf_node.set_next_page(right_leaf_node.next_page());
PageNum next_right_page_num = right_leaf_node.next_page();
if (next_right_page_num != BP_INVALID_PAGE_NUM) {
BPPageHandle next_right_page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, next_right_page_num, &next_right_page_handle);
Frame *next_right_frame;
rc = disk_buffer_pool_->get_this_page(next_right_page_num, &next_right_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next right page. page number:%d. rc=%d:%s", next_right_page_num, rc, strrc(rc));
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->unpin_page(&neighbor_page_handle);
disk_buffer_pool_->unpin_page(&parent_page_handle);
disk_buffer_pool_->unpin_page(frame);
disk_buffer_pool_->unpin_page(neighbor_frame);
disk_buffer_pool_->unpin_page(parent_frame);
return rc;
}
LeafIndexNodeHandler next_right_node(file_header_, next_right_page_handle);
LeafIndexNodeHandler next_right_node(file_header_, next_right_frame);
next_right_node.set_prev_page(left_node.page_num());
disk_buffer_pool_->unpin_page(&next_right_page_handle);
disk_buffer_pool_->unpin_page(next_right_frame);
}
}
PageNum right_page_num = right_page_handle->page_num();
disk_buffer_pool_->unpin_page(left_page_handle);
disk_buffer_pool_->unpin_page(right_page_handle);
disk_buffer_pool_->dispose_page(file_id_, right_page_num);
return coalesce_or_redistribute<InternalIndexNodeHandler>(parent_page_handle);
PageNum right_page_num = right_frame->page_num();
disk_buffer_pool_->unpin_page(left_frame);
disk_buffer_pool_->unpin_page(right_frame);
disk_buffer_pool_->dispose_page(right_page_num);
return coalesce_or_redistribute<InternalIndexNodeHandler>(parent_frame);
}
template <typename IndexNodeHandlerType>
RC BplusTreeHandler::redistribute(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index)
RC BplusTreeHandler::redistribute(Frame *neighbor_frame, Frame *frame, Frame *parent_frame, int index)
{
InternalIndexNodeHandler parent_node(file_header_, parent_page_handle);
IndexNodeHandlerType neighbor_node(file_header_, neighbor_page_handle);
IndexNodeHandlerType node(file_header_, page_handle);
InternalIndexNodeHandler parent_node(file_header_, parent_frame);
IndexNodeHandlerType neighbor_node(file_header_, neighbor_frame);
IndexNodeHandlerType node(file_header_, frame);
if (neighbor_node.size() < node.size()) {
LOG_ERROR("got invalid nodes. neighbor node size %d, this node size %d",
neighbor_node.size(), node.size());
}
if (index == 0) {
// the neighbor is at right
neighbor_node.move_first_to_end(node, disk_buffer_pool_, file_id_);
neighbor_node.move_first_to_end(node, disk_buffer_pool_);
// neighbor_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
// node.validate(key_comparator_, disk_buffer_pool_, file_id_);
parent_node.set_key_at(index + 1, neighbor_node.key_at(0));
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
} else {
// the neighbor is at left
neighbor_node.move_last_to_front(node, disk_buffer_pool_, file_id_);
neighbor_node.move_last_to_front(node, disk_buffer_pool_);
// neighbor_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
// node.validate(key_comparator_, disk_buffer_pool_, file_id_);
parent_node.set_key_at(index, node.key_at(0));
// parent_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
}
neighbor_page_handle.mark_dirty();
page_handle.mark_dirty();
parent_page_handle.mark_dirty();
disk_buffer_pool_->unpin_page(&parent_page_handle);
disk_buffer_pool_->unpin_page(&neighbor_page_handle);
disk_buffer_pool_->unpin_page(&page_handle);
neighbor_frame->mark_dirty();
frame->mark_dirty();
parent_frame->mark_dirty();
disk_buffer_pool_->unpin_page(parent_frame);
disk_buffer_pool_->unpin_page(neighbor_frame);
disk_buffer_pool_->unpin_page(frame);
return RC::SUCCESS;
}
RC BplusTreeHandler::delete_entry_internal(BPPageHandle &leaf_page_handle, const char *key)
RC BplusTreeHandler::delete_entry_internal(Frame *leaf_frame, const char *key)
{
LeafIndexNodeHandler leaf_index_node(file_header_, leaf_page_handle);
LeafIndexNodeHandler leaf_index_node(file_header_, leaf_frame);
const int remove_count = leaf_index_node.remove(key, key_comparator_);
if (remove_count == 0) {
LOG_TRACE("no data to remove");
disk_buffer_pool_->unpin_page(&leaf_page_handle);
disk_buffer_pool_->unpin_page(leaf_frame);
return RC::RECORD_RECORD_NOT_EXIST;
}
// leaf_index_node.validate(key_comparator_, disk_buffer_pool_, file_id_);
leaf_page_handle.mark_dirty();
leaf_frame->mark_dirty();
if (leaf_index_node.size() >= leaf_index_node.min_size()) {
disk_buffer_pool_->unpin_page(&leaf_page_handle);
disk_buffer_pool_->unpin_page(leaf_frame);
return RC::SUCCESS;
}
return coalesce_or_redistribute<LeafIndexNodeHandler>(leaf_page_handle);
return coalesce_or_redistribute<LeafIndexNodeHandler>(leaf_frame);
}
RC BplusTreeHandler::delete_entry(const char *user_key, const RID *rid)
{
if (file_id_ < 0) {
LOG_WARN("Failed to delete index entry, due to index is't ready");
return RC::RECORD_CLOSED;
}
char *key = (char *)mem_pool_item_->alloc();
if (nullptr == key) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
......@@ -1719,24 +1696,20 @@ RC BplusTreeHandler::delete_entry(const char *user_key, const RID *rid)
memcpy(key, user_key, file_header_.attr_length);
memcpy(key + file_header_.attr_length, rid, sizeof(*rid));
LOG_INFO("before delete");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
BPPageHandle leaf_page_handle;
RC rc = find_leaf(key, leaf_page_handle);
Frame *leaf_frame;
RC rc = find_leaf(key, leaf_frame);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to find leaf page. rc =%d:%s", rc, strrc(rc));
mem_pool_item_->free(key);
return rc;
}
rc = delete_entry_internal(leaf_page_handle, key);
rc = delete_entry_internal(leaf_frame, key);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index %d", file_id_);
LOG_WARN("Failed to delete index");
mem_pool_item_->free(key);
return rc;
}
mem_pool_item_->free(key);
LOG_INFO("after delete");
disk_buffer_pool_->check_all_pages_unpinned(file_id_);
return RC::SUCCESS;
}
......@@ -1771,7 +1744,7 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
}
if (nullptr == left_user_key) {
rc = tree_handler_.left_most_page(left_page_handle_);
rc = tree_handler_.left_most_page(left_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left most page. rc=%d:%s", rc, strrc(rc));
return rc;
......@@ -1785,14 +1758,14 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
} else {
left_key = tree_handler_.make_key(left_user_key, *RID::max());
}
rc = tree_handler_.find_leaf(left_key, left_page_handle_);
rc = tree_handler_.find_leaf(left_key, left_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left page. rc=%d:%s", rc, strrc(rc));
tree_handler_.free_key(left_key);
return rc;
}
LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_page_handle_);
LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_frame_);
int left_index = left_node.lookup(tree_handler_.key_comparator_, left_key);
tree_handler_.free_key(left_key);
// lookup 返回的是适合插入的位置,还需要判断一下是否在合适的边界范围内
......@@ -1802,8 +1775,8 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
return RC::SUCCESS;
}
tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, next_page_num, &left_page_handle_);
tree_handler_.disk_buffer_pool_->unpin_page(left_frame_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(next_page_num, &left_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", next_page_num, rc, strrc(rc));
return rc;
......@@ -1816,13 +1789,13 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
// 没有指定右边界范围,那么就返回右边界最大值
if (nullptr == right_user_key) {
rc = tree_handler_.right_most_page(right_page_handle_);
rc = tree_handler_.right_most_page(right_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch right most page. rc=%d:%s", rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler node(tree_handler_.file_header_, right_page_handle_);
LeafIndexNodeHandler node(tree_handler_.file_header_, right_frame_);
end_index_ = node.size() - 1;
} else {
......@@ -1833,14 +1806,14 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
right_key = tree_handler_.make_key(right_user_key, *RID::min());
}
rc = tree_handler_.find_leaf(right_key, right_page_handle_);
rc = tree_handler_.find_leaf(right_key, right_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to find left page. rc=%d:%s", rc, strrc(rc));
tree_handler_.free_key(right_key);
return rc;
}
LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_page_handle_);
LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_frame_);
int right_index = right_node.lookup(tree_handler_.key_comparator_, right_key);
tree_handler_.free_key(right_key);
// lookup 返回的是适合插入的位置,需要根据实际情况做调整
......@@ -1856,14 +1829,14 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
return RC::SUCCESS;
}
tree_handler_.disk_buffer_pool_->unpin_page(&right_page_handle_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, prev_page_num, &right_page_handle_);
tree_handler_.disk_buffer_pool_->unpin_page(right_frame_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(prev_page_num, &right_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch prev page num. page num=%d, rc=%d:%s", prev_page_num, rc, strrc(rc));
return rc;
}
LeafIndexNodeHandler tmp_node(tree_handler_.file_header_, right_page_handle_);
LeafIndexNodeHandler tmp_node(tree_handler_.file_header_, right_frame_);
right_index = tmp_node.size() - 1;
}
end_index_ = right_index;
......@@ -1872,12 +1845,12 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive,
// 判断是否左边界比右边界要靠后
// 两个边界最多会多一页
// 查找不存在的元素,或者不存在的范围数据时,可能会存在这个问题
if (left_page_handle_.page_num() == right_page_handle_.page_num() &&
if (left_frame_->page_num() == right_frame_->page_num() &&
iter_index_ > end_index_) {
end_index_ = -1;
} else {
LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_page_handle_);
LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_page_handle_);
LeafIndexNodeHandler left_node(tree_handler_.file_header_, left_frame_);
LeafIndexNodeHandler right_node(tree_handler_.file_header_, right_frame_);
if (left_node.prev_page() == right_node.page_num()) {
end_index_ = -1;
}
......@@ -1891,10 +1864,10 @@ RC BplusTreeScanner::next_entry(RID *rid)
return RC::RECORD_EOF;
}
LeafIndexNodeHandler node(tree_handler_.file_header_, left_page_handle_);
LeafIndexNodeHandler node(tree_handler_.file_header_, left_frame_);
memcpy(rid, node.value_at(iter_index_), sizeof(*rid));
if (left_page_handle_.page_num() == right_page_handle_.page_num() &&
if (left_frame_->page_num() == right_frame_->page_num() &&
iter_index_ == end_index_) {
end_index_ = -1;
return RC::SUCCESS;
......@@ -1906,14 +1879,14 @@ RC BplusTreeScanner::next_entry(RID *rid)
}
RC rc = RC::SUCCESS;
if (left_page_handle_.page_num() != right_page_handle_.page_num()) {
if (left_frame_->page_num() != right_frame_->page_num()) {
PageNum page_num = node.next_page();
tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
tree_handler_.disk_buffer_pool_->unpin_page(left_frame_);
if (page_num == BP_INVALID_PAGE_NUM) {
LOG_WARN("got invalid next page. page num=%d", page_num);
rc = RC::INTERNAL;
} else {
rc = tree_handler_.disk_buffer_pool_->get_this_page(tree_handler_.file_id_, page_num, &left_page_handle_);
rc = tree_handler_.disk_buffer_pool_->get_this_page(page_num, &left_frame_);
if (rc != RC::SUCCESS) {
LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", page_num, rc, strrc(rc));
return rc;
......@@ -1923,7 +1896,7 @@ RC BplusTreeScanner::next_entry(RID *rid)
}
} else if (end_index_ != -1) {
LOG_WARN("should have more pages but not. left page=%d, right page=%d",
left_page_handle_.page_num(), right_page_handle_.page_num());
left_frame_->page_num(), right_frame_->page_num());
rc = RC::INTERNAL;
}
return rc;
......@@ -1931,11 +1904,11 @@ RC BplusTreeScanner::next_entry(RID *rid)
RC BplusTreeScanner::close()
{
if (left_page_handle_.open) {
tree_handler_.disk_buffer_pool_->unpin_page(&left_page_handle_);
if (left_frame_ != nullptr) {
tree_handler_.disk_buffer_pool_->unpin_page(left_frame_);
}
if (right_page_handle_.open) {
tree_handler_.disk_buffer_pool_->unpin_page(&right_page_handle_);
if (right_frame_ != nullptr) {
tree_handler_.disk_buffer_pool_->unpin_page(right_frame_);
}
end_index_ = -1;
inited_ = false;
......
......@@ -19,6 +19,7 @@ See the Mulan PSL v2 for more details. */
#include <string.h>
#include <sstream>
#include <functional>
#include "storage/common/record_manager.h"
#include "storage/default/disk_buffer_pool.h"
......@@ -244,17 +245,17 @@ struct InternalIndexNode : public IndexNode {
class IndexNodeHandler {
public:
IndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
IndexNodeHandler(const IndexFileHeader &header, Frame *frame);
void init_empty(bool leaf);
bool is_leaf() const;
int key_size() const;
int value_size() const;
int item_size() const;
int key_size() const;
int value_size() const;
int item_size() const;
void increase_size(int n);
int size() const;
int size() const;
void set_parent_page_num(PageNum page_num);
PageNum parent_page_num() const;
......@@ -272,7 +273,7 @@ protected:
class LeafIndexNodeHandler : public IndexNodeHandler {
public:
LeafIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
LeafIndexNodeHandler(const IndexFileHeader &header, Frame *frame);
void init_empty();
void set_next_page(PageNum page_num);
......@@ -293,18 +294,18 @@ public:
void insert(int index, const char *key, const char *value);
void remove(int index);
int remove(const char *key, const KeyComparator &comparator);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp);
RC move_first_to_end(LeafIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool);
RC move_last_to_front(LeafIndexNodeHandler &other, DiskBufferPool *bp);
/**
* move all items to left page
*/
RC move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_to(LeafIndexNodeHandler &other, DiskBufferPool *bp);
int max_size() const;
int min_size() const;
bool validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const;
bool validate(const KeyComparator &comparator, DiskBufferPool *bp) const;
friend std::string to_string(const LeafIndexNodeHandler &handler, const KeyPrinter &printer);
private:
......@@ -321,20 +322,20 @@ private:
class InternalIndexNodeHandler : public IndexNodeHandler {
public:
InternalIndexNodeHandler(const IndexFileHeader &header, BPPageHandle &page_handle);
InternalIndexNodeHandler(const IndexFileHeader &header, Frame *frame);
void init_empty();
void create_new_root(PageNum first_page_num, const char *key, PageNum page_num);
void insert(const char *key, PageNum page_num, const KeyComparator &comparator);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_half_to(LeafIndexNodeHandler &other, DiskBufferPool *bp);
char *key_at(int index);
PageNum value_at(int index);
/**
* 返回指定子节点在当前节点中的索引
*/
int value_index(PageNum page_num);
int value_index(PageNum page_num);
void set_key_at(int index, const char *key);
void remove(int index);
......@@ -349,18 +350,18 @@ public:
int max_size() const;
int min_size() const;
RC move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool, int file_id);
RC move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp, int file_id);
RC move_to(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool);
RC move_first_to_end(InternalIndexNodeHandler &other, DiskBufferPool *disk_buffer_pool);
RC move_last_to_front(InternalIndexNodeHandler &other, DiskBufferPool *bp);
RC move_half_to(InternalIndexNodeHandler &other, DiskBufferPool *bp);
bool validate(const KeyComparator &comparator, DiskBufferPool *bp, int file_id) const;
bool validate(const KeyComparator &comparator, DiskBufferPool *bp) const;
friend std::string to_string(const InternalIndexNodeHandler &handler, const KeyPrinter &printer);
private:
RC copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool, int file_id);
RC append(const char *item, DiskBufferPool *bp, int file_id);
RC preappend(const char *item, DiskBufferPool *bp, int file_id);
RC copy_from(const char *items, int num, DiskBufferPool *disk_buffer_pool);
RC append(const char *item, DiskBufferPool *bp);
RC preappend(const char *item, DiskBufferPool *bp);
private:
char *__item_at(int index) const;
......@@ -418,11 +419,6 @@ public:
RC sync();
const int get_file_id()
{
return file_id_;
}
/**
* Check whether current B+ tree is invalid or not.
* return true means current tree is valid, return false means current tree is invalid.
......@@ -435,52 +431,48 @@ public:
RC print_leafs();
private:
RC print_leaf(BPPageHandle &page_handle);
RC print_internal_node_recursive(BPPageHandle &page_handle);
RC print_leaf(Frame *frame);
RC print_internal_node_recursive(Frame *frame);
bool validate_node(IndexNode *node);
bool validate_leaf_link();
bool validate_node_recursive(BPPageHandle &page_handle);
bool validate_node_recursive(Frame *frame);
protected:
RC find_leaf(const char *key, BPPageHandle &page_handle);
RC left_most_page(BPPageHandle &page_handle);
RC right_most_page(BPPageHandle &page_handle);
RC find_leaf(const char *key, Frame *&frame);
RC left_most_page(Frame *&frame);
RC right_most_page(Frame *&frame);
RC find_leaf_internal(const std::function<PageNum(InternalIndexNodeHandler &)> &child_page_getter,
BPPageHandle &page_handle);
Frame *&frame);
RC insert_into_parent(
PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC split_leaf(BPPageHandle &leaf_page_handle);
PageNum parent_page, Frame *left_frame, const char *pkey, Frame &right_frame);
RC delete_entry_internal(BPPageHandle &leaf_page_handle, const char *key);
RC delete_entry_internal(Frame *leaf_frame, const char *key);
RC insert_into_new_root(BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC insert_into_new_root(Frame *left_frame, const char *pkey, Frame &right_frame);
template <typename IndexNodeHandlerType>
RC split(BPPageHandle &page_handle, BPPageHandle &new_page_handle);
RC split(Frame *frame, Frame *&new_frame);
template <typename IndexNodeHandlerType>
RC coalesce_or_redistribute(BPPageHandle &page_handle);
RC coalesce_or_redistribute(Frame *frame);
template <typename IndexNodeHandlerType>
RC coalesce(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index);
RC coalesce(Frame *neighbor_frame, Frame *frame, Frame *parent_frame, int index);
template <typename IndexNodeHandlerType>
RC redistribute(BPPageHandle &neighbor_page_handle, BPPageHandle &page_handle,
BPPageHandle &parent_page_handle, int index);
RC redistribute(Frame *neighbor_frame, Frame *frame, Frame *parent_frame, int index);
RC insert_entry_into_parent(BPPageHandle &page_handle, BPPageHandle &new_page_handle, const char *key);
RC insert_entry_into_leaf_node(BPPageHandle &page_handle, const char *pkey, const RID *rid);
RC insert_entry_into_parent(Frame *frame, Frame *new_frame, const char *key);
RC insert_entry_into_leaf_node(Frame *frame, const char *pkey, const RID *rid);
RC update_root_page_num();
RC create_new_tree(const char *key, const RID *rid);
RC adjust_root(BPPageHandle &root_page_handle);
RC adjust_root(Frame *root_frame);
private:
char *make_key(const char *user_key, const RID &rid);
void free_key(char *key);
protected:
DiskBufferPool *disk_buffer_pool_ = nullptr;
int file_id_ = -1;
bool header_dirty_ = false;
IndexFileHeader file_header_;
......@@ -519,10 +511,10 @@ private:
/// 使用左右叶子节点和位置来表示扫描的起始位置和终止位置
/// 起始位置和终止位置都是有效的数据
BPPageHandle left_page_handle_;
BPPageHandle right_page_handle_;
int iter_index_ = -1;
int end_index_ = -1; // use -1 for end of scan
Frame * left_frame_ = nullptr;
Frame * right_frame_ = nullptr;
int iter_index_ = -1;
int end_index_ = -1; // use -1 for end of scan
};
#endif //__OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
......@@ -79,10 +79,8 @@ RC BplusTreeIndex::open(const char *file_name, const IndexMeta &index_meta, cons
RC BplusTreeIndex::close()
{
if (inited_) {
LOG_INFO("Begin to close index, file_id:%d, index:%s, field:%s",
index_handler_.get_file_id(),
index_meta_.name(),
index_meta_.field());
LOG_INFO("Begin to close index, index:%s, field:%s",
index_meta_.name(), index_meta_.field());
index_handler_.close();
inited_ = false;
}
......
......@@ -15,68 +15,68 @@ See the Mulan PSL v2 for more details. */
#include "storage/default/disk_buffer_pool.h"
#include "gtest/gtest.h"
void test_get(BPManager &bp_manager)
void test_get(BPFrameManager &frame_manager)
{
Frame *frame1 = bp_manager.alloc();
Frame *frame1 = frame_manager.alloc();
ASSERT_NE(frame1, nullptr);
frame1->file_desc = 0;
frame1->page.page_num = 1;
frame1->set_file_desc(0);
frame1->set_page_num(1);
ASSERT_EQ(frame1, bp_manager.get(0, 1));
ASSERT_EQ(frame1, frame_manager.get(0, 1));
Frame *frame2 = bp_manager.alloc();
Frame *frame2 = frame_manager.alloc();
ASSERT_NE(frame2, nullptr);
frame2->file_desc = 0;
frame2->page.page_num = 2;
frame2->set_file_desc(0);
frame2->set_page_num(2);
ASSERT_EQ(frame1, bp_manager.get(0, 1));
ASSERT_EQ(frame1, frame_manager.get(0, 1));
Frame *frame3 = bp_manager.alloc();
Frame *frame3 = frame_manager.alloc();
ASSERT_NE(frame3, nullptr);
frame3->file_desc = 0;
frame3->page.page_num = 3;
frame3->set_file_desc(0);
frame3->set_page_num(3);
frame2 = bp_manager.get(0, 2);
frame2 = frame_manager.get(0, 2);
ASSERT_NE(frame2, nullptr);
Frame *frame4 = bp_manager.alloc();
frame4->file_desc = 0;
frame4->page.page_num = 4;
Frame *frame4 = frame_manager.alloc();
frame4->set_file_desc(0);
frame4->set_page_num(4);
bp_manager.free(frame1);
frame1 = bp_manager.get(0, 1);
frame_manager.free(frame1);
frame1 = frame_manager.get(0, 1);
ASSERT_EQ(frame1, nullptr);
ASSERT_EQ(frame3, bp_manager.get(0, 3));
ASSERT_EQ(frame3, frame_manager.get(0, 3));
ASSERT_EQ(frame4, bp_manager.get(0, 4));
ASSERT_EQ(frame4, frame_manager.get(0, 4));
bp_manager.free(frame2);
bp_manager.free(frame3);
bp_manager.free(frame4);
frame_manager.free(frame2);
frame_manager.free(frame3);
frame_manager.free(frame4);
ASSERT_EQ(nullptr, bp_manager.get(0, 2));
ASSERT_EQ(nullptr, bp_manager.get(0, 3));
ASSERT_EQ(nullptr, bp_manager.get(0, 4));
ASSERT_EQ(nullptr, frame_manager.get(0, 2));
ASSERT_EQ(nullptr, frame_manager.get(0, 3));
ASSERT_EQ(nullptr, frame_manager.get(0, 4));
}
void test_alloc(BPManager &bp_manager)
void test_alloc(BPFrameManager &frame_manager)
{
int size = bp_manager.get_size();
int size = frame_manager.get_size();
std::list<Frame *> used_list;
for (int i = 0; i < size; i++) {
Frame *item = bp_manager.alloc();
Frame *item = frame_manager.alloc();
ASSERT_NE(item, nullptr);
used_list.push_back(item);
}
ASSERT_EQ(used_list.size(), bp_manager.get_used_num());
ASSERT_EQ(used_list.size(), frame_manager.get_used_num());
for (int i = 0; i < size; i++) {
Frame *item = bp_manager.alloc();
Frame *item = frame_manager.alloc();
ASSERT_EQ(item, nullptr);
}
......@@ -86,26 +86,26 @@ void test_alloc(BPManager &bp_manager)
Frame *item = used_list.front();
used_list.pop_front();
bp_manager.free(item);
frame_manager.free(item);
} else {
Frame *item = bp_manager.alloc();
Frame *item = frame_manager.alloc();
used_list.push_back(item);
}
ASSERT_EQ(used_list.size(), bp_manager.get_used_num());
ASSERT_EQ(used_list.size(), frame_manager.get_used_num());
}
}
TEST(test_bp_manager, test_bp_manager_simple_lru)
TEST(test_frame_manager, test_frame_manager_simple_lru)
{
BPManager bp_manager("Test");
bp_manager.init(false, 2);
BPFrameManager frame_manager("Test");
frame_manager.init(false, 2);
test_get(bp_manager);
test_get(frame_manager);
test_alloc(bp_manager);
test_alloc(frame_manager);
bp_manager.cleanup();
frame_manager.cleanup();
}
int main(int argc, char **argv)
......@@ -117,4 +117,4 @@ int main(int argc, char **argv)
// 调用RUN_ALL_TESTS()运行所有测试用例
// main函数返回RUN_ALL_TESTS()的运行结果
return RUN_ALL_TESTS();
}
\ No newline at end of file
}
......@@ -321,20 +321,11 @@ TEST(test_bplus_tree, test_leaf_index_node_handle)
index_file_header.attr_type = INTS;
Frame frame;
frame.dirty = false;
frame.pin_count = 0;
frame.acc_time = 0;
frame.file_desc = 0;
frame.page.page_num = 100;
BPPageHandle page_handle;
page_handle.open = true;
page_handle.frame = &frame;
KeyComparator key_comparator;
key_comparator.init(INTS, 4);
LeafIndexNodeHandler leaf_node(index_file_header, page_handle);
LeafIndexNodeHandler leaf_node(index_file_header, &frame);
leaf_node.init_empty();
ASSERT_EQ(0, leaf_node.size());
......@@ -389,20 +380,11 @@ TEST(test_bplus_tree, test_internal_index_node_handle)
index_file_header.attr_type = INTS;
Frame frame;
frame.dirty = false;
frame.pin_count = 0;
frame.acc_time = 0;
frame.file_desc = 0;
frame.page.page_num = 100;
BPPageHandle page_handle;
page_handle.open = true;
page_handle.frame = &frame;
KeyComparator key_comparator;
key_comparator.init(INTS, 4);
InternalIndexNodeHandler internal_node(index_file_header, page_handle);
InternalIndexNodeHandler internal_node(index_file_header, &frame);
internal_node.init_empty();
ASSERT_EQ(0, internal_node.size());
......@@ -480,8 +462,6 @@ TEST(test_bplus_tree, test_scanner)
{
LoggerFactory::init_default("test.log");
DiskBufferPool::set_pool_num(POOL_NUM);
const char *index_name = "scanner.btree";
::remove(index_name);
handler = new BplusTreeHandler();
......@@ -689,10 +669,7 @@ TEST(test_bplus_tree, test_scanner)
TEST(test_bplus_tree, test_bplus_tree_insert)
{
LoggerFactory::init_default("test.log");
// set the disk buffer pool's number to make it is easy to test
DiskBufferPool::set_pool_num(POOL_NUM);
::remove(index_name);
handler = new BplusTreeHandler();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册