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