提交 be6c2b45 编写于 作者: L Longda

fixed 22, reimplement b+ tree

Other improvement
1. add code format file
2. add gitignore
3. add memory pool utility
4. remove useless file mpool.h, index_manager.cpp/h
5. rename the interface of disk_buffer_pool basing on the new mem_pool
6. add some logs in db/table/disk_buffer_pool
7. add unit test mem_pool_test/log_test/bplus_tree_test
8. code format all modified files
9. redefine the interface of table_meta
10. change log's  full path as file name
11. add utility function, print_callstack, remove warning of path
上级 f7ea4fc2
---
Language: Cpp
# BasedOnStyle: LLVM
SortIncludes: false
AccessModifierOffset: -2
AlignAfterOpenBracket: DontAlign
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
DerivePointerAlignment: false
PointerAlignment: Right
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 120
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerBinding: true
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 200
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
PointerBindsToType: true
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 2
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Custom
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
IndentFunctionDeclarationAfterType: true
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpaceAfterControlStatementKeyword: true
SpaceBeforeAssignmentOperators: true
SpacesBeforeTrailingComments: 2
ContinuationIndentWidth: 4
CommentPragmas: '^lint'
MacroBlockBegin: "
END_CATCH_ERROR$"
...
./deps/libevent/*
./deps/googletest/*
./deps/jsoncpp/*
build/*
cmake-build-*/*
.vscode/*
.DS_Store
.idea
compile_commands.json
./.name
./miniob.iml
./vcs.xml
./workspace.xml
./modules.xml
......@@ -226,6 +226,9 @@ char *hex_to_bin(const char *s, char *bin_buff, int *dest_len) {
}
bool is_blank(const char *s) {
if (s == nullptr) {
return true;
}
while (*s != '\0') {
if (!isspace(*s)) {
return false;
......
......@@ -162,6 +162,11 @@ class LoggerFactory {
extern Log *g_log;
#ifndef __FILE_NAME__
#define __FILE_NAME__ (strrchr(__FILE__,'/')?strrchr(__FILE__,'/')+1:__FILE__)
#endif
#define LOG_HEAD(prefix, level) \
if (common::g_log) { \
time_t now_time; \
......@@ -175,17 +180,17 @@ extern Log *g_log;
common::g_log->rotate(p->tm_year + 1900, p->tm_mon + 1, p->tm_mday); \
} \
snprintf(prefix, sizeof(prefix), "[%s %s %s %s %u]>>", sz_head, \
(common::g_log)->prefix_msg(level), __FILE__, \
(common::g_log)->prefix_msg(level), __FILE_NAME__, \
__FUNCTION__, (u32_t)__LINE__); \
}
#define LOG_OUTPUT(level, fmt, ...) \
do { \
using namespace common; \
if (g_log && g_log->check_output(level, __FILE__)) { \
if (g_log && g_log->check_output(level, __FILE_NAME__)) { \
char prefix[ONE_KILO] = {0}; \
LOG_HEAD(prefix, level); \
g_log->output(level, __FILE__, prefix, fmt, ##__VA_ARGS__); \
g_log->output(level, __FILE_NAME__, prefix, fmt, ##__VA_ARGS__); \
} \
} while (0)
......
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2022/1/28.
//
#include "common/mm/mem_pool.h"
namespace common {
int MemPoolItem::init(int item_size, bool dynamic, int pool_num, int item_num_per_pool)
{
if (pools.empty() == false) {
LOG_WARN("Memory pool has been initialized, but still begin to be initialized, this->name:%s.", this->name.c_str());
return 0;
}
if (item_size <= 0 || pool_num <= 0 || item_num_per_pool <= 0) {
LOG_ERROR("Invalid arguments, item_size:%d, pool_num:%d, item_num_per_pool:%d, this->name:%s.",
item_size,
pool_num,
item_num_per_pool,
this->name.c_str());
return -1;
}
this->item_size = item_size;
this->item_num_per_pool = item_num_per_pool;
// in order to init memory pool, enable dynamic here
this->dynamic = true;
for (int i = 0; i < pool_num; i++) {
if (extend() < 0) {
cleanup();
return -1;
}
}
this->dynamic = dynamic;
LOG_INFO("Extend one pool, this->size:%d, item_size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_size,
item_num_per_pool,
this->name.c_str());
return 0;
}
void MemPoolItem::cleanup()
{
if (pools.empty() == true) {
LOG_WARN("Begin to do cleanup, but there is no memory pool, this->name:%s!", this->name.c_str());
return;
}
MUTEX_LOCK(&this->mutex);
used.clear();
frees.clear();
this->size = 0;
for (std::list<void *>::iterator iter = pools.begin(); iter != pools.end(); iter++) {
void *pool = *iter;
::free(pool);
}
pools.clear();
MUTEX_UNLOCK(&this->mutex);
LOG_INFO("Successfully do cleanup, this->name:%s.", this->name.c_str());
}
int MemPoolItem::extend()
{
if (this->dynamic == false) {
LOG_ERROR("Disable dynamic extend memory pool, but begin to extend, this->name:%s", this->name.c_str());
return -1;
}
MUTEX_LOCK(&this->mutex);
void *pool = malloc(item_num_per_pool * item_size);
if (pool == nullptr) {
MUTEX_UNLOCK(&this->mutex);
LOG_ERROR("Failed to extend memory pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_num_per_pool,
this->name.c_str());
return -1;
}
pools.push_back(pool);
this->size += item_num_per_pool;
for (int i = 0; i < item_num_per_pool; i++) {
char *item = (char *)pool + i * item_size;
frees.push_back((void *)item);
}
MUTEX_UNLOCK(&this->mutex);
LOG_INFO("Extend one pool, this->size:%d, item_size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_size,
item_num_per_pool,
this->name.c_str());
return 0;
}
void *MemPoolItem::alloc()
{
MUTEX_LOCK(&this->mutex);
if (frees.empty() == true) {
if (this->dynamic == false) {
MUTEX_UNLOCK(&this->mutex);
return nullptr;
}
if (extend() < 0) {
MUTEX_UNLOCK(&this->mutex);
return nullptr;
}
}
void *buffer = frees.front();
frees.pop_front();
used.insert(buffer);
MUTEX_UNLOCK(&this->mutex);
memset(buffer, 0, sizeof(item_size));
return buffer;
}
void MemPoolItem::free(void *buf)
{
MUTEX_LOCK(&this->mutex);
size_t num = used.erase(buf);
if (num == 0) {
MUTEX_UNLOCK(&this->mutex);
LOG_WARN("No entry of %p in %s.", buf, this->name.c_str());
return;
}
frees.push_back(buf);
MUTEX_UNLOCK(&this->mutex);
return; // TODO for test
}
} // namespace common
\ No newline at end of file
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2010
//
#ifndef __COMMON_MM_MPOOL_H__
#define __COMMON_MM_MPOOL_H__
#include <queue>
#include <list>
#include <set>
#include <string>
#include <sstream>
#include "common/lang/mutex.h"
#include "common/log/log.h"
#include "common/os/os.h"
namespace common {
#define DEFAULT_ITEM_NUM_PER_POOL 128
#define DEFAULT_POOL_NUM 1
typedef bool (*match)(void *item, void *input_arg);
template <class T>
class MemPool {
public:
MemPool(const char *tag) : name(tag)
{
this->size = 0;
pthread_mutexattr_t mutexatr;
pthread_mutexattr_init(&mutexatr);
pthread_mutexattr_settype(&mutexatr, PTHREAD_MUTEX_RECURSIVE);
MUTEX_INIT(&mutex, &mutexatr);
}
virtual ~MemPool()
{
MUTEX_DESTROY(&mutex);
}
/**
* init memory pool, the major job is to alloc memory for memory pool
* @param pool_num, memory pool's number
* @param item_num_per_pool, how many items per pool.
* @return
*/
virtual int init(
bool dynamic = true, int pool_num = DEFAULT_POOL_NUM, int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL) = 0;
/**
* Do cleanup job for memory pool
*/
virtual void cleanup() = 0;
/**
* If dynamic has been set, extend current memory pool,
*/
virtual int extend() = 0;
/**
* Alloc one frame from memory Pool
* @return
*/
virtual T *alloc() = 0;
/**
* Free one item, the resouce will return to memory Pool
* @param item
*/
virtual void free(T *item) = 0;
/**
* Find first used item which match the function of "func"
* @return
*/
virtual T *find(match func, void *arg) = 0;
/**
* Find used item which match the function of "func"
*/
virtual std::list<T *> find_all(match func, void *arg) = 0;
/**
* Mark the item has been changed;
*/
virtual void mark_modified(T *item) = 0;
/**
* Print the MemPool status
* @return
*/
virtual std::string to_string() = 0;
const std::string get_name() const
{
return name;
}
bool is_dynamic() const
{
return dynamic;
}
int get_size() const
{
return size;
}
protected:
pthread_mutex_t mutex;
int size;
bool dynamic;
std::string name;
};
/**
* MemoryPoolSimple is a simple Memory Pool manager,
*/
template <class T>
class MemPoolSimple : public MemPool<T> {
public:
MemPoolSimple(const char *tag) : MemPool<T>(tag)
{}
virtual ~MemPoolSimple()
{
cleanup();
}
/**
* init memory pool, the major job is to alloc memory for memory pool
* @param pool_num, memory pool's number
* @param item_num_per_pool, how many items per pool.
* @return
*/
int init(bool dynamic = true, int pool_num = DEFAULT_POOL_NUM, int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL);
/**
* Do cleanup job for memory pool
*/
void cleanup();
/**
* If dynamic has been set, extend current memory pool,
*/
int extend();
/**
* Alloc one frame from memory Pool
* @return
*/
T *alloc();
/**
* Free one item, the resouce will return to memory Pool
* @param item
*/
void free(T *item);
/**
* Find first used item which match the function of "func"
* @return
*/
T *find(match func, void *arg);
/**
* Find used item which match the function of "func"
*/
std::list<T *> find_all(match func, void *arg);
/**
* Mark the item has been changed;
*/
void mark_modified(T *item);
/**
* Print the MemPool status
* @return
*/
std::string to_string();
int get_item_num_per_pool() const
{
return item_num_per_pool;
}
int get_used_num()
{
MUTEX_LOCK(&this->mutex);
auto num = used.size();
MUTEX_UNLOCK(&this->mutex);
return num;
}
protected:
std::list<T *> pools;
std::list<T *> lru_used;
std::set<T *> used;
std::list<T *> frees;
int item_num_per_pool;
};
template <class T>
int MemPoolSimple<T>::init(bool dynamic, int pool_num, int item_num_per_pool)
{
if (pools.empty() == false) {
LOG_WARN("Memory pool has been initialized, but still begin to be initialized, this->name:%s.", this->name.c_str());
return 0;
}
if (pool_num <= 0 || item_num_per_pool <= 0) {
LOG_ERROR("Invalid arguments, pool_num:%d, item_num_per_pool:%d, this->name:%s.",
pool_num,
item_num_per_pool,
this->name.c_str());
return -1;
}
this->item_num_per_pool = item_num_per_pool;
// in order to init memory pool, enable dynamic here
this->dynamic = true;
for (int i = 0; i < pool_num; i++) {
if (extend() < 0) {
cleanup();
return -1;
}
}
this->dynamic = dynamic;
LOG_INFO("Extend one pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_num_per_pool,
this->name.c_str());
return 0;
}
template <class T>
void MemPoolSimple<T>::cleanup()
{
if (pools.empty() == true) {
LOG_WARN("Begin to do cleanup, but there is no memory pool, this->name:%s!", this->name.c_str());
return;
}
MUTEX_LOCK(&this->mutex);
lru_used.clear();
used.clear();
frees.clear();
this->size = 0;
for (typename std::list<T *>::iterator iter = pools.begin(); iter != pools.end(); iter++) {
T *pool = *iter;
delete[] pool;
}
pools.clear();
MUTEX_UNLOCK(&this->mutex);
LOG_INFO("Successfully do cleanup, this->name:%s.", this->name.c_str());
}
template <class T>
int MemPoolSimple<T>::extend()
{
if (this->dynamic == false) {
LOG_ERROR("Disable dynamic extend memory pool, but begin to extend, this->name:%s", this->name.c_str());
return -1;
}
MUTEX_LOCK(&this->mutex);
T *pool = new T[item_num_per_pool];
if (pool == nullptr) {
MUTEX_UNLOCK(&this->mutex);
LOG_ERROR("Failed to extend memory pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_num_per_pool,
this->name.c_str());
return -1;
}
pools.push_back(pool);
this->size += item_num_per_pool;
for (int i = 0; i < item_num_per_pool; i++) {
frees.push_back(pool + i);
}
MUTEX_UNLOCK(&this->mutex);
LOG_INFO("Extend one pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
this->size,
item_num_per_pool,
this->name.c_str());
return 0;
}
template <class T>
T *MemPoolSimple<T>::alloc()
{
MUTEX_LOCK(&this->mutex);
if (frees.empty() == true) {
if (this->dynamic == false) {
MUTEX_UNLOCK(&this->mutex);
return nullptr;
}
if (extend() < 0) {
MUTEX_UNLOCK(&this->mutex);
return nullptr;
}
}
T *buffer = frees.front();
frees.pop_front();
used.insert(buffer);
lru_used.push_back(buffer);
MUTEX_UNLOCK(&this->mutex);
return buffer;
}
template <class T>
void MemPoolSimple<T>::free(T *buf)
{
MUTEX_LOCK(&this->mutex);
size_t num = used.erase(buf);
if (num == 0) {
MUTEX_UNLOCK(&this->mutex);
LOG_WARN("No entry of %p in %s.", buf, this->name.c_str());
print_stacktrace();
return;
}
lru_used.remove(buf);
frees.push_back(buf);
MUTEX_UNLOCK(&this->mutex);
return; // TODO for test
}
template <class T>
T *MemPoolSimple<T>::find(match func, void *arg)
{
T *buffer = nullptr;
MUTEX_LOCK(&this->mutex);
for (typename std::list<T *>::iterator it = lru_used.begin(); it != lru_used.end(); ++it) {
T *item = *it;
if ((*func)(item, arg) == false) {
continue;
}
buffer = item;
break;
}
MUTEX_UNLOCK(&this->mutex);
return buffer;
}
template <class T>
std::list<T *> MemPoolSimple<T>::find_all(match func, void *arg)
{
std::list<T *> ret;
MUTEX_LOCK(&this->mutex);
for (typename std::list<T *>::iterator it = lru_used.begin(); it != lru_used.end(); ++it) {
T *item = *it;
if ((*func)(item, arg) == false) {
continue;
}
ret.push_back(item);
}
MUTEX_UNLOCK(&this->mutex);
return ret;
}
template <class T>
void MemPoolSimple<T>::mark_modified(T *buf)
{
MUTEX_LOCK(&this->mutex);
if (used.find(buf) == used.end()) {
MUTEX_UNLOCK(&this->mutex);
LOG_WARN("No entry of %p in %s.", buf, this->name.c_str());
return;
}
lru_used.remove(buf);
lru_used.push_back(buf);
MUTEX_UNLOCK(&this->mutex);
return;
}
template <class T>
std::string MemPoolSimple<T>::to_string()
{
std::stringstream ss;
ss << "name:" << this->name << ","
<< "dyanmic:" << this->dynamic << ","
<< "size:" << this->size << ","
<< "pool_size:" << this->pools.size() << ","
<< "used_size:" << this->used.size() << ","
<< "free_size:" << this->frees.size();
return ss.str();
}
class MemPoolItem {
public:
MemPoolItem(const char *tag) : name(tag)
{
this->size = 0;
pthread_mutexattr_t mutexatr;
pthread_mutexattr_init(&mutexatr);
pthread_mutexattr_settype(&mutexatr, PTHREAD_MUTEX_RECURSIVE);
MUTEX_INIT(&mutex, &mutexatr);
}
virtual ~MemPoolItem()
{
cleanup();
MUTEX_DESTROY(&mutex);
}
/**
* init memory pool, the major job is to alloc memory for memory pool
* @param pool_num, memory pool's number
* @param item_num_per_pool, how many items per pool.
* @return
*/
int init(int item_size, bool dynamic = true, int pool_num = DEFAULT_POOL_NUM,
int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL);
/**
* Do cleanup job for memory pool
*/
void cleanup();
/**
* If dynamic has been set, extend current memory pool,
*/
int extend();
/**
* Alloc one frame from memory Pool
* @return
*/
void *alloc();
/**
* Free one item, the resouce will return to memory Pool
* @param item
*/
void free(void *item);
/**
* Check whether this item has been used before.
* @param item
* @return
*/
bool is_used(void *item)
{
MUTEX_LOCK(&mutex);
auto it = used.find(item);
MUTEX_UNLOCK(&mutex);
return it != used.end();
}
std::string to_string()
{
std::stringstream ss;
ss << "name:" << this->name << ","
<< "dyanmic:" << this->dynamic << ","
<< "size:" << this->size << ","
<< "pool_size:" << this->pools.size() << ","
<< "used_size:" << this->used.size() << ","
<< "free_size:" << this->frees.size();
return ss.str();
}
const std::string get_name() const
{
return name;
}
bool is_dynamic() const
{
return dynamic;
}
int get_size() const
{
return size;
}
int get_item_size() const
{
return item_size;
}
int get_item_num_per_pool() const
{
return item_num_per_pool;
}
int get_used_num()
{
MUTEX_LOCK(&mutex);
auto num = used.size();
MUTEX_UNLOCK(&mutex);
return num;
}
protected:
pthread_mutex_t mutex;
std::string name;
bool dynamic;
int size;
int item_size;
int item_num_per_pool;
std::list<void *> pools;
std::set<void *> used;
std::list<void *> frees;
};
} // namespace common
#endif /* __COMMON_MM_MPOOL_H__ */
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2010
//
#ifndef __COMMON_MM_MPOOL_H__
#define __COMMON_MM_MPOOL_H__
#include <queue>
#include "common/lang/mutex.h"
#include "common/log/log.h"
namespace common {
#define CLMPOOL_DEFAULT_ADDSIZE 16
template<class T>
class MemPool {
public:
MemPool() : mQueue(), mAddSize(CLMPOOL_DEFAULT_ADDSIZE) {
MUTEX_INIT(&mLock, NULL);
}
~MemPool() {
MUTEX_LOCK(&mLock);
while (mQueue.empty() == false) {
T *item = mQueue.front();
mQueue.pop();
delete item;
}
MUTEX_UNLOCK(&mLock);
MUTEX_DESTROY(&mLock);
}
int add(int addSize) {
int ret = 0;
MUTEX_LOCK(&mLock);
for (int i = 0; i < addSize; i++) {
T *item = new T();
if (item == NULL) {
ret = -1;
break;
}
mQueue.push(item);
}
MUTEX_UNLOCK(&mLock);
return ret;
}
int init(int initSize) { return add(initSize); }
T *get() {
T *ret = NULL;
MUTEX_LOCK(&mLock);
if (mQueue.empty() == true) {
add(mAddSize);
}
if (mQueue.empty() == false) {
ret = mQueue.front();
mQueue.pop();
}
MUTEX_UNLOCK(&mLock);
return ret;
}
void put(T *item) {
MUTEX_LOCK(&mLock);
mQueue.push(item);
MUTEX_UNLOCK(&mLock);
}
private:
std::queue<T *> mQueue;
pthread_mutex_t mLock;
int mAddSize;
};
} //namespace common
#endif /* __COMMON_MM_MPOOL_H__ */
......@@ -13,9 +13,11 @@ See the Mulan PSL v2 for more details. */
//
#include <thread>
#include <execinfo.h>
#include "common/defs.h"
#include "common/os/os.h"
#include "common/log/log.h"
namespace common {
// Don't care windows
......@@ -23,4 +25,19 @@ u32_t getCpuNum() {
return std::thread::hardware_concurrency();
}
#define MAX_STACK_SIZE 32
void print_stacktrace()
{
int size = MAX_STACK_SIZE;
void * array[MAX_STACK_SIZE];
int stack_num = backtrace(array, size);
char ** stacktrace = backtrace_symbols(array, stack_num);
for (int i = 0; i < stack_num; ++i)
{
LOG_INFO("%d ----- %s\n", i, stacktrace[i]);
}
free(stacktrace);
}
}//namespace common
\ No newline at end of file
......@@ -18,5 +18,7 @@ namespace common {
u32_t getCpuNum();
void print_stacktrace();
} //namespace common
#endif /* __COMMON_OS_OS_H__ */
......@@ -23,7 +23,8 @@ See the Mulan PSL v2 for more details. */
#include "common/log/log.h"
namespace common {
std::string getFileName(const std::string &fullPath) {
std::string getFileName(const std::string &fullPath)
{
std::string szRt;
size_t pos;
try {
......@@ -36,12 +37,12 @@ std::string getFileName(const std::string &fullPath) {
szRt = "";
}
} catch (...) {
}
} catch (...) {}
return szRt;
}
void getFileName(const char *path, std::string &fileName) {
void getFileName(const char *path, std::string &fileName)
{
// Don't care the last character as FILE_PATH_SPLIT
const char *endPos = strrchr(path, FILE_PATH_SPLIT);
if (endPos == NULL) {
......@@ -58,7 +59,8 @@ void getFileName(const char *path, std::string &fileName) {
return;
}
std::string getDirName(const std::string &fullPath) {
std::string getDirName(const std::string &fullPath)
{
std::string szRt;
size_t pos;
try {
......@@ -72,11 +74,11 @@ std::string getDirName(const std::string &fullPath) {
szRt = FILE_PATH_SPLIT_STR;
}
} catch (...) {
}
} catch (...) {}
return szRt;
}
void getDirName(const char *path, std::string &parent) {
void getDirName(const char *path, std::string &parent)
{
// Don't care the last character as FILE_PATH_SPLIT
const char *endPos = strrchr(path, FILE_PATH_SPLIT);
if (endPos == NULL) {
......@@ -93,7 +95,8 @@ void getDirName(const char *path, std::string &parent) {
return;
}
std::string getFilePath(const std::string &fullPath) {
std::string getFilePath(const std::string &fullPath)
{
std::string szRt;
size_t pos;
try {
......@@ -106,43 +109,42 @@ std::string getFilePath(const std::string &fullPath) {
szRt = "";
}
} catch (...) {
}
} catch (...) {}
return szRt;
}
std::string getAboslutPath(const char *path) {
std::string getAboslutPath(const char *path)
{
std::string aPath(path);
if (path[0] != '/') {
const int MAX_SIZE = 256;
char current_absolute_path[MAX_SIZE];
if (NULL == getcwd(current_absolute_path, MAX_SIZE)) {
}
if (NULL == getcwd(current_absolute_path, MAX_SIZE)) {}
}
return aPath;
}
bool is_directory(const char *path) {
bool is_directory(const char *path)
{
struct stat st;
return (0 == stat(path, &st)) && (st.st_mode & S_IFDIR);
}
bool check_directory(std::string &path) {
bool check_directory(std::string &path)
{
while (!path.empty() && path.back() == '/')
path.erase(path.size() - 1, 1);
int len = path.size();
if (0 == mkdir(path.c_str(), 0777) || is_directory(path.c_str()) )
if (0 == mkdir(path.c_str(), 0777) || is_directory(path.c_str()))
return true;
bool sep_state = false;
for (int i = 0; i < len; i++)
{
if (path[i] != '/')
{
for (int i = 0; i < len; i++) {
if (path[i] != '/') {
if (sep_state)
sep_state = false;
continue;
......@@ -164,39 +166,33 @@ bool check_directory(std::string &path) {
return true;
}
int list_file(const char *path, const char *filter_pattern, std::vector<std::string> &files) {
int list_file(const char *path, const char *filter_pattern, std::vector<std::string> &files)
{
regex_t reg;
if (filter_pattern)
{
if (filter_pattern) {
const int res = regcomp(&reg, filter_pattern, REG_NOSUB);
if (res)
{
if (res) {
char errbuf[256];
regerror(res, &reg, errbuf, sizeof(errbuf));
LOG_ERROR("regcomp return error. filter pattern %s. errmsg %d:%s",
filter_pattern, res, errbuf);
LOG_ERROR("regcomp return error. filter pattern %s. errmsg %d:%s", filter_pattern, res, errbuf);
return -1;
}
}
DIR *pdir = opendir(path);
if (!pdir)
{
if (!pdir) {
if (filter_pattern)
regfree(&reg);
LOG_ERROR("open directory failure. path %s, errmsg %d:%s",
path, errno, strerror(errno));
closedir(pdir);
LOG_ERROR("open directory failure. path %s, errmsg %d:%s", path, errno, strerror(errno));
return -1;
}
files.clear();
struct dirent entry;
struct dirent * pentry = NULL;
struct dirent *pentry = NULL;
char tmp_path[PATH_MAX];
while((0 == readdir_r(pdir, &entry, &pentry)) && (NULL != pentry))
{
while ((0 == readdir_r(pdir, &entry, &pentry)) && (NULL != pentry)) {
if ('.' == entry.d_name[0]) // 跳过./..文件和隐藏文件
continue;
......@@ -215,4 +211,4 @@ int list_file(const char *path, const char *filter_pattern, std::vector<std::str
return files.size();
}
} //namespace common
\ No newline at end of file
} // namespace common
\ No newline at end of file
......@@ -9,7 +9,7 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2021/4/13.
// Created by Xie Meiyi
//
#include "storage/common/bplus_tree.h"
#include "storage/default/disk_buffer_pool.h"
......@@ -17,84 +17,132 @@ See the Mulan PSL v2 for more details. */
#include "common/log/log.h"
#include "sql/parser/parse_defs.h"
int float_compare(float f1, float f2) {
#define FIRST_INDEX_PAGE 1
int float_compare(float f1, float f2)
{
float result = f1 - f2;
if (result < 1e-6 && result > -1e-6) {
if (-1e-6 < result && result < 1e-6) {
return 0;
}
return result > 0 ? 1: -1;
return result > 0 ? 1 : -1;
}
int attribute_comp(const char *first, const char *second, AttrType attr_type, int attr_length)
{ // 简化
int i1, i2;
float f1, f2;
const char *s1, *s2;
switch (attr_type) {
case INTS: {
i1 = *(int *)first;
i2 = *(int *)second;
return i1 - i2;
} break;
case FLOATS: {
f1 = *(float *)first;
f2 = *(float *)second;
return float_compare(f1, f2);
} break;
case CHARS: {
s1 = first;
s2 = second;
return strncmp(s1, s2, attr_length);
} break;
default: {
LOG_PANIC("Unknown attr type: %d", attr_type);
}
}
return -2; // This means error happens
}
int key_compare(AttrType attr_type, int attr_length, const char *first, const char *second)
{
int result = attribute_comp(first, second, attr_type, attr_length);
if (0 != result) {
return result;
}
RID *rid1 = (RID *)(first + attr_length);
RID *rid2 = (RID *)(second + attr_length);
return RID::compare(rid1, rid2);
}
int get_page_index_capacity(int attr_length)
{
int capacity =
((int)BP_PAGE_DATA_SIZE - sizeof(IndexFileHeader) - sizeof(IndexNode)) / (attr_length + 2 * sizeof(RID));
// Here is some tricks
// 1. reserver one pair of kV for insert operation
// 2. make sure capacity % 2 == 0, otherwise it is likeyly to occur problem when split node
capacity = ((capacity - RECORD_RESERVER_PAIR_NUM) / 2) * 2;
return capacity;
}
IndexNode * BplusTreeHandler::get_index_node(char *page_data) const {
IndexNode *BplusTreeHandler::get_index_node(char *page_data) const
{
IndexNode *node = (IndexNode *)(page_data + sizeof(IndexFileHeader));
node->keys = (char *)node + sizeof(IndexNode);
node->rids = (RID *)(node->keys + file_header_.order * file_header_.key_length);
node->rids = (RID *)(node->keys + (file_header_.order + RECORD_RESERVER_PAIR_NUM) * file_header_.key_length);
return node;
}
RC BplusTreeHandler::sync() {
return disk_buffer_pool_->flush_all_pages(file_id_);
RC BplusTreeHandler::sync()
{
return disk_buffer_pool_->purge_all_pages(file_id_);
}
RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_length)
{
BPPageHandle page_handle;
IndexNode *root;
char *pdata;
RC rc;
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
rc = disk_buffer_pool->create_file(file_name);
if(rc!=SUCCESS){
RC rc = disk_buffer_pool->create_file(file_name);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to create file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
LOG_INFO("Successfully create index file:%s", file_name);
int file_id;
rc = disk_buffer_pool->open_file(file_name, &file_id);
if(rc != SUCCESS){
LOG_ERROR("Failed to open file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open file. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
rc = disk_buffer_pool->allocate_page(file_id, &page_handle);
if(rc!=SUCCESS){
LOG_ERROR("Failed to allocate page. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
LOG_INFO("Successfully open index file %s.", file_name);
rc = disk_buffer_pool->allocate_page(file_id, &root_page_handle_);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to allocate page. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool->close_file(file_id);
return rc;
}
rc = disk_buffer_pool->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
LOG_ERROR("Failed to get data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
char *pdata;
rc = disk_buffer_pool->get_data(&root_page_handle_, &pdata);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool->close_file(file_id);
return rc;
}
PageNum page_num;
rc = disk_buffer_pool->get_page_num(&page_handle, &page_num);
if(rc!=SUCCESS){
LOG_ERROR("Failed to get page num. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
rc = disk_buffer_pool->get_page_num(&root_page_handle_, &page_num);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get page num. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool->close_file(file_id);
return rc;
}
IndexFileHeader *file_header =(IndexFileHeader *)pdata;
IndexFileHeader *file_header = (IndexFileHeader *)pdata;
file_header->attr_length = attr_length;
file_header->key_length = attr_length + sizeof(RID);
file_header->attr_type = attr_type;
file_header->node_num = 1;
file_header->order=((int)BP_PAGE_DATA_SIZE-sizeof(IndexFileHeader)-sizeof(IndexNode))/(attr_length+2*sizeof(RID));
file_header->order = get_page_index_capacity(attr_length);
file_header->root_page = page_num;
root = get_index_node(pdata);
root->is_leaf = 1;
root->key_num = 0;
root->parent = -1;
root->keys = nullptr;
root->rids = nullptr;
rc = disk_buffer_pool->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
}
root_node_ = get_index_node(pdata);
root_node_->init_empty(*file_header);
rc = disk_buffer_pool->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
disk_buffer_pool->mark_dirty(&root_page_handle_);
disk_buffer_pool_ = disk_buffer_pool;
file_id_ = file_id;
......@@ -102,1603 +150,2036 @@ RC BplusTreeHandler::create(const char *file_name, AttrType attr_type, int attr_
memcpy(&file_header_, pdata, sizeof(file_header_));
header_dirty_ = false;
return SUCCESS;
mem_pool_item_ = new common::MemPoolItem(file_name);
if (mem_pool_item_->init(file_header->key_length) < 0) {
LOG_WARN("Failed to init memory pool for index %s", file_name);
close();
return RC::NOMEM;
}
LOG_INFO("Successfully create index %s", file_name);
return RC::SUCCESS;
}
RC BplusTreeHandler::open(const char *file_name) {
RC rc;
BPPageHandle page_handle;
char *pdata;
if (disk_buffer_pool_ != nullptr) {
RC BplusTreeHandler::open(const char *file_name)
{
if (file_id_ > 0) {
LOG_WARN("%s has been opened before index.open.", file_name);
return RC::RECORD_OPENNED;
}
DiskBufferPool *disk_buffer_pool = theGlobalDiskBufferPool();
int file_id;
rc = disk_buffer_pool->open_file(file_name, &file_id);
if(rc!=SUCCESS){
int file_id = 0;
RC rc = disk_buffer_pool->open_file(file_name, &file_id);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to open file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
return rc;
}
rc = disk_buffer_pool->get_this_page(file_id, 1, &page_handle);
if(rc!=SUCCESS){
BPPageHandle page_handle;
rc = disk_buffer_pool->get_this_page(file_id, FIRST_INDEX_PAGE, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
return rc;
}
char *pdata;
rc = disk_buffer_pool->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
return rc;
}
memcpy(&file_header_,pdata,sizeof(IndexFileHeader));
memcpy(&file_header_, pdata, sizeof(IndexFileHeader));
header_dirty_ = false;
disk_buffer_pool_ = disk_buffer_pool;
file_id_ = file_id;
rc = disk_buffer_pool->unpin_page(&page_handle);
if(rc!=SUCCESS){
mem_pool_item_ = new common::MemPoolItem(file_name);
if (mem_pool_item_->init(file_header_.key_length) < 0) {
LOG_WARN("Failed to init memory pool for index %s", file_name);
close();
return RC::NOMEM;
}
if (file_header_.root_page == FIRST_INDEX_PAGE) {
root_node_ = get_index_node(pdata);
root_page_handle_ = page_handle;
LOG_INFO("Successfully open index %s", file_name);
return RC::SUCCESS;
}
// close old page_handle
disk_buffer_pool->unpin_page(&page_handle);
LOG_INFO("Begin to load root page of index:%s, root_page:%d.", file_name, file_header_.root_page);
rc = disk_buffer_pool->get_this_page(file_id, file_header_.root_page, &root_page_handle_);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
return rc;
}
return SUCCESS;
rc = disk_buffer_pool->get_data(&root_page_handle_, &pdata);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first page data. file name=%s, rc=%d:%s", file_name, rc, strrc(rc));
disk_buffer_pool_->close_file(file_id);
return rc;
}
root_node_ = get_index_node(pdata);
LOG_INFO("Successfully open index %s", file_name);
return RC::SUCCESS;
}
RC BplusTreeHandler::close() {
sync();
RC BplusTreeHandler::close()
{
if (file_id_ != -1) {
disk_buffer_pool_->unpin_page(&root_page_handle_);
root_node_ = nullptr;
disk_buffer_pool_->close_file(file_id_);
file_id_ = -1;
delete mem_pool_item_;
mem_pool_item_ = nullptr;
}
disk_buffer_pool_ = nullptr;
return RC::SUCCESS;
}
static int CmpRid(const RID *rid1, const RID *rid2) {
if(rid1->page_num > rid2->page_num)
return 1;
if(rid1->page_num < rid2 ->page_num)
return -1;
if(rid1->slot_num > rid2->slot_num)
return 1;
if(rid1->slot_num < rid2->slot_num)
return -1;
return 0;
}
int CompareKey(const char *pdata, const char *pkey,AttrType attr_type,int attr_length) { // 简化
int i1,i2;
float f1,f2;
const char *s1,*s2;
switch(attr_type){
case INTS: {
i1 = *(int *) pdata;
i2 = *(int *) pkey;
if (i1 > i2)
return 1;
if (i1 < i2)
return -1;
if (i1 == i2)
return 0;
}
break;
case FLOATS: {
f1 = *(float *) pdata;
f2 = *(float *) pkey;
return float_compare(f1, f2);
}
break;
case CHARS: {
s1 = pdata;
s2 = pkey;
return strncmp(s1, s2, attr_length);
RC BplusTreeHandler::print_node(IndexNode *node, PageNum page_num)
{
LOG_INFO("PageNum:%d, node {%s}\n", page_num, node->to_string(file_header_).c_str());
if (node->is_leaf == false) {
for (int i = 0; i <= node->key_num; i++) {
PageNum child_page_num = node->rids[i].page_num;
BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page_num, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, child_page_num);
continue;
}
break;
default:{
LOG_PANIC("Unknown attr type: %d", attr_type);
char *pdata;
disk_buffer_pool_->get_data(&page_handle, &pdata);
IndexNode *child = get_index_node(pdata);
print_node(child, child_page_num);
disk_buffer_pool_->unpin_page(&page_handle);
}
}
return -2;//This means error happens
return RC::SUCCESS;
}
int CmpKey(AttrType attr_type, int attr_length, const char *pdata, const char *pkey)
RC BplusTreeHandler::print_tree()
{
int result = CompareKey(pdata, pkey, attr_type, attr_length);
if (0 != result) {
return result;
if (file_id_ < 0) {
LOG_WARN("Index hasn't been created or opened, fail to print");
return RC::SUCCESS;
}
RID *rid1 = (RID *) (pdata + attr_length);
RID *rid2 = (RID *) (pkey + attr_length);
return CmpRid(rid1, rid2);
}
RC BplusTreeHandler::find_leaf(const char *pkey,PageNum *leaf_page) {
RC rc;
BPPageHandle page_handle;
IndexNode *node;
char *pdata;
int i,tmp;
rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
if(rc!=SUCCESS){
int page_count;
RC rc = disk_buffer_pool_->get_page_count(file_id_, &page_count);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get page count of index %d", file_id_);
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
LOG_INFO("\n\n\n !!!! Begin to print index %s:%d, page_count:%d, file_header:%s\n\n\n",
mem_pool_item_->get_name().c_str(),
file_id_,
page_count,
file_header_.to_string().c_str());
print_node(root_node_, file_header_.root_page);
return RC::SUCCESS;
}
RC BplusTreeHandler::print_leafs()
{
PageNum page_num;
get_first_leaf_page(&page_num);
IndexNode *node;
BPPageHandle page_handle;
RC rc ;
while(page_num != -1) {
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to print leafs, due to failed to load. ");
return rc;
}
char *pdata;
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
while(0 == node->is_leaf){
for(i = 0; i < node->key_num; i++){
tmp = CmpKey(file_header_.attr_type, file_header_.attr_length,pkey,node->keys + i * file_header_.key_length);
if(tmp < 0)
break;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
LOG_INFO("Page:%d, Node:%s", page_num, node->to_string(file_header_).c_str());
page_num = node->next_brother;
disk_buffer_pool_->unpin_page(&page_handle);
}
rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[i].page_num, &page_handle);
if(rc!=SUCCESS){
return rc;
return RC::SUCCESS;
}
bool BplusTreeHandler::validate_node(IndexNode *node)
{
if (node->key_num > file_header_.order) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str());
return false;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
if (node->parent != -1) {
if (node->key_num < file_header_.order / 2) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str());
return false;
}
node = get_index_node(pdata);
} else {
// node is root
if (node->is_leaf == false) {
if (node->key_num < 1) {
LOG_WARN("NODE %s 's key number is invalid", node->to_string(file_header_).c_str());
return false;
}
rc = disk_buffer_pool_->get_page_num(&page_handle, leaf_page);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
return SUCCESS;
}
RC BplusTreeHandler::insert_into_leaf(PageNum leaf_page, const char *pkey, const RID *rid)
{
int i,insert_pos,tmp;
BPPageHandle page_handle;
char *pdata;
char *from,*to;
IndexNode *node;
RC rc;
if (node->is_leaf && node->prev_brother != -1) {
char *first_key = node->keys;
bool found = false;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle);
if(rc != SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc != SUCCESS){
return rc;
PageNum parent_page = node->parent;
while (parent_page != -1) {
BPPageHandle parent_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &parent_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to check parent's keys, file_id:%d", file_id_);
return false;
}
node = get_index_node(pdata);
for(insert_pos = 0; insert_pos < node->key_num; insert_pos++){
tmp = CmpKey(file_header_.attr_type, file_header_.attr_length, pkey, node->keys + insert_pos * file_header_.key_length);
char *pdata;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
IndexNode *parent = get_index_node(pdata);
for (int i = 0; i < parent->key_num; i++) {
char *cur_key = parent->keys + i * file_header_.key_length;
int tmp = key_compare(file_header_.attr_type, file_header_.attr_length, first_key, cur_key);
if (tmp == 0) {
return RC::RECORD_DUPLICATE_KEY;
found = true;
break;
} else if (tmp < 0) {
break;
}
if(tmp < 0)
}
disk_buffer_pool_->unpin_page(&parent_handle);
if (found == true) {
break;
}
for(i = node->key_num; i > insert_pos; i--){
from = node->keys+(i-1)*file_header_.key_length;
to = node->keys+i*file_header_.key_length;
memcpy(to, from, file_header_.key_length);
memcpy(node->rids + i, node->rids + i-1, sizeof(RID));
parent_page = parent->parent;
}
memcpy(node->keys + insert_pos * file_header_.key_length, pkey, file_header_.key_length);
memcpy(node->rids + insert_pos, rid, sizeof(RID));
node->key_num++; //叶子结点增加一条记录
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc != SUCCESS){
return rc;
if (found == false) {
LOG_WARN("Failed to find leaf's first key in internal node. leaf:%s, file_id:%d",
node->to_string(file_header_).c_str(),
file_id_);
return false;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc != SUCCESS){
return rc;
}
return SUCCESS;
}
RC BplusTreeHandler::print() {
IndexNode *node;
RC rc;
BPPageHandle page_handle;
int i,j;
char *pdata;
int page_count;
rc = disk_buffer_pool_->get_page_count(file_id_, &page_count);
if (rc != SUCCESS) {
return rc;
bool ret = false;
char *last_key = node->keys;
char *cur_key;
for (int i = 0; i < node->key_num; i++) {
int tmp;
cur_key = node->keys + i * file_header_.key_length;
if (i > 0) {
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, last_key);
if (tmp < 0) {
LOG_WARN("NODE %s 's key sequence is wrong", node->to_string(file_header_).c_str());
return false;
}
for(i=1; i <= page_count; i++){
rc = disk_buffer_pool_->get_this_page(file_id_, i, &page_handle);
if(rc==RC::BUFFERPOOL_INVALID_PAGE_NUM)
continue;
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
last_key = cur_key;
if (node->is_leaf) {
continue;
}
node = get_index_node(pdata);
printf("page_num :%d %d\n",i,node->is_leaf);
for(j=0;j<node->key_num&&j<6;j++){
printf("keynum :%d rids:page_num :%d,slotnum :%d\n", node->key_num, node->rids[j].page_num, node->rids[j].slot_num);
PageNum child_page = node->rids[i].page_num;
BPPageHandle child_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, child_page, &child_handle);
if (rc != RC::SUCCESS) {
LOG_WARN(
"Failed to validte node's child %d, file_id:%d, node:%s", i, file_id_, node->to_string(file_header_).c_str());
continue;
}
printf("\n");
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
char *pdata;
disk_buffer_pool_->get_data(&child_handle, &pdata);
IndexNode *child = get_index_node(pdata);
char *child_last_key = child->keys + (child->key_num - 1) * file_header_.key_length;
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, child_last_key);
if (tmp <= 0) {
LOG_WARN("Child's last key is bigger than current key, child:%s, current:%s, file_id:%d",
child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
ret = validate_node(child);
if (ret == false) {
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
BPPageHandle next_child_handle;
PageNum next_child_page = node->rids[i + 1].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, next_child_page, &next_child_handle);
if (rc != RC::SUCCESS) {
LOG_WARN(
"Failed to validte node's child %d, file_id:%d, node:%s", i, file_id_, node->to_string(file_header_).c_str());
disk_buffer_pool_->unpin_page(&child_handle);
continue;
}
disk_buffer_pool_->get_data(&next_child_handle, &pdata);
IndexNode *next_child = get_index_node(pdata);
char *first_next_child_key = next_child->keys;
tmp = key_compare(file_header_.attr_type, file_header_.attr_length, cur_key, first_next_child_key);
if (next_child->is_leaf) {
if (tmp != 0) {
LOG_WARN("Next child's first key isn't equal current key, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
} else {
if (tmp >= 0) {
LOG_WARN("Next child's first key isn't equal current key, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
}
if (i == node->key_num - 1) {
ret = validate_node(next_child);
if (ret == false) {
LOG_WARN("Next child is invalid, next_child:%s, current:%s, file_id:%d",
next_child->to_string(file_header_).c_str(),
node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
}
if (child->is_leaf) {
if (child->next_brother != next_child_page || next_child->prev_brother != child_page) {
LOG_WARN("The child 's next brother or the next child's previous brother isn't correct, child:%s, "
"next_child:%s, file_id:%d",
child->to_string(file_header_).c_str(),
next_child->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
return false;
}
}
disk_buffer_pool_->unpin_page(&next_child_handle);
disk_buffer_pool_->unpin_page(&child_handle);
}
return rc;
return true;
}
RC BplusTreeHandler::insert_into_leaf_after_split(PageNum leaf_page, const char *pkey, const RID *rid) {
bool BplusTreeHandler::validate_leaf_link()
{
BPPageHandle first_leaf_handle;
IndexNode *first_leaf = root_node_;
PageNum first_page;
RC rc;
BPPageHandle page_handle1,page_handle2;
IndexNode *leaf,*new_node;
PageNum new_page,parent_page;
RID *temp_pointers,tmprid;
char *temp_keys,*new_key;
char *pdata;
int insert_pos,split,i,j,tmp;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle1);
if(rc!=SUCCESS){
return rc;
while (first_leaf->is_leaf == false) {
if (first_leaf_handle.open) {
disk_buffer_pool_->unpin_page(&first_leaf_handle);
}
rc = disk_buffer_pool_->get_data(&page_handle1, &pdata);
if(rc!=SUCCESS){
return rc;
first_page = first_leaf->rids[0].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, first_page, &first_leaf_handle);
if (rc != RC::SUCCESS) {
return false;
}
leaf = get_index_node(pdata);
//add a new node
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle2);
if(rc!=SUCCESS){
return rc;
char *pdata;
disk_buffer_pool_->get_data(&first_leaf_handle, &pdata);
first_leaf = get_index_node(pdata);
}
rc = disk_buffer_pool_->get_data(&page_handle2, &pdata);
if(rc!=SUCCESS){
return rc;
if (first_leaf_handle.open == false) {
// only root node
if (first_leaf->prev_brother != -1 || first_leaf->next_brother != -1) {
LOG_WARN("root node is the only node, but either root node's previous brother or next brother is wrong, root:%s, "
"file_id:%s",
first_leaf->to_string(file_header_).c_str(),
file_id_);
return false;
}
rc = disk_buffer_pool_->get_page_num(&page_handle2, &new_page);
if(rc!=SUCCESS){
return rc;
return true;
}
new_node = get_index_node(pdata);
new_node->key_num = 0;
new_node->is_leaf = 1;
new_node->parent = leaf->parent;
parent_page = leaf->parent;
// print();
temp_keys = (char *)malloc(file_header_.key_length*file_header_.order);
if(temp_keys == nullptr){
LOG_ERROR("Failed to alloc memory for temp key. size=%d", file_header_.key_length*file_header_.order);
return RC::NOMEM;
if (first_leaf->prev_brother != -1 || first_leaf->next_brother == -1) {
LOG_WARN("First leaf is invalid, node:%s, file_id:%d", first_leaf->to_string(file_header_).c_str(), file_id_);
disk_buffer_pool_->unpin_page(&first_leaf_handle);
return false;
}
temp_pointers = (RID *)malloc((file_header_.order+1)*sizeof(RID));
if(temp_pointers == nullptr){
LOG_ERROR("Failed to alloc memory for temp pointers. size=%ld", (file_header_.order + 1)* sizeof(RID));
free(temp_keys);
return RC::NOMEM;
}
BPPageHandle last_leaf_handle;
IndexNode *last_leaf = root_node_;
PageNum last_page = -1;
for(insert_pos=0;insert_pos<leaf->key_num;insert_pos++){
tmp=CmpKey(file_header_.attr_type, file_header_.attr_length, pkey, leaf->keys+insert_pos*file_header_.key_length);
if(tmp<0)
break;
while (last_leaf->is_leaf == false) {
if (last_leaf_handle.open) {
disk_buffer_pool_->unpin_page(&last_leaf_handle);
}
for(i=0,j=0;i<leaf->key_num;i++,j++){
if(j==insert_pos)
j++;
memcpy(temp_keys+j*file_header_.key_length,leaf->keys+i*file_header_.key_length,file_header_.key_length);
memcpy(temp_pointers+j,leaf->rids+i,sizeof(RID));
last_page = last_leaf->rids[last_leaf->key_num].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, last_page, &last_leaf_handle);
if (rc != RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&first_leaf_handle);
return false;
}
memcpy(temp_keys+insert_pos*file_header_.key_length,pkey,file_header_.key_length);
memcpy(temp_pointers+insert_pos,rid,sizeof(RID));
split=file_header_.order/2;
char *pdata;
disk_buffer_pool_->get_data(&last_leaf_handle, &pdata);
last_leaf = get_index_node(pdata);
}
for(i=0;i<split;i++){
memcpy(leaf->keys+i*file_header_.key_length,temp_keys+i*file_header_.key_length,file_header_.key_length);
memcpy(leaf->rids+i,temp_pointers+i,sizeof(RID));
if (last_page == -1) {
LOG_WARN(
"The last leaf is invalid, last leaf is root:%s, file_id:%d", last_leaf->to_string(file_header_).c_str(), file_id_);
disk_buffer_pool_->unpin_page(&first_leaf_handle);
return false;
}
leaf->key_num=split;
for(i=split,j=0;i<file_header_.order;i++,j++){
memcpy(new_node->keys+j*file_header_.key_length,temp_keys+i*file_header_.key_length,file_header_.key_length);
memcpy(new_node->rids+j,temp_pointers+i,sizeof(RID));
new_node->key_num++;
if (last_leaf->next_brother != -1 || last_leaf->prev_brother == -1) {
LOG_WARN(
"The last leaf is invalid, last leaf:%s, file_id:%d", last_leaf->to_string(file_header_).c_str(), file_id_);
disk_buffer_pool_->unpin_page(&first_leaf_handle);
disk_buffer_pool_->unpin_page(&last_leaf_handle);
return false;
}
free(temp_pointers);
free(temp_keys);
std::set<PageNum> leaf_pages;
leaf_pages.insert(first_page);
memcpy(new_node->rids+file_header_.order-1,leaf->rids+file_header_.order-1,sizeof(RID));
tmprid.page_num = new_page;
tmprid.slot_num = -1;
memcpy(leaf->rids+file_header_.order-1,&tmprid,sizeof(RID));
BPPageHandle current_handle;
IndexNode *cur_node = first_leaf;
PageNum cur_page = first_page;
new_key=(char *)malloc(file_header_.key_length);
if(new_key == nullptr){
LOG_ERROR("Failed to alloc memory for new key. size=%d", file_header_.key_length);
return RC::NOMEM;
BPPageHandle next_handle;
IndexNode *next_node = nullptr;
PageNum next_page = cur_node->next_brother;
bool found = false;
bool ret = false;
while (next_page != -1) {
rc = disk_buffer_pool_->get_this_page(file_id_, next_page, &next_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to check leaf link ");
goto cleanup;
}
memcpy(new_key,new_node->keys,file_header_.key_length);
rc = disk_buffer_pool_->mark_dirty(&page_handle1);
if(rc!=SUCCESS){
free(new_key);
return rc;
char *pdata;
disk_buffer_pool_->get_data(&next_handle, &pdata);
next_node = get_index_node(pdata);
if (cur_node->next_brother != next_page || next_node->prev_brother != cur_page) {
LOG_WARN("The leaf 's next brother or the next leaf's previous brother isn't correct, child:%s, next_child:%s, "
"file_id:%d",
cur_node->to_string(file_header_).c_str(),
next_node->to_string(file_header_).c_str(),
file_id_);
disk_buffer_pool_->unpin_page(&next_handle);
goto cleanup;
}
if (next_page == last_page) {
found = true;
disk_buffer_pool_->unpin_page(&next_handle);
break;
}
rc = disk_buffer_pool_->unpin_page(&page_handle1);
if(rc!=SUCCESS){
free(new_key);
return rc;
if (leaf_pages.find(next_page) != leaf_pages.end()) {
LOG_WARN(
"Leaf links occur loop, current node:%s, file_id:%d", cur_node->to_string(file_header_).c_str(), file_id_);
disk_buffer_pool_->unpin_page(&next_handle);
goto cleanup;
} else {
leaf_pages.insert(next_page);
}
rc = disk_buffer_pool_->mark_dirty(&page_handle2);
if(rc!=SUCCESS){
free(new_key);
return rc;
if (current_handle.open) {
disk_buffer_pool_->unpin_page(&current_handle);
}
rc = disk_buffer_pool_->unpin_page(&page_handle2);
if(rc!=SUCCESS){
free(new_key);
return rc;
current_handle = next_handle;
cur_node = next_node;
cur_page = next_page;
next_page = cur_node->next_brother;
}
rc=insert_into_parent(parent_page,leaf_page,new_key,new_page); // 插入失败,应该回滚之前的叶子节点
if(rc!=SUCCESS){
free(new_key);
return rc;
if (found == true) {
ret = true;
}
free(new_key);
return SUCCESS;
}
RC BplusTreeHandler::insert_intern_node(PageNum parent_page,PageNum left_page,PageNum right_page,const char *pkey) {
int i,insert_pos;
BPPageHandle page_handle;
char *pdata;
IndexNode *node;
RID rid;
RC rc;
cleanup:
if (first_leaf_handle.open) {
disk_buffer_pool_->unpin_page(&first_leaf_handle);
}
rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &page_handle);
if(rc!=SUCCESS){
return rc;
if (last_leaf_handle.open) {
disk_buffer_pool_->unpin_page(&last_leaf_handle);
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
if (current_handle.open) {
disk_buffer_pool_->unpin_page(&current_handle);
}
node = get_index_node(pdata);
return ret;
}
insert_pos=0;
while((insert_pos<=node->key_num)&&(node->rids[insert_pos].page_num != left_page))
insert_pos++;
for(i=node->key_num;i>insert_pos;i--){
memcpy(node->rids+i+1,node->rids+i,sizeof(RID));
memcpy(node->keys+i*file_header_.key_length,node->keys+(i-1)*file_header_.key_length,file_header_.key_length);
}
rid.page_num = right_page;
rid.slot_num = BP_INVALID_PAGE_NUM; // change to invalid page num
memcpy(node->rids+insert_pos+1,&rid,sizeof(RID));
memcpy(node->keys+insert_pos*file_header_.key_length,pkey,file_header_.key_length);
node->key_num++;
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
bool BplusTreeHandler::validate_tree()
{
IndexNode *node = root_node_;
if (validate_node(node) == false || validate_leaf_link() == false) {
LOG_WARN("Current B+ Tree is invalid");
print_tree();
return false;
}
return SUCCESS;
return true;
}
RC BplusTreeHandler::insert_intern_node_after_split(PageNum inter_page,PageNum left_page,PageNum right_page,const char *pkey) {
RC rc;
BPPageHandle page_handle1,page_handle2,child_page_handle;
IndexNode *inter_node,*new_node,*child_node;
PageNum new_page,child_page,parent_page;
RID *temp_pointers,tmprid;
char *temp_keys,*new_key;
RC BplusTreeHandler::find_leaf(const char *pkey, PageNum *leaf_page)
{
BPPageHandle page_handle;
IndexNode *node = root_node_;
while (false == node->is_leaf) {
char *pdata;
int insert_pos,i,j,split;
rc = disk_buffer_pool_->get_this_page(file_id_, inter_page, &page_handle1);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle1, &pdata);
if(rc!=SUCCESS){
return rc;
int i;
for (i = 0; i < node->key_num; i++) {
int tmp =
key_compare(file_header_.attr_type, file_header_.attr_length, pkey, node->keys + i * file_header_.key_length);
if (tmp < 0)
break;
}
inter_node = get_index_node(pdata);
if (page_handle.open == true) {
disk_buffer_pool_->unpin_page(&page_handle);
}
//add a new node
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle2);
if(rc!=SUCCESS){
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[i].page_num, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, node->rids[i].page_num);
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle2, &pdata);
if(rc!=SUCCESS){
return rc;
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
}
rc = disk_buffer_pool_->get_page_num(&page_handle2, &new_page);
if(rc!=SUCCESS){
return rc;
if (page_handle.open == false) {
*leaf_page = file_header_.root_page;
return RC::SUCCESS;
}
new_node = get_index_node(pdata);
new_node->key_num=0;
new_node->is_leaf=false;
new_node->parent=inter_node->parent;
disk_buffer_pool_->get_page_num(&page_handle, leaf_page);
disk_buffer_pool_->unpin_page(&page_handle);
parent_page=inter_node->parent;
return RC::SUCCESS;
}
// print();
RC BplusTreeHandler::insert_entry_into_node(IndexNode *node, const char *pkey, const RID *rid, PageNum left_page)
{
int insert_pos = 0, tmp;
temp_keys=(char *)malloc(file_header_.key_length*file_header_.order);
if(temp_keys == nullptr){
LOG_ERROR("Failed to alloc memory for temp keys. size=%d",
file_header_.key_length * file_header_.order);
return RC::NOMEM;
for (; insert_pos < node->key_num; insert_pos++) {
tmp = key_compare(
file_header_.attr_type, file_header_.attr_length, pkey, node->keys + insert_pos * file_header_.key_length);
if (tmp == 0) {
LOG_TRACE("Insert into %d occur duplicated key, rid:%s.", file_id_, node->rids[insert_pos].to_string().c_str());
return RC::RECORD_DUPLICATE_KEY;
}
temp_pointers = (RID *)malloc((file_header_.order + 1) * sizeof(RID));
if(temp_pointers == nullptr){
LOG_ERROR("Failed to alloc memory for temp pointers. size=%ld",
(file_header_.order + 1) * sizeof(RID));
free(temp_keys);
return RC::NOMEM;
if (tmp < 0)
break;
}
new_key=(char *)malloc(file_header_.key_length);
if(new_key==nullptr){
LOG_ERROR("Failed to alloc memory for new key. size=%d", file_header_.key_length);
free(temp_keys);
free(temp_pointers);
return RC::NOMEM;
}
char *from = node->keys + insert_pos * file_header_.key_length;
char *to = from + file_header_.key_length;
int len = (node->key_num - insert_pos) * file_header_.key_length;
memmove(to, from, len);
memcpy(node->keys + insert_pos * file_header_.key_length, pkey, file_header_.key_length);
insert_pos=0;
while((insert_pos<=inter_node->key_num)&&(inter_node->rids[insert_pos].page_num != left_page))
insert_pos++;
for(i=0,j=0;i<inter_node->key_num+1;i++,j++){
if(j==insert_pos+1)
j++;
memcpy(temp_pointers+j,inter_node->rids+i,sizeof(RID));
}
for(i=0,j=0;i<inter_node->key_num;i++,j++){
if(j==insert_pos)
j++;
memcpy(temp_keys+j*file_header_.key_length,inter_node->keys+i*file_header_.key_length,file_header_.key_length);
}
tmprid.page_num = right_page;
tmprid.slot_num = -1;
memcpy(temp_keys+insert_pos*file_header_.key_length,pkey,file_header_.key_length);
memcpy(temp_pointers+insert_pos+1,&tmprid,sizeof(RID));
if (node->is_leaf) {
len = (node->key_num - insert_pos) * sizeof(RID);
memmove(node->rids + insert_pos + 1, node->rids + insert_pos, len);
memcpy(node->rids + insert_pos, rid, sizeof(RID));
split=(file_header_.order+1)/2;
change_leaf_parent_key_insert(node, insert_pos, left_page);
} else {
for(i=0;i<split-1;i++){
memcpy(inter_node->keys+i*file_header_.key_length,temp_keys+i*file_header_.key_length,file_header_.key_length);
memcpy(inter_node->rids+i,temp_pointers+i,sizeof(RID));
len = (node->key_num - insert_pos) * sizeof(RID);
memmove(node->rids + insert_pos + 2, node->rids + insert_pos + 1, len);
memcpy(node->rids + insert_pos + 1, rid, sizeof(RID));
}
inter_node->key_num=split-1;
memcpy(inter_node->rids+i,temp_pointers+i,sizeof(RID));
memcpy(new_key,temp_keys+i*file_header_.key_length,file_header_.key_length);
for(++i,j=0;i<file_header_.order;i++,j++){
memcpy(new_node->keys+j*file_header_.key_length,temp_keys+i*file_header_.key_length,file_header_.key_length);
memcpy(new_node->rids+j,temp_pointers+i,sizeof(RID));
new_node->key_num++;
}
memcpy(new_node->rids+j,temp_pointers+i,sizeof(RID));
node->key_num++; //叶子结点增加一条记录
return RC::SUCCESS;
}
free(temp_keys);
free(temp_pointers);
RC BplusTreeHandler::split_leaf(BPPageHandle &leaf_page_handle)
{
PageNum leaf_page;
disk_buffer_pool_->get_page_num(&leaf_page_handle, &leaf_page);
for(i=0;i<=new_node->key_num;i++){
child_page=new_node->rids[i].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, child_page, &child_page_handle);
if(rc!=SUCCESS){
free(new_key);
char *pdata;
RC rc = disk_buffer_pool_->get_data(&leaf_page_handle, &pdata);
if (rc != RC::SUCCESS) {
return rc;
}
rc = disk_buffer_pool_->get_data(&child_page_handle, &pdata);
if(rc!=SUCCESS){
free(new_key);
return rc;
IndexNode *old_node = get_index_node(pdata);
char *new_parent_key = (char *)mem_pool_item_->alloc();
if (new_parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for new key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
child_node=(IndexNode *)(pdata+sizeof(IndexFileHeader));
child_node->parent=new_page;
rc = disk_buffer_pool_->mark_dirty(&child_page_handle);
if(rc!=SUCCESS){
free(new_key);
// add a new node
BPPageHandle page_handle2;
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle2);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to split index page due to failed to allocate page, file_id:%d ", file_id_);
return rc;
}
PageNum new_page;
disk_buffer_pool_->get_page_num(&page_handle2, &new_page);
disk_buffer_pool_->get_data(&page_handle2, &pdata);
IndexNode *new_node = get_index_node(pdata);
new_node->init_empty(file_header_);
new_node->parent = old_node->parent;
new_node->prev_brother = leaf_page;
new_node->next_brother = old_node->next_brother;
old_node->next_brother = new_page;
// begin to move data from leaf_node to new_node
split_node(old_node, new_node, leaf_page, new_page, new_parent_key);
disk_buffer_pool_->mark_dirty(&leaf_page_handle);
disk_buffer_pool_->mark_dirty(&page_handle2);
PageNum parent_page = old_node->parent;
rc = insert_into_parent(parent_page, leaf_page_handle, new_parent_key, page_handle2);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert into parent of index %d", file_id_);
// restore status before insert into parent
// merge_nodes function will move left node into right node
merge_nodes(old_node, new_node, new_page, new_parent_key);
copy_node(old_node, new_node);
change_insert_leaf_link(old_node, new_node, leaf_page);
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&page_handle2);
disk_buffer_pool_->dispose_page(file_id_, new_page);
return rc;
}
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&page_handle2);
return RC::SUCCESS;
}
RC BplusTreeHandler::insert_intern_node(
BPPageHandle &parent_page_handle, BPPageHandle &left_page_handle, BPPageHandle &right_page_handle, const char *pkey)
{
PageNum left_page;
disk_buffer_pool_->get_page_num(&left_page_handle, &left_page);
PageNum right_page;
disk_buffer_pool_->get_page_num(&right_page_handle, &right_page);
char *pdata;
RC rc = disk_buffer_pool_->get_data(&parent_page_handle, &pdata);
if (rc != RC::SUCCESS) {
return rc;
}
rc = disk_buffer_pool_->unpin_page(&child_page_handle);
if(rc!=SUCCESS){
free(new_key);
IndexNode *node = get_index_node(pdata);
RID rid;
rid.page_num = right_page;
rid.slot_num = BP_INVALID_PAGE_NUM; // change to invalid page num
insert_entry_into_node(node, pkey, &rid, right_page);
disk_buffer_pool_->mark_dirty(&parent_page_handle);
return RC::SUCCESS;
}
RC BplusTreeHandler::split_intern_node(BPPageHandle &inter_page_handle, const char *pkey)
{
PageNum inter_page_num;
disk_buffer_pool_->get_page_num(&inter_page_handle, &inter_page_num);
char *pdata;
RC rc = disk_buffer_pool_->get_data(&inter_page_handle, &pdata);
if (rc != RC::SUCCESS) {
return rc;
}
IndexNode *inter_node = get_index_node(pdata);
char *new_parent_key = (char *)mem_pool_item_->alloc();
if (new_parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for new key when split intern node index %d", file_id_);
return RC::NOMEM;
}
rc = disk_buffer_pool_->mark_dirty(&page_handle1);
if(rc!=SUCCESS){
free(new_key);
// add a new node
BPPageHandle new_page_handle;
rc = disk_buffer_pool_->allocate_page(file_id_, &new_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Faild to alloc new page when split inter node of index, file_id:%d", file_id_);
mem_pool_item_->free(new_parent_key);
return rc;
}
rc = disk_buffer_pool_->unpin_page(&page_handle1);
if(rc!=SUCCESS){
free(new_key);
disk_buffer_pool_->get_data(&new_page_handle, &pdata);
PageNum new_page;
disk_buffer_pool_->get_page_num(&new_page_handle, &new_page);
IndexNode *new_node = get_index_node(pdata);
new_node->init_empty(file_header_);
new_node->is_leaf = false;
new_node->parent = inter_node->parent;
split_node(inter_node, new_node, inter_page_num, new_page, new_parent_key);
disk_buffer_pool_->mark_dirty(&inter_page_handle);
disk_buffer_pool_->mark_dirty(&new_page_handle);
// print();
PageNum parent_page = inter_node->parent;
rc = insert_into_parent(parent_page, inter_page_handle, new_parent_key, new_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert key to parents, file_id:%d", file_id_);
merge_nodes(inter_node, new_node, new_page, new_parent_key);
copy_node(inter_node, new_node);
change_children_parent(inter_node->rids, inter_node->key_num + 1, inter_page_num);
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&new_page_handle);
disk_buffer_pool_->dispose_page(file_id_, new_page);
return rc;
}
rc = disk_buffer_pool_->mark_dirty(&page_handle2);
if(rc!=SUCCESS){
free(new_key);
mem_pool_item_->free(new_parent_key);
disk_buffer_pool_->unpin_page(&new_page_handle);
return rc;
}
RC BplusTreeHandler::insert_into_parent(
PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle)
{
if (parent_page == -1) {
return insert_into_new_root(left_page_handle, pkey, right_page_handle);
}
rc = disk_buffer_pool_->unpin_page(&page_handle2);
if(rc!=SUCCESS){
free(new_key);
BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get parent page file_id:%d, page:%d", file_id_, parent_page);
return rc;
}
// print();
rc=insert_into_parent(parent_page,inter_page,new_key,new_page);
char *pdata;
disk_buffer_pool_->get_data(&page_handle, &pdata);
IndexNode *node = get_index_node(pdata);
// print();
if(rc!=SUCCESS){
free(new_key);
rc = insert_intern_node(page_handle, left_page_handle, right_page_handle, pkey);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert intern node of index :%d", file_id_);
return rc;
}
free(new_key);
return SUCCESS;
if (node->key_num > file_header_.order) {
rc = split_intern_node(page_handle, pkey);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to split intern node of index %d", file_id_);
int delete_index;
delete_entry_from_node(node, pkey, delete_index);
}
}
disk_buffer_pool_->unpin_page(&page_handle);
return rc;
}
RC BplusTreeHandler::insert_into_parent(PageNum parent_page, PageNum left_page, const char *pkey,PageNum right_page) {
RC rc;
BPPageHandle page_handle;
IndexNode *node;
void BplusTreeHandler::swith_root(BPPageHandle &new_root_page_handle, IndexNode *root, PageNum root_page)
{
//@@@ TODO here should add lock
disk_buffer_pool_->unpin_page(&root_page_handle_);
root_page_handle_ = new_root_page_handle;
root_node_ = root;
file_header_.root_page = root_page;
header_dirty_ = true;
}
/**
* Create one new root node
* @param left_page_handle
* @param pkey
* @param right_page_handle
* @return
*/
RC BplusTreeHandler::insert_into_new_root(
BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle)
{
BPPageHandle new_root_page_handle;
RC rc = disk_buffer_pool_->allocate_page(file_id_, &new_root_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to alloc new page for the new root node of index, file_id:%d", file_id_);
return rc;
}
PageNum root_page;
disk_buffer_pool_->get_page_num(&new_root_page_handle, &root_page);
// modify the left node
PageNum left_page;
char *pdata;
if(parent_page==-1){
return insert_into_new_root(left_page,pkey,right_page);
disk_buffer_pool_->get_page_num(&left_page_handle, &left_page);
disk_buffer_pool_->get_data(&left_page_handle, &pdata);
IndexNode *left = get_index_node(pdata);
left->parent = root_page;
disk_buffer_pool_->mark_dirty(&left_page_handle);
// modify the right node
PageNum right_page;
disk_buffer_pool_->get_page_num(&right_page_handle, &right_page);
disk_buffer_pool_->get_data(&right_page_handle, &pdata);
IndexNode *right = get_index_node(pdata);
right->parent = root_page;
disk_buffer_pool_->mark_dirty(&right_page_handle);
// handle the root node
disk_buffer_pool_->get_data(&new_root_page_handle, &pdata);
IndexNode *root = get_index_node(pdata);
root->init_empty(file_header_);
root->is_leaf = false;
root->key_num = 1;
memcpy(root->keys, pkey, file_header_.key_length);
RID rid;
rid.page_num = left_page;
rid.slot_num = EMPTY_RID_SLOT_NUM;
memcpy(root->rids, &rid, sizeof(RID));
rid.page_num = right_page;
rid.slot_num = EMPTY_RID_SLOT_NUM;
memcpy(root->rids + root->key_num, &rid, sizeof(RID));
disk_buffer_pool_->mark_dirty(&new_root_page_handle);
swith_root(new_root_page_handle, root, root_page);
return RC::SUCCESS;
}
RC BplusTreeHandler::insert_entry(const char *pkey, const RID *rid)
{
if (file_id_ < 0) {
LOG_WARN("Index isn't ready!");
return RC::RECORD_CLOSED;
}
rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &page_handle);
if(rc!=SUCCESS){
return rc;
if (pkey == nullptr || rid == nullptr) {
LOG_WARN("Invalid arguments, key is empty or rid is empty");
return RC::INVALID_ARGUMENT;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
char *key = (char *)mem_pool_item_->alloc();
if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. file_id:%d", file_id_);
return RC::NOMEM;
}
memcpy(key, pkey, file_header_.attr_length);
memcpy(key + file_header_.attr_length, rid, sizeof(*rid));
PageNum leaf_page;
RC rc = find_leaf(key, &leaf_page);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to find leaf file_id:%d, %s", file_id_, rid->to_string().c_str());
mem_pool_item_->free(key);
return rc;
}
node=(IndexNode *)(pdata+sizeof(IndexFileHeader));
if(node->key_num<file_header_.order-1){
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
BPPageHandle page_handle;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load leaf file_id:%d, page_num:%d", file_id_, leaf_page);
mem_pool_item_->free(key);
return rc;
}
return insert_intern_node(parent_page,left_page,right_page,pkey);
char *pdata;
disk_buffer_pool_->get_data(&page_handle, &pdata);
IndexNode *leaf = get_index_node(pdata);
rc = insert_entry_into_node(leaf, key, rid, leaf_page);
if (rc != RC::SUCCESS) {
LOG_TRACE("Failed to insert into leaf of index %d, rid:%s", file_id_, rid->to_string().c_str());
disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return rc;
}
else{
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
disk_buffer_pool_->mark_dirty(&page_handle);
if (leaf->key_num > file_header_.order) {
rc = split_leaf(page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to insert index of %d, failed to split for rid:%s", file_id_, rid->to_string().c_str());
int delete_index = 0;
delete_entry_from_node(leaf, key, delete_index);
disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return rc;
}
return insert_intern_node_after_split(parent_page,left_page,right_page,pkey);
}
disk_buffer_pool_->unpin_page(&page_handle);
mem_pool_item_->free(key);
return RC::SUCCESS;
}
void BplusTreeHandler::get_entry_from_leaf(
IndexNode *node, const char *pkey, std::list<RID> &rids, bool &continue_check)
{
for (int i = node->key_num - 1; i >= 0; i--) {
int tmp = attribute_comp(
pkey, node->keys + (i * file_header_.key_length), file_header_.attr_type, file_header_.attr_length);
if (tmp < 0) {
if (continue_check == true) {
LOG_WARN("Something is wrong, the sequence is wrong.");
print_tree();
continue_check = false;
break;
} else {
continue;
}
} else if (tmp == 0) {
rids.push_back(node->rids[i]);
continue_check = true;
} else {
continue_check = false;
break;
}
}
}
RC BplusTreeHandler::insert_into_new_root(PageNum left_page, const char *pkey, PageNum right_page) {
RC BplusTreeHandler::get_entry(const char *pkey, std::list<RID> &rids)
{
if (file_id_ < 0) {
LOG_WARN("Index isn't ready!");
return RC::RECORD_CLOSED;
}
char *key = (char *)mem_pool_item_->alloc();
if (key == nullptr) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(key, pkey, file_header_.attr_length);
RC rc;
BPPageHandle page_handle;
IndexNode *root,*left,*right;
PageNum root_page;
RID rid;
char *pdata;
rc = disk_buffer_pool_->allocate_page(file_id_, &page_handle);
if(rc!=SUCCESS){
return rc;
IndexNode *node = root_node_;
while (false == node->is_leaf) {
int i;
for (i = 0; i < node->key_num; i++) {
int tmp = attribute_comp(
pkey, node->keys + i * file_header_.key_length, file_header_.attr_type, file_header_.attr_length);
if (tmp < 0)
break;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
if (page_handle.open == true) {
disk_buffer_pool_->unpin_page(&page_handle);
}
rc = disk_buffer_pool_->get_page_num(&page_handle, &root_page);
if(rc!=SUCCESS){
rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[i].page_num, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page file_id:%d, page_num:%d", file_id_, node->rids[i].page_num);
return rc;
}
disk_buffer_pool_->get_data(&page_handle, &pdata);
root = get_index_node(pdata);
root->is_leaf=false;
root->key_num=1;
root->parent=-1;
memcpy(root->keys,pkey,file_header_.key_length);
rid.page_num = left_page;
rid.slot_num = -1;
memcpy(root->rids,&rid,sizeof(RID));
rid.page_num = right_page;
rid.slot_num = -1;
memcpy(root->rids+1,&rid,sizeof(RID));
node = get_index_node(pdata);
}
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
bool continue_check = false;
get_entry_from_leaf(node, key, rids, continue_check);
while (continue_check == true) {
PageNum prev_brother = node->prev_brother;
if (prev_brother == EMPTY_RID_PAGE_NUM) {
break;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
if (page_handle.open) {
disk_buffer_pool_->unpin_page(&page_handle);
}
rc = disk_buffer_pool_->get_this_page(file_id_, left_page, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
rc = disk_buffer_pool_->get_this_page(file_id_, prev_brother, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Skip load the previous page, file_id:%d", file_id_);
break;
}
left=(IndexNode *)(pdata+sizeof(IndexFileHeader));
left->parent=root_page;
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
get_entry_from_leaf(node, key, rids, continue_check);
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
if (page_handle.open) {
disk_buffer_pool_->unpin_page(&page_handle);
}
mem_pool_item_->free(key);
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_this_page(file_id_, right_page, &page_handle);
if(rc!=SUCCESS){
return rc;
void BplusTreeHandler::delete_entry_from_node(IndexNode *node, const int delete_index)
{
char *from = node->keys + (delete_index + 1) * file_header_.key_length;
char *to = from - file_header_.key_length;
int len = (node->key_num - delete_index - 1) * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = node->rids + (delete_index + 1);
RID *to_rid = from_rid - 1;
len = (node->key_num - delete_index - 1) * sizeof(RID);
if (node->is_leaf == false) {
len += sizeof(RID);
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
memmove(to_rid, from_rid, len);
node->key_num--;
}
RC BplusTreeHandler::get_parent_changed_index(
BPPageHandle &parent_handle, IndexNode *&parent, IndexNode *node, PageNum page_num, int &changed_index)
{
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->parent, &parent_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get pareent page, file_id:%d, parent_page:%d",
file_id_,
node->parent);
return rc;
}
right=(IndexNode *)(pdata+sizeof(IndexFileHeader));
right->parent=root_page;
char *pdata;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
while (changed_index <= parent->key_num) {
if ((parent->rids[changed_index].page_num) == page_num)
break;
changed_index++;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
if (changed_index == parent->key_num + 1) {
LOG_WARN("Something is wrong, failed to find the target page %d in parent, node:%s file_id:%d",
page_num,
node->to_string(file_header_).c_str(),
file_id_);
print_tree();
return RC::RECORD_CLOSED;
}
file_header_.root_page=root_page;
header_dirty_ = true;
return SUCCESS;
return RC::SUCCESS;
}
RC BplusTreeHandler::insert_entry(const char *pkey, const RID *rid) {
RC rc;
PageNum leaf_page;
BPPageHandle page_handle;
char *pdata,*key;
IndexNode *leaf;
if(nullptr == disk_buffer_pool_){
return RC::RECORD_CLOSED;
RC BplusTreeHandler::change_leaf_parent_key_insert(IndexNode *node, int changed_indx, PageNum page_num)
{
if (changed_indx != 0) {
return RC::SUCCESS;
}
key=(char *)malloc(file_header_.key_length);
if(key == nullptr){
LOG_ERROR("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
if (node->is_leaf == false) {
return RC::SUCCESS;
}
memcpy(key,pkey,file_header_.attr_length);
memcpy(key + file_header_.attr_length, rid, sizeof(*rid));
rc= find_leaf(key, &leaf_page);
if(rc!=SUCCESS){
free(key);
return rc;
if (node->parent == -1) {
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle);
if(rc!=SUCCESS){
free(key);
return rc;
if (node->key_num == 0) {
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
free(key);
return rc;
if (node->prev_brother == -1) {
return RC::SUCCESS;
}
leaf=(IndexNode *)(pdata+sizeof(IndexFileHeader));
if(leaf->key_num<file_header_.order-1){
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
free(key);
int parent_changed_index = 0;
BPPageHandle parent_handle;
IndexNode *parent = nullptr;
RC rc = get_parent_changed_index(parent_handle, parent, node, page_num, parent_changed_index);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get parent's delete index, file_id:%d, child's page_num:%d", file_id_, page_num);
if (parent_handle.open) {
disk_buffer_pool_->unpin_page(&parent_handle);
return rc;
}
rc=insert_into_leaf(leaf_page,key,rid);
if(rc!=SUCCESS){
free(key);
return rc;
}
free(key);
return SUCCESS;
if (parent_changed_index > 0) {
memcpy(parent->keys + (parent_changed_index - 1) * file_header_.key_length, node->keys, file_header_.key_length);
}
else{
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
free(key);
return rc;
disk_buffer_pool_->unpin_page(&parent_handle);
return RC::SUCCESS;
}
RC BplusTreeHandler::change_leaf_parent_key_delete(IndexNode *leaf, int delete_indx, const char *old_first_key)
{
if (delete_indx != 0) {
return RC::SUCCESS;
}
// print();
if (leaf->is_leaf == false) {
return RC::SUCCESS;
}
rc=insert_into_leaf_after_split(leaf_page,key,rid);
free(key);
return SUCCESS;
if (leaf->parent == -1) {
return RC::SUCCESS;
}
}
RC BplusTreeHandler::get_entry(const char *pkey,RID *rid) {
RC rc;
PageNum leaf_page;
BPPageHandle page_handle;
int i;
char *pdata,*key;
IndexNode *leaf;
if (leaf->prev_brother == -1) {
return RC::SUCCESS;
}
key=(char *)malloc(file_header_.key_length);
if(key == nullptr){
LOG_ERROR("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
if (leaf->key_num == 0) {
return RC::SUCCESS;
}
memcpy(key,pkey,file_header_.attr_length);
memcpy(key+file_header_.attr_length,rid,sizeof(RID));
rc=find_leaf(key,&leaf_page);
if(rc!=SUCCESS){
free(key);
IndexNode *node = leaf;
bool found = false;
while (node->parent != -1) {
int index = 0;
BPPageHandle parent_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, node->parent, &parent_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get pareent page, file_id:%d, parent_page:%d",
file_id_,
node->parent);
return rc;
}
char *pdata;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
node = get_index_node(pdata);
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &page_handle);
if(rc!=SUCCESS){
free(key);
return rc;
int tmp = 0;
while (index < node->key_num) {
tmp = key_compare(file_header_.attr_type,
file_header_.attr_length,
old_first_key,
node->keys + index * file_header_.key_length);
if (tmp == 0) {
found = true;
memcpy(node->keys + index * file_header_.key_length, leaf->keys, file_header_.key_length);
break;
} else if (tmp > 0) {
index++;
continue;
} else {
break;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
free(key);
return rc;
}
leaf = get_index_node(pdata);
for(i=0;i<leaf->key_num;i++){
if(CmpKey(file_header_.attr_type, file_header_.attr_length,key,leaf->keys+(i*file_header_.key_length))==0){
memcpy(rid,leaf->rids+i,sizeof(RID));
free(key);
return SUCCESS;
disk_buffer_pool_->unpin_page(&parent_handle);
if (found == true) {
return RC::SUCCESS;
}
}
free(key);
if (found == false) {
LOG_INFO("The old fist key has been changed, leaf:%s", leaf->to_string(file_header_).c_str());
print_tree();
}
return RC::SUCCESS;
}
RC BplusTreeHandler::delete_entry_from_node(IndexNode *node, const char *pkey, int &node_delete_index)
{
int delete_index, tmp;
for (delete_index = 0; delete_index < node->key_num; delete_index++) {
tmp = key_compare(
file_header_.attr_type, file_header_.attr_length, pkey, node->keys + delete_index * file_header_.key_length);
if (tmp == 0) {
node_delete_index = delete_index;
break;
}
}
if (delete_index >= node->key_num) {
// LOG_WARN("Failed to delete index of %d", file_id_);
return RC::RECORD_INVALID_KEY;
}
delete_entry_from_node(node, delete_index);
// change parent's key
change_leaf_parent_key_delete(node, delete_index, pkey);
return RC::SUCCESS;
}
RC BplusTreeHandler::delete_entry_from_node(PageNum node_page,const char *pkey) {
BPPageHandle page_handle;
IndexNode *node;
char *pdata;
int delete_index,i,tmp;
RC rc;
RC BplusTreeHandler::change_insert_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page)
{
if (left->is_leaf == false) {
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_this_page(file_id_, node_page, &page_handle);
if(rc!=SUCCESS){
if (right->next_brother != -1) {
PageNum next_right_page = right->next_brother;
BPPageHandle next_right_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, next_right_page, &next_right_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to set link for leaf for node %s, file_id:%d", file_id_, right->to_string(file_header_).c_str());
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
char *pdata;
disk_buffer_pool_->get_data(&next_right_handle, &pdata);
IndexNode *next_right = get_index_node(pdata);
next_right->prev_brother = right_page;
disk_buffer_pool_->mark_dirty(&next_right_handle);
disk_buffer_pool_->unpin_page(&next_right_handle);
}
node = get_index_node(pdata);
return RC::SUCCESS;
}
for(delete_index=0;delete_index<node->key_num;delete_index++){
tmp=CmpKey(file_header_.attr_type, file_header_.attr_length, pkey, node->keys+delete_index*file_header_.key_length);
if(tmp==0)
break;
RC BplusTreeHandler::change_delete_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page)
{
if (left->is_leaf == false) {
return RC::SUCCESS;
}
if(delete_index>=node->key_num){
return RC::RECORD_INVALID_KEY;
right->prev_brother = left->prev_brother;
if (left->prev_brother != -1) {
PageNum prev_left_page = left->prev_brother;
BPPageHandle prev_left_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, prev_left_page, &prev_left_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to set link for leaf for node %s, file_id:%d", file_id_, right->to_string(file_header_).c_str());
return rc;
}
i=delete_index;
while(i<(node->key_num-1)){
memcpy(node->keys+i*file_header_.key_length,node->keys+(i+1)*file_header_.key_length,file_header_.key_length);
i++;
char *pdata;
disk_buffer_pool_->get_data(&prev_left_handle, &pdata);
IndexNode *prev_left = get_index_node(pdata);
prev_left->next_brother = right_page;
disk_buffer_pool_->mark_dirty(&prev_left_handle);
disk_buffer_pool_->unpin_page(&prev_left_handle);
}
if(node->is_leaf)
for(i=delete_index;i<(node->key_num-1);i++)
memcpy(node->rids+i,node->rids+i+1,sizeof(RID));
else
for(i=delete_index+1;i<node->key_num;i++)
memcpy(node->rids+i,node->rids+i+1,sizeof(RID));
node->key_num--;
return RC::SUCCESS;
}
rc = disk_buffer_pool_->mark_dirty(&page_handle);
if(rc!=SUCCESS){
return rc;
/**
* merge left node into right node.
* @param parent_handle
* @param left_handle
* @param right_handle
* @param delete_index
* @return
*/
RC BplusTreeHandler::coalesce_node(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle,
int delete_index, bool check_change_leaf_key, int node_delete_index, const char *pkey)
{
PageNum left_page, right_page, parent_page;
IndexNode *left, *right, *parent;
char *pdata, *parent_key;
RC rc;
disk_buffer_pool_->get_page_num(&left_handle, &left_page);
disk_buffer_pool_->get_data(&left_handle, &pdata);
left = get_index_node(pdata);
disk_buffer_pool_->get_page_num(&right_handle, &right_page);
disk_buffer_pool_->get_data(&right_handle, &pdata);
right = get_index_node(pdata);
parent_page = left->parent;
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
parent_key = (char *)mem_pool_item_->alloc();
if (parent_key == nullptr) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(parent_key, parent->keys + delete_index * file_header_.key_length, file_header_.key_length);
merge_nodes(left, right, right_page, parent_key);
disk_buffer_pool_->mark_dirty(&left_handle);
disk_buffer_pool_->mark_dirty(&right_handle);
change_delete_leaf_link(left, right, right_page);
if (check_change_leaf_key) {
change_leaf_parent_key_delete(right, node_delete_index, pkey);
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
rc = delete_entry_internal(parent_page, parent_key);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete internal entry of index ", file_id_);
// restore status
copy_node(left, right);
right->key_num = 0;
split_node(left, right, left_page, right_page, parent_key);
change_delete_leaf_link(left, right, left_page);
left->next_brother = right_page;
right->prev_brother = left_page;
mem_pool_item_->free(parent_key);
return rc;
}
return SUCCESS;
mem_pool_item_->free(parent_key);
return RC::SUCCESS;
}
RC BplusTreeHandler::coalesce_node(PageNum leaf_page,PageNum right_page)
void BplusTreeHandler::change_children_parent(RID *rids, int rid_len, PageNum new_parent_page)
{
BPPageHandle left_handle,right_handle,parent_handle,tmphandle;
IndexNode *left,*right,*parent,*node;
char *pdata,*tmp_key;
PageNum parent_page;
RC rc;
int i,j,k,start;
for (int i = 0; i < rid_len; i++) {
RID rid = rids[i];
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &left_handle);
if(rc!=SUCCESS){
return rc;
PageNum page_num = rid.page_num;
BPPageHandle child_page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &child_page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load child page %d of index %d when change child's parent.", file_id_, page_num);
continue;
}
rc = disk_buffer_pool_->get_data(&left_handle, &pdata);
if(rc!=SUCCESS){
return rc;
char *pdata;
disk_buffer_pool_->get_data(&child_page_handle, &pdata);
IndexNode *child_node = get_index_node(pdata);
child_node->parent = new_parent_page;
disk_buffer_pool_->mark_dirty(&child_page_handle);
disk_buffer_pool_->unpin_page(&child_page_handle);
}
}
left = get_index_node(pdata);
/**
* merge left node into right node;
*
* This function is contrary to split_node
*/
void BplusTreeHandler::merge_nodes(IndexNode *left_node, IndexNode *right_node, PageNum right_page, char *parent_key)
{
bool is_leaf = left_node->is_leaf;
int old_left_key_num = left_node->key_num;
int old_right_key_num = right_node->key_num;
int new_left_key_num = 0;
int new_right_key_num = old_left_key_num + old_right_key_num;
if (is_leaf == false) {
new_right_key_num++;
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
if (is_leaf) {
int delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = right_node->rids;
RID *to_rid = right_node->rids + delta;
len = old_right_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
from = left_node->keys;
to = right_node->keys;
len = old_left_key_num * file_header_.key_length;
memmove(to, from, len);
from_rid = left_node->rids;
to_rid = right_node->rids;
len = old_left_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
} else {
int delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = right_node->rids;
RID *to_rid = right_node->rids + delta;
len = (old_right_key_num + 1) * sizeof(RID);
memmove(to_rid, from_rid, len);
memcpy(right_node->keys + (delta - 1) * file_header_.key_length, parent_key, file_header_.key_length);
from = left_node->keys;
to = right_node->keys;
len = old_left_key_num * file_header_.key_length;
memmove(to, from, len);
from_rid = left_node->rids;
to_rid = right_node->rids;
len = (old_left_key_num + 1) * sizeof(RID);
memmove(to_rid, from_rid, len);
change_children_parent(to_rid, len / sizeof(RID), right_page);
}
}
/**
* split left node to two node
* This function is contrary to merge_node
*/
void BplusTreeHandler::split_node(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_parent_key)
{
bool is_leaf = left_node->is_leaf;
int old_left_key_num = left_node->key_num;
int old_right_key_num = right_node->key_num; // right_node->key_num should be zero
int total_key_num = left_node->key_num + right_node->key_num;
int mid, new_left_key_num, new_right_key_num;
/**
* if node is leaf, all key will be distributed both in left and right node
* if node is intern node, all keys except the middle key will be distributed both in the left and the right node
*/
if (is_leaf == true) {
new_left_key_num = total_key_num / 2;
mid = new_left_key_num;
new_right_key_num = total_key_num - mid;
} else {
new_left_key_num = (total_key_num - 1) / 2;
mid = new_left_key_num + 1;
new_right_key_num = (total_key_num - mid);
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
if (is_leaf) {
memcpy(new_parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length);
} else {
memmove(new_parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length);
}
char *from = left_node->keys + mid * file_header_.key_length;
char *to = right_node->keys;
int len = new_right_key_num * file_header_.key_length;
memmove(to, from, len);
RID *from_rid = left_node->rids + mid;
RID *to_rid = right_node->rids;
len = new_right_key_num * sizeof(RID);
memmove(to_rid, from_rid, len);
// handle the last rid
if (is_leaf == false) {
RID *changed_rids = to_rid;
int changed_rids_len = len;
PageNum changed_page = right_page;
if (old_right_key_num == 0) {
memmove(right_node->rids + new_right_key_num, left_node->rids + old_left_key_num, sizeof(RID));
changed_rids_len += sizeof(RID);
}
change_children_parent(changed_rids, changed_rids_len / sizeof(RID), changed_page);
} else {
change_insert_leaf_link(left_node, right_node, right_page);
}
return;
}
void BplusTreeHandler::copy_node(IndexNode *to, IndexNode *from)
{
memcpy(to->keys, from->keys, from->key_num * file_header_.key_length);
memcpy(to->rids, from->rids, (from->key_num + 1) * sizeof(RID));
memcpy(to, from, sizeof(IndexNode));
}
rc = disk_buffer_pool_->get_this_page(file_id_, right_page, &right_handle);
if(rc!=SUCCESS){
return rc;
}
void BplusTreeHandler::redistribute_nodes(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *parent_key)
{
bool is_leaf = left_node->is_leaf;
int old_left_key_num = left_node->key_num;
int old_right_key_num = right_node->key_num;
int total_key_num = left_node->key_num + right_node->key_num;
if (is_leaf == false) {
total_key_num++;
}
// mid represent the parent key's position
int mid, new_left_key_num, new_right_key_num;
/**
* if node is leaf, all key will be distributed both in left and right node
* if node is intern node, all keys except the middle key will be distributed both in the left and the right node
*/
if (is_leaf == true) {
new_left_key_num = total_key_num / 2;
mid = new_left_key_num;
new_right_key_num = total_key_num - mid;
} else {
new_left_key_num = (total_key_num - 1) / 2;
mid = new_left_key_num + 1;
new_right_key_num = (total_key_num - mid);
}
left_node->key_num = new_left_key_num;
right_node->key_num = new_right_key_num;
rc = disk_buffer_pool_->get_data(&right_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
RID *changed_rids = nullptr;
int changed_rids_len = 0;
PageNum changed_page = 0;
right = get_index_node(pdata);
int delta = old_left_key_num - new_left_key_num;
if (delta == 0) {
return;
} else if (delta > 0) {
// move kv from left to right
delta = new_right_key_num - old_right_key_num;
char *from = right_node->keys;
char *to = right_node->keys + delta * file_header_.key_length;
int len = old_right_key_num * file_header_.key_length;
memmove(to, from, len);
parent_page=left->parent;
rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &parent_handle);
if(rc!=SUCCESS){
return rc;
RID *from_rid = right_node->rids;
RID *to_rid = right_node->rids + delta;
len = old_right_key_num * sizeof(RID);
if (left_node->is_leaf == false) {
len += sizeof(RID);
}
memmove(to_rid, from_rid, len);
rc = disk_buffer_pool_->get_data(&parent_handle, &pdata);
if(rc!=SUCCESS){
return rc;
if (is_leaf == false) {
memcpy(left_node->keys + old_left_key_num * file_header_.key_length, parent_key, file_header_.key_length);
}
parent = get_index_node(pdata);
delta = old_left_key_num - new_left_key_num;
for(k=0;k<parent->key_num;k++)
if((parent->rids[k].page_num) == leaf_page)
break;
from = left_node->keys + mid * file_header_.key_length;
to = right_node->keys;
len = delta * file_header_.key_length;
memmove(to, from, len);
start=left->key_num;
if(left->is_leaf==false){
memcpy(left->keys+start*file_header_.key_length,parent->keys+k*file_header_.key_length,file_header_.key_length);
start++;
left->key_num++;
}
for(i=start,j=0;j<right->key_num;i++,j++){
memcpy(left->keys+i*file_header_.key_length,right->keys+j*file_header_.key_length,file_header_.key_length);
memcpy(left->rids+i,right->rids+j,sizeof(RID));
left->key_num++;
}
from_rid = left_node->rids + mid;
to_rid = right_node->rids;
len = delta * sizeof(RID);
memmove(to_rid, from_rid, len);
if(left->is_leaf)
memcpy(left->rids+file_header_.order-1,right->rids+file_header_.order-1,sizeof(RID));
else{
memcpy(left->rids+i,right->rids+j,sizeof(RID));
changed_rids = to_rid;
changed_rids_len = len;
changed_page = right_page;
for(i=start;i<=left->key_num;i++){
rc = disk_buffer_pool_->get_this_page(file_id_, left->rids[i].page_num, &tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&tmphandle, &pdata);
if(rc!=SUCCESS){
return rc;
if (is_leaf) {
memcpy(parent_key, right_node->keys, file_header_.key_length);
} else {
memmove(parent_key, left_node->keys + new_left_key_num * file_header_.key_length, file_header_.key_length);
}
node=(IndexNode *)(pdata+sizeof(IndexFileHeader));
node->parent=leaf_page;
rc = disk_buffer_pool_->mark_dirty(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
} else {
// move kv from right to left
if (is_leaf == false) {
memcpy(left_node->keys + old_left_key_num * file_header_.key_length, parent_key, file_header_.key_length);
}
int start_pos = old_left_key_num;
int len = (new_left_key_num - old_left_key_num);
if (is_leaf == false) {
start_pos++;
len--;
}
tmp_key=(char *)malloc(file_header_.key_length);
if(tmp_key== nullptr){
LOG_ERROR("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(tmp_key,parent->keys+k*file_header_.key_length,file_header_.key_length);
char *from = right_node->keys;
char *to = left_node->keys + start_pos * file_header_.key_length;
memmove(to, from, len * file_header_.key_length);
rc = disk_buffer_pool_->mark_dirty(&left_handle);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
}
rc = disk_buffer_pool_->unpin_page(&left_handle);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
RID *from_rid = right_node->rids;
RID *to_rid = left_node->rids + start_pos;
memmove(to_rid, from_rid, len * sizeof(RID));
changed_rids = to_rid;
changed_rids_len = (new_left_key_num - old_left_key_num) * sizeof(RID);
changed_page = left_page;
if (is_leaf == false) {
memcpy(parent_key, right_node->keys + len * file_header_.key_length, file_header_.key_length);
memcpy(left_node->rids + new_left_key_num, right_node->rids + len, sizeof(RID));
} else {
memcpy(parent_key, right_node->keys + len * file_header_.key_length, file_header_.key_length);
}
rc = disk_buffer_pool_->unpin_page(&right_handle);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
delta = old_right_key_num - new_right_key_num;
from = right_node->keys + delta * file_header_.key_length;
to = right_node->keys;
len = new_right_key_num * file_header_.key_length;
memmove(to, from, len);
from_rid = right_node->rids + delta;
to_rid = right_node->rids;
len = new_right_key_num * sizeof(RID);
if (left_node->is_leaf == false) {
len += sizeof(RID);
}
rc = disk_buffer_pool_->dispose_page(file_id_, right_page);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
memmove(to_rid, from_rid, len);
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
// handle the last rid
if (left_node->is_leaf == false) {
change_children_parent(changed_rids, changed_rids_len / sizeof(RID), changed_page);
}
rc= delete_entry_internal(parent_page,tmp_key);
if(rc!=SUCCESS){
free(tmp_key);
return rc;
}
free(tmp_key);
return SUCCESS;
return;
}
RC BplusTreeHandler::redistribute_nodes(PageNum leaf_page,PageNum right_page)
RC BplusTreeHandler::redistribute_nodes(
BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle)
{
BPPageHandle left_handle,right_handle,parent_handle,tmphandle;
IndexNode *left,*right,*parent,*node;
char *pdata;
PageNum parent_page;
RC rc;
int min_key,i,k;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &left_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&left_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
PageNum left_page, right_page;
IndexNode *left, *right, *parent;
char *pdata;
disk_buffer_pool_->get_page_num(&left_handle, &left_page);
disk_buffer_pool_->get_data(&left_handle, &pdata);
left = get_index_node(pdata);
rc = disk_buffer_pool_->get_this_page(file_id_, right_page, &right_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&right_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
disk_buffer_pool_->get_page_num(&right_handle, &right_page);
disk_buffer_pool_->get_data(&right_handle, &pdata);
right = get_index_node(pdata);
parent_page=left->parent;
rc = disk_buffer_pool_->get_this_page(file_id_, parent_page, &parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&parent_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
disk_buffer_pool_->get_data(&parent_handle, &pdata);
parent = get_index_node(pdata);
for(k=0;k<parent->key_num;k++)
if(parent->rids[k].page_num == leaf_page)
break;
if(left->is_leaf){
min_key=file_header_.order/2;
if(left->key_num<min_key){
memcpy(left->keys+left->key_num*file_header_.key_length,right->keys,file_header_.key_length);
memcpy(left->rids+left->key_num,right->rids,sizeof(RID));
left->key_num++;
int parent_change_pos = -1;
for (int k = 0; k < parent->key_num; k++) {
for(i=0;i<right->key_num-1;i++){
memcpy(right->keys+i*file_header_.key_length,right->keys+(i+1)*file_header_.key_length,file_header_.key_length);
memcpy(right->rids+i,right->rids+i+1,sizeof(RID));
}
right->key_num--;
memcpy(parent->keys+k*file_header_.key_length,right->keys,file_header_.key_length);
if (parent->rids[k].page_num == left_page) {
parent_change_pos = k;
break;
}
else{
for(i=right->key_num;i>0;i--){
memcpy(right->keys+i*file_header_.key_length,right->keys+(i-1)*file_header_.key_length,file_header_.key_length);
memcpy(right->rids+i,right->rids+i-1,sizeof(RID));
}
memcpy(right->keys,left->keys+(left->key_num-1)*file_header_.key_length,file_header_.key_length);
left->key_num--;
right->key_num++;
memcpy(parent->keys+k*file_header_.key_length,right->keys,file_header_.key_length);
}
if (parent_change_pos == -1) {
LOG_WARN("Failed to find the parent pos during redistribute node");
return RC::RECORD_INVALID_KEY;
}
else{
min_key=(file_header_.order+1)/2-1;
if(left->key_num<min_key){
memcpy(left->keys+left->key_num*file_header_.key_length,parent->keys+k*file_header_.key_length,file_header_.key_length);
memcpy(left->rids+left->key_num+1,right->rids,sizeof(RID));
left->key_num++;
memcpy(parent->keys+k*file_header_.key_length,right->keys,file_header_.key_length);
for(i=0;i<right->key_num-1;i++){
memcpy(right->keys+i*file_header_.key_length,right->keys+(i+1)*file_header_.key_length,file_header_.key_length);
memcpy(right->rids+i,right->rids+i+1,sizeof(RID));
}
right->key_num--;
char *parent_key = parent->keys + parent_change_pos * file_header_.key_length;
redistribute_nodes(left, right, left_page, right_page, parent_key);
rc = disk_buffer_pool_->get_this_page(file_id_, left->rids[left->key_num].page_num,&tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&tmphandle, &pdata);
if(rc!=SUCCESS){
return rc;
}
node=(IndexNode *)(pdata+sizeof(IndexFileHeader));
node->parent=leaf_page;
rc = disk_buffer_pool_->mark_dirty(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
}
else{
for(i=right->key_num;i>0;i--){
memcpy(right->keys+i*file_header_.key_length,right->keys+(i-1)*file_header_.key_length,file_header_.key_length);
memcpy(right->rids+i,right->rids+i-1,sizeof(RID));
}
memcpy(right->keys,parent->keys+k*file_header_.key_length,file_header_.key_length);
memcpy(right->rids,left->rids+left->key_num,sizeof(RID));
disk_buffer_pool_->mark_dirty(&left_handle);
disk_buffer_pool_->mark_dirty(&right_handle);
disk_buffer_pool_->mark_dirty(&parent_handle);
right->key_num++;
memcpy(parent->keys+k*file_header_.key_length,left->keys+(left->key_num-1)*file_header_.key_length,file_header_.key_length);
left->key_num--;
return RC::SUCCESS;
}
rc = disk_buffer_pool_->get_this_page(file_id_, right->rids[0].page_num, &tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&tmphandle, &pdata);
if(rc!=SUCCESS){
return rc;
}
node = get_index_node(pdata);
node->parent=right_page;
rc = disk_buffer_pool_->mark_dirty(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
}
}
rc = disk_buffer_pool_->mark_dirty(&left_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&left_handle);
if(rc!=SUCCESS){
return rc;
RC BplusTreeHandler::clean_root_after_delete(IndexNode *old_root)
{
if (old_root->key_num > 0) {
return RC::SUCCESS;
}
rc = disk_buffer_pool_->mark_dirty(&right_handle);
if(rc!=SUCCESS){
BPPageHandle root_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, old_root->rids[0].page_num, &root_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get new root page %d of index %d", old_root->rids[0].page_num, file_id_);
return rc;
}
rc = disk_buffer_pool_->unpin_page(&right_handle);
if(rc!=SUCCESS){
return rc;
}
char *pdata;
disk_buffer_pool_->get_data(&root_handle, &pdata);
IndexNode *root = get_index_node(pdata);
root->parent = -1;
disk_buffer_pool_->mark_dirty(&root_handle);
swith_root(root_handle, root, old_root->rids[0].page_num);
rc = disk_buffer_pool_->mark_dirty(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
return SUCCESS;
return RC::SUCCESS;
}
RC BplusTreeHandler::delete_entry_internal(PageNum page_num,const char *pkey) {
BPPageHandle parent_handle,page_handle,left_handle,right_handle,tmphandle;
IndexNode *node,*parent,*left,*right,*tmpnode;
PageNum leaf_page,right_page;
char *pdata;
RC rc;
int delete_index,min_key;
rc=delete_entry_from_node(page_num,pkey);
if(rc!=SUCCESS){
RC BplusTreeHandler::can_merge_with_other(BPPageHandle *page_handle, PageNum page_num, bool *can_merge)
{
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get page of current delete page, file_id:%d, page:%d",
file_id_,
page_num);
return rc;
}
char *pdata;
disk_buffer_pool_->get_data(page_handle, &pdata);
IndexNode *node = get_index_node(pdata);
*can_merge = node->key_num > (file_header_.order / 2);
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if(rc!=SUCCESS){
return RC::SUCCESS;
}
RC BplusTreeHandler::delete_entry_internal(PageNum page_num, const char *pkey)
{
BPPageHandle page_handle;
RC rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if (rc != RC::SUCCESS) {
LOG_WARN(
"Failed to delete entry in index node, due to failed to get page!, file_id:%d, page:%d", file_id_, page_num);
return rc;
}
char *pdata;
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
if (rc != RC::SUCCESS) {
return rc;
}
node = get_index_node(pdata);
IndexNode *node = get_index_node(pdata);
if(node->parent==-1){
if(node->key_num==0&&node->is_leaf==false){
rc = disk_buffer_pool_->get_this_page(file_id_, node->rids[0].page_num, &tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&tmphandle, &pdata);
if(rc!=SUCCESS){
return rc;
}
tmpnode=(IndexNode *)(pdata+sizeof(IndexFileHeader));
tmpnode->parent=-1;
rc = disk_buffer_pool_->mark_dirty(&tmphandle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&tmphandle);
if(rc!=SUCCESS){
int node_delete_index = -1;
rc = delete_entry_from_node(node, pkey, node_delete_index);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index %d", file_id_);
return rc;
}
file_header_.root_page=node->rids[0].page_num;
header_dirty_ = true;
disk_buffer_pool_->mark_dirty(&page_handle);
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
int min_key = file_header_.order / 2;
if (node->key_num >= min_key) {
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
rc = disk_buffer_pool_->dispose_page(file_id_, page_num);
if(rc!=SUCCESS){
if (node->parent == -1) {
if (node->key_num == 0 && node->is_leaf == false) {
rc = clean_root_after_delete(node);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to clean root after delete all entry in the root, file_id:%d", file_id_);
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num);
disk_buffer_pool_->unpin_page(&page_handle);
return rc;
}
return SUCCESS;
}
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->dispose_page(file_id_, page_num);
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
return RC::SUCCESS;
}
return SUCCESS;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
if(node->is_leaf)
min_key=file_header_.order/2;
else
min_key=(file_header_.order+1)/2-1;
int delete_index = 0;
BPPageHandle parent_handle;
IndexNode *parent = nullptr;
if(node->key_num>=min_key){
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
rc = get_parent_changed_index(parent_handle, parent, node, page_num, delete_index);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get parent delete index");
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num);
disk_buffer_pool_->unpin_page(&page_handle);
return rc;
}
return SUCCESS;
bool can_merge_with_right = false;
bool force_collapse_with_right = false;
bool can_merge_with_left = false;
// bool force_collapse_with_left = false;
PageNum left_page = 0, right_page = 0;
BPPageHandle right_handle, left_handle;
if (delete_index == 0) {
right_page = parent->rids[delete_index + 1].page_num;
rc = can_merge_with_other(&right_handle, right_page, &can_merge_with_right);
if (rc != RC::SUCCESS) {
goto cleanup;
}
rc = disk_buffer_pool_->get_this_page(file_id_, node->parent, &parent_handle);
if(rc!=SUCCESS){
return rc;
if (can_merge_with_right == false) {
force_collapse_with_right = true;
}
rc = disk_buffer_pool_->get_data(&parent_handle, &pdata);
if(rc!=SUCCESS){
return rc;
} else {
left_page = parent->rids[delete_index - 1].page_num;
rc = can_merge_with_other(&left_handle, left_page, &can_merge_with_left);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed delete index, due to failed to get page, file_id:%d, page:%d", file_id_, left_page);
goto cleanup;
}
if (can_merge_with_left == false) {
// begin to merge with right
// force_collapse_with_left = true;
if (delete_index < parent->key_num) {
parent = get_index_node(pdata);
right_page = parent->rids[delete_index + 1].page_num;
rc = can_merge_with_other(&right_handle, right_page, &can_merge_with_right);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index, due to failed to get right page of current delete page, file_id:%d, "
"right_page:$d",
file_id_,
right_page);
delete_index=0;
while(delete_index<=parent->key_num){
if((parent->rids[delete_index].page_num) == page_num)
break;
delete_index++;
goto cleanup;
}
if(delete_index==0){
leaf_page=page_num;
right_page=parent->rids[delete_index+1].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, right_page, &right_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&right_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
right=(IndexNode *)(pdata+sizeof(IndexFileHeader));
} // delete_index < parent->key_num - 1
} // if can_merge_with_left = false
} // delete_index = 0
if(right->key_num>min_key){
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&right_handle);
if(rc!=SUCCESS){
return rc;
}
return redistribute_nodes(page_num,right_page);
}
else{
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&right_handle);
if(rc!=SUCCESS){
return rc;
}
return coalesce_node(page_num,right_page);
if (can_merge_with_left) {
rc = redistribute_nodes(parent_handle, left_handle, page_handle);
} else if (can_merge_with_right) {
rc = redistribute_nodes(parent_handle, page_handle, right_handle);
change_leaf_parent_key_delete(node, node_delete_index, pkey);
} else if (force_collapse_with_right) {
rc = coalesce_node(parent_handle, page_handle, right_handle, delete_index, true, node_delete_index, pkey);
if (rc == RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&page_handle);
disk_buffer_pool_->dispose_page(file_id_, page_num);
page_handle.open = false;
}
} else {
rc = coalesce_node(parent_handle, left_handle, page_handle, delete_index - 1, false, node_delete_index, pkey);
if (rc == RC::SUCCESS) {
disk_buffer_pool_->unpin_page(&left_handle);
disk_buffer_pool_->dispose_page(file_id_, left_page);
left_handle.open = false;
}
else{
leaf_page=parent->rids[delete_index-1].page_num;
rc = disk_buffer_pool_->get_this_page(file_id_, leaf_page, &left_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&left_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
left=(IndexNode *)(pdata+sizeof(IndexFileHeader));
if(left->key_num>min_key){
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&left_handle);
if(rc!=SUCCESS){
return rc;
cleanup:
if (rc != RC::SUCCESS) {
insert_entry_into_node(node, pkey, (RID *)(pkey + file_header_.attr_length), page_num);
}
return redistribute_nodes(leaf_page,page_num);
if (right_handle.open) {
disk_buffer_pool_->unpin_page(&right_handle);
}
else{
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&parent_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&left_handle);
if(rc!=SUCCESS){
return rc;
}
return coalesce_node(leaf_page,page_num);
if (left_handle.open) {
disk_buffer_pool_->unpin_page(&left_handle);
}
disk_buffer_pool_->unpin_page(&parent_handle);
if (page_handle.open) {
disk_buffer_pool_->unpin_page(&page_handle);
}
}
RC BplusTreeHandler::delete_entry(const char *data, const RID *rid) {
RC rc;
PageNum leaf_page;
char *pkey;
pkey=(char *)malloc(file_header_.key_length);
if(nullptr == pkey){
LOG_ERROR("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(pkey,data,file_header_.attr_length);
memcpy(pkey + file_header_.attr_length, rid ,sizeof(*rid));
rc=find_leaf(pkey,&leaf_page);
if(rc!=SUCCESS){
free(pkey);
return rc;
}
rc=delete_entry_internal(leaf_page,pkey);
if(rc!=SUCCESS){
free(pkey);
return rc;
}
free(pkey);
return SUCCESS;
}
RC BplusTreeHandler::print_tree() {
BPPageHandle page_handle;
IndexNode *node;
PageNum page_num;
char *pdata,*pkey;
int i;
RC rc;
rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
RC BplusTreeHandler::delete_entry(const char *data, const RID *rid)
{
if (file_id_ < 0) {
LOG_WARN("Failed to delete index entry, due to index is't ready");
return RC::RECORD_CLOSED;
}
node = get_index_node(pdata);
while(!node->is_leaf){
page_num=node->rids[0].page_num;
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
node=(IndexNode *)(pdata+sizeof(IndexFileHeader));
node->keys=(char *)node+sizeof(IndexNode);
node->rids=(RID *)(node->keys+file_header_.order*file_header_.key_length);
}
page_num=1;
while(page_num!=0){
for(i=0;i<node->key_num;i++){
pkey=node->keys+i*file_header_.key_length;
printf("key : %d,rids (page_num:%d slotnum %d)\n",*(int *)pkey,node->rids[i].page_num,node->rids[i].slot_num);
}
printf("next node:%d\n",page_num);
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
page_num=node->rids[file_header_.order-1].page_num;
if(page_num==0)
break;
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
char *pkey = (char *)mem_pool_item_->alloc();
if (nullptr == pkey) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(pkey, data, file_header_.attr_length);
memcpy(pkey + file_header_.attr_length, rid, sizeof(*rid));
node = get_index_node(pdata);
PageNum leaf_page;
RC rc = find_leaf(pkey, &leaf_page);
if (rc != RC::SUCCESS) {
mem_pool_item_->free(pkey);
return rc;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
rc = delete_entry_internal(leaf_page, pkey);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to delete index %d", file_id_);
mem_pool_item_->free(pkey);
return rc;
}
return SUCCESS;
mem_pool_item_->free(pkey);
return RC::SUCCESS;
}
RC BplusTreeHandler::find_first_index_satisfied(CompOp compop, const char *key, PageNum *page_num, int *rididx) {
RC BplusTreeHandler::find_first_index_satisfied(CompOp compop, const char *key, PageNum *page_num, int *rididx)
{
BPPageHandle page_handle;
IndexNode *node;
PageNum leaf_page,next;
char *pdata,*pkey;
PageNum leaf_page, next;
char *pdata, *pkey;
RC rc;
int i,tmp;
int i, tmp;
RID rid;
if(compop == LESS_THAN || compop == LESS_EQUAL || compop == NOT_EQUAL){
if (compop == LESS_THAN || compop == LESS_EQUAL || compop == NOT_EQUAL) {
rc = get_first_leaf_page(page_num);
if(rc != SUCCESS){
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get first leaf page, index:%d", file_id_);
return rc;
}
*rididx=0;
return SUCCESS;
*rididx = 0;
return RC::SUCCESS;
}
rid.page_num = -1;
rid.slot_num = -1;
pkey=(char *)malloc(file_header_.key_length);
if(pkey == nullptr){
LOG_ERROR("Failed to alloc memory for key. size=%d", file_header_.key_length);
pkey = (char *)mem_pool_item_->alloc();
if (pkey == nullptr) {
LOG_WARN("Failed to alloc memory for key. size=%d", file_header_.key_length);
return RC::NOMEM;
}
memcpy(pkey, key, file_header_.attr_length);
memcpy(pkey + file_header_.attr_length, &rid, sizeof(RID));
rc = find_leaf(pkey, &leaf_page);
if(rc != SUCCESS){
free(pkey);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to find leaf page of index %d", file_id_);
mem_pool_item_->free(pkey);
return rc;
}
free(pkey);
mem_pool_item_->free(pkey);
next=leaf_page;
next = leaf_page;
while(next > 0){
while (next > 0) {
rc = disk_buffer_pool_->get_this_page(file_id_, next, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to scan index due to failed to load page %d of index %d", next, file_id_);
return rc;
}
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
for(i = 0; i < node->key_num; i++){
tmp=CompareKey(node->keys+i*file_header_.key_length,key,file_header_.attr_type,file_header_.attr_length);
if(compop == EQUAL_TO ||compop == GREAT_EQUAL){
if(tmp>=0){
rc = disk_buffer_pool_->get_page_num(&page_handle, page_num);
if(rc != SUCCESS){
return rc;
}
*rididx=i;
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc != SUCCESS){
return rc;
}
return SUCCESS;
for (i = 0; i < node->key_num; i++) {
tmp = attribute_comp(
node->keys + i * file_header_.key_length, key, file_header_.attr_type, file_header_.attr_length);
if (compop == EQUAL_TO || compop == GREAT_EQUAL) {
if (tmp >= 0) {
disk_buffer_pool_->get_page_num(&page_handle, page_num);
*rididx = i;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
}
if(compop == GREAT_THAN){
if(tmp > 0){
rc = disk_buffer_pool_->get_page_num(&page_handle, page_num);
if(rc!=SUCCESS){
return rc;
if (compop == GREAT_THAN) {
if (tmp > 0) {
disk_buffer_pool_->get_page_num(&page_handle, page_num);
*rididx = i;
disk_buffer_pool_->unpin_page(&page_handle);
return RC::SUCCESS;
}
*rididx=i;
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
}
return SUCCESS;
}
next = node->next_brother;
}
disk_buffer_pool_->unpin_page(&page_handle);
}
next=node->rids[file_header_.order-1].page_num;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc != SUCCESS){
return rc;
}
return RC::RECORD_EOF;
}
RC BplusTreeHandler::get_first_leaf_page(PageNum *leaf_page) {
RC BplusTreeHandler::get_first_leaf_page(PageNum *leaf_page)
{
RC rc;
BPPageHandle page_handle;
PageNum page_num;
IndexNode *node;
char *pdata;
rc = disk_buffer_pool_->get_this_page(file_id_, file_header_.root_page, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
return rc;
}
node = get_index_node(pdata);
node = root_node_;
while(node->is_leaf==false){
page_num=node->rids[0].page_num;
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
while (node->is_leaf == false) {
page_num = node->rids[0].page_num;
if (page_handle.open) {
disk_buffer_pool_->unpin_page(&page_handle);
}
rc = disk_buffer_pool_->get_this_page(file_id_, page_num, &page_handle);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->get_data(&page_handle, &pdata);
if(rc!=SUCCESS){
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to load page %d of index %d", page_num, file_id_);
return rc;
}
disk_buffer_pool_->get_data(&page_handle, &pdata);
node = get_index_node(pdata);
}
rc = disk_buffer_pool_->get_page_num(&page_handle, leaf_page);
if(rc!=SUCCESS){
return rc;
}
rc = disk_buffer_pool_->unpin_page(&page_handle);
if(rc!=SUCCESS){
return rc;
if (page_handle.open) {
disk_buffer_pool_->get_page_num(&page_handle, leaf_page);
disk_buffer_pool_->unpin_page(&page_handle);
} else {
disk_buffer_pool_->get_page_num(&root_page_handle_, leaf_page);
}
return SUCCESS;
}
BplusTreeScanner::BplusTreeScanner(BplusTreeHandler &index_handler) : index_handler_(index_handler){
return RC::SUCCESS;
}
RC BplusTreeScanner::open(CompOp comp_op,const char *value) {
BplusTreeScanner::BplusTreeScanner(BplusTreeHandler &index_handler) : index_handler_(index_handler)
{}
RC BplusTreeScanner::open(CompOp comp_op, const char *value)
{
RC rc;
if(opened_){
if (opened_) {
return RC::RECORD_OPENNED;
}
comp_op_ = comp_op;
char *value_copy =(char *)malloc(index_handler_.file_header_.attr_length);
if(value_copy == nullptr){
LOG_ERROR("Failed to alloc memory for value. size=%d", index_handler_.file_header_.attr_length);
char *value_copy = (char *)malloc(index_handler_.file_header_.attr_length);
if (value_copy == nullptr) {
LOG_WARN("Failed to alloc memory for value. size=%d", index_handler_.file_header_.attr_length);
return RC::NOMEM;
}
memcpy(value_copy, value, index_handler_.file_header_.attr_length);
value_ = value_copy; // free value_
value_ = value_copy; // mem_pool_item_->free value_
rc = index_handler_.find_first_index_satisfied(comp_op, value, &next_page_num_, &index_in_node_);
if(rc != SUCCESS){
if(rc == RC::RECORD_EOF){
if (rc != RC::SUCCESS) {
if (rc == RC::RECORD_EOF) {
next_page_num_ = -1;
index_in_node_ = -1;
}
else
} else
return rc;
}
num_fixed_pages_ = 1;
next_index_of_page_handle_=0;
next_index_of_page_handle_ = 0;
pinned_page_count_ = 0;
opened_ = true;
return SUCCESS;
return RC::SUCCESS;
}
RC BplusTreeScanner::close() {
RC BplusTreeScanner::close()
{
if (!opened_) {
return RC::RECORD_SCANCLOSED;
}
......@@ -1708,36 +2189,37 @@ RC BplusTreeScanner::close() {
return RC::SUCCESS;
}
RC BplusTreeScanner::next_entry(RID *rid) {
RC BplusTreeScanner::next_entry(RID *rid)
{
RC rc;
if(!opened_){
if (!opened_) {
return RC::RECORD_CLOSED;
}
rc = get_next_idx_in_memory(rid);//和RM中一样,有可能有错误,一次只查当前页和当前页的下一页,有待确定
if(rc == RC::RECORD_NO_MORE_IDX_IN_MEM){
rc = get_next_idx_in_memory(rid); //和RM中一样,有可能有错误,一次只查当前页和当前页的下一页,有待确定
if (rc == RC::RECORD_NO_MORE_IDX_IN_MEM) {
rc = find_idx_pages();
if(rc != SUCCESS){
if (rc != RC::SUCCESS) {
return rc;
}
return get_next_idx_in_memory(rid);
}
else{
if(rc != SUCCESS){
} else {
if (rc != RC::SUCCESS) {
return rc;
}
}
return SUCCESS;
return RC::SUCCESS;
}
RC BplusTreeScanner::find_idx_pages() {
RC BplusTreeScanner::find_idx_pages()
{
RC rc;
if(!opened_){
if (!opened_) {
return RC::RECORD_CLOSED;
}
if(pinned_page_count_ > 0){
for(int i = 0; i < pinned_page_count_; i++){
if (pinned_page_count_ > 0) {
for (int i = 0; i < pinned_page_count_; i++) {
rc = index_handler_.disk_buffer_pool_->unpin_page(page_handles_ + i);
if(rc != SUCCESS){
if (rc != RC::SUCCESS) {
return rc;
}
}
......@@ -1745,53 +2227,54 @@ RC BplusTreeScanner::find_idx_pages() {
next_index_of_page_handle_ = 0;
pinned_page_count_ = 0;
for(int i = 0; i < num_fixed_pages_; i++){
if(next_page_num_ <= 0)
for (int i = 0; i < num_fixed_pages_; i++) {
if (next_page_num_ <= 0)
break;
rc = index_handler_.disk_buffer_pool_->get_this_page(index_handler_.file_id_, next_page_num_, page_handles_ + i);
if(rc != SUCCESS){
if (rc != RC::SUCCESS) {
return rc;
}
char *pdata;
rc = index_handler_.disk_buffer_pool_->get_data(page_handles_ + i, &pdata);
if(rc != SUCCESS){
if (rc != RC::SUCCESS) {
return rc;
}
IndexNode *node = index_handler_.get_index_node(pdata);
pinned_page_count_++;
next_page_num_ = node->rids[index_handler_.file_header_.order-1].page_num;
next_page_num_ = node->next_brother;
}
if(pinned_page_count_ > 0)
return SUCCESS;
if (pinned_page_count_ > 0)
return RC::SUCCESS;
return RC::RECORD_EOF;
}
RC BplusTreeScanner::get_next_idx_in_memory(RID *rid) {
RC BplusTreeScanner::get_next_idx_in_memory(RID *rid)
{
char *pdata;
IndexNode *node;
RC rc;
if(next_index_of_page_handle_ >= pinned_page_count_) {
if (next_index_of_page_handle_ >= pinned_page_count_) {
return RC::RECORD_NO_MORE_IDX_IN_MEM;
}
if(next_page_num_ == -1 && index_in_node_ == -1) {
if (next_page_num_ == -1 && index_in_node_ == -1) {
return RC::RECORD_EOF;
}
for( ; next_index_of_page_handle_ < pinned_page_count_; next_index_of_page_handle_++){
for (; next_index_of_page_handle_ < pinned_page_count_; next_index_of_page_handle_++) {
rc = index_handler_.disk_buffer_pool_->get_data(page_handles_ + next_index_of_page_handle_, &pdata);
if(rc != SUCCESS){
LOG_ERROR("Failed to get data from disk buffer pool. rc=%s", strrc);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to get data from disk buffer pool. rc=%s", strrc);
return rc;
}
node = index_handler_.get_index_node(pdata);
for( ; index_in_node_ < node->key_num; index_in_node_++){
if(satisfy_condition(node->keys + index_in_node_ * index_handler_.file_header_.key_length)){
memcpy(rid,node->rids+index_in_node_,sizeof(RID));
for (; index_in_node_ < node->key_num; index_in_node_++) {
if (satisfy_condition(node->keys + index_in_node_ * index_handler_.file_header_.key_length)) {
memcpy(rid, node->rids + index_in_node_, sizeof(RID));
index_in_node_++;
return SUCCESS;
return RC::SUCCESS;
}
}
......@@ -1799,122 +2282,123 @@ RC BplusTreeScanner::get_next_idx_in_memory(RID *rid) {
}
return RC::RECORD_NO_MORE_IDX_IN_MEM;
}
bool BplusTreeScanner::satisfy_condition(const char *pkey) {
int i1=0,i2=0;
float f1=0,f2=0;
const char *s1=nullptr,*s2=nullptr;
bool BplusTreeScanner::satisfy_condition(const char *pkey)
{
int i1 = 0, i2 = 0;
float f1 = 0, f2 = 0;
const char *s1 = nullptr, *s2 = nullptr;
if(comp_op_ == NO_OP){
if (comp_op_ == NO_OP) {
return true;
}
AttrType attr_type = index_handler_.file_header_.attr_type;
switch(attr_type){
switch (attr_type) {
case INTS:
i1=*(int *)pkey;
i2=*(int *)value_;
i1 = *(int *)pkey;
i2 = *(int *)value_;
break;
case FLOATS:
f1=*(float *)pkey;
f2=*(float *)value_;
f1 = *(float *)pkey;
f2 = *(float *)value_;
break;
case CHARS:
s1=pkey;
s2=value_;
s1 = pkey;
s2 = value_;
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
bool flag=false;
bool flag = false;
int attr_length = index_handler_.file_header_.attr_length;
switch(comp_op_){
switch (comp_op_) {
case EQUAL_TO:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1==i2);
flag = (i1 == i2);
break;
case FLOATS:
flag= 0 == float_compare(f1, f2);
flag = 0 == float_compare(f1, f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)==0);
flag = (strncmp(s1, s2, attr_length) == 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case LESS_THAN:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1<i2);
flag = (i1 < i2);
break;
case FLOATS:
flag=(f1<f2);
flag = (f1 < f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)<0);
flag = (strncmp(s1, s2, attr_length) < 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case GREAT_THAN:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1>i2);
flag = (i1 > i2);
break;
case FLOATS:
flag=(f1>f2);
flag = (f1 > f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)>0);
flag = (strncmp(s1, s2, attr_length) > 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case LESS_EQUAL:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1<=i2);
flag = (i1 <= i2);
break;
case FLOATS:
flag=(f1<=f2);
flag = (f1 <= f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)<=0);
flag = (strncmp(s1, s2, attr_length) <= 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case GREAT_EQUAL:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1>=i2);
flag = (i1 >= i2);
break;
case FLOATS:
flag=(f1>=f2);
flag = (f1 >= f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)>=0);
flag = (strncmp(s1, s2, attr_length) >= 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
}
break;
case NOT_EQUAL:
switch(attr_type){
switch (attr_type) {
case INTS:
flag=(i1!=i2);
flag = (i1 != i2);
break;
case FLOATS:
flag= 0 != float_compare(f1, f2);
flag = 0 != float_compare(f1, f2);
break;
case CHARS:
flag=(strncmp(s1,s2,attr_length)!=0);
flag = (strncmp(s1, s2, attr_length) != 0);
break;
default:
LOG_PANIC("Unknown attr type: %d", attr_type);
......
......@@ -14,40 +14,102 @@ See the Mulan PSL v2 for more details. */
#ifndef __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#define __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#include <sstream>
#include "record_manager.h"
#include "storage/default/disk_buffer_pool.h"
#include "sql/parser/parse_defs.h"
#define EMPTY_RID_PAGE_NUM -1
#define EMPTY_RID_SLOT_NUM -1
struct IndexFileHeader {
IndexFileHeader()
{
memset(this, 0, sizeof(IndexFileHeader));
}
int attr_length;
int key_length;
AttrType attr_type;
PageNum root_page; // 初始时,root_page一定是1
int node_num;
PageNum root_page;
int order;
const std::string to_string()
{
std::stringstream ss;
ss << "attr_length:" << attr_length << ","
<< "key_length:" << key_length << ","
<< "attr_type:" << attr_type << ","
<< "root_page:" << root_page << ","
<< "order:" << order << ";";
return ss.str();
}
};
#define RECORD_RESERVER_PAIR_NUM 2
struct IndexNode {
int is_leaf;
bool is_leaf;
int key_num;
PageNum parent;
PageNum prev_brother; // valid when is_leaf = true
PageNum next_brother; // valid when is_leaf = true
/**
* leaf can store order keys and rids at most
* internal node just store order -1 keys and order rids, the last rid is last rght child.
*/
char *keys;
/**
* In the node which isn't leaf, the rids point to child's page,
* rids[i] is keys[i]'s left child, rids[key_num] is the last right child.
* In the node which is leaf, the rids point to record's rid.
*/
RID *rids;
};
struct TreeNode {
int key_num;
char **keys;
TreeNode *parent;
TreeNode *sibling;
TreeNode *first_child;
};
void init_empty(IndexFileHeader &file_header)
{
is_leaf = true;
key_num = 0;
parent = -1;
prev_brother = -1;
next_brother = -1;
keys = (char *)(this + 1);
rids = (RID *)(keys + (file_header.order + RECORD_RESERVER_PAIR_NUM) * file_header.key_length);
}
struct Tree {
AttrType attr_type;
int attr_length;
int order;
TreeNode *root;
std::string to_string(IndexFileHeader &file_header)
{
std::stringstream ss;
ss << "is_leaf:" << is_leaf << ","
<< "key_num:" << key_num << ","
<< "parent:" << parent << ","
<< "prev_brother:" << prev_brother << ","
<< "next_brother:" << next_brother << ",";
if (file_header.attr_type == INTS) { // CHARS, INTS, FLOATS
ss << "start_key:" << *(int *)(keys) << ","
<< "end_key:" << *(int *)(keys + (key_num - 1) * file_header.key_length) << ";";
} else if (file_header.attr_type == FLOATS) {
ss << "start_key:" << *(float *)(keys) << ","
<< "end_key:" << *(float *)(keys + (key_num - 1) * file_header.key_length) << ";";
} else if (file_header.attr_type == CHARS) {
char *temp = (char *)malloc(file_header.attr_length + 1);
memset(temp, 0, file_header.attr_length + 1);
memcpy(temp, keys, file_header.attr_length);
ss << "start_key:" << temp << ",";
memcpy(temp, keys + (key_num - 1) * file_header.key_length, file_header.attr_length);
ss << "end_key:" << temp << ";";
free(temp);
} else {
ss << "Unkown key range." << std::endl;
}
return ss.str();
}
};
class BplusTreeHandler {
......@@ -87,40 +149,89 @@ public:
* 获取指定值的record
* @param rid 返回值,记录记录所在的页面号和slot
*/
RC get_entry(const char *pkey, RID *rid);
RC get_entry(const char *pkey, std::list<RID> &rids);
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.
* @return
*/
bool validate_tree();
public:
RC print();
RC print_tree();
RC print_node(IndexNode *node, PageNum page_num);
RC print_leafs();
bool validate_node(IndexNode *node);
bool validate_leaf_link();
protected:
RC find_leaf(const char *pkey, PageNum *leaf_page);
RC insert_into_leaf(PageNum leaf_page, const char *pkey, const RID *rid);
RC insert_into_leaf_after_split(PageNum leaf_page, const char *pkey, const RID *rid);
RC insert_into_parent(PageNum parent_page, PageNum leaf_page, const char *pkey, PageNum right_page);
RC insert_into_new_root(PageNum leaf_page, const char *pkey, PageNum right_page);
RC insert_intern_node(PageNum parent_page, PageNum leaf_page, PageNum right_page, const char *pkey);
RC insert_intern_node_after_split(PageNum intern_page, PageNum leaf_page, PageNum right_page, const char *pkey);
RC delete_entry_from_node(PageNum node_page, const char *pkey);
RC insert_into_parent(
PageNum parent_page, BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC insert_intern_node(BPPageHandle &parent_page_handle, BPPageHandle &left_page_handle,
BPPageHandle &right_page_handle, const char *pkey);
RC split_leaf(BPPageHandle &leaf_page_handle);
RC split_intern_node(BPPageHandle &parent_page_handle, const char *pkey);
RC delete_entry_internal(PageNum page_num, const char *pkey);
RC coalesce_node(PageNum leaf_page, PageNum right_page);
RC redistribute_nodes(PageNum left_page, PageNum right_page);
RC coalesce_node(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle, int delete_index,
bool check_change_leaf_key, int node_delete_index, const char *pkey);
RC insert_into_new_root(BPPageHandle &left_page_handle, const char *pkey, BPPageHandle &right_page_handle);
RC clean_root_after_delete(IndexNode *old_root);
RC insert_entry_into_node(IndexNode *node, const char *pkey, const RID *rid, PageNum left_page);
RC delete_entry_from_node(IndexNode *node, const char *pkey, int &node_delete_index);
void delete_entry_from_node(IndexNode *node, const int delete_index);
RC redistribute_nodes(BPPageHandle &parent_handle, BPPageHandle &left_handle, BPPageHandle &right_handle);
void redistribute_nodes(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_key);
void merge_nodes(IndexNode *left_node, IndexNode *right_node, PageNum left_page, char *parent_key);
RC can_merge_with_other(BPPageHandle *page_handle, PageNum page_num, bool *can_merge);
void split_node(
IndexNode *left_node, IndexNode *right_node, PageNum left_page, PageNum right_page, char *new_parent_key);
void copy_node(IndexNode *to, IndexNode *from);
void get_entry_from_leaf(IndexNode *node, const char *pkey, std::list<RID> &rids, bool &continue_check);
RC find_first_index_satisfied(CompOp comp_op, const char *pkey, PageNum *page_num, int *rididx);
RC get_first_leaf_page(PageNum *leaf_page);
private:
IndexNode *get_index_node(char *page_data) const;
void swith_root(BPPageHandle &new_root_page_handle, IndexNode *root, PageNum root_page);
private:
DiskBufferPool * disk_buffer_pool_ = nullptr;
void change_children_parent(RID *rid, int rid_len, PageNum new_parent_page);
RC get_parent_changed_index(
BPPageHandle &parent_handle, IndexNode *&parent, IndexNode *node, PageNum page_num, int &changed_index);
RC change_leaf_parent_key_insert(IndexNode *node, int changed_indx, PageNum page_num);
RC change_leaf_parent_key_delete(IndexNode *leaf, int delete_indx, const char *old_first_key);
RC change_insert_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page);
RC change_delete_leaf_link(IndexNode *left, IndexNode *right, PageNum right_page);
protected:
DiskBufferPool *disk_buffer_pool_ = nullptr;
int file_id_ = -1;
bool header_dirty_ = false;
IndexFileHeader file_header_;
BPPageHandle root_page_handle_;
IndexNode *root_node_ = nullptr;
common::MemPoolItem *mem_pool_item_ = nullptr;
private:
friend class BplusTreeScanner;
friend class BplusTreeTester;
};
class BplusTreeScanner {
......@@ -157,7 +268,7 @@ private:
bool satisfy_condition(const char *key);
private:
BplusTreeHandler & index_handler_;
BplusTreeHandler &index_handler_;
bool opened_ = false;
CompOp comp_op_ = NO_OP; // 用于比较的操作符
const char *value_ = nullptr; // 与属性行比较的值
......@@ -169,4 +280,29 @@ private:
PageNum next_page_num_ = -1; // 下一个将要被读入的页面号
};
class BplusTreeTester {
public:
BplusTreeTester(BplusTreeHandler &index_handler) : index_handler_(index_handler)
{}
~BplusTreeTester() = default;
void set_order(int order)
{
if (order >= 2 && order % 2 == 0) {
index_handler_.file_header_.order = order;
LOG_INFO("Successfully set index %d's order as %d", index_handler_.file_id_, order);
} else {
LOG_INFO("Invalid input order argument %d", order);
}
}
const int get_oder()
{
return index_handler_.file_header_.order;
}
protected:
BplusTreeHandler &index_handler_;
};
#endif //__OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
\ No newline at end of file
......@@ -15,64 +15,97 @@ See the Mulan PSL v2 for more details. */
#include "storage/common/bplus_tree_index.h"
#include "common/log/log.h"
BplusTreeIndex::~BplusTreeIndex() noexcept {
BplusTreeIndex::~BplusTreeIndex() noexcept
{
close();
}
RC BplusTreeIndex::create(const char *file_name, const IndexMeta &index_meta, const FieldMeta &field_meta) {
RC BplusTreeIndex::create(const char *file_name, const IndexMeta &index_meta, const FieldMeta &field_meta)
{
if (inited_) {
LOG_WARN("Failed to create index due to the index has been created before. file_name:%s, index:%s, field:%s",
file_name,
index_meta.name(),
index_meta.field());
return RC::RECORD_OPENNED;
}
RC rc = Index::init(index_meta, field_meta);
if (rc != RC::SUCCESS) {
Index::init(index_meta, field_meta);
RC rc = index_handler_.create(file_name, field_meta.type(), field_meta.len());
if (RC::SUCCESS != rc) {
LOG_WARN("Failed to create index_handler, file_name:%s, index:%s, field:%s, rc:%s",
file_name,
index_meta.name(),
index_meta.field(),
strrc(rc));
return rc;
}
rc = index_handler_.create(file_name, field_meta.type(), field_meta.len());
if (RC::SUCCESS == rc) {
inited_ = true;
}
return rc;
LOG_INFO(
"Successfully create index, file_name:%s, index:%s, field:%s", file_name, index_meta.name(), index_meta.field());
return RC::SUCCESS;
}
RC BplusTreeIndex::open(const char *file_name, const IndexMeta &index_meta, const FieldMeta &field_meta) {
RC BplusTreeIndex::open(const char *file_name, const IndexMeta &index_meta, const FieldMeta &field_meta)
{
if (inited_) {
LOG_WARN("Failed to open index due to the index has been initedd before. file_name:%s, index:%s, field:%s",
file_name,
index_meta.name(),
index_meta.field());
return RC::RECORD_OPENNED;
}
RC rc = Index::init(index_meta, field_meta);
if (rc != RC::SUCCESS) {
Index::init(index_meta, field_meta);
RC rc = index_handler_.open(file_name);
if (RC::SUCCESS != rc) {
LOG_WARN("Failed to open index_handler, file_name:%s, index:%s, field:%s, rc:%s",
file_name,
index_meta.name(),
index_meta.field(),
strrc(rc));
return rc;
}
rc = index_handler_.open(file_name);
if (RC::SUCCESS == rc) {
inited_ = true;
}
return rc;
LOG_INFO(
"Successfully open index, file_name:%s, index:%s, field:%s", file_name, index_meta.name(), index_meta.field());
return RC::SUCCESS;
}
RC BplusTreeIndex::close() {
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());
index_handler_.close();
inited_ = false;
}
LOG_INFO("Successfully close index.");
return RC::SUCCESS;
}
RC BplusTreeIndex::insert_entry(const char *record, const RID *rid) {
RC BplusTreeIndex::insert_entry(const char *record, const RID *rid)
{
return index_handler_.insert_entry(record + field_meta_.offset(), rid);
}
RC BplusTreeIndex::delete_entry(const char *record, const RID *rid) {
RC BplusTreeIndex::delete_entry(const char *record, const RID *rid)
{
return index_handler_.delete_entry(record + field_meta_.offset(), rid);
}
IndexScanner *BplusTreeIndex::create_scanner(CompOp comp_op, const char *value) {
IndexScanner *BplusTreeIndex::create_scanner(CompOp comp_op, const char *value)
{
BplusTreeScanner *bplus_tree_scanner = new BplusTreeScanner(index_handler_);
RC rc = bplus_tree_scanner->open(comp_op, value);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to open index scanner. rc=%d:%s", rc, strrc(rc));
LOG_WARN("Failed to open index scanner. file_id:%d, rc=%d:%s", index_handler_.get_file_id(), rc, strrc(rc));
delete bplus_tree_scanner;
return nullptr;
}
......@@ -81,25 +114,28 @@ IndexScanner *BplusTreeIndex::create_scanner(CompOp comp_op, const char *value)
return index_scanner;
}
RC BplusTreeIndex::sync() {
RC BplusTreeIndex::sync()
{
return index_handler_.sync();
}
////////////////////////////////////////////////////////////////////////////////
BplusTreeIndexScanner::BplusTreeIndexScanner(BplusTreeScanner *tree_scanner) :
tree_scanner_(tree_scanner) {
}
BplusTreeIndexScanner::BplusTreeIndexScanner(BplusTreeScanner *tree_scanner) : tree_scanner_(tree_scanner)
{}
BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept {
BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept
{
tree_scanner_->close();
delete tree_scanner_;
}
RC BplusTreeIndexScanner::next_entry(RID *rid) {
RC BplusTreeIndexScanner::next_entry(RID *rid)
{
return tree_scanner_->next_entry(rid);
}
RC BplusTreeIndexScanner::destroy() {
RC BplusTreeIndexScanner::destroy()
{
delete this;
return RC::SUCCESS;
}
\ No newline at end of file
......@@ -25,23 +25,24 @@ See the Mulan PSL v2 for more details. */
#include "storage/common/table.h"
#include "storage/common/meta_util.h"
Db::~Db() {
Db::~Db()
{
for (auto &iter : opened_tables_) {
delete iter.second;
}
LOG_INFO("Db has been closed: %s", name_.c_str());
}
RC Db::init(const char *name, const char *dbpath) {
RC Db::init(const char *name, const char *dbpath)
{
if (nullptr == name || common::is_blank(name)) {
LOG_WARN("Name cannot be empty");
if (common::is_blank(name)) {
LOG_ERROR("Failed to init DB, name cannot be empty");
return RC::INVALID_ARGUMENT;
}
if (!common::is_directory(dbpath)) {
LOG_ERROR("Path is not a directory: %s", dbpath);
LOG_ERROR("Failed to init DB, path is not a directory: %s", dbpath);
return RC::GENERIC_ERROR;
}
......@@ -51,17 +52,21 @@ RC Db::init(const char *name, const char *dbpath) {
return open_all_tables();
}
RC Db::create_table(const char *table_name, int attribute_count, const AttrInfo *attributes) {
RC Db::create_table(const char *table_name, int attribute_count, const AttrInfo *attributes)
{
RC rc = RC::SUCCESS;
// check table_name
if (opened_tables_.count(table_name) != 0) {
LOG_WARN("%s has been opened before.", table_name);
return RC::SCHEMA_TABLE_EXIST;
}
std::string table_file_path = table_meta_file(path_.c_str(), table_name); // 文件路径可以移到Table模块
// 文件路径可以移到Table模块
std::string table_file_path = table_meta_file(path_.c_str(), table_name);
Table *table = new Table();
rc = table->create(table_file_path.c_str(), table_name, path_.c_str(), attribute_count, attributes);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to create table %s.", table_name);
delete table;
return rc;
}
......@@ -71,7 +76,8 @@ RC Db::create_table(const char *table_name, int attribute_count, const AttrInfo
return RC::SUCCESS;
}
Table *Db::find_table(const char *table_name) const {
Table *Db::find_table(const char *table_name) const
{
std::unordered_map<std::string, Table *>::const_iterator iter = opened_tables_.find(table_name);
if (iter != opened_tables_.end()) {
return iter->second;
......@@ -79,7 +85,8 @@ Table *Db::find_table(const char *table_name) const {
return nullptr;
}
RC Db::open_all_tables() {
RC Db::open_all_tables()
{
std::vector<std::string> table_meta_files;
int ret = common::list_file(path_.c_str(), TABLE_META_FILE_PATTERN, table_meta_files);
if (ret < 0) {
......@@ -100,7 +107,8 @@ RC Db::open_all_tables() {
if (opened_tables_.count(table->name()) != 0) {
delete table;
LOG_ERROR("Duplicate table with difference file name. table=%s, the other filename=%s",
table->name(), filename.c_str());
table->name(),
filename.c_str());
return RC::GENERIC_ERROR;
}
......@@ -112,26 +120,30 @@ RC Db::open_all_tables() {
return rc;
}
const char *Db::name() const {
const char *Db::name() const
{
return name_.c_str();
}
void Db::all_tables(std::vector<std::string> &table_names) const {
for (const auto &table_item: opened_tables_) {
void Db::all_tables(std::vector<std::string> &table_names) const
{
for (const auto &table_item : opened_tables_) {
table_names.emplace_back(table_item.first);
}
}
RC Db::sync() {
RC Db::sync()
{
RC rc = RC::SUCCESS;
for (const auto &table_pair: opened_tables_) {
for (const auto &table_pair : opened_tables_) {
Table *table = table_pair.second;
rc = table->sync();
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush table. table=%s.%s, rc=%d:%s", name_.c_str(), table->name(), rc, strrc(rc));
return rc;
}
LOG_INFO("Successfully sync table db:%s, table:%s.", name_.c_str(), table->name());
}
LOG_INFO("Sync db over. db=%s", name_.c_str());
LOG_INFO("Successfully sync db. db=%s", name_.c_str());
return rc;
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ See the Mulan PSL v2 for more details. */
// Created by Wangyunlai on 2021/5/12.
//
#include <common/lang/string.h>
#include "storage/common/field_meta.h"
#include "common/log/log.h"
......@@ -23,22 +24,19 @@ const static Json::StaticString FIELD_OFFSET("offset");
const static Json::StaticString FIELD_LEN("len");
const static Json::StaticString FIELD_VISIBLE("visible");
const char *ATTR_TYPE_NAME[] = {
"undefined",
"chars",
"ints",
"floats"
};
const char *ATTR_TYPE_NAME[] = {"undefined", "chars", "ints", "floats"};
const char *attr_type_to_string(AttrType type) {
const char *attr_type_to_string(AttrType type)
{
if (type >= UNDEFINED && type <= FLOATS) {
return ATTR_TYPE_NAME[type];
}
return "unknown";
}
AttrType attr_type_from_string(const char *s) {
for (unsigned int i = 0; i < sizeof(ATTR_TYPE_NAME)/sizeof(ATTR_TYPE_NAME[0]); i++) {
AttrType attr_type_from_string(const char *s)
{
for (unsigned int i = 0; i < sizeof(ATTR_TYPE_NAME) / sizeof(ATTR_TYPE_NAME[0]); i++) {
if (0 == strcmp(ATTR_TYPE_NAME[i], s)) {
return (AttrType)i;
}
......@@ -46,18 +44,19 @@ AttrType attr_type_from_string(const char *s) {
return UNDEFINED;
}
FieldMeta::FieldMeta() : attr_type_(AttrType::UNDEFINED), attr_offset_(-1), attr_len_(0), visible_(false) {
}
FieldMeta::FieldMeta() : attr_type_(AttrType::UNDEFINED), attr_offset_(-1), attr_len_(0), visible_(false)
{}
RC FieldMeta::init(const char *name, AttrType attr_type, int attr_offset, int attr_len, bool visible) {
if (nullptr == name || '\0' == name[0]) {
RC FieldMeta::init(const char *name, AttrType attr_type, int attr_offset, int attr_len, bool visible)
{
if (common::is_blank(name)) {
LOG_WARN("Name cannot be empty");
return RC::INVALID_ARGUMENT;
}
if (AttrType::UNDEFINED == attr_type || attr_offset < 0 || attr_len <= 0) {
LOG_WARN("Invalid argument. name=%s, attr_type=%d, attr_offset=%d, attr_len=%d",
name, attr_type, attr_offset, attr_len);
LOG_WARN(
"Invalid argument. name=%s, attr_type=%d, attr_offset=%d, attr_len=%d", name, attr_type, attr_offset, attr_len);
return RC::INVALID_ARGUMENT;
}
......@@ -71,34 +70,39 @@ RC FieldMeta::init(const char *name, AttrType attr_type, int attr_offset, int at
return RC::SUCCESS;
}
const char *FieldMeta::name() const {
const char *FieldMeta::name() const
{
return name_.c_str();
}
AttrType FieldMeta::type() const {
AttrType FieldMeta::type() const
{
return attr_type_;
}
int FieldMeta::offset() const {
int FieldMeta::offset() const
{
return attr_offset_;
}
int FieldMeta::len() const {
int FieldMeta::len() const
{
return attr_len_;
}
bool FieldMeta::visible() const {
bool FieldMeta::visible() const
{
return visible_;
}
void FieldMeta::desc(std::ostream &os) const {
os << "field name=" << name_
<< ", type=" << attr_type_to_string(attr_type_)
<< ", len=" << attr_len_
void FieldMeta::desc(std::ostream &os) const
{
os << "field name=" << name_ << ", type=" << attr_type_to_string(attr_type_) << ", len=" << attr_len_
<< ", visible=" << (visible_ ? "yes" : "no");
}
void FieldMeta::to_json(Json::Value &json_value) const {
void FieldMeta::to_json(Json::Value &json_value) const
{
json_value[FIELD_NAME] = name_;
json_value[FIELD_TYPE] = attr_type_to_string(attr_type_);
json_value[FIELD_OFFSET] = attr_offset_;
......@@ -106,10 +110,10 @@ void FieldMeta::to_json(Json::Value &json_value) const {
json_value[FIELD_VISIBLE] = visible_;
}
RC FieldMeta::from_json(const Json::Value &json_value, FieldMeta &field) {
RC FieldMeta::from_json(const Json::Value &json_value, FieldMeta &field)
{
if (!json_value.isObject()) {
LOG_ERROR("Failed to deserialize field. json is not an object. json value=%s",
json_value.toStyledString().c_str());
LOG_ERROR("Failed to deserialize field. json is not an object. json value=%s", json_value.toStyledString().c_str());
return RC::GENERIC_ERROR;
}
......
......@@ -24,6 +24,7 @@ namespace Json {
class Value;
} // namespace Json
// Take care of shallow copy
class FieldMeta {
public:
FieldMeta();
......@@ -40,11 +41,12 @@ public:
public:
void desc(std::ostream &os) const;
public:
void to_json(Json::Value &json_value) const;
static RC from_json(const Json::Value &json_value, FieldMeta &field);
private:
protected:
std::string name_;
AttrType attr_type_;
int attr_offset_;
......
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2021/4/13.
//
#include "storage/common/index_manager.h"
#include "rc.h"
RC createIndex(const char *fileName, AttrType attrType, int attrLength) {
//TODO
return RC::SUCCESS;
}
RC openIndex(const char *fileName, IndexHandle *indexHandle) {
//TODO
return RC::SUCCESS;
}
RC closeIndex(IndexHandle *indexHandle) {
//TODO
return RC::SUCCESS;
}
RC insertEntry(IndexHandle *indexHandle, void *data, const RID *rid) {
//TODO
return RC::SUCCESS;
}
RC deleteEntry(IndexHandle *indexHandle, void *data, const RID *rid) {
//TODO
return RC::SUCCESS;
}
RC openIndexScan(IndexScan *indexScan, IndexHandle *indexHandle,
CompOp compOp, char *value) {
//TODO
return RC::SUCCESS;
}
RC getNextIndexEntry(IndexScan *indexScan, RID *rid) {
//TODO
return RC::SUCCESS;
}
RC closeIndexScan(IndexScan *indexScan) {
//TODO
return RC::SUCCESS;
}
RC getIndexTree(char *fileName, Tree *index) {
//TODO
return RC::SUCCESS;
}
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by Longda on 2021/4/13.
//
#ifndef __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#define __OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
#include "handler/handler.h"
#include "storage/common/record_manager.h"
typedef struct {
int attrLength;
int keyLength;
AttrType attrType;
PageNum rootPage;
PageNum first_leaf;
int order;
} IndexFileHeader;
typedef struct {
bool open;
BPFileHandle fileHandle;
IndexFileHeader fileHeader;
} IndexHandle;
typedef struct {
int is_leaf;
int keynum;
PageNum parent;
PageNum brother;
char *keys;
RID *rids;
} IndexNode;
typedef struct {
bool open;
IndexHandle *pIXIndexHandle;
CompOp compOp;
char *value;
BPPageHandle pfPageHandles[BP_BUFFER_SIZE];
PageNum pnNext;
} IndexScan;
typedef struct TreeNode {
int keyNum;
char **keys;
TreeNode *parent;
TreeNode *sibling;
TreeNode *firstChild;
} TreeNode;
typedef struct {
AttrType attrType;
int attrLength;
int order;
TreeNode *root;
} Tree;
/**
* 此函数创建一个名为fileName的索引。
* attrType描述被索引属性的类型,attrLength描述被索引属性的长度
* @param fileName
* @param attrType
* @param attrLength
* @return
*/
RC createIndex(const char *fileName, AttrType attrType, int attrLength);
/**
* 打开名为fileName的索引文件。
* 如果方法调用成功,则indexHandle为指向被打开的索引句柄的指针。
* 索引句柄用于在索引中插入或删除索引项,也可用于索引的扫描
* @param fileName
* @param indexHandle
* @return
*/
RC openIndex(const char *fileName, IndexHandle *indexHandle);
/**
* 关闭句柄indexHandle对应的索引文件
* @param indexHandle
* @return
*/
RC closeIndex(IndexHandle *indexHandle);
/**
* 此函数向IndexHandle对应的索引中插入一个索引项。
* 参数pData指向要插入的属性值,参数rid标识该索引项对应的元组,
* 即向索引中插入一个值为(*pData,rid)的键值对
* @param indexHandle
* @param data
* @param rid
* @return
*/
RC insertEntry(IndexHandle *indexHandle, void *data, const RID *rid);
/**
* 从IndexHandle句柄对应的索引中删除一个值为(*pData,rid)的索引项
* @param indexHandle
* @param data
* @param rid
* @return
*/
RC deleteEntry(IndexHandle *indexHandle, void *data, const RID *rid);
/**
* 用于在indexHandle对应的索引上初始化一个基于条件的扫描。
* compOp和*value指定比较符和比较值,indexScan为初始化后的索引扫描结构指针
* @param indexScan
* @param indexHandle
* @param compOp
* @param value
* @return
*/
RC openIndexScan(IndexScan *indexScan, IndexHandle *indexHandle,
CompOp compOp, char *value);
/**
* 用于继续IndexScan句柄对应的索引扫描,获得下一个满足条件的索引项,
* 并返回该索引项对应的记录的ID
* @param indexScan
* @param rid
* @return
*/
RC getNextIndexEntry(IndexScan *indexScan, RID *rid);
/**
* 关闭一个索引扫描,释放相应的资源
* @param indexScan
* @return
*/
RC closeIndexScan(IndexScan *indexScan);
/**
* 获取由fileName指定的B+树索引内容,返回指向B+树的指针。
* 此函数提供给测试程序调用,用于检查B+树索引内容的正确性
* @param fileName
* @param index
* @return
*/
RC getIndexTree(char *fileName, Tree *index);
#endif //__OBSERVER_STORAGE_COMMON_INDEX_MANAGER_H_
......@@ -23,8 +23,10 @@ See the Mulan PSL v2 for more details. */
const static Json::StaticString FIELD_NAME("name");
const static Json::StaticString FIELD_FIELD_NAME("field_name");
RC IndexMeta::init(const char *name, const FieldMeta &field) {
if (nullptr == name || common::is_blank(name)) {
RC IndexMeta::init(const char *name, const FieldMeta &field)
{
if (common::is_blank(name)) {
LOG_ERROR("Failed to init index, name is empty.");
return RC::INVALID_ARGUMENT;
}
......@@ -33,12 +35,14 @@ RC IndexMeta::init(const char *name, const FieldMeta &field) {
return RC::SUCCESS;
}
void IndexMeta::to_json(Json::Value &json_value) const {
void IndexMeta::to_json(Json::Value &json_value) const
{
json_value[FIELD_NAME] = name_;
json_value[FIELD_FIELD_NAME] = field_;
}
RC IndexMeta::from_json(const TableMeta &table, const Json::Value &json_value, IndexMeta &index) {
RC IndexMeta::from_json(const TableMeta &table, const Json::Value &json_value, IndexMeta &index)
{
const Json::Value &name_value = json_value[FIELD_NAME];
const Json::Value &field_value = json_value[FIELD_FIELD_NAME];
if (!name_value.isString()) {
......@@ -48,7 +52,8 @@ RC IndexMeta::from_json(const TableMeta &table, const Json::Value &json_value, I
if (!field_value.isString()) {
LOG_ERROR("Field name of index [%s] is not a string. json value=%s",
name_value.asCString(), field_value.toStyledString().c_str());
name_value.asCString(),
field_value.toStyledString().c_str());
return RC::GENERIC_ERROR;
}
......@@ -61,15 +66,17 @@ RC IndexMeta::from_json(const TableMeta &table, const Json::Value &json_value, I
return index.init(name_value.asCString(), *field);
}
const char *IndexMeta::name() const {
const char *IndexMeta::name() const
{
return name_.c_str();
}
const char *IndexMeta::field() const {
const char *IndexMeta::field() const
{
return field_.c_str();
}
void IndexMeta::desc(std::ostream &os) const {
os << "index name=" << name_
<< ", field=" << field_;
void IndexMeta::desc(std::ostream &os) const
{
os << "index name=" << name_ << ", field=" << field_;
}
\ No newline at end of file
......@@ -36,12 +36,13 @@ public:
const char *field() const;
void desc(std::ostream &os) const;
public:
void to_json(Json::Value &json_value) const;
static RC from_json(const TableMeta &table, const Json::Value &json_value, IndexMeta &index);
private:
std::string name_;
std::string field_;
protected:
std::string name_; // index's name
std::string field_; // field's name
};
#endif // __OBSERVER_STORAGE_COMMON_INDEX_META_H__
\ No newline at end of file
......@@ -11,13 +11,19 @@ See the Mulan PSL v2 for more details. */
// Created by wangyunlai.wyl on 2021/5/18.
//
#include "common/defs.h"
#include "storage/common/meta_util.h"
std::string table_meta_file(const char *base_dir, const char *table_name) {
return std::string(base_dir) + "/" + table_name + TABLE_META_SUFFIX;
std::string table_meta_file(const char *base_dir, const char *table_name)
{
return std::string(base_dir) + common::FILE_PATH_SPLIT_STR + table_name + TABLE_META_SUFFIX;
}
std::string index_data_file(const char *base_dir, const char *table_name, const char *index_name) {
return std::string(base_dir) + "/" + table_name + "-" + index_name + TABLE_INDEX_SUFFIX;
std::string table_data_file(const char *base_dir, const char *table_name)
{
return std::string(base_dir) + common::FILE_PATH_SPLIT_STR + table_name + TABLE_DATA_SUFFIX;
}
std::string table_index_file(const char *base_dir, const char *table_name, const char *index_name)
{
return std::string(base_dir) + common::FILE_PATH_SPLIT_STR + table_name + "-" + index_name + TABLE_INDEX_SUFFIX;
}
......@@ -22,6 +22,7 @@ static const char *TABLE_DATA_SUFFIX = ".data";
static const char *TABLE_INDEX_SUFFIX = ".index";
std::string table_meta_file(const char *base_dir, const char *table_name);
std::string index_data_file(const char *base_dir, const char *table_name, const char *index_name);
std::string table_data_file(const char *base_dir, const char *table_name);
std::string table_index_file(const char *base_dir, const char *table_name, const char *index_name);
#endif //__OBSERVER_STORAGE_COMMON_META_UTIL_H_
......@@ -19,64 +19,56 @@ See the Mulan PSL v2 for more details. */
using namespace common;
struct PageHeader {
int record_num; // 当前页面记录的个数
int record_capacity; // 最大记录个数
int record_real_size; // 每条记录的实际大小
int record_size; // 每条记录占用实际空间大小(可能对齐)
int first_record_offset; // 第一条记录的偏移量
};
int align8(int size) {
int align8(int size)
{
return size / 8 * 8 + ((size % 8 == 0) ? 0 : 8);
}
int page_fix_size() {
return sizeof(PageHeader::record_num)
+ sizeof(PageHeader::record_capacity)
+ sizeof(PageHeader::record_real_size)
+ sizeof(PageHeader::record_size)
+ sizeof(PageHeader::first_record_offset);
int page_fix_size()
{
return sizeof(PageHeader);
}
int page_record_capacity(int page_size, int record_size) {
int page_record_capacity(int page_size, int record_size)
{
// (record_capacity * record_size) + record_capacity/8 + 1 <= (page_size - fix_size)
// ==> record_capacity = ((page_size - fix_size) - 1) / (record_size + 0.125)
return (int)((page_size - page_fix_size() - 1) / (record_size + 0.125));
}
int page_bitmap_size(int record_capacity) {
int page_bitmap_size(int record_capacity)
{
return record_capacity / 8 + ((record_capacity % 8 == 0) ? 0 : 1);
}
int page_header_size(int record_capacity) {
int page_header_size(int record_capacity)
{
const int bitmap_size = page_bitmap_size(record_capacity);
return align8(page_fix_size() + bitmap_size);
}
////////////////////////////////////////////////////////////////////////////////
RecordPageHandler::RecordPageHandler() :
disk_buffer_pool_(nullptr),
file_id_(-1),
page_header_(nullptr),
bitmap_(nullptr) {
RecordPageHandler::RecordPageHandler()
: disk_buffer_pool_(nullptr), file_id_(-1), page_header_(nullptr), bitmap_(nullptr)
{
page_handle_.open = false;
page_handle_.frame = nullptr;
}
RecordPageHandler::~RecordPageHandler() {
deinit();
RecordPageHandler::~RecordPageHandler()
{
cleanup();
}
RC RecordPageHandler::init(DiskBufferPool &buffer_pool, int file_id, PageNum page_num) {
RC RecordPageHandler::init(DiskBufferPool &buffer_pool, int file_id, 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 file_id:page_num %d:%d.", file_id, 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. ret=%d:%s", ret, strrc(ret));
LOG_ERROR("Failed to get page handle from disk buffer pool. file_id:%d, ret=%d:%s", file_id, ret, strrc(ret));
return ret;
}
......@@ -90,17 +82,17 @@ RC RecordPageHandler::init(DiskBufferPool &buffer_pool, int file_id, PageNum pag
disk_buffer_pool_ = &buffer_pool;
file_id_ = file_id;
page_header_ = (PageHeader*)(data);
page_header_ = (PageHeader *)(data);
bitmap_ = data + page_fix_size();
LOG_TRACE("Successfully init file_id:page_num %d:%d.", file_id, 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, int file_id, PageNum page_num, int record_size)
{
RC ret = init(buffer_pool, file_id, 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 file_id:page_num:record_size %d:%d:%d.", file_id, page_num, record_size);
return ret;
}
......@@ -114,36 +106,28 @@ RC RecordPageHandler::init_empty_page(DiskBufferPool &buffer_pool, int file_id,
bitmap_ = page_handle_.frame->page.data + page_fix_size();
memset(bitmap_, 0, page_bitmap_size(page_header_->record_capacity));
ret = disk_buffer_pool_->mark_dirty(&page_handle_);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to mark page dirty. ret=%s", strrc(ret));
}
disk_buffer_pool_->mark_dirty(&page_handle_);
return RC::SUCCESS;
}
RC RecordPageHandler::deinit() {
// if (page_header_ != nullptr) {
// disk_buffer_pool_->unpin_page(&page_handle_);
// disk_buffer_pool_->force_page(file_id_, page_handle_.frame->page.page_num);
// page_header_ = nullptr;
// }
RC RecordPageHandler::cleanup()
{
if (disk_buffer_pool_ != nullptr) {
RC rc = disk_buffer_pool_->unpin_page(&page_handle_);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to unpin page when deinit record page handler. rc=%s", strrc(rc));
}
disk_buffer_pool_->unpin_page(&page_handle_);
disk_buffer_pool_ = nullptr;
// skip purge page,
// skip reset page_header & bitmap
}
return RC::SUCCESS;
}
RC RecordPageHandler::insert_record(const char *data, RID *rid) {
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, file_id:page_num %d:%d.", file_id_, page_handle_.frame->page.page_num);
return RC::RECORD_NOMEM;
}
......@@ -154,28 +138,22 @@ RC RecordPageHandler::insert_record(const char *data, RID *rid) {
page_header_->record_num++;
// assert index < page_header_->record_capacity
char *record_data = page_handle_.frame->page.data +
page_header_->first_record_offset + (index * page_header_->record_size);
char *record_data = get_record_data(index);
memcpy(record_data, data, page_header_->record_real_size);
RC rc = disk_buffer_pool_->mark_dirty(&page_handle_);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to mark page dirty. rc =%d:%s", rc, strrc(rc));
// hard to rollback
}
disk_buffer_pool_->mark_dirty(&page_handle_);
if (rid) {
rid->page_num = get_page_num();
rid->slot_num = index;
}
LOG_TRACE("Insert record. rid page_num=%d, slot num=%d", get_page_num(), index);
// LOG_TRACE("Insert record. rid page_num=%d, slot num=%d", get_page_num(), index);
return RC::SUCCESS;
}
RC RecordPageHandler::update_record(const Record *rec) {
RC ret = RC::SUCCESS;
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,
......@@ -190,24 +168,19 @@ RC RecordPageHandler::update_record(const Record *rec) {
rec->rid.slot_num,
file_id_,
page_handle_.frame->page.page_num);
ret = RC::RECORD_RECORD_NOT_EXIST;
return RC::RECORD_RECORD_NOT_EXIST;
} else {
char *record_data = page_handle_.frame->page.data +
page_header_->first_record_offset + (rec->rid.slot_num * page_header_->record_size);
char *record_data = get_record_data(rec->rid.slot_num);
memcpy(record_data, rec->data, page_header_->record_real_size);
ret = disk_buffer_pool_->mark_dirty(&page_handle_);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to mark page dirty. ret=%s", strrc(ret));
}
bitmap.set_bit(rec->rid.slot_num);
disk_buffer_pool_->mark_dirty(&page_handle_);
// 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;
}
LOG_TRACE("Update record. page num=%d,slot=%d", rec->rid.page_num, rec->rid.slot_num);
return ret;
}
RC RecordPageHandler::delete_record(const RID *rid) {
RC ret = RC::SUCCESS;
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,
......@@ -220,30 +193,27 @@ RC RecordPageHandler::delete_record(const RID *rid) {
if (bitmap.get_bit(rid->slot_num)) {
bitmap.clear_bit(rid->slot_num);
page_header_->record_num--;
ret = disk_buffer_pool_->mark_dirty(&page_handle_);
if (ret != RC::SUCCESS) {
LOG_ERROR("failed to mark page dirty in delete record. ret=%d:%s", ret, strrc(ret));
// hard to rollback
}
disk_buffer_pool_->mark_dirty(&page_handle_);
if (page_header_->record_num == 0) {
DiskBufferPool *disk_buffer_pool = disk_buffer_pool_;
int file_id = file_id_;
PageNum page_num = get_page_num();
deinit();
cleanup();
disk_buffer_pool->dispose_page(file_id, 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);
ret = RC::RECORD_RECORD_NOT_EXIST;
return RC::RECORD_RECORD_NOT_EXIST;
}
return ret;
}
RC RecordPageHandler::get_record(const RID *rid, Record *rec) {
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,
......@@ -261,21 +231,19 @@ RC RecordPageHandler::get_record(const RID *rid, Record *rec) {
return RC::RECORD_RECORD_NOT_EXIST;
}
char *data = page_handle_.frame->page.data +
page_header_->first_record_offset + (page_header_->record_size * rid->slot_num);
// rec->valid = true;
rec->rid = *rid;
rec->data = data;
rec->data = get_record_data(rid->slot_num);
return RC::SUCCESS;
}
RC RecordPageHandler::get_first_record(Record *rec) {
RC RecordPageHandler::get_first_record(Record *rec)
{
rec->rid.slot_num = -1;
return get_next_record(rec);
}
RC RecordPageHandler::get_next_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,
......@@ -288,77 +256,73 @@ RC RecordPageHandler::get_next_record(Record *rec) {
int index = bitmap.next_setted_bit(rec->rid.slot_num + 1);
if (index < 0) {
LOG_TRACE("There is no empty slot, file_id:page_num %d:%d.",
file_id_,
page_handle_.frame->page.page_num);
LOG_WARN("There is no empty slot on page -- file_id:%d, page_num:%d.", file_id_, page_handle_.frame->page.page_num);
return RC::RECORD_EOF;
}
rec->rid.page_num = get_page_num();
rec->rid.slot_num = index;
// rec->valid = true;
char *record_data = page_handle_.frame->page.data +
page_header_->first_record_offset + (index * page_header_->record_size);
rec->data = record_data;
rec->data = get_record_data(index);
return RC::SUCCESS;
}
PageNum RecordPageHandler::get_page_num() const {
PageNum RecordPageHandler::get_page_num() const
{
if (nullptr == page_header_) {
return (PageNum)(-1);
}
return page_handle_.frame->page.page_num;
}
bool RecordPageHandler::is_full() const {
bool RecordPageHandler::is_full() const
{
return page_header_->record_num >= page_header_->record_capacity;
}
////////////////////////////////////////////////////////////////////////////////
RecordFileHandler::RecordFileHandler() :
disk_buffer_pool_(nullptr),
file_id_(-1) {
}
RC RecordFileHandler::init(DiskBufferPool &buffer_pool, int file_id) {
RecordFileHandler::RecordFileHandler() : disk_buffer_pool_(nullptr), file_id_(-1)
{}
RC ret = RC::SUCCESS;
RC RecordFileHandler::init(DiskBufferPool *buffer_pool, int file_id)
{
if (disk_buffer_pool_ != nullptr) {
LOG_ERROR("%d has been openned.", file_id);
return RC::RECORD_OPENNED;
}
disk_buffer_pool_ = &buffer_pool;
disk_buffer_pool_ = buffer_pool;
file_id_ = file_id;
LOG_TRACE("Successfully open %d.", file_id);
return ret;
LOG_INFO("Successfully open %d.", file_id);
return RC::SUCCESS;
}
void RecordFileHandler::close() {
void RecordFileHandler::close()
{
if (disk_buffer_pool_ != nullptr) {
disk_buffer_pool_ = nullptr;
}
}
RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid) {
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");
LOG_ERROR("Failed to get page count while inserting record, file_id:%d", this->file_id_);
return ret;
}
PageNum current_page_num = record_page_handler_.get_page_num();
if (current_page_num < 0) {
if (page_count >= 2) { // 当前buffer pool 有页面时才尝试加载第一页
// 参考diskBufferPool,pageNum从1开始
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.ret=%d", ret);
LOG_ERROR("Failed to init record page handler, file_id:%d, ret=%d", file_id_, ret);
return ret;
}
current_page_num = record_page_handler_.get_page_num();
......@@ -374,10 +338,11 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
continue;
}
if (current_page_num != record_page_handler_.get_page_num()) {
record_page_handler_.deinit();
record_page_handler_.cleanup();
ret = record_page_handler_.init(*disk_buffer_pool_, file_id_, 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;
}
}
......@@ -392,13 +357,12 @@ 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);
LOG_ERROR("Failed to allocate page while inserting record. file_it:%d, ret:%d", file_id_, ret);
return ret;
}
current_page_num = page_handle.frame->page.page_num;
record_page_handler_.deinit();
record_page_handler_.cleanup();
ret = record_page_handler_.init_empty_page(*disk_buffer_pool_, file_id_, current_page_num, record_size);
if (ret != RC::SUCCESS) {
LOG_ERROR("Failed to init empty page. file_id:%d, ret:%d", file_id_, ret);
......@@ -407,52 +371,64 @@ RC RecordFileHandler::insert_record(const char *data, int record_size, RID *rid)
}
return ret;
}
if (RC::SUCCESS != disk_buffer_pool_->unpin_page(&page_handle)) {
LOG_ERROR("Failed to unpin page. file_id:%d", file_id_);
}
//@@@ 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_);
// }
}
// 找到空闲位置
return record_page_handler_.insert_record(data, rid);
}
RC RecordFileHandler::update_record(const Record *rec) {
RC ret = RC::SUCCESS;
RC RecordFileHandler::update_record(const Record *rec)
{
if (record_page_handler_.get_page_num() == rec->rid.page_num) {
return record_page_handler_.update_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_, 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_);
return ret;
}
return page_handler.update_record(rec);
}
RC RecordFileHandler::delete_record(const RID *rid) {
RC RecordFileHandler::delete_record(const RID *rid)
{
if (record_page_handler_.get_page_num() == rid->page_num) {
return record_page_handler_.delete_record(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_);
LOG_ERROR("Failed to init record page handler.page number=%d, file_id:%d", rid->page_num, file_id_);
return ret;
}
return page_handler.delete_record(rid);
}
RC RecordFileHandler::get_record(const RID *rid, Record *rec) {
//lock?
RC RecordFileHandler::get_record(const RID *rid, Record *rec)
{
// lock?
RC ret = RC::SUCCESS;
if (nullptr == rid || nullptr == rec) {
LOG_ERROR("Invalid rid %p or rec %p, one of them is null. ", rid, rec);
return RC::INVALID_ARGUMENT;
}
if (record_page_handler_.get_page_num() == rid->page_num) {
return record_page_handler_.get_record(rid, 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_);
LOG_ERROR("Failed to init record page handler.page number=%d, file_id:%d", rid->page_num, file_id_);
return ret;
}
......@@ -461,13 +437,10 @@ RC RecordFileHandler::get_record(const RID *rid, Record *rec) {
////////////////////////////////////////////////////////////////////////////////
RecordFileScanner::RecordFileScanner() :
disk_buffer_pool_(nullptr),
file_id_(-1),
condition_filter_(nullptr) {
}
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, int file_id, ConditionFilter *condition_filter)
{
close_scan();
......@@ -478,7 +451,8 @@ RC RecordFileScanner::open_scan(DiskBufferPool & buffer_pool, int file_id, Condi
return RC::SUCCESS;
}
RC RecordFileScanner::close_scan() {
RC RecordFileScanner::close_scan()
{
if (disk_buffer_pool_ != nullptr) {
disk_buffer_pool_ = nullptr;
}
......@@ -490,14 +464,16 @@ RC RecordFileScanner::close_scan() {
return RC::SUCCESS;
}
RC RecordFileScanner::get_first_record(Record *rec) {
RC RecordFileScanner::get_first_record(Record *rec)
{
rec->rid.page_num = 1; // from 1 参考DiskBufferPool
rec->rid.slot_num = -1;
// rec->valid = false;
return get_next_record(rec);
}
RC RecordFileScanner::get_next_record(Record *rec) {
RC RecordFileScanner::get_next_record(Record *rec)
{
if (nullptr == disk_buffer_pool_) {
LOG_ERROR("Scanner has been closed.");
return RC::RECORD_CLOSED;
......@@ -519,7 +495,7 @@ RC RecordFileScanner::get_next_record(Record *rec) {
while (current_record.rid.page_num < page_count) {
if (current_record.rid.page_num != record_page_handler_.get_page_num()) {
record_page_handler_.deinit();
record_page_handler_.cleanup();
ret = record_page_handler_.init(*disk_buffer_pool_, file_id_, 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);
......
......@@ -14,32 +14,60 @@ See the Mulan PSL v2 for more details. */
#ifndef __OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_
#define __OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_
#include <sstream>
#include "storage/default/disk_buffer_pool.h"
typedef int SlotNum;
struct PageHeader;
class ConditionFilter;
struct RID
{
struct PageHeader {
int record_num; // 当前页面记录的个数
int record_capacity; // 最大记录个数
int record_real_size; // 每条记录的实际大小
int record_size; // 每条记录占用实际空间大小(可能对齐)
int first_record_offset; // 第一条记录的偏移量
};
struct RID {
PageNum page_num; // record's page number
SlotNum slot_num; // record's slot number
// bool valid; // true means a valid record
bool operator== (const RID &other) const {
const std::string to_string() const
{
std::stringstream ss;
ss << "PageNum:" << page_num << ", SlotNum:" << slot_num;
return ss.str();
}
bool operator==(const RID &other) const
{
return page_num == other.page_num && slot_num == other.slot_num;
}
static int compare(const RID *rid1, const RID *rid2)
{
int page_diff = rid1->page_num - rid2->page_num;
if (page_diff != 0) {
return page_diff;
} else {
return rid1->slot_num - rid2->slot_num;
}
}
};
class RidDigest {
public:
size_t operator() (const RID &rid) const {
size_t operator()(const RID &rid) const
{
return ((size_t)(rid.page_num) << 32) | rid.slot_num;
}
};
struct Record
{
struct Record {
// bool valid; // false means the record hasn't been load
RID rid; // record's rid
char *data; // record's data
......@@ -51,13 +79,14 @@ public:
~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 deinit();
RC cleanup();
RC insert_record(const char *data, RID *rid);
RC update_record(const Record *rec);
template <class RecordUpdater>
RC update_record_in_place(const RID *rid, RecordUpdater updater) {
RC update_record_in_place(const RID *rid, RecordUpdater updater)
{
Record record;
RC rc = get_record(rid, &record);
if (rc != RC::SUCCESS) {
......@@ -78,18 +107,24 @@ public:
bool is_full() const;
private:
DiskBufferPool * disk_buffer_pool_;
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);
}
protected:
DiskBufferPool *disk_buffer_pool_;
int file_id_;
BPPageHandle page_handle_;
PageHeader * page_header_;
char * bitmap_;
PageHeader *page_header_;
char *bitmap_;
};
class RecordFileHandler {
public:
RecordFileHandler();
RC init(DiskBufferPool &buffer_pool, int file_id);
RC init(DiskBufferPool *buffer_pool, int file_id);
void close();
/**
......@@ -123,8 +158,9 @@ public:
*/
RC get_record(const RID *rid, Record *rec);
template<class RecordUpdater> // 改成普通模式, 不使用模板
RC update_record_in_place(const RID *rid, RecordUpdater updater) {
template <class RecordUpdater> // 改成普通模式, 不使用模板
RC update_record_in_place(const RID *rid, RecordUpdater updater)
{
RC rc = RC::SUCCESS;
RecordPageHandler page_handler;
......@@ -136,14 +172,13 @@ public:
}
private:
DiskBufferPool * disk_buffer_pool_;
DiskBufferPool *disk_buffer_pool_;
int file_id_; // 参考DiskBufferPool中的fileId
RecordPageHandler record_page_handler_; // 目前只有insert record使用
};
class RecordFileScanner
{
class RecordFileScanner {
public:
RecordFileScanner();
......@@ -160,7 +195,7 @@ public:
* @param conditions
* @return
*/
RC open_scan(DiskBufferPool & buffer_pool, int file_id, ConditionFilter *condition_filter);
RC open_scan(DiskBufferPool &buffer_pool, int file_id, ConditionFilter *condition_filter);
/**
* 关闭一个文件扫描,释放相应的资源
......@@ -180,13 +215,11 @@ public:
RC get_next_record(Record *rec);
private:
DiskBufferPool * disk_buffer_pool_;
DiskBufferPool *disk_buffer_pool_;
int file_id_; // 参考DiskBufferPool中的fileId
ConditionFilter * condition_filter_;
ConditionFilter *condition_filter_;
RecordPageHandler record_page_handler_;
};
#endif //__OBSERVER_STORAGE_COMMON_RECORD_MANAGER_H_
\ No newline at end of file
......@@ -16,6 +16,7 @@ See the Mulan PSL v2 for more details. */
#include <string.h>
#include <algorithm>
#include "common/defs.h"
#include "storage/common/table.h"
#include "storage/common/table_meta.h"
#include "common/log/log.h"
......@@ -28,35 +29,42 @@ See the Mulan PSL v2 for more details. */
#include "storage/common/bplus_tree_index.h"
#include "storage/trx/trx.h"
Table::Table() :
data_buffer_pool_(nullptr),
file_id_(-1),
record_handler_(nullptr) {
}
Table::Table() : data_buffer_pool_(nullptr), file_id_(-1), record_handler_(nullptr)
{}
Table::~Table() {
Table::~Table()
{
if (record_handler_ != nullptr) {
delete record_handler_;
record_handler_ = nullptr;
}
if (data_buffer_pool_ != nullptr && file_id_ >= 0) {
data_buffer_pool_->close_file(file_id_);
data_buffer_pool_ = nullptr;
}
for (std::vector<Index *>::iterator it = indexes_.begin(); it != indexes_.end(); ++it) {
Index *index = *it;
delete index;
}
indexes_.clear();
LOG_INFO("Table has been closed: %s", name());
}
RC Table::create(const char *path, const char *name, const char *base_dir, int attribute_count, const AttrInfo attributes[]) {
RC Table::create(
const char *path, const char *name, const char *base_dir, int attribute_count, const AttrInfo attributes[])
{
if (nullptr == name || common::is_blank(name)) {
if (common::is_blank(name)) {
LOG_WARN("Name cannot be empty");
return RC::INVALID_ARGUMENT;
}
LOG_INFO("Begin to create table %s:%s", base_dir, name);
if (attribute_count <= 0 || nullptr == attributes) {
LOG_WARN("Invalid arguments. table_name=%s, attribute_count=%d, attributes=%p",
name, attribute_count, attributes);
LOG_WARN("Invalid arguments. table_name=%s, attribute_count=%d, attributes=%p", name, attribute_count, attributes);
return RC::INVALID_ARGUMENT;
}
......@@ -64,16 +72,13 @@ RC Table::create(const char *path, const char *name, const char *base_dir, int a
// 使用 table_name.table记录一个表的元数据
// 判断表文件是否已经存在
int fd = ::open(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
if (-1 == fd) {
if (fd < 0) {
if (EEXIST == errno) {
LOG_ERROR("Failed to create table file, it has been created. %s, EEXIST, %s",
path, strerror(errno));
LOG_ERROR("Failed to create table file, it has been created. %s, EEXIST, %s", path, strerror(errno));
return RC::SCHEMA_TABLE_EXIST;
}
LOG_ERROR("Create table file failed. filename=%s, errmsg=%d:%s",
path, errno, strerror(errno));
LOG_ERROR("Create table file failed. filename=%s, errmsg=%d:%s", path, errno, strerror(errno));
return RC::IOERR;
}
......@@ -96,7 +101,7 @@ RC Table::create(const char *path, const char *name, const char *base_dir, int a
table_meta_.serialize(fs);
fs.close();
std::string data_file = std::string(base_dir) + "/" + name + TABLE_DATA_SUFFIX;
std::string data_file = table_data_file(base_dir, name);
data_buffer_pool_ = theGlobalDiskBufferPool();
rc = data_buffer_pool_->create_file(data_file.c_str());
if (rc != RC::SUCCESS) {
......@@ -105,29 +110,41 @@ RC Table::create(const char *path, const char *name, const char *base_dir, int a
}
rc = init_record_handler(base_dir);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to create table %s due to init record handler failed.", data_file.c_str());
// don't need to remove the data_file
return rc;
}
base_dir_ = base_dir;
LOG_INFO("Successfully create table %s:%s", base_dir, name);
return rc;
}
RC Table::open(const char *meta_file, const char *base_dir) {
RC Table::open(const char *meta_file, const char *base_dir)
{
// 加载元数据文件
std::fstream fs;
std::string meta_file_path = std::string(base_dir) + "/" + meta_file;
std::string meta_file_path = std::string(base_dir) + common::FILE_PATH_SPLIT_STR + meta_file;
fs.open(meta_file_path, std::ios_base::in | std::ios_base::binary);
if (!fs.is_open()) {
LOG_ERROR("Failed to open meta file for read. file name=%s, errmsg=%s", meta_file, strerror(errno));
LOG_ERROR("Failed to open meta file for read. file name=%s, errmsg=%s", meta_file_path.c_str(), strerror(errno));
return RC::IOERR;
}
if (table_meta_.deserialize(fs) < 0) {
LOG_ERROR("Failed to deserialize table meta. file name=%s", meta_file);
LOG_ERROR("Failed to deserialize table meta. file name=%s", meta_file_path.c_str());
fs.close();
return RC::GENERIC_ERROR;
}
fs.close();
// 加载数据文件
RC rc = init_record_handler(base_dir);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to open table %s due to init record handler failed.", base_dir);
// don't need to remove the data_file
return rc;
}
base_dir_ = base_dir;
......@@ -136,18 +153,28 @@ RC Table::open(const char *meta_file, const char *base_dir) {
const IndexMeta *index_meta = table_meta_.index(i);
const FieldMeta *field_meta = table_meta_.field(index_meta->field());
if (field_meta == nullptr) {
LOG_PANIC("Found invalid index meta info which has a non-exists field. table=%s, index=%s, field=%s",
name(), index_meta->name(), index_meta->field());
LOG_ERROR("Found invalid index meta info which has a non-exists field. table=%s, index=%s, field=%s",
name(),
index_meta->name(),
index_meta->field());
// skip cleanup
// do all cleanup action in destructive Table function
return RC::GENERIC_ERROR;
}
BplusTreeIndex *index = new BplusTreeIndex();
std::string index_file = index_data_file(base_dir, name(), index_meta->name());
std::string index_file = table_index_file(base_dir, name(), index_meta->name());
rc = index->open(index_file.c_str(), *index_meta, *field_meta);
if (rc != RC::SUCCESS) {
delete index;
LOG_ERROR("Failed to open index. table=%s, index=%s, file=%s, rc=%d:%s",
name(), index_meta->name(), index_file.c_str(), rc, strrc(rc));
name(),
index_meta->name(),
index_file.c_str(),
rc,
strrc(rc));
// skip cleanup
// do all cleanup action in destructive Table function.
return rc;
}
indexes_.push_back(index);
......@@ -155,21 +182,25 @@ RC Table::open(const char *meta_file, const char *base_dir) {
return rc;
}
RC Table::commit_insert(Trx *trx, const RID &rid) {
RC Table::commit_insert(Trx *trx, const RID &rid)
{
Record record;
RC rc = record_handler_->get_record(&rid, &record);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to get record %s: %s", this->name(), rid.to_string().c_str());
return rc;
}
return trx->commit_insert(this, record);
}
RC Table::rollback_insert(Trx *trx, const RID &rid) {
RC Table::rollback_insert(Trx *trx, const RID &rid)
{
Record record;
RC rc = record_handler_->get_record(&rid, &record);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to get record %s: %s", this->name(), rid.to_string().c_str());
return rc;
}
......@@ -177,14 +208,19 @@ RC Table::rollback_insert(Trx *trx, const RID &rid) {
rc = delete_entry_of_indexes(record.data, rid, false);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to delete indexes of record(rid=%d.%d) while rollback insert, rc=%d:%s",
rid.page_num, rid.slot_num, rc, strrc(rc));
} else {
rc = record_handler_->delete_record(&rid);
rid.page_num,
rid.slot_num,
rc,
strrc(rc));
return rc;
}
rc = record_handler_->delete_record(&rid);
return rc;
}
RC Table::insert_record(Trx *trx, Record *record) {
RC Table::insert_record(Trx *trx, Record *record)
{
RC rc = RC::SUCCESS;
if (trx != nullptr) {
......@@ -203,8 +239,10 @@ RC Table::insert_record(Trx *trx, Record *record) {
RC rc2 = record_handler_->delete_record(&record->rid);
if (rc2 != RC::SUCCESS) {
LOG_PANIC("Failed to rollback record data when insert index entries failed. table name=%s, rc=%d:%s",
name(), rc2, strrc(rc2));
LOG_ERROR("Failed to rollback record data when insert index entries failed. table name=%s, rc=%d:%s",
name(),
rc2,
strrc(rc2));
}
return rc;
}
......@@ -214,21 +252,26 @@ RC Table::insert_record(Trx *trx, Record *record) {
if (rc != RC::SUCCESS) {
RC rc2 = delete_entry_of_indexes(record->data, record->rid, true);
if (rc2 != RC::SUCCESS) {
LOG_PANIC("Failed to rollback index data when insert index entries failed. table name=%s, rc=%d:%s",
name(), rc2, strrc(rc2));
LOG_ERROR("Failed to rollback index data when insert index entries failed. table name=%s, rc=%d:%s",
name(),
rc2,
strrc(rc2));
}
rc2 = record_handler_->delete_record(&record->rid);
if (rc2 != RC::SUCCESS) {
LOG_PANIC("Failed to rollback record data when insert index entries failed. table name=%s, rc=%d:%s",
name(), rc2, strrc(rc2));
name(),
rc2,
strrc(rc2));
}
return rc;
}
return rc;
}
RC Table::insert_record(Trx *trx, int value_num, const Value *values) {
if (value_num <= 0 || nullptr == values ) {
LOG_ERROR("Invalid argument. value num=%d, values=%p", value_num, values);
RC Table::insert_record(Trx *trx, int value_num, const Value *values)
{
if (value_num <= 0 || nullptr == values) {
LOG_ERROR("Invalid argument. table name: %s, value num=%d, values=%p", name(), value_num, values);
return RC::INVALID_ARGUMENT;
}
......@@ -247,17 +290,21 @@ RC Table::insert_record(Trx *trx, int value_num, const Value *values) {
return rc;
}
const char *Table::name() const {
const char *Table::name() const
{
return table_meta_.name();
}
const TableMeta &Table::table_meta() const {
const TableMeta &Table::table_meta() const
{
return table_meta_;
}
RC Table::make_record(int value_num, const Value *values, char * &record_out) {
RC Table::make_record(int value_num, const Value *values, char *&record_out)
{
// 检查字段类型是否一致
if (value_num + table_meta_.sys_field_num() != table_meta_.field_num()) {
LOG_WARN("Input values don't match the table's schema, table name:%s", table_meta_.name());
return RC::SCHEMA_FIELD_MISSING;
}
......@@ -266,15 +313,18 @@ RC Table::make_record(int value_num, const Value *values, char * &record_out) {
const FieldMeta *field = table_meta_.field(i + normal_field_start_index);
const Value &value = values[i];
if (field->type() != value.type) {
LOG_ERROR("Invalid value type. field name=%s, type=%d, but given=%d",
field->name(), field->type(), value.type);
LOG_ERROR("Invalid value type. table name =%s, field name=%s, type=%d, but given=%d",
table_meta_.name(),
field->name(),
field->type(),
value.type);
return RC::SCHEMA_FIELD_TYPE_MISMATCH;
}
}
// 复制所有字段的值
int record_size = table_meta_.record_size();
char *record = new char [record_size];
char *record = new char[record_size];
for (int i = 0; i < value_num; i++) {
const FieldMeta *field = table_meta_.field(i + normal_field_start_index);
......@@ -286,8 +336,9 @@ RC Table::make_record(int value_num, const Value *values, char * &record_out) {
return RC::SUCCESS;
}
RC Table::init_record_handler(const char *base_dir) {
std::string data_file = std::string(base_dir) + "/" + table_meta_.name() + TABLE_DATA_SUFFIX;
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();
}
......@@ -295,15 +346,17 @@ RC Table::init_record_handler(const char *base_dir) {
int data_buffer_pool_file_id;
RC rc = data_buffer_pool_->open_file(data_file.c_str(), &data_buffer_pool_file_id);
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));
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_, data_buffer_pool_file_id);
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);
delete record_handler_;
record_handler_ = nullptr;
return rc;
}
......@@ -317,28 +370,36 @@ RC Table::init_record_handler(const char *base_dir) {
class RecordReaderScanAdapter {
public:
explicit RecordReaderScanAdapter(void (*record_reader)(const char *data, void *context), void *context)
: record_reader_(record_reader), context_(context){
}
: record_reader_(record_reader), context_(context)
{}
void consume(const Record *record) {
void consume(const Record *record)
{
record_reader_(record->data, context_);
}
private:
void (*record_reader_)(const char *, void *);
void *context_;
};
static RC scan_record_reader_adapter(Record *record, void *context) {
static RC scan_record_reader_adapter(Record *record, void *context)
{
RecordReaderScanAdapter &adapter = *(RecordReaderScanAdapter *)context;
adapter.consume(record);
return RC::SUCCESS;
}
RC Table::scan_record(Trx *trx, ConditionFilter *filter, int limit, void *context, void (*record_reader)(const char *data, void *context)) {
RC Table::scan_record(
Trx *trx, ConditionFilter *filter, int limit, void *context, void (*record_reader)(const char *data, void *context))
{
RecordReaderScanAdapter adapter(record_reader, context);
return scan_record(trx, filter, limit, (void *)&adapter, scan_record_reader_adapter);
}
RC Table::scan_record(Trx *trx, ConditionFilter *filter, int limit, void *context, RC (*record_reader)(Record *record, void *context)) {
RC Table::scan_record(
Trx *trx, ConditionFilter *filter, int limit, void *context, RC (*record_reader)(Record *record, void *context))
{
if (nullptr == record_reader) {
return RC::INVALID_ARGUMENT;
}
......@@ -367,7 +428,7 @@ RC Table::scan_record(Trx *trx, ConditionFilter *filter, int limit, void *contex
int record_count = 0;
Record record;
rc = scanner.get_first_record(&record);
for ( ; RC::SUCCESS == rc && record_count < limit; rc = scanner.get_next_record(&record)) {
for (; RC::SUCCESS == rc && record_count < limit; rc = scanner.get_next_record(&record)) {
if (trx == nullptr || trx->is_visible(this, &record)) {
rc = record_reader(&record, context);
if (rc != RC::SUCCESS) {
......@@ -387,7 +448,8 @@ RC Table::scan_record(Trx *trx, ConditionFilter *filter, int limit, void *contex
}
RC Table::scan_record_by_index(Trx *trx, IndexScanner *scanner, ConditionFilter *filter, int limit, void *context,
RC (*record_reader)(Record *, void *)) {
RC (*record_reader)(Record *, void *))
{
RC rc = RC::SUCCESS;
RID rid;
Record record;
......@@ -426,45 +488,54 @@ RC Table::scan_record_by_index(Trx *trx, IndexScanner *scanner, ConditionFilter
class IndexInserter {
public:
explicit IndexInserter(Index *index) : index_(index) {
}
explicit IndexInserter(Index *index) : index_(index)
{}
RC insert_index(const Record *record) {
RC insert_index(const Record *record)
{
return index_->insert_entry(record->data, &record->rid);
}
private:
Index * index_;
Index *index_;
};
static RC insert_index_record_reader_adapter(Record *record, void *context) {
static RC insert_index_record_reader_adapter(Record *record, void *context)
{
IndexInserter &inserter = *(IndexInserter *)context;
return inserter.insert_index(record);
}
RC Table::create_index(Trx *trx, const char *index_name, const char *attribute_name) {
if (index_name == nullptr || common::is_blank(index_name) ||
attribute_name == nullptr || common::is_blank(attribute_name)) {
RC Table::create_index(Trx *trx, const char *index_name, const char *attribute_name)
{
if (common::is_blank(index_name) || common::is_blank(attribute_name)) {
LOG_INFO("Invalid input arguments, table name is %s, index_name is blank or attribute_name is blank", name());
return RC::INVALID_ARGUMENT;
}
if (table_meta_.index(index_name) != nullptr ||
table_meta_.find_index_by_field((attribute_name))) {
if (table_meta_.index(index_name) != nullptr || table_meta_.find_index_by_field((attribute_name))) {
LOG_INFO("Invalid input arguments, table name is %s, index %s exist or attribute %s exist index",
name(),
index_name,
attribute_name);
return RC::SCHEMA_INDEX_EXIST;
}
const FieldMeta *field_meta = table_meta_.field(attribute_name);
if (!field_meta) {
LOG_INFO("Invalid input arguments, there is no field of %s in table:%s.", attribute_name, name());
return RC::SCHEMA_FIELD_MISSING;
}
IndexMeta new_index_meta;
RC rc = new_index_meta.init(index_name, *field_meta);
if (rc != RC::SUCCESS) {
LOG_INFO("Failed to init IndexMeta in table:%s, index_name:%s, field_name:%s", name(), index_name, attribute_name);
return rc;
}
// 创建索引相关数据
BplusTreeIndex *index = new BplusTreeIndex();
std::string index_file = index_data_file(base_dir_.c_str(), name(), index_name);
std::string index_file = table_index_file(base_dir_.c_str(), name(), index_name);
rc = index->create(index_file.c_str(), new_index_meta, *field_meta);
if (rc != RC::SUCCESS) {
delete index;
......@@ -507,28 +578,37 @@ RC Table::create_index(Trx *trx, const char *index_name, const char *attribute_n
std::string meta_file = table_meta_file(base_dir_.c_str(), name());
int ret = rename(tmp_file.c_str(), meta_file.c_str());
if (ret != 0) {
LOG_ERROR("Failed to rename tmp meta file (%s) to normal meta file (%s) while creating index (%s) on table (%s). " \
"system error=%d:%s", tmp_file.c_str(), meta_file.c_str(), index_name, name(), errno, strerror(errno));
LOG_ERROR("Failed to rename tmp meta file (%s) to normal meta file (%s) while creating index (%s) on table (%s). "
"system error=%d:%s",
tmp_file.c_str(),
meta_file.c_str(),
index_name,
name(),
errno,
strerror(errno));
return RC::IOERR;
}
table_meta_.swap(new_table_meta);
LOG_INFO("add a new index (%s) on the table (%s)", index_name, name());
LOG_INFO("Successfully added a new index (%s) on the table (%s)", index_name, name());
return rc;
}
RC Table::update_record(Trx *trx, const char *attribute_name, const Value *value, int condition_num, const Condition conditions[], int *updated_count) {
RC Table::update_record(Trx *trx, const char *attribute_name, const Value *value, int condition_num,
const Condition conditions[], int *updated_count)
{
return RC::GENERIC_ERROR;
}
class RecordDeleter {
public:
RecordDeleter(Table &table, Trx *trx) : table_(table), trx_(trx) {
}
RecordDeleter(Table &table, Trx *trx) : table_(table), trx_(trx)
{}
RC delete_record(Record *record) {
RC delete_record(Record *record)
{
RC rc = RC::SUCCESS;
rc = table_.delete_record(trx_, record);
if (rc == RC::SUCCESS) {
......@@ -537,22 +617,25 @@ public:
return rc;
}
int deleted_count() const {
int deleted_count() const
{
return deleted_count_;
}
private:
Table & table_;
Table &table_;
Trx *trx_;
int deleted_count_ = 0;
};
static RC record_reader_delete_adapter(Record *record, void *context) {
static RC record_reader_delete_adapter(Record *record, void *context)
{
RecordDeleter &record_deleter = *(RecordDeleter *)context;
return record_deleter.delete_record(record);
}
RC Table::delete_record(Trx *trx, ConditionFilter *filter, int *deleted_count) {
RC Table::delete_record(Trx *trx, ConditionFilter *filter, int *deleted_count)
{
RecordDeleter deleter(*this, trx);
RC rc = scan_record(trx, filter, -1, &deleter, record_reader_delete_adapter);
if (deleted_count != nullptr) {
......@@ -561,15 +644,19 @@ RC Table::delete_record(Trx *trx, ConditionFilter *filter, int *deleted_count) {
return rc;
}
RC Table::delete_record(Trx *trx, Record *record) {
RC Table::delete_record(Trx *trx, Record *record)
{
RC rc = RC::SUCCESS;
if (trx != nullptr) {
rc = trx->delete_record(this, record);
} else {
rc = delete_entry_of_indexes(record->data, record->rid, false);// 重复代码 refer to commit_delete
rc = delete_entry_of_indexes(record->data, record->rid, false); // 重复代码 refer to commit_delete
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to delete indexes of record (rid=%d.%d). rc=%d:%s",
record->rid.page_num, record->rid.slot_num, rc, strrc(rc));
record->rid.page_num,
record->rid.slot_num,
rc,
strrc(rc));
} else {
rc = record_handler_->delete_record(&record->rid);
}
......@@ -577,7 +664,8 @@ RC Table::delete_record(Trx *trx, Record *record) {
return rc;
}
RC Table::commit_delete(Trx *trx, const RID &rid) {
RC Table::commit_delete(Trx *trx, const RID &rid)
{
RC rc = RC::SUCCESS;
Record record;
rc = record_handler_->get_record(&rid, &record);
......@@ -587,7 +675,10 @@ RC Table::commit_delete(Trx *trx, const RID &rid) {
rc = delete_entry_of_indexes(record.data, record.rid, false);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to delete indexes of record(rid=%d.%d). rc=%d:%s",
rid.page_num, rid.slot_num, rc, strrc(rc));// panic?
rid.page_num,
rid.slot_num,
rc,
strrc(rc)); // panic?
}
rc = record_handler_->delete_record(&rid);
......@@ -598,7 +689,8 @@ RC Table::commit_delete(Trx *trx, const RID &rid) {
return rc;
}
RC Table::rollback_delete(Trx *trx, const RID &rid) {
RC Table::rollback_delete(Trx *trx, const RID &rid)
{
RC rc = RC::SUCCESS;
Record record;
rc = record_handler_->get_record(&rid, &record);
......@@ -609,7 +701,8 @@ RC Table::rollback_delete(Trx *trx, const RID &rid) {
return trx->rollback_delete(this, record); // update record in place
}
RC Table::insert_entry_of_indexes(const char *record, const RID &rid) {
RC Table::insert_entry_of_indexes(const char *record, const RID &rid)
{
RC rc = RC::SUCCESS;
for (Index *index : indexes_) {
rc = index->insert_entry(record, &rid);
......@@ -620,7 +713,8 @@ RC Table::insert_entry_of_indexes(const char *record, const RID &rid) {
return rc;
}
RC Table::delete_entry_of_indexes(const char *record, const RID &rid, bool error_on_not_exists) {
RC Table::delete_entry_of_indexes(const char *record, const RID &rid, bool error_on_not_exists)
{
RC rc = RC::SUCCESS;
for (Index *index : indexes_) {
rc = index->delete_entry(record, &rid);
......@@ -633,8 +727,9 @@ RC Table::delete_entry_of_indexes(const char *record, const RID &rid, bool error
return rc;
}
Index *Table::find_index(const char *index_name) const {
for (Index *index: indexes_) {
Index *Table::find_index(const char *index_name) const
{
for (Index *index : indexes_) {
if (0 == strcmp(index->index_meta().name(), index_name)) {
return index;
}
......@@ -642,7 +737,8 @@ Index *Table::find_index(const char *index_name) const {
return nullptr;
}
IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) {
IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter)
{
const ConDesc *field_cond_desc = nullptr;
const ConDesc *value_cond_desc = nullptr;
if (filter.left().is_attr && !filter.right().is_attr) {
......@@ -658,8 +754,7 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) {
const FieldMeta *field_meta = table_meta_.find_field_by_offset(field_cond_desc->attr_offset);
if (nullptr == field_meta) {
LOG_PANIC("Cannot find field by offset %d. table=%s",
field_cond_desc->attr_offset, name());
LOG_PANIC("Cannot find field by offset %d. table=%s", field_cond_desc->attr_offset, name());
return nullptr;
}
......@@ -676,7 +771,8 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) {
return index->create_scanner(filter.comp_op(), (const char *)value_cond_desc->value);
}
IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) {
IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter)
{
if (nullptr == filter) {
return nullptr;
}
......@@ -691,7 +787,7 @@ IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) {
if (composite_condition_filter != nullptr) {
int filter_num = composite_condition_filter->filter_num();
for (int i = 0; i < filter_num; i++) {
IndexScanner *scanner= find_index_for_scan(&composite_condition_filter->filter(i));
IndexScanner *scanner = find_index_for_scan(&composite_condition_filter->filter(i));
if (scanner != nullptr) {
return scanner; // 可以找到一个最优的,比如比较符号是=
}
......@@ -700,18 +796,22 @@ IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) {
return nullptr;
}
RC Table::sync() {
RC rc = data_buffer_pool_->flush_all_pages(file_id_);
RC Table::sync()
{
RC rc = data_buffer_pool_->purge_all_pages(file_id_);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush table's data pages. table=%s, rc=%d:%s", name(), rc, strrc(rc));
return rc;
}
for (Index *index: indexes_) {
for (Index *index : indexes_) {
rc = index->sync();
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush index's pages. table=%s, index=%s, rc=%d:%s",
name(), index->index_meta().name(), rc, strrc(rc));
name(),
index->index_meta().name(),
rc,
strrc(rc));
return rc;
}
}
......
......@@ -13,6 +13,7 @@ See the Mulan PSL v2 for more details. */
//
#include <algorithm>
#include <common/lang/string.h>
#include "storage/common/table_meta.h"
#include "json/json.h"
......@@ -25,21 +26,20 @@ static const Json::StaticString FIELD_INDEXES("indexes");
std::vector<FieldMeta> TableMeta::sys_fields_;
TableMeta::TableMeta(const TableMeta &other) :
name_(other.name_),
fields_(other.fields_),
indexes_(other.indexes_),
record_size_(other.record_size_){
}
TableMeta::TableMeta(const TableMeta &other)
: name_(other.name_), fields_(other.fields_), indexes_(other.indexes_), record_size_(other.record_size_)
{}
void TableMeta::swap(TableMeta &other) noexcept{
void TableMeta::swap(TableMeta &other) noexcept
{
name_.swap(other.name_);
fields_.swap(other.fields_);
indexes_.swap(other.indexes_);
std::swap(record_size_, other.record_size_);
}
RC TableMeta::init_sys_fields() {
RC TableMeta::init_sys_fields()
{
sys_fields_.reserve(1);
FieldMeta field_meta;
RC rc = field_meta.init(Trx::trx_field_name(), Trx::trx_field_type(), 0, Trx::trx_field_len(), false);
......@@ -51,14 +51,15 @@ RC TableMeta::init_sys_fields() {
sys_fields_.push_back(field_meta);
return rc;
}
RC TableMeta::init(const char *name, int field_num, const AttrInfo attributes[]) {
if (nullptr == name || '\0' == name[0]) {
RC TableMeta::init(const char *name, int field_num, const AttrInfo attributes[])
{
if (common::is_blank(name)) {
LOG_ERROR("Name cannot be empty");
return RC::INVALID_ARGUMENT;
}
if (field_num <= 0 || nullptr == attributes) {
LOG_ERROR("Invalid argument. field_num=%d, attributes=%p", field_num, attributes);
LOG_ERROR("Invalid argument. name=%s, field_num=%d, attributes=%p", name, field_num, attributes);
return RC::INVALID_ARGUMENT;
}
......@@ -76,7 +77,8 @@ RC TableMeta::init(const char *name, int field_num, const AttrInfo attributes[])
fields_[i] = sys_fields_[i];
}
int field_offset = sys_fields_.back().offset() + sys_fields_.back().len(); // 当前实现下,所有类型都是4字节对齐的,所以不再考虑字节对齐问题
// 当前实现下,所有类型都是4字节对齐的,所以不再考虑字节对齐问题
int field_offset = sys_fields_.back().offset() + sys_fields_.back().len();
for (int i = 0; i < field_num; i++) {
const AttrInfo &attr_info = attributes[i];
......@@ -92,27 +94,32 @@ RC TableMeta::init(const char *name, int field_num, const AttrInfo attributes[])
record_size_ = field_offset;
name_ = name;
LOG_INFO("Init table meta success. table name=%s", name);
LOG_INFO("Sussessfully initialized table meta. table name=%s", name);
return RC::SUCCESS;
}
RC TableMeta::add_index(const IndexMeta &index) {
RC TableMeta::add_index(const IndexMeta &index)
{
indexes_.push_back(index);
return RC::SUCCESS;
}
const char *TableMeta::name() const {
const char *TableMeta::name() const
{
return name_.c_str();
}
const FieldMeta * TableMeta::trx_field() const {
const FieldMeta *TableMeta::trx_field() const
{
return &fields_[0];
}
const FieldMeta * TableMeta::field(int index) const {
const FieldMeta *TableMeta::field(int index) const
{
return &fields_[index];
}
const FieldMeta * TableMeta::field(const char *name) const {
const FieldMeta *TableMeta::field(const char *name) const
{
if (nullptr == name) {
return nullptr;
}
......@@ -124,7 +131,8 @@ const FieldMeta * TableMeta::field(const char *name) const {
return nullptr;
}
const FieldMeta * TableMeta::find_field_by_offset(int offset) const {
const FieldMeta *TableMeta::find_field_by_offset(int offset) const
{
for (const FieldMeta &field : fields_) {
if (field.offset() == offset) {
return &field;
......@@ -132,15 +140,18 @@ const FieldMeta * TableMeta::find_field_by_offset(int offset) const {
}
return nullptr;
}
int TableMeta::field_num() const {
int TableMeta::field_num() const
{
return fields_.size();
}
int TableMeta::sys_field_num() const {
int TableMeta::sys_field_num() const
{
return sys_fields_.size();
}
const IndexMeta * TableMeta::index(const char *name) const {
const IndexMeta *TableMeta::index(const char *name) const
{
for (const IndexMeta &index : indexes_) {
if (0 == strcmp(index.name(), name)) {
return &index;
......@@ -149,7 +160,8 @@ const IndexMeta * TableMeta::index(const char *name) const {
return nullptr;
}
const IndexMeta * TableMeta::find_index_by_field(const char *field) const {
const IndexMeta *TableMeta::find_index_by_field(const char *field) const
{
for (const IndexMeta &index : indexes_) {
if (0 == strcmp(index.field(), field)) {
return &index;
......@@ -158,25 +170,29 @@ const IndexMeta * TableMeta::find_index_by_field(const char *field) const {
return nullptr;
}
const IndexMeta * TableMeta::index(int i ) const {
const IndexMeta *TableMeta::index(int i) const
{
return &indexes_[i];
}
int TableMeta::index_num() const {
int TableMeta::index_num() const
{
return indexes_.size();
}
int TableMeta::record_size() const {
int TableMeta::record_size() const
{
return record_size_;
}
int TableMeta::serialize(std::ostream &ss) const {
int TableMeta::serialize(std::ostream &ss) const
{
Json::Value table_value;
table_value[FIELD_TABLE_NAME] = name_;
Json::Value fields_value;
for (const FieldMeta & field : fields_) {
for (const FieldMeta &field : fields_) {
Json::Value field_value;
field.to_json(field_value);
fields_value.append(std::move(field_value));
......@@ -203,7 +219,8 @@ int TableMeta::serialize(std::ostream &ss) const {
return ret;
}
int TableMeta::deserialize(std::istream &is) {
int TableMeta::deserialize(std::istream &is)
{
if (sys_fields_.empty()) {
init_sys_fields();
}
......@@ -246,12 +263,12 @@ int TableMeta::deserialize(std::istream &is) {
}
}
std::sort(fields.begin(), fields.end(),
[](const FieldMeta &f1, const FieldMeta &f2){return f1.offset() < f2.offset();});
std::sort(
fields.begin(), fields.end(), [](const FieldMeta &f1, const FieldMeta &f2) { return f1.offset() < f2.offset(); });
name_.swap(table_name);
fields_.swap(fields);
record_size_ = fields_.back().offset() + fields_.back().len();
record_size_ = fields_.back().offset() + fields_.back().len() - fields_.begin()->offset();
const Json::Value &indexes_value = table_value[FIELD_INDEXES];
if (!indexes_value.empty()) {
......@@ -277,22 +294,24 @@ int TableMeta::deserialize(std::istream &is) {
return (int)(is.tellg() - old_pos);
}
int TableMeta::get_serial_size() const {
int TableMeta::get_serial_size() const
{
return -1;
}
void TableMeta::to_string(std::string &output) const {
}
void TableMeta::to_string(std::string &output) const
{}
void TableMeta::desc(std::ostream &os) const {
void TableMeta::desc(std::ostream &os) const
{
os << name_ << '(' << std::endl;
for (const auto &field: fields_) {
for (const auto &field : fields_) {
os << '\t';
field.desc(os);
os << std::endl;
}
for (const auto &index: indexes_) {
for (const auto &index : indexes_) {
os << '\t';
index.desc(os);
os << std::endl;
......
......@@ -37,17 +37,17 @@ public:
RC add_index(const IndexMeta &index);
public:
const char * name() const;
const FieldMeta * trx_field() const;
const FieldMeta * field(int index) const;
const FieldMeta * field(const char *name) const;
const FieldMeta * find_field_by_offset(int offset) const;
const char *name() const;
const FieldMeta *trx_field() const;
const FieldMeta *field(int index) const;
const FieldMeta *field(const char *name) const;
const FieldMeta *find_field_by_offset(int offset) const;
int field_num() const;
int sys_field_num() const;
const IndexMeta * index(const char *name) const;
const IndexMeta * find_index_by_field(const char *field) const;
const IndexMeta * index(int i) const;
const IndexMeta *index(const char *name) const;
const IndexMeta *find_index_by_field(const char *field) const;
const IndexMeta *index(int i) const;
int index_num() const;
int record_size() const;
......@@ -59,15 +59,17 @@ public:
void to_string(std::string &output) const override;
void desc(std::ostream &os) const;
private:
protected:
static RC init_sys_fields();
private:
protected:
std::string name_;
std::vector<FieldMeta> fields_; // 包含sys_fields
std::vector<IndexMeta> indexes_;
int record_size_ = 0;
//@@@ TODO why used static variable?
static std::vector<FieldMeta> sys_fields_;
};
......
......@@ -38,23 +38,25 @@ See the Mulan PSL v2 for more details. */
using namespace common;
const std::string DefaultStorageStage::QUERY_METRIC_TAG = "DefaultStorageStage.query";
const char * CONF_BASE_DIR = "BaseDir";
const char * CONF_SYSTEM_DB = "SystemDb";
const char *CONF_BASE_DIR = "BaseDir";
const char *CONF_SYSTEM_DB = "SystemDb";
const char * DEFAULT_SYSTEM_DB = "sys";
const char *DEFAULT_SYSTEM_DB = "sys";
//! Constructor
DefaultStorageStage::DefaultStorageStage(const char *tag) : Stage(tag), handler_(nullptr) {
}
DefaultStorageStage::DefaultStorageStage(const char *tag) : Stage(tag), handler_(nullptr)
{}
//! Destructor
DefaultStorageStage::~DefaultStorageStage() {
DefaultStorageStage::~DefaultStorageStage()
{
delete handler_;
handler_ = nullptr;
}
//! Parse properties, instantiate a stage object
Stage *DefaultStorageStage::make_stage(const std::string &tag) {
Stage *DefaultStorageStage::make_stage(const std::string &tag)
{
DefaultStorageStage *stage = new (std::nothrow) DefaultStorageStage(tag.c_str());
if (stage == nullptr) {
LOG_ERROR("new DefaultStorageStage failed");
......@@ -65,10 +67,10 @@ Stage *DefaultStorageStage::make_stage(const std::string &tag) {
}
//! Set properties for this object set in stage specific properties
bool DefaultStorageStage::set_properties() {
bool DefaultStorageStage::set_properties()
{
std::string stageNameStr(stage_name_);
std::map<std::string, std::string> section =
get_properties()->get(stageNameStr);
std::map<std::string, std::string> section = get_properties()->get(stageNameStr);
// 初始化时打开默认的database,没有的话会自动创建
std::map<std::string, std::string>::iterator iter = section.find(CONF_BASE_DIR);
......@@ -112,7 +114,8 @@ bool DefaultStorageStage::set_properties() {
}
//! Initialize stage params and validate outputs
bool DefaultStorageStage::initialize() {
bool DefaultStorageStage::initialize()
{
LOG_TRACE("Enter");
MetricsRegistry &metricsRegistry = get_metrics_registry();
......@@ -124,7 +127,8 @@ bool DefaultStorageStage::initialize() {
}
//! Cleanup after disconnection
void DefaultStorageStage::cleanup() {
void DefaultStorageStage::cleanup()
{
LOG_TRACE("Enter");
if (handler_) {
......@@ -134,7 +138,8 @@ void DefaultStorageStage::cleanup() {
LOG_TRACE("Exit");
}
void DefaultStorageStage::handle_event(StageEvent *event) {
void DefaultStorageStage::handle_event(StageEvent *event)
{
LOG_TRACE("Enter\n");
TimerStat timerStat(*query_metric_);
......@@ -159,47 +164,48 @@ void DefaultStorageStage::handle_event(StageEvent *event) {
RC rc = RC::SUCCESS;
char response[256];
switch (sql->flag)
{
switch (sql->flag) {
case SCF_INSERT: { // insert into
const Inserts &inserts = sql->sstr.insertion;
const char *table_name = inserts.relation_name;
rc = handler_->insert_record(current_trx, current_db, table_name, inserts.value_num, inserts.values);
snprintf(response, sizeof(response), "%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE");
}
break;
} break;
case SCF_UPDATE: {
const Updates &updates = sql->sstr.update;
const char *table_name = updates.relation_name;
const char *field_name = updates.attribute_name;
int updated_count = 0;
rc = handler_->update_record(current_trx, current_db, table_name, field_name, &updates.value,
updates.condition_num, updates.conditions, &updated_count);
rc = handler_->update_record(current_trx,
current_db,
table_name,
field_name,
&updates.value,
updates.condition_num,
updates.conditions,
&updated_count);
snprintf(response, sizeof(response), "%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE");
}
break;
} break;
case SCF_DELETE: {
const Deletes &deletes = sql->sstr.deletion;
const char *table_name = deletes.relation_name;
int deleted_count = 0;
rc = handler_->delete_record(current_trx, current_db, table_name, deletes.condition_num, deletes.conditions, &deleted_count);
rc = handler_->delete_record(
current_trx, current_db, table_name, deletes.condition_num, deletes.conditions, &deleted_count);
snprintf(response, sizeof(response), "%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE");
}
break;
} break;
case SCF_CREATE_TABLE: { // create table
const CreateTable &create_table = sql->sstr.create_table;
rc = handler_->create_table(current_db, create_table.relation_name,
create_table.attribute_count, create_table.attributes);
rc = handler_->create_table(
current_db, create_table.relation_name, create_table.attribute_count, create_table.attributes);
snprintf(response, sizeof(response), "%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE");
}
break;
} break;
case SCF_CREATE_INDEX: {
const CreateIndex &create_index = sql->sstr.create_index;
rc = handler_->create_index(current_trx, current_db, create_index.relation_name,
create_index.index_name, create_index.attribute_name);
rc = handler_->create_index(
current_trx, current_db, create_index.relation_name, create_index.index_name, create_index.attribute_name);
snprintf(response, sizeof(response), "%s\n", rc == RC::SUCCESS ? "SUCCESS" : "FAILURE");
}
break;
} break;
case SCF_SHOW_TABLES: {
Db *db = handler_->find_db(current_db);
......@@ -212,14 +218,13 @@ void DefaultStorageStage::handle_event(StageEvent *event) {
snprintf(response, sizeof(response), "No table\n");
} else {
std::stringstream ss;
for (const auto &table: all_tables) {
for (const auto &table : all_tables) {
ss << table << std::endl;
}
snprintf(response, sizeof(response), "%s\n", ss.str().c_str());
}
}
}
break;
} break;
case SCF_DESC_TABLE: {
const char *table_name = sql->sstr.desc_table.relation_name;
Table *table = handler_->find_table(current_db, table_name);
......@@ -230,8 +235,7 @@ void DefaultStorageStage::handle_event(StageEvent *event) {
ss << "No such table: " << table_name << std::endl;
}
snprintf(response, sizeof(response), "%s", ss.str().c_str());
}
break;
} break;
case SCF_LOAD_DATA: {
/*
......@@ -242,8 +246,7 @@ void DefaultStorageStage::handle_event(StageEvent *event) {
const char *file_name = sql->sstr.load_data.file_name;
std::string result = load_data(current_db, table_name, file_name);
snprintf(response, sizeof(response), "%s", result.c_str());
}
break;
} break;
default:
snprintf(response, sizeof(response), "Unsupported sql: %d\n", sql->flag);
break;
......@@ -262,8 +265,8 @@ void DefaultStorageStage::handle_event(StageEvent *event) {
LOG_TRACE("Exit\n");
}
void DefaultStorageStage::callback_event(StageEvent *event,
CallbackContext *context) {
void DefaultStorageStage::callback_event(StageEvent *event, CallbackContext *context)
{
LOG_TRACE("Enter\n");
StorageEvent *storage_event = static_cast<StorageEvent *>(event);
storage_event->exe_event()->done_immediate();
......@@ -279,8 +282,9 @@ void DefaultStorageStage::callback_event(StageEvent *event,
* @param errmsg 如果出现错误,通过这个参数返回错误信息
* @return 成功返回RC::SUCCESS
*/
RC insert_record_from_file(Table *table, std::vector<std::string> &file_values,
std::vector<Value> &record_values, std::stringstream &errmsg) {
RC insert_record_from_file(
Table *table, std::vector<std::string> &file_values, std::vector<Value> &record_values, std::stringstream &errmsg)
{
const int field_num = record_values.size();
const int sys_field_num = table->table_meta().sys_field_num();
......@@ -306,8 +310,7 @@ RC insert_record_from_file(Table *table, std::vector<std::string> &file_values,
int int_value;
deserialize_stream >> int_value;
if (!deserialize_stream || !deserialize_stream.eof()) {
errmsg << "need an integer but got '" << file_values[i]
<< "' (field index:" << i << ")";
errmsg << "need an integer but got '" << file_values[i] << "' (field index:" << i << ")";
rc = RC::SCHEMA_FIELD_TYPE_MISMATCH;
} else {
......@@ -323,23 +326,19 @@ RC insert_record_from_file(Table *table, std::vector<std::string> &file_values,
float float_value;
deserialize_stream >> float_value;
if (!deserialize_stream || !deserialize_stream.eof()) {
errmsg << "need a float number but got '" << file_values[i]
<< "'(field index:" << i << ")";
errmsg << "need a float number but got '" << file_values[i] << "'(field index:" << i << ")";
rc = RC::SCHEMA_FIELD_TYPE_MISMATCH;
} else {
value_init_float(&record_values[i], float_value);
}
}
break;
} break;
case CHARS: {
value_init_string(&record_values[i], file_value.c_str());
}
break;
} break;
default: {
errmsg << "Unsupported field type to loading: " << field->type();
rc = RC::SCHEMA_FIELD_TYPE_MISMATCH;
}
break;
} break;
}
}
......@@ -355,8 +354,8 @@ RC insert_record_from_file(Table *table, std::vector<std::string> &file_values,
return rc;
}
std::string DefaultStorageStage::load_data(const char *db_name,
const char *table_name, const char *file_name) {
std::string DefaultStorageStage::load_data(const char *db_name, const char *table_name, const char *file_name)
{
std::stringstream result_string;
Table *table = handler_->find_table(db_name, table_name);
......@@ -368,8 +367,7 @@ std::string DefaultStorageStage::load_data(const char *db_name,
std::fstream fs;
fs.open(file_name, std::ios_base::in | std::ios_base::binary);
if (!fs.is_open()) {
result_string << "Failed to open file: " << file_name
<< ". system error=" << strerror(errno) << std::endl;
result_string << "Failed to open file: " << file_name << ". system error=" << strerror(errno) << std::endl;
return result_string.str();
}
......@@ -397,8 +395,8 @@ std::string DefaultStorageStage::load_data(const char *db_name,
std::stringstream errmsg;
rc = insert_record_from_file(table, file_values, record_values, errmsg);
if (rc != RC::SUCCESS) {
result_string << "Line:" << line_num << " insert record failed:"
<< errmsg.str() << ". error:" << strrc(rc) << std::endl;
result_string << "Line:" << line_num << " insert record failed:" << errmsg.str() << ". error:" << strrc(rc)
<< std::endl;
} else {
insertion_count++;
}
......@@ -407,12 +405,10 @@ std::string DefaultStorageStage::load_data(const char *db_name,
struct timespec end_time;
clock_gettime(CLOCK_MONOTONIC, &end_time);
long cost_nano = (end_time.tv_sec - begin_time.tv_sec) * 1000000000L
+ (end_time.tv_nsec - begin_time.tv_nsec);
long cost_nano = (end_time.tv_sec - begin_time.tv_sec) * 1000000000L + (end_time.tv_nsec - begin_time.tv_nsec);
if (RC::SUCCESS == rc) {
result_string << strrc(rc) << ". total " << line_num << " line(s) handled and "
<< insertion_count << " record(s) loaded, total cost " << cost_nano / 1000000000.0
<< " second(s)" << std::endl;
result_string << strrc(rc) << ". total " << line_num << " line(s) handled and " << insertion_count
<< " record(s) loaded, total cost " << cost_nano / 1000000000.0 << " second(s)" << std::endl;
}
return result_string.str();
}
\ No newline at end of file
......@@ -15,10 +15,14 @@ See the Mulan PSL v2 for more details. */
#include <errno.h>
#include <string.h>
#include "common/lang/mutex.h"
#include "common/log/log.h"
#include "common/os/os.h"
using namespace common;
int DiskBufferPool::POOL_NUM = MAX_OPEN_FILE / 4;
unsigned long current_time()
{
struct timespec tp;
......@@ -26,13 +30,104 @@ 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)
{}
static bool match_purge(void *item, void *arg)
{
Frame *frame = (Frame *)item;
return frame->can_purge();
}
Frame *BPManager::begin_purge()
{
return MemPoolSimple<Frame>::find(match_purge, nullptr);
}
struct MatchFilePage {
MatchFilePage(int file_desc, PageNum page_num)
{
this->file_desc = file_desc;
this->page_num = page_num;
}
int file_desc;
PageNum page_num;
};
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)
return true;
return false;
}
Frame *BPManager::get(int file_desc, PageNum page_num)
{
MatchFilePage file_page(file_desc, page_num);
return MemPoolSimple<Frame>::find(match_file_page, &file_page);
}
static bool match_file(void *item, void *arg)
{
Frame *frame = (Frame *)item;
int *file_desc = (int *)arg;
if (frame->file_desc == *file_desc)
return true;
return false;
}
std::list<Frame *> BPManager::find_list(int file_desc)
{
return find_all(match_file, &file_desc);
}
DiskBufferPool *theGlobalDiskBufferPool()
{
static DiskBufferPool *instance = new DiskBufferPool();
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();
LOG_INFO("Exit");
}
RC DiskBufferPool::create_file(const char *file_name)
{
int fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
......@@ -81,22 +176,24 @@ RC DiskBufferPool::create_file(const char *file_name)
RC DiskBufferPool::open_file(const char *file_name, int *file_id)
{
int fd, i;
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 = 0;
while (i < MAX_OPEN_FILE && open_list_[i++])
;
i = size;
if (i >= MAX_OPEN_FILE && open_list_[i - 1]) {
LOG_ERROR("Failed to open file %s, because too much files has been opened.", file_name);
LOG_ERROR("Failed to open file %s, because too much files have been opened.", file_name);
return RC::BUFFERPOOL_OPEN_TOO_MANY_FILES;
}
......@@ -113,27 +210,24 @@ RC DiskBufferPool::open_file(const char *file_name, int *file_id)
return RC::NOMEM;
}
RC tmp;
RC tmp = RC::SUCCESS;
file_handle->bopen = true;
int file_name_len = strlen(file_name) + 1;
char *cloned_file_name = new char[file_name_len];
snprintf(cloned_file_name, file_name_len, "%s", file_name);
cloned_file_name[file_name_len - 1] = '\0';
file_handle->file_name = cloned_file_name;
file_handle->file_name = strdup(file_name);
file_handle->file_desc = fd;
if ((tmp = allocate_block(&file_handle->hdr_frame)) != RC::SUCCESS) {
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;
close(fd);
return tmp;
}
file_handle->hdr_frame->dirty = false;
file_handle->hdr_frame->acc_time = current_time();
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) {
LOG_ERROR("Failed to load first page of %s, due to %s.", file_name, strerror(errno));
file_handle->hdr_frame->pin_count = 0;
dispose_block(file_handle->hdr_frame);
purge_page(file_handle->hdr_frame);
close(fd);
delete file_handle;
return tmp;
......@@ -142,8 +236,9 @@ RC DiskBufferPool::open_file(const char *file_name, int *file_id)
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_[i - 1] = file_handle;
*file_id = i - 1;
open_list_[empty_id] = file_handle;
*file_id = empty_id;
LOG_INFO("Successfully open %s. file_id=%d, hdr_frame=%p", file_name, *file_id, file_handle->hdr_frame);
return RC::SUCCESS;
}
......@@ -158,19 +253,21 @@ RC DiskBufferPool::close_file(int file_id)
BPFileHandle *file_handle = open_list_[file_id];
file_handle->hdr_frame->pin_count--;
if ((tmp = force_all_pages(file_handle)) != RC::SUCCESS) {
if ((tmp = purge_all_pages(file_handle)) != RC::SUCCESS) {
file_handle->hdr_frame->pin_count++;
LOG_ERROR("Failed to closeFile %d:%s, due to failed to force all pages.", file_id, file_handle->file_name);
LOG_ERROR("Failed to close file %d:%s, due to failed to purge all pages.", file_id, file_handle->file_name);
return tmp;
}
disposed_pages.erase(file_handle->file_desc);
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));
return RC::IOERR_CLOSE;
}
open_list_[file_id] = nullptr;
delete (file_handle);
LOG_INFO("Successfully close file %d:%s.", file_id, file_handle->file_name);
delete file_handle;
return RC::SUCCESS;
}
......@@ -188,24 +285,20 @@ RC DiskBufferPool::get_this_page(int file_id, PageNum page_num, BPPageHandle *pa
return tmp;
}
for (int i = 0; i < BP_BUFFER_SIZE; i++) {
if (!bp_manager_.allocated[i])
continue;
if (bp_manager_.frame[i].file_desc != file_handle->file_desc)
continue;
// This page has been loaded.
if (bp_manager_.frame[i].page.page_num == page_num) {
page_handle->frame = bp_manager_.frame + i;
Frame *used_match_frame = bp_manager_.get(file_handle->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;
bp_manager_.mark_modified(used_match_frame);
return RC::SUCCESS;
}
}
// Allocate one page and load the data into this page
if ((tmp = allocate_block(&(page_handle->frame))) != RC::SUCCESS) {
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;
}
......@@ -216,7 +309,7 @@ RC DiskBufferPool::get_this_page(int file_id, PageNum page_num, BPPageHandle *pa
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;
dispose_block(page_handle->frame);
purge_page(page_handle->frame);
return tmp;
}
......@@ -243,12 +336,13 @@ RC DiskBufferPool::allocate_page(int file_id, BPPageHandle *page_handle)
if (((file_handle->bitmap[byte]) & (1 << bit)) == 0) {
(file_handle->file_sub_header->allocated_pages)++;
file_handle->bitmap[byte] |= (1 << bit);
// TODO, do we need clean the loaded page's data?
return get_this_page(file_id, i, page_handle);
}
}
}
if ((tmp = allocate_block(&(page_handle->frame))) != RC::SUCCESS) {
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;
}
......@@ -269,10 +363,11 @@ RC DiskBufferPool::allocate_page(int file_id, BPPageHandle *page_handle)
memset(&(page_handle->frame->page), 0, sizeof(Page));
page_handle->frame->page.page_num = file_handle->file_sub_header->page_count - 1;
// Use flush operation to extion file
if ((tmp = flush_block(page_handle->frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to alloc page %s , due to failed to extend one page.", file_handle->file_name);
return tmp;
// 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);
// skip return false, delay flush the extended page
// return tmp;
}
page_handle->open = true;
......@@ -304,13 +399,27 @@ RC DiskBufferPool::mark_dirty(BPPageHandle *page_handle)
RC DiskBufferPool::unpin_page(BPPageHandle *page_handle)
{
page_handle->open = false;
page_handle->frame->pin_count--;
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);
}
}
}
return RC::SUCCESS;
}
/**
* dispose_page will delete the data of the page of pageNum
* force_page will flush the page of pageNum
* 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
......@@ -329,18 +438,22 @@ RC DiskBufferPool::dispose_page(int file_id, PageNum page_num)
return rc;
}
for (int i = 0; i < BP_BUFFER_SIZE; i++) {
if (!bp_manager_.allocated[i])
continue;
if (bp_manager_.frame[i].file_desc != file_handle->file_desc) {
continue;
}
rc = purge_page(file_handle, 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);
if (bp_manager_.frame[i].page.page_num == page_num) {
if (bp_manager_.frame[i].pin_count != 0)
return RC::BUFFERPOOL_PAGE_PINNED;
bp_manager_.allocated[i] = false;
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);
}
return rc;
}
file_handle->hdr_frame->dirty = true;
......@@ -351,7 +464,7 @@ RC DiskBufferPool::dispose_page(int file_id, PageNum page_num)
return RC::SUCCESS;
}
RC DiskBufferPool::force_page(int file_id, PageNum page_num)
RC DiskBufferPool::purge_page(int file_id, PageNum page_num)
{
RC rc;
if ((rc = check_file_id(file_id)) != RC::SUCCESS) {
......@@ -359,8 +472,32 @@ RC DiskBufferPool::force_page(int file_id, PageNum page_num)
return rc;
}
BPFileHandle *file_handle = open_list_[file_id];
return force_page(file_handle, page_num);
return purge_page(file_handle, page_num);
}
RC DiskBufferPool::purge_page(Frame *buf)
{
if (buf->pin_count > 0) {
LOG_INFO("Begin to free page %d of %d, but it's pinned, pin_count:%d.",
buf->page.page_num,
buf->file_desc,
buf->pin_count);
return RC::LOCKED_UNLOCK;
}
if (buf->dirty) {
RC rc = flush_page(buf);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to flush page %d of %d during purge page.", buf->page.page_num, buf->file_desc);
return rc;
}
}
LOG_DEBUG("Successfully purge frame =%p, page %d of %d", buf, buf->page.page_num, buf->file_desc);
bp_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
......@@ -368,39 +505,17 @@ RC DiskBufferPool::force_page(int file_id, PageNum page_num)
* @param pageNum
* @return
*/
RC DiskBufferPool::force_page(BPFileHandle *file_handle, PageNum page_num)
RC DiskBufferPool::purge_page(BPFileHandle *file_handle, PageNum page_num)
{
int i;
for (i = 0; i < BP_BUFFER_SIZE; i++) {
if (!bp_manager_.allocated[i])
continue;
Frame *frame = &bp_manager_.frame[i];
if (frame->file_desc != file_handle->file_desc)
continue;
if (frame->page.page_num != page_num && page_num != -1) {
continue;
Frame *used_frame = bp_manager_.get(file_handle->file_desc, page_num);
if (used_frame != nullptr) {
return purge_page(used_frame);
}
if (frame->pin_count != 0) {
LOG_ERROR("Page :%s:%d has been pinned.", file_handle->file_name, page_num);
return RC::BUFFERPOOL_PAGE_PINNED;
}
if (frame->dirty) {
RC rc = RC::SUCCESS;
if ((rc = flush_block(frame)) != RC::SUCCESS) {
LOG_ERROR("Failed to flush page:%s:%d.", file_handle->file_name, page_num);
return rc;
}
}
bp_manager_.allocated[i] = false;
return RC::SUCCESS;
}
return RC::SUCCESS;
}
RC DiskBufferPool::flush_all_pages(int file_id)
RC DiskBufferPool::purge_all_pages(int file_id)
{
RC rc = check_file_id(file_id);
if (rc != RC::SUCCESS) {
......@@ -409,32 +524,31 @@ RC DiskBufferPool::flush_all_pages(int file_id)
}
BPFileHandle *file_handle = open_list_[file_id];
return force_all_pages(file_handle);
return purge_all_pages(file_handle);
}
RC DiskBufferPool::force_all_pages(BPFileHandle *file_handle)
RC DiskBufferPool::purge_all_pages(BPFileHandle *file_handle)
{
for (int i = 0; i < BP_BUFFER_SIZE; i++) {
if (!bp_manager_.allocated[i])
std::list<Frame *> used = bp_manager_.find_list(file_handle->file_desc);
for (std::list<Frame *>::iterator it = used.begin(); it != used.end(); ++it) {
Frame *frame = *it;
if (frame->pin_count > 0) {
LOG_WARN("The page has been pinned, file_id:%d, pagenum:%d", frame->file_desc, frame->page.page_num);
continue;
if (bp_manager_.frame[i].file_desc != file_handle->file_desc)
continue;
if (bp_manager_.frame[i].dirty) {
RC rc = flush_block(&bp_manager_.frame[i]);
}
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);
return rc;
}
}
bp_manager_.allocated[i] = false;
bp_manager_.free(frame);
}
return RC::SUCCESS;
}
RC DiskBufferPool::flush_block(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.
......@@ -455,68 +569,31 @@ RC DiskBufferPool::flush_block(Frame *frame)
return RC::SUCCESS;
}
RC DiskBufferPool::allocate_block(Frame **buffer)
RC DiskBufferPool::allocate_page(Frame **buffer)
{
// There is one Frame which is free.
for (int i = 0; i < BP_BUFFER_SIZE; i++) {
if (!bp_manager_.allocated[i]) {
bp_manager_.allocated[i] = true;
*buffer = bp_manager_.frame + i;
LOG_DEBUG("Allocate block frame=%p", bp_manager_.frame + i);
Frame *frame = bp_manager_.alloc();
if (frame != nullptr) {
*buffer = frame;
return RC::SUCCESS;
}
}
int min = 0;
unsigned long mintime = 0;
bool flag = false;
for (int i = 0; i < BP_BUFFER_SIZE; i++) {
if (bp_manager_.frame[i].pin_count != 0)
continue;
if (!flag) {
flag = true;
min = i;
mintime = bp_manager_.frame[i].acc_time;
}
if (bp_manager_.frame[i].acc_time < mintime) {
min = i;
mintime = bp_manager_.frame[i].acc_time;
}
}
if (!flag) {
frame = bp_manager_.begin_purge();
if (frame == nullptr) {
LOG_ERROR("All pages have been used and pinned.");
return RC::NOMEM;
}
if (bp_manager_.frame[min].dirty) {
RC rc = flush_block(&(bp_manager_.frame[min]));
if (frame->dirty) {
RC rc = flush_page(frame);
if (rc != RC::SUCCESS) {
LOG_ERROR("Failed to flush block of %d for %d.", min, bp_manager_.frame[min].file_desc);
LOG_ERROR("Failed to aclloc block due to failed to flush old block.");
return rc;
}
}
*buffer = bp_manager_.frame + min;
return RC::SUCCESS;
}
RC DiskBufferPool::dispose_block(Frame *buf)
{
if (buf->pin_count != 0) {
LOG_WARN("Begin to free page %d of %d, but it's pinned.", buf->page.page_num, buf->file_desc);
return RC::LOCKED_UNLOCK;
}
if (buf->dirty) {
RC rc = flush_block(buf);
if (rc != RC::SUCCESS) {
LOG_WARN("Failed to flush block %d of %d during dispose block.", buf->page.page_num, buf->file_desc);
return rc;
}
}
buf->dirty = false;
int pos = buf - bp_manager_.frame;
bp_manager_.allocated[pos] = false;
LOG_DEBUG("dispost block frame =%p", buf);
bp_manager_.mark_modified(frame);
*buffer = frame;
return RC::SUCCESS;
}
......
......@@ -17,23 +17,23 @@ See the Mulan PSL v2 for more details. */
#include <fcntl.h>
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <vector>
#include "rc.h"
#include "common/mm/mem_pool.h"
typedef int PageNum;
//
#define BP_INVALID_PAGE_NUM (-1)
#define BP_PAGE_SIZE (1 << 12)
#define BP_PAGE_SIZE (1 << 13)
#define BP_PAGE_DATA_SIZE (BP_PAGE_SIZE - sizeof(PageNum))
#define BP_FILE_SUB_HDR_SIZE (sizeof(BPFileSubHeader))
#define BP_BUFFER_SIZE 50
#define BP_BUFFER_SIZE 256
#define MAX_OPEN_FILE 1024
typedef struct {
......@@ -48,23 +48,35 @@ typedef struct {
} 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;
bool can_purge()
{
return pin_count <= 0;
}
} Frame;
typedef struct {
typedef struct BPPageHandle {
BPPageHandle() : open(false), frame(nullptr)
{}
bool open;
Frame *frame;
} BPPageHandle;
class BPFileHandle{
class BPFileHandle {
public:
BPFileHandle() {
memset(this, 0, sizeof(*this));
}
BPFileHandle();
~BPFileHandle();
public:
bool bopen;
......@@ -74,48 +86,44 @@ public:
Page *hdr_page;
char *bitmap;
BPFileSubHeader *file_sub_header;
} ;
};
class BPManager {
class BPManager : public common::MemPoolSimple<Frame> {
public:
BPManager(int size = BP_BUFFER_SIZE) {
this->size = size;
frame = new Frame[size];
allocated = new bool[size];
for (int i = 0; i < size; i++) {
allocated[i] = false;
frame[i].pin_count = 0;
}
}
BPManager(const char *tag);
~BPManager() {
delete[] frame;
delete[] allocated;
size = 0;
frame = nullptr;
allocated = nullptr;
}
Frame *get(int file_desc, PageNum page_num);
std::list<Frame *> find_list(int file_desc);
Frame *alloc() {
return nullptr; // TODO for test
Frame *begin_purge();
};
class DiskBufferPool {
public:
static DiskBufferPool *mk_instance()
{
return new DiskBufferPool();
}
Frame *get(int file_desc, PageNum page_num) {
return nullptr; // TODO for test
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);
}
Frame *getFrame() { return frame; }
}
bool *getAllocated() { return allocated; }
static const int get_pool_num()
{
return POOL_NUM;
}
public:
int size;
Frame * frame = nullptr;
bool *allocated = nullptr;
};
~DiskBufferPool();
class DiskBufferPool {
public:
/**
* 创建一个名称为指定文件名的分页文件
*/
......@@ -156,7 +164,7 @@ public:
RC get_data(BPPageHandle *page_handle, char **data);
/**
* 丢弃文件中编号为pageNum的页面,将其变为空闲页
* 比purge_page多一个动作, 在磁盘上将对应的页数据删掉。
*/
RC dispose_page(int file_id, PageNum page_num);
......@@ -165,7 +173,7 @@ public:
* @param file_handle
* @param page_num 如果不指定page_num 将刷新所有页
*/
RC force_page(int file_id, PageNum page_num);
RC purge_page(int file_id, PageNum page_num);
/**
* 标记指定页面为“脏”页。如果修改了页面的内容,则应调用此函数,
......@@ -186,27 +194,33 @@ public:
*/
RC get_page_count(int file_id, int *page_count);
RC flush_all_pages(int file_id);
RC purge_all_pages(int file_id);
protected:
RC allocate_block(Frame **buf);
RC dispose_block(Frame *buf);
RC allocate_page(Frame **buf);
/**
* 刷新指定文件关联的所有脏页到磁盘,除了pinned page
* @param file_handle
* @param page_num 如果不指定page_num 将刷新所有页
*/
RC force_page(BPFileHandle *file_handle, PageNum page_num);
RC force_all_pages(BPFileHandle *file_handle);
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_block(Frame *frame);
RC flush_page(Frame *frame);
private:
DiskBufferPool();
private:
BPManager bp_manager_;
BPFileHandle *open_list_[MAX_OPEN_FILE] = {nullptr};
std::map<int, BPDisposedPages> disposed_pages;
static int POOL_NUM;
};
DiskBufferPool *theGlobalDiskBufferPool();
......
......@@ -15,10 +15,9 @@ See the Mulan PSL v2 for more details. */
#include "storage/default/disk_buffer_pool.h"
#include "gtest/gtest.h"
TEST(test_bp_manager, test_bp_manager_simple_lru) {
BPManager bp_manager(2);
Frame * frame1 = bp_manager.alloc();
void test_get(BPManager &bp_manager)
{
Frame *frame1 = bp_manager.alloc();
ASSERT_NE(frame1, nullptr);
frame1->file_desc = 0;
......@@ -39,24 +38,78 @@ TEST(test_bp_manager, test_bp_manager_simple_lru) {
frame3->page.page_num = 3;
frame2 = bp_manager.get(0, 2);
ASSERT_EQ(frame2, nullptr);
ASSERT_NE(frame2, nullptr);
Frame *frame4 = bp_manager.alloc();
frame4->file_desc = 0;
frame4->page.page_num = 4;
bp_manager.free(frame1);
frame1 = bp_manager.get(0, 1);
ASSERT_EQ(frame1, nullptr);
frame3 = bp_manager.get(0, 3);
ASSERT_NE(frame3, nullptr);
ASSERT_EQ(frame3, bp_manager.get(0, 3));
ASSERT_EQ(frame4, bp_manager.get(0, 4));
bp_manager.free(frame2);
bp_manager.free(frame3);
bp_manager.free(frame4);
frame4 = bp_manager.get(0, 4);
ASSERT_NE(frame4, nullptr);
ASSERT_EQ(nullptr, bp_manager.get(0, 2));
ASSERT_EQ(nullptr, bp_manager.get(0, 3));
ASSERT_EQ(nullptr, bp_manager.get(0, 4));
}
int main(int argc, char **argv) {
void test_alloc(BPManager &bp_manager)
{
int size = bp_manager.get_size();
std::list<Frame *> used_list;
for (int i = 0; i < size; i++) {
Frame *item = bp_manager.alloc();
ASSERT_NE(item, nullptr);
used_list.push_back(item);
}
ASSERT_EQ(used_list.size(), bp_manager.get_used_num());
for (int i = 0; i < size; i++) {
Frame *item = bp_manager.alloc();
ASSERT_EQ(item, nullptr);
}
for (int i = 0; i < size * 10; i++) {
if (i % 2 == 0) {
Frame *item = used_list.front();
used_list.pop_front();
bp_manager.free(item);
} else {
Frame *item = bp_manager.alloc();
used_list.push_back(item);
}
ASSERT_EQ(used_list.size(), bp_manager.get_used_num());
}
}
TEST(test_bp_manager, test_bp_manager_simple_lru)
{
BPManager bp_manager("Test");
bp_manager.init(false, 2);
test_get(bp_manager);
test_alloc(bp_manager);
bp_manager.cleanup();
}
int main(int argc, char **argv)
{
// 分析gtest程序的命令行参数
testing::InitGoogleTest(&argc, argv);
......
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by longda on 2022
//
#include <list>
#include <iostream>
#include "storage/common/bplus_tree.h"
#include "storage/default/disk_buffer_pool.h"
#include "rc.h"
#include "common/log/log.h"
#include "sql/parser/parse_defs.h"
#include "gtest/gtest.h"
using namespace common;
#define TIMES 3
// order must small real order
// if page is 8k, it is 400
#define ORDER 4
#define INSERT_NUM (TIMES * ORDER * ORDER * ORDER * ORDER)
#define POOL_NUM 2
BplusTreeHandler *handler = nullptr;
const char *index_name = "test.btree";
int insert_num = INSERT_NUM;
const int page_size = 1024;
RID rid, check_rid;
int k = 0;
void test_insert()
{
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (i % TIMES == 1) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Insert %d", i);
}
RC rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree());
}
}
handler->print_tree();
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (i % TIMES == 2) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Insert %d", i);
}
RC rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree());
}
}
handler->print_tree();
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (i % TIMES == 0) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to insert the page's num %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Insert %d", i);
}
RC rc = handler->insert_entry((const char *)&i, &rid);
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree());
}
}
LOG_INFO("@@@@ finish first step insert");
handler->print_tree();
handler->print_leafs();
int start = insert_num / TIMES > page_size ? page_size : insert_num / TIMES;
int end = insert_num / TIMES > page_size ? (2 * page_size) : (2 * insert_num / TIMES);
for (int i = start; i < end; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to check duplicated insert the page's num %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Check duplicate insert %d", i);
}
RC rc = handler->insert_entry((const char *)&i, &rid);
int t = i % TIMES;
if (t == 0 || t == 1 || t == 2) {
ASSERT_EQ(RC::RECORD_DUPLICATE_KEY, rc);
} else {
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree());
}
}
}
void test_get()
{
std::list<RID> rids;
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to get every entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to get every entry of index, rid: %s", rid.to_string().c_str());
}
rids.clear();
RC rc = handler->get_entry((const char *)&i, rids);
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(1, rids.size());
check_rid = rids.front();
ASSERT_EQ(rid.page_num, check_rid.page_num);
ASSERT_EQ(rid.slot_num, check_rid.slot_num);
}
}
void test_delete()
{
std::list<RID> rids;
for (int i = 0; i < insert_num / 2; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
int t = i % TIMES;
if (t == 0 || t == 1) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
RC rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc);
}
}
handler->print_tree();
for (int i = insert_num - 1; i >= insert_num / 2; i--) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
int t = i % TIMES;
if (t == 0 || t == 1) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
RC rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc);
}
}
handler->print_tree();
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to get entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to get entry of index, rid: %s", rid.to_string().c_str());
}
rids.clear();
RC rc = handler->get_entry((const char *)&i, rids);
ASSERT_EQ(RC::SUCCESS, rc);
int t = i % TIMES;
if (t == 0 || t == 1) {
ASSERT_EQ(0, rids.size());
} else {
ASSERT_EQ(1, rids.size());
check_rid = rids.front();
ASSERT_EQ(rid.page_num, check_rid.page_num);
ASSERT_EQ(rid.slot_num, check_rid.slot_num);
ASSERT_EQ(true, handler->validate_tree());
}
}
handler->print_tree();
for (int i = 0; i < insert_num / 2; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
int t = i % TIMES;
if (t == 2) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
RC rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc);
}
}
handler->print_tree();
for (int i = insert_num - 1; i >= insert_num / 2; i--) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
int t = i % TIMES;
if (t == 2) {
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to delete entry of index, rid: %s", rid.to_string().c_str());
}
RC rc = handler->delete_entry((const char *)&i, &rid);
ASSERT_EQ(true, handler->validate_tree());
ASSERT_EQ(RC::SUCCESS, rc);
}
}
handler->print_tree();
for (int i = 0; i < insert_num; i++) {
rid.page_num = i / page_size;
rid.slot_num = i % page_size;
if (insert_num > page_size) {
if (k++ % 100 == 0) {
LOG_INFO("Begin to insert entry of index, rid: %s", rid.to_string().c_str());
}
} else {
LOG_INFO("Begin to insert entry of index, rid: %s", rid.to_string().c_str());
}
RC rc = handler->insert_entry((const char *)&i, &rid);
int t = i % TIMES;
if (t == 0 || t == 1 || t == 2) {
ASSERT_EQ(RC::SUCCESS, rc);
ASSERT_EQ(true, handler->validate_tree());
} else {
ASSERT_EQ(RC::RECORD_DUPLICATE_KEY, rc);
}
}
handler->print_tree();
}
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();
handler->create(index_name, INTS, sizeof(int));
BplusTreeTester bplus_tree_tester(*handler);
bplus_tree_tester.set_order(ORDER);
test_insert();
test_get();
test_delete();
handler->close();
delete handler;
handler = nullptr;
}
int main(int argc, char **argv)
{
// 分析gtest程序的命令行参数
testing::InitGoogleTest(&argc, argv);
// 调用RUN_ALL_TESTS()运行所有测试用例
// main函数返回RUN_ALL_TESTS()的运行结果
int rc = RUN_ALL_TESTS();
return rc;
}
\ No newline at end of file
......@@ -12,28 +12,26 @@ See the Mulan PSL v2 for more details. */
// Created by Longda on 2021
//
#include "log_test.h"
#include "gtest/gtest.h"
#include "common/log/log.h"
using namespace common;
LogTest::LogTest() {
LogTest::LogTest()
{
// Auto-generated constructor stub
}
LogTest::~LogTest() {
LogTest::~LogTest()
{
// Auto-generated destructor stub
}
int LogTest::init(const std::string &logFile) {
int LogTest::init(const std::string &logFile)
{
LoggerFactory::init_default(logFile);
......@@ -42,8 +40,9 @@ int LogTest::init(const std::string &logFile) {
return 0;
}
void *LogTest::log_loop(void *param) {
int index = *(int *) param;
void *LogTest::log_loop(void *param)
{
int index = *(int *)param;
int i = 0;
while (i < 100) {
i++;
......@@ -53,7 +52,8 @@ void *LogTest::log_loop(void *param) {
return NULL;
}
void checkRotate() {
void checkRotate()
{
LogTest test;
test.init();
......@@ -65,15 +65,15 @@ void checkRotate() {
TEST(checkRotateTest, CheckRoateTest)
{
checkRotate();
}
void testEnableTest() {
void testEnableTest()
{
LogTest test;
test.init();
ASSERT_EQ(g_log->check_output(LOG_LEVEL_PANIC, __FILE__), true);
ASSERT_EQ(g_log->check_output(LOG_LEVEL_ERR, __FILE__), true);
ASSERT_EQ(g_log->check_output(LOG_LEVEL_WARN, __FILE__), true);
......@@ -95,11 +95,11 @@ void testEnableTest() {
TEST(testEnableTest, CheckEnableTest)
{
testEnableTest();
}
int main(int argc, char **argv) {
int main(int argc, char **argv)
{
// 分析gtest程序的命令行参数
testing::InitGoogleTest(&argc, argv);
......
/* Copyright (c) 2021 Xie Meiyi(xiemeiyi@hust.edu.cn) and OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
//
// Created by longda on 2022
//
#include <list>
#include <iostream>
#include "common/mm/mem_pool.h"
#include "gtest/gtest.h"
using namespace common;
TEST(test_mem_pool_item, test_mem_pool_item_basic)
{
MemPoolItem mem_pool_item("test");
const int item_num_per_pool = 128;
mem_pool_item.init(32, true, 1, item_num_per_pool);
std::list<void *> used_list;
int alloc_num = 1000;
for (int i = 0; i < alloc_num; i++) {
void *item = mem_pool_item.alloc();
used_list.push_back(item);
}
std::cout << mem_pool_item.to_string() << std::endl;
int pool_size = ((alloc_num + item_num_per_pool - 1) / item_num_per_pool) * item_num_per_pool;
ASSERT_EQ(alloc_num, mem_pool_item.get_used_num());
ASSERT_EQ(pool_size, mem_pool_item.get_size());
ASSERT_EQ(item_num_per_pool, mem_pool_item.get_item_num_per_pool());
ASSERT_EQ(32, mem_pool_item.get_item_size());
int free_num = item_num_per_pool * 3;
for (int i = 0; i < free_num; i++) {
auto item = used_list.front();
used_list.pop_front();
char *check = (char *)item + 10;
mem_pool_item.free(item);
mem_pool_item.free(check);
}
std::cout << mem_pool_item.to_string() << std::endl;
ASSERT_EQ(used_list.size(), mem_pool_item.get_used_num());
ASSERT_EQ(pool_size, mem_pool_item.get_size());
}
int main(int argc, char **argv)
{
// 分析gtest程序的命令行参数
testing::InitGoogleTest(&argc, argv);
// 调用RUN_ALL_TESTS()运行所有测试用例
// main函数返回RUN_ALL_TESTS()的运行结果
return RUN_ALL_TESTS();
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册