From db181edbb3a304b1d63b351964a5caa47072ec8b Mon Sep 17 00:00:00 2001 From: hnwyllmm Date: Fri, 12 Aug 2022 14:16:02 +0800 Subject: [PATCH] fix var len char --- 1.patch | 797 ++++++++++++++++++ src/observer/sql/expr/expression.h | 7 +- src/observer/sql/expr/tuple.h | 1 + src/observer/sql/expr/tuple_cell.cpp | 4 +- src/observer/sql/expr/tuple_cell.h | 5 + .../sql/operator/index_scan_operator.cpp | 4 +- .../storage/common/condition_filter.h | 2 + src/observer/storage/common/table.cpp | 18 +- src/observer/storage/common/table.h | 1 + .../storage/default/disk_buffer_pool.cpp | 2 + src/observer/storage/index/bplus_tree.cpp | 110 ++- src/observer/storage/index/bplus_tree.h | 30 +- .../storage/index/bplus_tree_index.cpp | 11 +- src/observer/storage/index/bplus_tree_index.h | 7 +- src/observer/storage/index/index.h | 4 +- src/observer/util/comparator.cpp | 18 +- src/observer/util/comparator.h | 2 +- unitest/bplus_tree_test.cpp | 88 +- 18 files changed, 1058 insertions(+), 53 deletions(-) create mode 100644 1.patch diff --git a/1.patch b/1.patch new file mode 100644 index 0000000..5eb5986 --- /dev/null +++ b/1.patch @@ -0,0 +1,797 @@ +diff --git a/src/observer/sql/expr/expression.h b/src/observer/sql/expr/expression.h +index c586bf2..59b1750 100644 +--- a/src/observer/sql/expr/expression.h ++++ b/src/observer/sql/expr/expression.h +@@ -14,6 +14,7 @@ See the Mulan PSL v2 for more details. */ + + #pragma once + ++#include + #include "storage/common/field.h" + #include "sql/expr/tuple_cell.h" + +@@ -79,7 +80,11 @@ class ValueExpr : public Expression + public: + ValueExpr() = default; + ValueExpr(const Value &value) : tuple_cell_(value.type, (char *)value.data) +- {} ++ { ++ if (value.type == CHARS) { ++ tuple_cell_.set_length(strlen((const char *)value.data)); ++ } ++ } + + virtual ~ValueExpr() = default; + +diff --git a/src/observer/sql/expr/tuple.h b/src/observer/sql/expr/tuple.h +index 07c33c7..7efed51 100644 +--- a/src/observer/sql/expr/tuple.h ++++ b/src/observer/sql/expr/tuple.h +@@ -115,6 +115,7 @@ public: + const FieldMeta *field_meta = field_expr->field().meta(); + cell.set_type(field_meta->type()); + cell.set_data(this->record_->data() + field_meta->offset()); ++ cell.set_length(field_meta->len()); + return RC::SUCCESS; + } + +diff --git a/src/observer/sql/expr/tuple_cell.cpp b/src/observer/sql/expr/tuple_cell.cpp +index 9ccd3d3..c878b31 100644 +--- a/src/observer/sql/expr/tuple_cell.cpp ++++ b/src/observer/sql/expr/tuple_cell.cpp +@@ -27,7 +27,7 @@ void TupleCell::to_string(std::ostream &os) const + os << *(float *)data_; + } break; + case CHARS: { +- for (int i = 0; i < 4; i++) { // the max length of CHARS is 4 ++ for (int i = 0; i < length_; i++) { + if (data_[i] == '\0') { + break; + } +@@ -46,7 +46,7 @@ int TupleCell::compare(const TupleCell &other) const + switch (this->attr_type_) { + case INTS: return compare_int(this->data_, other.data_); + case FLOATS: return compare_float(this->data_, other.data_); +- case CHARS: return compare_string(this->data_, other.data_, 4); ++ case CHARS: return compare_string(this->data_, this->length_, other.data_, other.length_); + default: { + LOG_WARN("unsupported type: %d", this->attr_type_); + } +diff --git a/src/observer/sql/expr/tuple_cell.h b/src/observer/sql/expr/tuple_cell.h +index 89170f2..faf3996 100644 +--- a/src/observer/sql/expr/tuple_cell.h ++++ b/src/observer/sql/expr/tuple_cell.h +@@ -31,6 +31,7 @@ public: + {} + + void set_type(AttrType type) { this->attr_type_ = type; } ++ void set_length(int length) { this->length_ = length; } + void set_data(char *data) { this->data_ = data; } + void set_data(const char *data) { this->set_data(const_cast(data)); } + +@@ -43,11 +44,15 @@ public: + return data_; + } + ++ int length() const { return length_; } ++ + AttrType attr_type() const + { + return attr_type_; + } ++ + private: + AttrType attr_type_ = UNDEFINED; ++ int length_ = -1; + char *data_ = nullptr; // real data. no need to move to field_meta.offset + }; +diff --git a/src/observer/sql/operator/index_scan_operator.cpp b/src/observer/sql/operator/index_scan_operator.cpp +index 1be1a37..2aad13b 100644 +--- a/src/observer/sql/operator/index_scan_operator.cpp ++++ b/src/observer/sql/operator/index_scan_operator.cpp +@@ -36,8 +36,8 @@ RC IndexScanOperator::open() + } + + +- IndexScanner *index_scanner = index_->create_scanner(left_cell_.data(), left_inclusive_, +- right_cell_.data(), right_inclusive_); ++ IndexScanner *index_scanner = index_->create_scanner(left_cell_.data(), left_cell_.length(), left_inclusive_, ++ right_cell_.data(), right_cell_.length(), right_inclusive_); + if (nullptr == index_scanner) { + LOG_WARN("failed to create index scanner"); + return RC::INTERNAL; +diff --git a/src/observer/storage/common/condition_filter.h b/src/observer/storage/common/condition_filter.h +index 890195a..e4b7f98 100644 +--- a/src/observer/storage/common/condition_filter.h ++++ b/src/observer/storage/common/condition_filter.h +@@ -66,6 +66,8 @@ public: + return comp_op_; + } + ++ AttrType attr_type() const { return attr_type_; } ++ + private: + ConDesc left_; + ConDesc right_; +diff --git a/src/observer/storage/common/table.cpp b/src/observer/storage/common/table.cpp +index 7ff43ca..f53be21 100644 +--- a/src/observer/storage/common/table.cpp ++++ b/src/observer/storage/common/table.cpp +@@ -326,7 +326,14 @@ RC Table::make_record(int value_num, const Value *values, char *&record_out) + for (int i = 0; i < value_num; i++) { + const FieldMeta *field = table_meta_.field(i + normal_field_start_index); + const Value &value = values[i]; +- memcpy(record + field->offset(), value.data, field->len()); ++ size_t copy_len = field->len(); ++ if (field->type() == CHARS) { ++ const size_t data_len = strlen((const char *)value.data); ++ if (copy_len > data_len) { ++ copy_len = data_len + 1; ++ } ++ } ++ memcpy(record + field->offset(), value.data, copy_len); + } + + record_out = record; +@@ -775,6 +782,8 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) + + const char *left_key = nullptr; + const char *right_key = nullptr; ++ int left_len = 4; ++ int right_len = 4; + bool left_inclusive = false; + bool right_inclusive = false; + switch (filter.comp_op()) { +@@ -809,7 +818,12 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) + return nullptr; + } + } +- return index->create_scanner(left_key, left_inclusive, right_key, right_inclusive); ++ ++ if (filter.attr_type() == CHARS) { ++ left_len = left_key != nullptr ? strlen(left_key) : 0; ++ right_len = right_key != nullptr ? strlen(right_key) : 0; ++ } ++ return index->create_scanner(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); + } + + IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) +diff --git a/src/observer/storage/common/table.h b/src/observer/storage/common/table.h +index a185535..7075537 100644 +--- a/src/observer/storage/common/table.h ++++ b/src/observer/storage/common/table.h +@@ -29,6 +29,7 @@ class IndexScanner; + class RecordDeleter; + class Trx; + ++// TODO remove the routines with condition + class Table { + public: + Table() = default; +diff --git a/src/observer/storage/default/disk_buffer_pool.cpp b/src/observer/storage/default/disk_buffer_pool.cpp +index e3953ae..18a2450 100644 +--- a/src/observer/storage/default/disk_buffer_pool.cpp ++++ b/src/observer/storage/default/disk_buffer_pool.cpp +@@ -295,6 +295,8 @@ RC DiskBufferPool::allocate_page(Frame **frame) + + RC DiskBufferPool::unpin_page(Frame *frame) + { ++ assert(frame->pin_count_ >= 1); ++ + if (--frame->pin_count_ == 0) { + PageNum page_num = frame->page_num(); + auto pages_it = disposed_pages.find(page_num); +diff --git a/src/observer/storage/index/bplus_tree.cpp b/src/observer/storage/index/bplus_tree.cpp +index 50e49f1..0e7a62d 100644 +--- a/src/observer/storage/index/bplus_tree.cpp ++++ b/src/observer/storage/index/bplus_tree.cpp +@@ -1443,10 +1443,10 @@ RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid) + return RC::SUCCESS; + } + +-RC BplusTreeHandler::get_entry(const char *user_key, std::list &rids) ++RC BplusTreeHandler::get_entry(const char *user_key, int key_len, std::list &rids) + { + BplusTreeScanner scanner(*this); +- RC rc = scanner.open(user_key, true/*left_inclusive*/, user_key, true/*right_inclusive*/); ++ RC rc = scanner.open(user_key, key_len, true/*left_inclusive*/, user_key, key_len, true/*right_inclusive*/); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to open scanner. rc=%d:%s", rc, strrc(rc)); + return rc; +@@ -1721,8 +1721,8 @@ BplusTreeScanner::~BplusTreeScanner() + close(); + } + +-RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, +- const char *right_user_key, bool right_inclusive) ++RC BplusTreeScanner::open(const char *left_user_key, int left_len, bool left_inclusive, ++ const char *right_user_key, int right_len, bool right_inclusive) + { + RC rc = RC::SUCCESS; + if (inited_) { +@@ -1753,10 +1753,30 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, + iter_index_ = 0; + } else { + char *left_key = nullptr; +- if (left_inclusive) { +- left_key = tree_handler_.make_key(left_user_key, *RID::min()); ++ ++ char *fixed_left_key = const_cast(left_user_key); ++ if (tree_handler_.file_header_.attr_type == CHARS) { ++ bool should_inclusive_after_fix = false; ++ rc = fix_user_key(left_user_key, left_len, true/*greater*/, &fixed_left_key, &should_inclusive_after_fix); ++ if (rc != RC::SUCCESS) { ++ LOG_WARN("failed to fix left user key. rc=%s", strrc(rc)); ++ return rc; ++ } ++ ++ if (should_inclusive_after_fix) { ++ left_inclusive = true; ++ } ++ } ++ ++ if (left_inclusive) { ++ left_key = tree_handler_.make_key(fixed_left_key, *RID::min()); + } else { +- left_key = tree_handler_.make_key(left_user_key, *RID::max()); ++ left_key = tree_handler_.make_key(fixed_left_key, *RID::max()); ++ } ++ ++ if (fixed_left_key != left_user_key) { ++ delete[] fixed_left_key; ++ fixed_left_key = nullptr; + } + rc = tree_handler_.find_leaf(left_key, left_frame_); + +@@ -1800,10 +1820,28 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, + } else { + + char *right_key = nullptr; ++ char *fixed_right_key = const_cast(right_user_key); ++ bool should_include_after_fix = false; ++ if (tree_handler_.file_header_.attr_type == CHARS) { ++ rc = fix_user_key(right_user_key, right_len, false/*want_greater*/, &fixed_right_key, &should_include_after_fix); ++ if (rc != RC::SUCCESS) { ++ LOG_WARN("failed to fix right user key. rc=%s", strrc(rc)); ++ return rc; ++ } ++ ++ if (should_include_after_fix) { ++ right_inclusive = true; ++ } ++ } + if (right_inclusive) { +- right_key = tree_handler_.make_key(right_user_key, *RID::max()); ++ right_key = tree_handler_.make_key(fixed_right_key, *RID::max()); + } else { +- right_key = tree_handler_.make_key(right_user_key, *RID::min()); ++ right_key = tree_handler_.make_key(fixed_right_key, *RID::min()); ++ } ++ ++ if (fixed_right_key != right_user_key) { ++ delete[] fixed_right_key; ++ fixed_right_key = nullptr; + } + + rc = tree_handler_.find_leaf(right_key, right_frame_); +@@ -1883,11 +1921,13 @@ RC BplusTreeScanner::next_entry(RID *rid) + PageNum page_num = node.next_page(); + tree_handler_.disk_buffer_pool_->unpin_page(left_frame_); + if (page_num == BP_INVALID_PAGE_NUM) { ++ left_frame_ = nullptr; + LOG_WARN("got invalid next page. page num=%d", page_num); + rc = RC::INTERNAL; + } else { + rc = tree_handler_.disk_buffer_pool_->get_this_page(page_num, &left_frame_); + if (rc != RC::SUCCESS) { ++ left_frame_ = nullptr; + LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", page_num, rc, strrc(rc)); + return rc; + } +@@ -1906,12 +1946,64 @@ RC BplusTreeScanner::close() + { + if (left_frame_ != nullptr) { + tree_handler_.disk_buffer_pool_->unpin_page(left_frame_); ++ left_frame_ = nullptr; + } + if (right_frame_ != nullptr) { + tree_handler_.disk_buffer_pool_->unpin_page(right_frame_); ++ right_frame_ = nullptr; + } + end_index_ = -1; + inited_ = false; + LOG_INFO("bplus tree scanner closed"); + return RC::SUCCESS; + } ++ ++RC BplusTreeScanner::fix_user_key(const char *user_key, int key_len, bool want_greater, ++ char **fixed_key, bool *should_inclusive) ++{ ++ if (nullptr == fixed_key || nullptr == should_inclusive) { ++ return RC::INVALID_ARGUMENT; ++ } ++ ++ // 这里很粗暴,变长字段才需要做调整,其它默认都不需要做调整 ++ assert(tree_handler_.file_header_.attr_type == CHARS); ++ assert(strlen(user_key) >= static_cast(key_len)); ++ ++ *should_inclusive = false; ++ ++ int32_t attr_length = tree_handler_.file_header_.attr_length; ++ char *key_buf = new (std::nothrow)char [attr_length]; ++ if (nullptr == key_buf) { ++ return RC::NOMEM; ++ } ++ ++ if (key_len <= attr_length) { ++ memcpy(key_buf, user_key, key_len); ++ memset(key_buf + key_len, 0, attr_length - key_len); ++ ++ *fixed_key = key_buf; ++ return RC::SUCCESS; ++ } ++ ++ // key_len > attr_length ++ memcpy(key_buf, user_key, attr_length); ++ ++ char c = user_key[attr_length]; ++ if (c == 0) { ++ *fixed_key = key_buf; ++ return RC::SUCCESS; ++ } ++ ++ // 扫描 >=/> user_key 的数据 ++ // 示例:>=/> ABCD1 的数据,attr_length=4, ++ // 等价于扫描 >= ABCE 的数据 ++ // 如果是扫描 <=/< user_key的数据 ++ // 示例:<=/< ABCD1 <==> <= ABCD (attr_length=4) ++ *should_inclusive = true; ++ if (want_greater) { ++ key_buf[attr_length - 1]++; ++ } ++ ++ *fixed_key = key_buf; ++ return RC::SUCCESS; ++} +diff --git a/src/observer/storage/index/bplus_tree.h b/src/observer/storage/index/bplus_tree.h +index 91d9d48..7a09b1b 100644 +--- a/src/observer/storage/index/bplus_tree.h ++++ b/src/observer/storage/index/bplus_tree.h +@@ -118,7 +118,14 @@ public: + return std::to_string(*(float*)v); + } + case CHARS: { +- return std::string(v, attr_length_); ++ std::string str; ++ for (int i = 0; i < attr_length_; i++) { ++ if (v[i] == 0) { ++ break; ++ } ++ str.push_back(v[i]); ++ } ++ return str; + } + default:{ + LOG_ERROR("unknown attr type. %d", attr_type_); +@@ -400,12 +407,14 @@ public: + * 此函数向IndexHandle对应的索引中插入一个索引项。 + * 参数user_key指向要插入的属性值,参数rid标识该索引项对应的元组, + * 即向索引中插入一个值为(user_key,rid)的键值对 ++ * @note 这里假设user_key的内存大小与attr_length 一致 + */ + RC insert_entry(const char *user_key, const RID *rid); + + /** + * 从IndexHandle句柄对应的索引中删除一个值为(*pData,rid)的索引项 + * @return RECORD_INVALID_KEY 指定值不存在 ++ * @note 这里假设user_key的内存大小与attr_length 一致 + */ + RC delete_entry(const char *user_key, const RID *rid); + +@@ -413,9 +422,10 @@ public: + + /** + * 获取指定值的record ++ * @param key_len user_key的长度 + * @param rid 返回值,记录记录所在的页面号和slot + */ +- RC get_entry(const char *user_key, std::list &rids); ++ RC get_entry(const char *user_key, int key_len, std::list &rids); + + RC sync(); + +@@ -493,18 +503,26 @@ public: + + /** + * 扫描指定范围的数据 +- * @param left_key 扫描范围的左边界,如果是null,则没有左边界 ++ * @param left_user_key 扫描范围的左边界,如果是null,则没有左边界 ++ * @param left_len left_user_key 的内存大小(只有在变长字段中才会关注) + * @param left_inclusive 左边界的值是否包含在内 +- * @param right_key 扫描范围的右边界。如果是null,则没有右边界 ++ * @param right_user_key 扫描范围的右边界。如果是null,则没有右边界 ++ * @param right_len right_user_key 的内存大小(只有在变长字段中才会关注) + * @param right_inclusive 右边界的值是否包含在内 + */ +- RC open(const char *left_user_key, bool left_inclusive, +- const char *right_user_key, bool right_inclusive); ++ RC open(const char *left_user_key, int left_len, bool left_inclusive, ++ const char *right_user_key, int right_len, bool right_inclusive); + + RC next_entry(RID *rid); + + RC close(); + ++private: ++ /** ++ * 如果key的类型是CHARS, 扩展或缩减user_key的大小刚好是schema中定义的大小 ++ */ ++ RC fix_user_key(const char *user_key, int key_len, bool want_greater, ++ char **fixed_key, bool *should_inclusive); + private: + bool inited_ = false; + BplusTreeHandler &tree_handler_; +diff --git a/src/observer/storage/index/bplus_tree_index.cpp b/src/observer/storage/index/bplus_tree_index.cpp +index ea69bcc..cbaef5c 100644 +--- a/src/observer/storage/index/bplus_tree_index.cpp ++++ b/src/observer/storage/index/bplus_tree_index.cpp +@@ -98,11 +98,11 @@ RC BplusTreeIndex::delete_entry(const char *record, const RID *rid) + return index_handler_.delete_entry(record + field_meta_.offset(), rid); + } + +-IndexScanner *BplusTreeIndex::create_scanner(const char *left_key, bool left_inclusive, +- const char *right_key, bool right_inclusive) ++IndexScanner *BplusTreeIndex::create_scanner(const char *left_key, int left_len, bool left_inclusive, ++ const char *right_key, int right_len, bool right_inclusive) + { + BplusTreeIndexScanner *index_scanner = new BplusTreeIndexScanner(index_handler_); +- RC rc = index_scanner->open(left_key, left_inclusive, right_key, right_inclusive); ++ RC rc = index_scanner->open(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to open index scanner. rc=%d:%s", rc, strrc(rc)); + delete index_scanner; +@@ -125,9 +125,10 @@ BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept + tree_scanner_.close(); + } + +-RC BplusTreeIndexScanner::open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive) ++RC BplusTreeIndexScanner::open(const char *left_key, int left_len, bool left_inclusive, ++ const char *right_key, int right_len, bool right_inclusive) + { +- return tree_scanner_.open(left_key, left_inclusive, right_key, right_inclusive); ++ return tree_scanner_.open(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); + } + + RC BplusTreeIndexScanner::next_entry(RID *rid) +diff --git a/src/observer/storage/index/bplus_tree_index.h b/src/observer/storage/index/bplus_tree_index.h +index 1c3ff92..c2e66f1 100644 +--- a/src/observer/storage/index/bplus_tree_index.h ++++ b/src/observer/storage/index/bplus_tree_index.h +@@ -33,8 +33,8 @@ public: + /** + * 扫描指定范围的数据 + */ +- IndexScanner *create_scanner(const char *left_key, bool left_inclusive, +- const char *right_key, bool right_inclusive) override; ++ IndexScanner *create_scanner(const char *left_key, int left_len, bool left_inclusive, ++ const char *right_key, int right_len, bool right_inclusive) override; + + RC sync() override; + +@@ -51,7 +51,8 @@ public: + RC next_entry(RID *rid) override; + RC destroy() override; + +- RC open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive); ++ RC open(const char *left_key, int left_len, bool left_inclusive, ++ const char *right_key, int right_len, bool right_inclusive); + private: + BplusTreeScanner tree_scanner_; + }; +diff --git a/src/observer/storage/index/index.h b/src/observer/storage/index/index.h +index d66a093..4f04fb4 100644 +--- a/src/observer/storage/index/index.h ++++ b/src/observer/storage/index/index.h +@@ -46,8 +46,8 @@ public: + virtual RC insert_entry(const char *record, const RID *rid) = 0; + virtual RC delete_entry(const char *record, const RID *rid) = 0; + +- virtual IndexScanner *create_scanner(const char *left_key, bool left_inclusive, +- const char *right_key, bool right_inclusive) = 0; ++ virtual IndexScanner *create_scanner(const char *left_key, int left_len, bool left_inclusive, ++ const char *right_key, int right_len, bool right_inclusive) = 0; + + virtual RC sync() = 0; + +diff --git a/src/observer/util/comparator.cpp b/src/observer/util/comparator.cpp +index f7e6a8e..1c8615f 100644 +--- a/src/observer/util/comparator.cpp ++++ b/src/observer/util/comparator.cpp +@@ -13,6 +13,7 @@ See the Mulan PSL v2 for more details. */ + // + + #include ++#include + + const double epsilon = 1E-6; + +@@ -37,9 +38,22 @@ int compare_float(void *arg1, void *arg2) + return 0; + } + +-int compare_string(void *arg1, void *arg2, int maxlen) ++int compare_string(void *arg1, int arg1_max_length, void *arg2, int arg2_max_length) + { + const char *s1 = (const char *)arg1; + const char *s2 = (const char *)arg2; +- return strncmp(s1, s2, maxlen); ++ int maxlen = std::min(arg1_max_length, arg2_max_length); ++ int result = strncmp(s1, s2, maxlen); ++ if (0 != result) { ++ return result; ++ } ++ ++ if (arg1_max_length > maxlen) { ++ return s1[maxlen] - 0; ++ } ++ ++ if (arg2_max_length > maxlen) { ++ return 0 - s2[maxlen]; ++ } ++ return 0; + } +diff --git a/src/observer/util/comparator.h b/src/observer/util/comparator.h +index c80e9f2..18ab99f 100644 +--- a/src/observer/util/comparator.h ++++ b/src/observer/util/comparator.h +@@ -16,4 +16,4 @@ See the Mulan PSL v2 for more details. */ + + int compare_int(void *arg1, void *arg2); + int compare_float(void *arg1, void *arg2); +-int compare_string(void *arg1, void *arg2, int max_length); ++int compare_string(void *arg1, int arg1_max_length, void *arg2, int arg2_max_length); +diff --git a/unitest/bplus_tree_test.cpp b/unitest/bplus_tree_test.cpp +index 5fa48fd..dabfe08 100644 +--- a/unitest/bplus_tree_test.cpp ++++ b/unitest/bplus_tree_test.cpp +@@ -31,6 +31,7 @@ using namespace common; + #define INSERT_NUM (TIMES * ORDER * ORDER * ORDER * ORDER) + #define POOL_NUM 2 + ++BufferPoolManager bpm; + BplusTreeHandler *handler = nullptr; + const char *index_name = "test.btree"; + int insert_num = INSERT_NUM; +@@ -38,6 +39,12 @@ const int page_size = 1024; + RID rid, check_rid; + int k = 0; + ++void init_bpm() ++{ ++ if (&BufferPoolManager::instance() == nullptr) { ++ BufferPoolManager::set_instance(&bpm); ++ } ++} + void test_insert() + { + RC rc = RC::SUCCESS; +@@ -148,7 +155,7 @@ void test_get() + } + + rids.clear(); +- RC rc = handler->get_entry((const char *)&i, rids); ++ RC rc = handler->get_entry((const char *)&i, 4, rids); + + ASSERT_EQ(RC::SUCCESS, rc); + ASSERT_EQ(1, rids.size()); +@@ -221,7 +228,7 @@ void test_delete() + LOG_INFO("Begin to get entry of index, i=%d, rid: %s", i, rid.to_string().c_str()); + } + rids.clear(); +- rc = handler->get_entry((const char *)&i, rids); ++ rc = handler->get_entry((const char *)&i, 4, rids); + ASSERT_EQ(RC::SUCCESS, rc); + int t = i % TIMES; + if (t == 0 || t == 1) { +@@ -458,6 +465,50 @@ TEST(test_bplus_tree, test_internal_index_node_handle) + ASSERT_EQ(i, index); + } + } ++ ++TEST(test_bplus_tree, test_chars) ++{ ++ LoggerFactory::init_default("test_chars.log"); ++ ++ const char *index_name = "chars.btree"; ++ ::remove(index_name); ++ handler = new BplusTreeHandler(); ++ handler->create(index_name, CHARS, 8, ORDER, ORDER); ++ ++ char keys[][9] = { ++ "abcdefg", ++ "12345678", ++ "12345678", ++ "abcdefg", ++ "abcdefga" ++ }; ++ ++ RID rid; ++ RC rc = RC::SUCCESS; ++ for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { ++ rid.page_num = 0; ++ rid.slot_num = i; ++ rc = handler->insert_entry(keys[i], &rid); ++ ASSERT_EQ(RC::SUCCESS, rc); ++ } ++ ++ LOG_INFO("begin to print bplus tree of chars"); ++ handler->print_tree(); ++ LOG_INFO("end to print bplus tree of chars"); ++ ++ BplusTreeScanner scanner(*handler); ++ const char *key = "abcdefg"; ++ rc = scanner.open(key, strlen(key), true, key, strlen(key), true); ++ ASSERT_EQ(rc, RC::SUCCESS); ++ ++ int count = 0; ++ while (RC::SUCCESS == (rc = scanner.next_entry(&rid))) { ++ count++; ++ } ++ scanner.close(); ++ ASSERT_EQ(2, count); ++} ++ + TEST(test_bplus_tree, test_scanner) + { + LoggerFactory::init_default("test.log"); +@@ -484,7 +535,7 @@ TEST(test_bplus_tree, test_scanner) + + int begin = -100; + int end = -20; +- rc = scanner.open((const char *)&begin, false, (const char *)&end, false); ++ rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false); + ASSERT_EQ(RC::SUCCESS, rc); + + rc = scanner.next_entry(&rid); +@@ -494,7 +545,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = -100; + end = 1; +- rc = scanner.open((const char *)&begin, false, (const char *)&end, false); ++ rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false); + ASSERT_EQ(RC::SUCCESS, rc); + rc = scanner.next_entry(&rid); + ASSERT_EQ(RC::RECORD_EOF, rc); +@@ -503,7 +554,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = -100; + end = 1; +- rc = scanner.open((const char *)&begin, false, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + rc = scanner.next_entry(&rid); + ASSERT_EQ(RC::SUCCESS, rc); +@@ -514,7 +565,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 1; + end = 3; +- rc = scanner.open((const char *)&begin, false, (const char *)&end, false/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + rc = scanner.next_entry(&rid); + ASSERT_EQ(RC::RECORD_EOF, rc); +@@ -523,7 +574,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 1; + end = 3; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { + count++; +@@ -535,7 +586,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 0; + end = 3; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -548,7 +599,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 11; + end = 21; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -561,7 +612,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 11; + end = 91; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -574,7 +625,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 191; + end = 199; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -587,7 +638,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 191; + end = 201; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -600,7 +651,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 200; + end = 301; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + rc = scanner.next_entry(&rid); + ASSERT_EQ(RC::RECORD_EOF, rc); +@@ -609,14 +660,14 @@ TEST(test_bplus_tree, test_scanner) + + begin = 300; + end = 201; +- rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::INVALID_ARGUMENT, rc); + + scanner.close(); + + begin = 300; + end = 201; +- rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open(nullptr, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -629,7 +680,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 300; + end = 10; +- rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/); ++ rc = scanner.open(nullptr, 4, true, (const char *)&end, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -642,7 +693,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 190; + end = 10; +- rc = scanner.open((const char *)&begin, true, nullptr, true/*inclusive*/); ++ rc = scanner.open((const char *)&begin, 4, true, nullptr, 4, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -655,7 +706,7 @@ TEST(test_bplus_tree, test_scanner) + + begin = 190; + end = 10; +- rc = scanner.open(nullptr, true, nullptr, true/*inclusive*/); ++ rc = scanner.open(nullptr, 0, true, nullptr, 0, true/*inclusive*/); + ASSERT_EQ(RC::SUCCESS, rc); + count = 0; + while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { +@@ -695,6 +746,7 @@ int main(int argc, char **argv) + // 调用RUN_ALL_TESTS()运行所有测试用例 + // main函数返回RUN_ALL_TESTS()的运行结果 + ++ init_bpm(); + int rc = RUN_ALL_TESTS(); + + return rc; diff --git a/src/observer/sql/expr/expression.h b/src/observer/sql/expr/expression.h index c586bf2..59b1750 100644 --- a/src/observer/sql/expr/expression.h +++ b/src/observer/sql/expr/expression.h @@ -14,6 +14,7 @@ See the Mulan PSL v2 for more details. */ #pragma once +#include #include "storage/common/field.h" #include "sql/expr/tuple_cell.h" @@ -79,7 +80,11 @@ class ValueExpr : public Expression public: ValueExpr() = default; ValueExpr(const Value &value) : tuple_cell_(value.type, (char *)value.data) - {} + { + if (value.type == CHARS) { + tuple_cell_.set_length(strlen((const char *)value.data)); + } + } virtual ~ValueExpr() = default; diff --git a/src/observer/sql/expr/tuple.h b/src/observer/sql/expr/tuple.h index 07c33c7..7efed51 100644 --- a/src/observer/sql/expr/tuple.h +++ b/src/observer/sql/expr/tuple.h @@ -115,6 +115,7 @@ public: const FieldMeta *field_meta = field_expr->field().meta(); cell.set_type(field_meta->type()); cell.set_data(this->record_->data() + field_meta->offset()); + cell.set_length(field_meta->len()); return RC::SUCCESS; } diff --git a/src/observer/sql/expr/tuple_cell.cpp b/src/observer/sql/expr/tuple_cell.cpp index 9ccd3d3..c878b31 100644 --- a/src/observer/sql/expr/tuple_cell.cpp +++ b/src/observer/sql/expr/tuple_cell.cpp @@ -27,7 +27,7 @@ void TupleCell::to_string(std::ostream &os) const os << *(float *)data_; } break; case CHARS: { - for (int i = 0; i < 4; i++) { // the max length of CHARS is 4 + for (int i = 0; i < length_; i++) { if (data_[i] == '\0') { break; } @@ -46,7 +46,7 @@ int TupleCell::compare(const TupleCell &other) const switch (this->attr_type_) { case INTS: return compare_int(this->data_, other.data_); case FLOATS: return compare_float(this->data_, other.data_); - case CHARS: return compare_string(this->data_, other.data_, 4); + case CHARS: return compare_string(this->data_, this->length_, other.data_, other.length_); default: { LOG_WARN("unsupported type: %d", this->attr_type_); } diff --git a/src/observer/sql/expr/tuple_cell.h b/src/observer/sql/expr/tuple_cell.h index 89170f2..faf3996 100644 --- a/src/observer/sql/expr/tuple_cell.h +++ b/src/observer/sql/expr/tuple_cell.h @@ -31,6 +31,7 @@ public: {} void set_type(AttrType type) { this->attr_type_ = type; } + void set_length(int length) { this->length_ = length; } void set_data(char *data) { this->data_ = data; } void set_data(const char *data) { this->set_data(const_cast(data)); } @@ -43,11 +44,15 @@ public: return data_; } + int length() const { return length_; } + AttrType attr_type() const { return attr_type_; } + private: AttrType attr_type_ = UNDEFINED; + int length_ = -1; char *data_ = nullptr; // real data. no need to move to field_meta.offset }; diff --git a/src/observer/sql/operator/index_scan_operator.cpp b/src/observer/sql/operator/index_scan_operator.cpp index 1be1a37..2aad13b 100644 --- a/src/observer/sql/operator/index_scan_operator.cpp +++ b/src/observer/sql/operator/index_scan_operator.cpp @@ -36,8 +36,8 @@ RC IndexScanOperator::open() } - IndexScanner *index_scanner = index_->create_scanner(left_cell_.data(), left_inclusive_, - right_cell_.data(), right_inclusive_); + IndexScanner *index_scanner = index_->create_scanner(left_cell_.data(), left_cell_.length(), left_inclusive_, + right_cell_.data(), right_cell_.length(), right_inclusive_); if (nullptr == index_scanner) { LOG_WARN("failed to create index scanner"); return RC::INTERNAL; diff --git a/src/observer/storage/common/condition_filter.h b/src/observer/storage/common/condition_filter.h index 890195a..e4b7f98 100644 --- a/src/observer/storage/common/condition_filter.h +++ b/src/observer/storage/common/condition_filter.h @@ -66,6 +66,8 @@ public: return comp_op_; } + AttrType attr_type() const { return attr_type_; } + private: ConDesc left_; ConDesc right_; diff --git a/src/observer/storage/common/table.cpp b/src/observer/storage/common/table.cpp index 7ff43ca..f53be21 100644 --- a/src/observer/storage/common/table.cpp +++ b/src/observer/storage/common/table.cpp @@ -326,7 +326,14 @@ RC Table::make_record(int value_num, const Value *values, char *&record_out) for (int i = 0; i < value_num; i++) { const FieldMeta *field = table_meta_.field(i + normal_field_start_index); const Value &value = values[i]; - memcpy(record + field->offset(), value.data, field->len()); + size_t copy_len = field->len(); + if (field->type() == CHARS) { + const size_t data_len = strlen((const char *)value.data); + if (copy_len > data_len) { + copy_len = data_len + 1; + } + } + memcpy(record + field->offset(), value.data, copy_len); } record_out = record; @@ -775,6 +782,8 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) const char *left_key = nullptr; const char *right_key = nullptr; + int left_len = 4; + int right_len = 4; bool left_inclusive = false; bool right_inclusive = false; switch (filter.comp_op()) { @@ -809,7 +818,12 @@ IndexScanner *Table::find_index_for_scan(const DefaultConditionFilter &filter) return nullptr; } } - return index->create_scanner(left_key, left_inclusive, right_key, right_inclusive); + + if (filter.attr_type() == CHARS) { + left_len = left_key != nullptr ? strlen(left_key) : 0; + right_len = right_key != nullptr ? strlen(right_key) : 0; + } + return index->create_scanner(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); } IndexScanner *Table::find_index_for_scan(const ConditionFilter *filter) diff --git a/src/observer/storage/common/table.h b/src/observer/storage/common/table.h index a185535..7075537 100644 --- a/src/observer/storage/common/table.h +++ b/src/observer/storage/common/table.h @@ -29,6 +29,7 @@ class IndexScanner; class RecordDeleter; class Trx; +// TODO remove the routines with condition class Table { public: Table() = default; diff --git a/src/observer/storage/default/disk_buffer_pool.cpp b/src/observer/storage/default/disk_buffer_pool.cpp index e3953ae..18a2450 100644 --- a/src/observer/storage/default/disk_buffer_pool.cpp +++ b/src/observer/storage/default/disk_buffer_pool.cpp @@ -295,6 +295,8 @@ RC DiskBufferPool::allocate_page(Frame **frame) RC DiskBufferPool::unpin_page(Frame *frame) { + assert(frame->pin_count_ >= 1); + if (--frame->pin_count_ == 0) { PageNum page_num = frame->page_num(); auto pages_it = disposed_pages.find(page_num); diff --git a/src/observer/storage/index/bplus_tree.cpp b/src/observer/storage/index/bplus_tree.cpp index 50e49f1..0e7a62d 100644 --- a/src/observer/storage/index/bplus_tree.cpp +++ b/src/observer/storage/index/bplus_tree.cpp @@ -1443,10 +1443,10 @@ RC BplusTreeHandler::insert_entry(const char *user_key, const RID *rid) return RC::SUCCESS; } -RC BplusTreeHandler::get_entry(const char *user_key, std::list &rids) +RC BplusTreeHandler::get_entry(const char *user_key, int key_len, std::list &rids) { BplusTreeScanner scanner(*this); - RC rc = scanner.open(user_key, true/*left_inclusive*/, user_key, true/*right_inclusive*/); + RC rc = scanner.open(user_key, key_len, true/*left_inclusive*/, user_key, key_len, true/*right_inclusive*/); if (rc != RC::SUCCESS) { LOG_WARN("failed to open scanner. rc=%d:%s", rc, strrc(rc)); return rc; @@ -1721,8 +1721,8 @@ BplusTreeScanner::~BplusTreeScanner() close(); } -RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, - const char *right_user_key, bool right_inclusive) +RC BplusTreeScanner::open(const char *left_user_key, int left_len, bool left_inclusive, + const char *right_user_key, int right_len, bool right_inclusive) { RC rc = RC::SUCCESS; if (inited_) { @@ -1753,10 +1753,30 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, iter_index_ = 0; } else { char *left_key = nullptr; - if (left_inclusive) { - left_key = tree_handler_.make_key(left_user_key, *RID::min()); + + char *fixed_left_key = const_cast(left_user_key); + if (tree_handler_.file_header_.attr_type == CHARS) { + bool should_inclusive_after_fix = false; + rc = fix_user_key(left_user_key, left_len, true/*greater*/, &fixed_left_key, &should_inclusive_after_fix); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to fix left user key. rc=%s", strrc(rc)); + return rc; + } + + if (should_inclusive_after_fix) { + left_inclusive = true; + } + } + + if (left_inclusive) { + left_key = tree_handler_.make_key(fixed_left_key, *RID::min()); } else { - left_key = tree_handler_.make_key(left_user_key, *RID::max()); + left_key = tree_handler_.make_key(fixed_left_key, *RID::max()); + } + + if (fixed_left_key != left_user_key) { + delete[] fixed_left_key; + fixed_left_key = nullptr; } rc = tree_handler_.find_leaf(left_key, left_frame_); @@ -1800,10 +1820,28 @@ RC BplusTreeScanner::open(const char *left_user_key, bool left_inclusive, } else { char *right_key = nullptr; + char *fixed_right_key = const_cast(right_user_key); + bool should_include_after_fix = false; + if (tree_handler_.file_header_.attr_type == CHARS) { + rc = fix_user_key(right_user_key, right_len, false/*want_greater*/, &fixed_right_key, &should_include_after_fix); + if (rc != RC::SUCCESS) { + LOG_WARN("failed to fix right user key. rc=%s", strrc(rc)); + return rc; + } + + if (should_include_after_fix) { + right_inclusive = true; + } + } if (right_inclusive) { - right_key = tree_handler_.make_key(right_user_key, *RID::max()); + right_key = tree_handler_.make_key(fixed_right_key, *RID::max()); } else { - right_key = tree_handler_.make_key(right_user_key, *RID::min()); + right_key = tree_handler_.make_key(fixed_right_key, *RID::min()); + } + + if (fixed_right_key != right_user_key) { + delete[] fixed_right_key; + fixed_right_key = nullptr; } rc = tree_handler_.find_leaf(right_key, right_frame_); @@ -1883,11 +1921,13 @@ RC BplusTreeScanner::next_entry(RID *rid) PageNum page_num = node.next_page(); tree_handler_.disk_buffer_pool_->unpin_page(left_frame_); if (page_num == BP_INVALID_PAGE_NUM) { + left_frame_ = nullptr; LOG_WARN("got invalid next page. page num=%d", page_num); rc = RC::INTERNAL; } else { rc = tree_handler_.disk_buffer_pool_->get_this_page(page_num, &left_frame_); if (rc != RC::SUCCESS) { + left_frame_ = nullptr; LOG_WARN("failed to fetch next page. page num=%d, rc=%d:%s", page_num, rc, strrc(rc)); return rc; } @@ -1906,12 +1946,64 @@ RC BplusTreeScanner::close() { if (left_frame_ != nullptr) { tree_handler_.disk_buffer_pool_->unpin_page(left_frame_); + left_frame_ = nullptr; } if (right_frame_ != nullptr) { tree_handler_.disk_buffer_pool_->unpin_page(right_frame_); + right_frame_ = nullptr; } end_index_ = -1; inited_ = false; LOG_INFO("bplus tree scanner closed"); return RC::SUCCESS; } + +RC BplusTreeScanner::fix_user_key(const char *user_key, int key_len, bool want_greater, + char **fixed_key, bool *should_inclusive) +{ + if (nullptr == fixed_key || nullptr == should_inclusive) { + return RC::INVALID_ARGUMENT; + } + + // 这里很粗暴,变长字段才需要做调整,其它默认都不需要做调整 + assert(tree_handler_.file_header_.attr_type == CHARS); + assert(strlen(user_key) >= static_cast(key_len)); + + *should_inclusive = false; + + int32_t attr_length = tree_handler_.file_header_.attr_length; + char *key_buf = new (std::nothrow)char [attr_length]; + if (nullptr == key_buf) { + return RC::NOMEM; + } + + if (key_len <= attr_length) { + memcpy(key_buf, user_key, key_len); + memset(key_buf + key_len, 0, attr_length - key_len); + + *fixed_key = key_buf; + return RC::SUCCESS; + } + + // key_len > attr_length + memcpy(key_buf, user_key, attr_length); + + char c = user_key[attr_length]; + if (c == 0) { + *fixed_key = key_buf; + return RC::SUCCESS; + } + + // 扫描 >=/> user_key 的数据 + // 示例:>=/> ABCD1 的数据,attr_length=4, + // 等价于扫描 >= ABCE 的数据 + // 如果是扫描 <=/< user_key的数据 + // 示例:<=/< ABCD1 <==> <= ABCD (attr_length=4) + *should_inclusive = true; + if (want_greater) { + key_buf[attr_length - 1]++; + } + + *fixed_key = key_buf; + return RC::SUCCESS; +} diff --git a/src/observer/storage/index/bplus_tree.h b/src/observer/storage/index/bplus_tree.h index 91d9d48..7a09b1b 100644 --- a/src/observer/storage/index/bplus_tree.h +++ b/src/observer/storage/index/bplus_tree.h @@ -118,7 +118,14 @@ public: return std::to_string(*(float*)v); } case CHARS: { - return std::string(v, attr_length_); + std::string str; + for (int i = 0; i < attr_length_; i++) { + if (v[i] == 0) { + break; + } + str.push_back(v[i]); + } + return str; } default:{ LOG_ERROR("unknown attr type. %d", attr_type_); @@ -400,12 +407,14 @@ public: * 此函数向IndexHandle对应的索引中插入一个索引项。 * 参数user_key指向要插入的属性值,参数rid标识该索引项对应的元组, * 即向索引中插入一个值为(user_key,rid)的键值对 + * @note 这里假设user_key的内存大小与attr_length 一致 */ RC insert_entry(const char *user_key, const RID *rid); /** * 从IndexHandle句柄对应的索引中删除一个值为(*pData,rid)的索引项 * @return RECORD_INVALID_KEY 指定值不存在 + * @note 这里假设user_key的内存大小与attr_length 一致 */ RC delete_entry(const char *user_key, const RID *rid); @@ -413,9 +422,10 @@ public: /** * 获取指定值的record + * @param key_len user_key的长度 * @param rid 返回值,记录记录所在的页面号和slot */ - RC get_entry(const char *user_key, std::list &rids); + RC get_entry(const char *user_key, int key_len, std::list &rids); RC sync(); @@ -493,18 +503,26 @@ public: /** * 扫描指定范围的数据 - * @param left_key 扫描范围的左边界,如果是null,则没有左边界 + * @param left_user_key 扫描范围的左边界,如果是null,则没有左边界 + * @param left_len left_user_key 的内存大小(只有在变长字段中才会关注) * @param left_inclusive 左边界的值是否包含在内 - * @param right_key 扫描范围的右边界。如果是null,则没有右边界 + * @param right_user_key 扫描范围的右边界。如果是null,则没有右边界 + * @param right_len right_user_key 的内存大小(只有在变长字段中才会关注) * @param right_inclusive 右边界的值是否包含在内 */ - RC open(const char *left_user_key, bool left_inclusive, - const char *right_user_key, bool right_inclusive); + RC open(const char *left_user_key, int left_len, bool left_inclusive, + const char *right_user_key, int right_len, bool right_inclusive); RC next_entry(RID *rid); RC close(); +private: + /** + * 如果key的类型是CHARS, 扩展或缩减user_key的大小刚好是schema中定义的大小 + */ + RC fix_user_key(const char *user_key, int key_len, bool want_greater, + char **fixed_key, bool *should_inclusive); private: bool inited_ = false; BplusTreeHandler &tree_handler_; diff --git a/src/observer/storage/index/bplus_tree_index.cpp b/src/observer/storage/index/bplus_tree_index.cpp index ea69bcc..cbaef5c 100644 --- a/src/observer/storage/index/bplus_tree_index.cpp +++ b/src/observer/storage/index/bplus_tree_index.cpp @@ -98,11 +98,11 @@ RC BplusTreeIndex::delete_entry(const char *record, const RID *rid) return index_handler_.delete_entry(record + field_meta_.offset(), rid); } -IndexScanner *BplusTreeIndex::create_scanner(const char *left_key, bool left_inclusive, - const char *right_key, bool right_inclusive) +IndexScanner *BplusTreeIndex::create_scanner(const char *left_key, int left_len, bool left_inclusive, + const char *right_key, int right_len, bool right_inclusive) { BplusTreeIndexScanner *index_scanner = new BplusTreeIndexScanner(index_handler_); - RC rc = index_scanner->open(left_key, left_inclusive, right_key, right_inclusive); + RC rc = index_scanner->open(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); if (rc != RC::SUCCESS) { LOG_WARN("failed to open index scanner. rc=%d:%s", rc, strrc(rc)); delete index_scanner; @@ -125,9 +125,10 @@ BplusTreeIndexScanner::~BplusTreeIndexScanner() noexcept tree_scanner_.close(); } -RC BplusTreeIndexScanner::open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive) +RC BplusTreeIndexScanner::open(const char *left_key, int left_len, bool left_inclusive, + const char *right_key, int right_len, bool right_inclusive) { - return tree_scanner_.open(left_key, left_inclusive, right_key, right_inclusive); + return tree_scanner_.open(left_key, left_len, left_inclusive, right_key, right_len, right_inclusive); } RC BplusTreeIndexScanner::next_entry(RID *rid) diff --git a/src/observer/storage/index/bplus_tree_index.h b/src/observer/storage/index/bplus_tree_index.h index 1c3ff92..c2e66f1 100644 --- a/src/observer/storage/index/bplus_tree_index.h +++ b/src/observer/storage/index/bplus_tree_index.h @@ -33,8 +33,8 @@ public: /** * 扫描指定范围的数据 */ - IndexScanner *create_scanner(const char *left_key, bool left_inclusive, - const char *right_key, bool right_inclusive) override; + IndexScanner *create_scanner(const char *left_key, int left_len, bool left_inclusive, + const char *right_key, int right_len, bool right_inclusive) override; RC sync() override; @@ -51,7 +51,8 @@ public: RC next_entry(RID *rid) override; RC destroy() override; - RC open(const char *left_key, bool left_inclusive, const char *right_key, bool right_inclusive); + RC open(const char *left_key, int left_len, bool left_inclusive, + const char *right_key, int right_len, bool right_inclusive); private: BplusTreeScanner tree_scanner_; }; diff --git a/src/observer/storage/index/index.h b/src/observer/storage/index/index.h index d66a093..4f04fb4 100644 --- a/src/observer/storage/index/index.h +++ b/src/observer/storage/index/index.h @@ -46,8 +46,8 @@ public: virtual RC insert_entry(const char *record, const RID *rid) = 0; virtual RC delete_entry(const char *record, const RID *rid) = 0; - virtual IndexScanner *create_scanner(const char *left_key, bool left_inclusive, - const char *right_key, bool right_inclusive) = 0; + virtual IndexScanner *create_scanner(const char *left_key, int left_len, bool left_inclusive, + const char *right_key, int right_len, bool right_inclusive) = 0; virtual RC sync() = 0; diff --git a/src/observer/util/comparator.cpp b/src/observer/util/comparator.cpp index f7e6a8e..1c8615f 100644 --- a/src/observer/util/comparator.cpp +++ b/src/observer/util/comparator.cpp @@ -13,6 +13,7 @@ See the Mulan PSL v2 for more details. */ // #include +#include const double epsilon = 1E-6; @@ -37,9 +38,22 @@ int compare_float(void *arg1, void *arg2) return 0; } -int compare_string(void *arg1, void *arg2, int maxlen) +int compare_string(void *arg1, int arg1_max_length, void *arg2, int arg2_max_length) { const char *s1 = (const char *)arg1; const char *s2 = (const char *)arg2; - return strncmp(s1, s2, maxlen); + int maxlen = std::min(arg1_max_length, arg2_max_length); + int result = strncmp(s1, s2, maxlen); + if (0 != result) { + return result; + } + + if (arg1_max_length > maxlen) { + return s1[maxlen] - 0; + } + + if (arg2_max_length > maxlen) { + return 0 - s2[maxlen]; + } + return 0; } diff --git a/src/observer/util/comparator.h b/src/observer/util/comparator.h index c80e9f2..18ab99f 100644 --- a/src/observer/util/comparator.h +++ b/src/observer/util/comparator.h @@ -16,4 +16,4 @@ See the Mulan PSL v2 for more details. */ int compare_int(void *arg1, void *arg2); int compare_float(void *arg1, void *arg2); -int compare_string(void *arg1, void *arg2, int max_length); +int compare_string(void *arg1, int arg1_max_length, void *arg2, int arg2_max_length); diff --git a/unitest/bplus_tree_test.cpp b/unitest/bplus_tree_test.cpp index 5fa48fd..dabfe08 100644 --- a/unitest/bplus_tree_test.cpp +++ b/unitest/bplus_tree_test.cpp @@ -31,6 +31,7 @@ using namespace common; #define INSERT_NUM (TIMES * ORDER * ORDER * ORDER * ORDER) #define POOL_NUM 2 +BufferPoolManager bpm; BplusTreeHandler *handler = nullptr; const char *index_name = "test.btree"; int insert_num = INSERT_NUM; @@ -38,6 +39,12 @@ const int page_size = 1024; RID rid, check_rid; int k = 0; +void init_bpm() +{ + if (&BufferPoolManager::instance() == nullptr) { + BufferPoolManager::set_instance(&bpm); + } +} void test_insert() { RC rc = RC::SUCCESS; @@ -148,7 +155,7 @@ void test_get() } rids.clear(); - RC rc = handler->get_entry((const char *)&i, rids); + RC rc = handler->get_entry((const char *)&i, 4, rids); ASSERT_EQ(RC::SUCCESS, rc); ASSERT_EQ(1, rids.size()); @@ -221,7 +228,7 @@ void test_delete() LOG_INFO("Begin to get entry of index, i=%d, rid: %s", i, rid.to_string().c_str()); } rids.clear(); - rc = handler->get_entry((const char *)&i, rids); + rc = handler->get_entry((const char *)&i, 4, rids); ASSERT_EQ(RC::SUCCESS, rc); int t = i % TIMES; if (t == 0 || t == 1) { @@ -458,6 +465,50 @@ TEST(test_bplus_tree, test_internal_index_node_handle) ASSERT_EQ(i, index); } } + +TEST(test_bplus_tree, test_chars) +{ + LoggerFactory::init_default("test_chars.log"); + + const char *index_name = "chars.btree"; + ::remove(index_name); + handler = new BplusTreeHandler(); + handler->create(index_name, CHARS, 8, ORDER, ORDER); + + char keys[][9] = { + "abcdefg", + "12345678", + "12345678", + "abcdefg", + "abcdefga" + }; + + RID rid; + RC rc = RC::SUCCESS; + for (size_t i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { + rid.page_num = 0; + rid.slot_num = i; + rc = handler->insert_entry(keys[i], &rid); + ASSERT_EQ(RC::SUCCESS, rc); + } + + LOG_INFO("begin to print bplus tree of chars"); + handler->print_tree(); + LOG_INFO("end to print bplus tree of chars"); + + BplusTreeScanner scanner(*handler); + const char *key = "abcdefg"; + rc = scanner.open(key, strlen(key), true, key, strlen(key), true); + ASSERT_EQ(rc, RC::SUCCESS); + + int count = 0; + while (RC::SUCCESS == (rc = scanner.next_entry(&rid))) { + count++; + } + scanner.close(); + ASSERT_EQ(2, count); +} + TEST(test_bplus_tree, test_scanner) { LoggerFactory::init_default("test.log"); @@ -484,7 +535,7 @@ TEST(test_bplus_tree, test_scanner) int begin = -100; int end = -20; - rc = scanner.open((const char *)&begin, false, (const char *)&end, false); + rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false); ASSERT_EQ(RC::SUCCESS, rc); rc = scanner.next_entry(&rid); @@ -494,7 +545,7 @@ TEST(test_bplus_tree, test_scanner) begin = -100; end = 1; - rc = scanner.open((const char *)&begin, false, (const char *)&end, false); + rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false); ASSERT_EQ(RC::SUCCESS, rc); rc = scanner.next_entry(&rid); ASSERT_EQ(RC::RECORD_EOF, rc); @@ -503,7 +554,7 @@ TEST(test_bplus_tree, test_scanner) begin = -100; end = 1; - rc = scanner.open((const char *)&begin, false, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); rc = scanner.next_entry(&rid); ASSERT_EQ(RC::SUCCESS, rc); @@ -514,7 +565,7 @@ TEST(test_bplus_tree, test_scanner) begin = 1; end = 3; - rc = scanner.open((const char *)&begin, false, (const char *)&end, false/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, false, (const char *)&end, 4, false/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); rc = scanner.next_entry(&rid); ASSERT_EQ(RC::RECORD_EOF, rc); @@ -523,7 +574,7 @@ TEST(test_bplus_tree, test_scanner) begin = 1; end = 3; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { count++; @@ -535,7 +586,7 @@ TEST(test_bplus_tree, test_scanner) begin = 0; end = 3; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -548,7 +599,7 @@ TEST(test_bplus_tree, test_scanner) begin = 11; end = 21; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -561,7 +612,7 @@ TEST(test_bplus_tree, test_scanner) begin = 11; end = 91; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -574,7 +625,7 @@ TEST(test_bplus_tree, test_scanner) begin = 191; end = 199; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -587,7 +638,7 @@ TEST(test_bplus_tree, test_scanner) begin = 191; end = 201; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -600,7 +651,7 @@ TEST(test_bplus_tree, test_scanner) begin = 200; end = 301; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); rc = scanner.next_entry(&rid); ASSERT_EQ(RC::RECORD_EOF, rc); @@ -609,14 +660,14 @@ TEST(test_bplus_tree, test_scanner) begin = 300; end = 201; - rc = scanner.open((const char *)&begin, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::INVALID_ARGUMENT, rc); scanner.close(); begin = 300; end = 201; - rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open(nullptr, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -629,7 +680,7 @@ TEST(test_bplus_tree, test_scanner) begin = 300; end = 10; - rc = scanner.open(nullptr, true, (const char *)&end, true/*inclusive*/); + rc = scanner.open(nullptr, 4, true, (const char *)&end, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -642,7 +693,7 @@ TEST(test_bplus_tree, test_scanner) begin = 190; end = 10; - rc = scanner.open((const char *)&begin, true, nullptr, true/*inclusive*/); + rc = scanner.open((const char *)&begin, 4, true, nullptr, 4, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -655,7 +706,7 @@ TEST(test_bplus_tree, test_scanner) begin = 190; end = 10; - rc = scanner.open(nullptr, true, nullptr, true/*inclusive*/); + rc = scanner.open(nullptr, 0, true, nullptr, 0, true/*inclusive*/); ASSERT_EQ(RC::SUCCESS, rc); count = 0; while ((rc = scanner.next_entry(&rid)) == RC::SUCCESS) { @@ -695,6 +746,7 @@ int main(int argc, char **argv) // 调用RUN_ALL_TESTS()运行所有测试用例 // main函数返回RUN_ALL_TESTS()的运行结果 + init_bpm(); int rc = RUN_ALL_TESTS(); return rc; -- GitLab