599 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			599 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /**
 | |
|  * Copyright (c) 2021 OceanBase
 | |
|  * OceanBase CE is licensed under Mulan PubL v2.
 | |
|  * You can use this software according to the terms and conditions of the Mulan PubL v2.
 | |
|  * You may obtain a copy of Mulan PubL v2 at:
 | |
|  *          http://license.coscl.org.cn/MulanPubL-2.0
 | |
|  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | |
|  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | |
|  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | |
|  * See the Mulan PubL v2 for more details.
 | |
|  */
 | |
| 
 | |
| #define USING_LOG_PREFIX STORAGE
 | |
| #include "ob_sstable_rowkey_helper.h"
 | |
| #include "lib/container/ob_fixed_array_iterator.h"
 | |
| #include "share/ob_get_compat_mode.h"
 | |
| #include "storage/ob_sstable.h"
 | |
| 
 | |
| namespace oceanbase {
 | |
| using namespace common;
 | |
| using namespace blocksstable;
 | |
| using namespace share;
 | |
| using namespace share::schema;
 | |
| namespace storage {
 | |
| /*
 | |
|  *ObRowkeyObjComparer
 | |
|  */
 | |
| // temporarily keep if in compare func
 | |
| // remove if to build more compare funcs array when perf critical
 | |
| int ObRowkeyObjComparer::sstable_number_cmp_func(const ObObj& obj1, const ObObj& obj2, const ObCompareCtx& cmp_ctx)
 | |
| {
 | |
|   int cmp = 0;
 | |
|   UNUSED(cmp_ctx);
 | |
|   if (OB_UNLIKELY(!obj1.is_number() || !obj2.is_number())) {
 | |
|     LOG_ERROR("unexpected error. mismatch function for comparison", K(obj1), K(obj2));
 | |
|     right_to_die_or_duty_to_live();
 | |
|   } else if (OB_LIKELY(((is_smallint_number(obj1) && is_smallint_number(obj2))))) {
 | |
|     cmp = obj1.v_.nmb_digits_[0] - obj2.v_.nmb_digits_[0];
 | |
|     cmp = cmp > 0 ? ObObjCmpFuncs::CR_GT : cmp < 0 ? ObObjCmpFuncs::CR_LT : ObObjCmpFuncs::CR_EQ;
 | |
|   } else {
 | |
|     cmp = number::ObNumber::compare(obj1.nmb_desc_, obj1.v_.nmb_digits_, obj2.nmb_desc_, obj2.v_.nmb_digits_);
 | |
|   }
 | |
|   return cmp;
 | |
| }
 | |
| 
 | |
| int ObRowkeyObjComparer::sstable_collation_free_cmp_func(
 | |
|     const ObObj& obj1, const ObObj& obj2, const ObCompareCtx& cmp_ctx)
 | |
| {
 | |
|   int cmp = 0;
 | |
| 
 | |
|   UNUSED(cmp_ctx);
 | |
|   if (OB_UNLIKELY(
 | |
|           CS_TYPE_COLLATION_FREE != obj2.get_collation_type() || obj1.get_collation_type() != obj2.get_collation_type()
 | |
|           //|| obj1.get_type() != obj2.get_type()
 | |
|           //|| !obj1.is_varchar_or_char()
 | |
|           )) {
 | |
|     STORAGE_LOG(ERROR, "unexpected error, invalid argument", K(obj1), K(obj2));
 | |
|     right_to_die_or_duty_to_live();
 | |
|   } else {
 | |
|     const int32_t lhs_len = obj1.get_val_len();
 | |
|     const int32_t rhs_len = obj2.get_val_len();
 | |
|     const int32_t cmp_len = MIN(lhs_len, rhs_len);
 | |
|     cmp = MEMCMP(obj1.get_string_ptr(), obj2.get_string_ptr(), cmp_len);
 | |
|     if (0 == cmp) {
 | |
|       if (lhs_len != rhs_len) {
 | |
|         // in mysql mode, we should strip all trailing blanks before comparing two strings
 | |
|         const int32_t left_len = (lhs_len > cmp_len) ? lhs_len - cmp_len : rhs_len - cmp_len;
 | |
|         const char* ptr = (lhs_len > cmp_len) ? obj1.get_string_ptr() : obj2.get_string_ptr();
 | |
|         const unsigned char* uptr = reinterpret_cast<const unsigned char*>(ptr + cmp_len);
 | |
|         // int32_t is always capable of stroing the max lenth of varchar or char
 | |
|         for (int32_t i = 0; i < left_len; ++i) {
 | |
|           if (*(uptr + i) != ' ') {
 | |
|             // special behavior in mysql mode, 'a\1 < a' and 'ab > a'
 | |
|             if (*(uptr + i) < ' ') {
 | |
|               cmp = lhs_len > cmp_len ? ObObjCmpFuncs::CR_LT : ObObjCmpFuncs::CR_GT;
 | |
|             } else {
 | |
|               cmp = lhs_len > cmp_len ? ObObjCmpFuncs::CR_GT : ObObjCmpFuncs::CR_LT;
 | |
|             }
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       cmp = cmp > 0 ? ObObjCmpFuncs::CR_GT : ObObjCmpFuncs::CR_LT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return cmp;
 | |
| }
 | |
| 
 | |
| int ObRowkeyObjComparer::sstable_oracle_collation_free_cmp_func(
 | |
|     const ObObj& obj1, const ObObj& obj2, const ObCompareCtx& cmp_ctx)
 | |
| {
 | |
|   int cmp = 0;
 | |
| 
 | |
|   UNUSED(cmp_ctx);
 | |
|   if (OB_UNLIKELY(
 | |
|           CS_TYPE_COLLATION_FREE != obj2.get_collation_type() || obj1.get_collation_type() != obj2.get_collation_type()
 | |
|           //|| obj1.get_type() != obj2.get_type()
 | |
|           //|| !obj1.is_varchar_or_char()
 | |
|           )) {
 | |
|     STORAGE_LOG(ERROR, "unexpected error, invalid argument", K(obj1), K(obj2));
 | |
|     right_to_die_or_duty_to_live();
 | |
|   } else {
 | |
|     const int32_t lhs_len = obj1.get_val_len();
 | |
|     const int32_t rhs_len = obj2.get_val_len();
 | |
|     const int32_t cmp_len = MIN(lhs_len, rhs_len);
 | |
|     cmp = MEMCMP(obj1.get_string_ptr(), obj2.get_string_ptr(), cmp_len);
 | |
|     if (0 == cmp) {
 | |
|       // in oracle mode, we should consider the trailing blanks during comparing two varchar
 | |
|       if (obj1.is_varying_len_char_type()) {
 | |
|         if (lhs_len != rhs_len) {
 | |
|           cmp = lhs_len > cmp_len ? ObObjCmpFuncs::CR_GT : ObObjCmpFuncs::CR_LT;
 | |
|         }
 | |
|       } else {
 | |
|         // in oracle mode, we should strip all trailing blanks before comparing two char
 | |
|         const int32_t left_len = (lhs_len > cmp_len) ? lhs_len - cmp_len : rhs_len - cmp_len;
 | |
|         const char* ptr = (lhs_len > cmp_len) ? obj1.get_string_ptr() : obj2.get_string_ptr();
 | |
|         const unsigned char* uptr = reinterpret_cast<const unsigned char*>(ptr + cmp_len);
 | |
|         // int32_t is always capable of stroing the max lenth of varchar or char
 | |
|         for (int32_t i = 0; i < left_len; ++i) {
 | |
|           if (*(uptr + i) != ' ') {
 | |
|             // mysql特殊行为:a\1 < a,但ab > a
 | |
|             if (*(uptr + i) < ' ') {
 | |
|               cmp = lhs_len > cmp_len ? ObObjCmpFuncs::CR_LT : ObObjCmpFuncs::CR_GT;
 | |
|             } else {
 | |
|               cmp = lhs_len > cmp_len ? ObObjCmpFuncs::CR_GT : ObObjCmpFuncs::CR_LT;
 | |
|             }
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     } else {
 | |
|       cmp = cmp > 0 ? ObObjCmpFuncs::CR_GT : ObObjCmpFuncs::CR_LT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return cmp;
 | |
| }
 | |
| 
 | |
| ObRowkeyObjComparer::ObRowkeyObjComparer()
 | |
|     : cmp_func_(NULL),
 | |
|       cmp_ctx_(ObMaxType, CS_TYPE_INVALID, false, INVALID_TZ_OFF, NULL_FIRST),
 | |
|       is_collation_free_(false),
 | |
|       type_(COMPARER_MYSQL)
 | |
| {}
 | |
| 
 | |
| void ObRowkeyObjComparer::reset()
 | |
| {
 | |
|   cmp_func_ = NULL;
 | |
|   cmp_ctx_.cmp_cs_type_ = CS_TYPE_INVALID;
 | |
|   is_collation_free_ = false;
 | |
| }
 | |
| 
 | |
| int ObRowkeyObjComparer::init_compare_func(const ObObjMeta& obj_meta)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(!obj_meta.is_valid())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to init compare func", K(obj_meta), K(ret));
 | |
|   } else {
 | |
|     reset();
 | |
|     if (obj_meta.is_number()) {
 | |
|       cmp_func_ = sstable_number_cmp_func;
 | |
|     } else {
 | |
|       ObObjTypeClass obj_tc = obj_meta.get_type_class();
 | |
|       if (OB_FAIL(ObObjCmpFuncs::get_cmp_func(obj_tc, obj_tc, CO_CMP, cmp_func_))) {
 | |
|         STORAGE_LOG(WARN, "Failed to find rowkey obj cmp func", K(obj_meta), K(obj_tc), K(ret));
 | |
|       } else if (OB_ISNULL(cmp_func_)) {
 | |
|         ret = OB_ERR_UNEXPECTED;
 | |
|         STORAGE_LOG(WARN, "Failed to find rowkey cmp func", K(ret));
 | |
|       }
 | |
|     }
 | |
|     if (OB_SUCC(ret)) {
 | |
|       cmp_ctx_.cmp_cs_type_ = obj_meta.get_collation_type();
 | |
|       is_collation_free_ = false;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObRowkeyObjComparer::init_compare_func_collation_free(const common::ObObjMeta& obj_meta)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(!obj_meta.is_valid())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to init collation free compare func", K(obj_meta), K(ret));
 | |
|   } else if (obj_meta.is_collation_free_compatible()) {
 | |
|     reset();
 | |
|     cmp_func_ = sstable_collation_free_cmp_func;
 | |
|     cmp_ctx_.cmp_cs_type_ = obj_meta.get_collation_type();
 | |
|     is_collation_free_ = true;
 | |
|   } else if (OB_FAIL(init_compare_func(obj_meta))) {
 | |
|     STORAGE_LOG(WARN, "Failed to init compare func", K(obj_meta), K(ret));
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *ObRowkeyObjComparerOracle
 | |
|  */
 | |
| 
 | |
| int ObRowkeyObjComparerOracle::init_compare_func_collation_free(const common::ObObjMeta& obj_meta)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   // TODO  oracle mode need add raw type future
 | |
|   if (OB_UNLIKELY(!obj_meta.is_valid() || !obj_meta.is_collation_free_compatible())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to init collation free compare func", K(obj_meta), K(ret));
 | |
|   } else {
 | |
|     reset();
 | |
|     cmp_func_ = sstable_oracle_collation_free_cmp_func;
 | |
|     cmp_ctx_.cmp_cs_type_ = obj_meta.get_collation_type();
 | |
|     is_collation_free_ = true;
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  *ObSSTableRowkeyHelper
 | |
|  */
 | |
| 
 | |
| ObSSTableRowkeyHelper::ObSSTableRowkeyHelper()
 | |
|     : endkeys_(),
 | |
|       collation_free_endkeys_(),
 | |
|       cmp_funcs_(),
 | |
|       collation_free_cmp_funcs_(),
 | |
|       rowkey_column_cnt_(0),
 | |
|       column_type_array_(NULL),
 | |
|       sstable_(nullptr),
 | |
|       exist_collation_free_(false),
 | |
|       use_cmp_nullsafe_(false),
 | |
|       is_oracle_mode_(false),
 | |
|       is_inited_(false)
 | |
| {}
 | |
| 
 | |
| void ObSSTableRowkeyHelper::reset()
 | |
| {
 | |
|   endkeys_.reset();
 | |
|   collation_free_endkeys_.reset();
 | |
|   cmp_funcs_.reset();
 | |
|   collation_free_cmp_funcs_.reset();
 | |
|   rowkey_column_cnt_ = 0;
 | |
|   column_type_array_ = NULL;
 | |
|   sstable_ = nullptr;
 | |
|   exist_collation_free_ = false;
 | |
|   use_cmp_nullsafe_ = false;
 | |
|   is_oracle_mode_ = false;
 | |
|   is_inited_ = false;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::get_macro_block_meta(
 | |
|     const MacroBlockId& macro_id, ObFullMacroBlockMeta& macro_meta, const int64_t schema_rowkey_column_cnt)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (!macro_id.is_valid() || schema_rowkey_column_cnt <= 0) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to get macro block meta", K(macro_id), K(schema_rowkey_column_cnt), K(ret));
 | |
|   } else if (OB_FAIL(sstable_->get_meta(macro_id, macro_meta))) {
 | |
|     STORAGE_LOG(WARN, "fail to get meta", K(ret), K(macro_id));
 | |
|   } else if (!macro_meta.is_valid()) {
 | |
|     ret = OB_ERR_SYS;
 | |
|     STORAGE_LOG(WARN, "Unexpected null macro meta", K(ret));
 | |
|   } else if (OB_ISNULL(macro_meta.meta_->endkey_) || OB_ISNULL(macro_meta.schema_->column_type_array_)) {
 | |
|     ret = OB_ERR_SYS;
 | |
|     STORAGE_LOG(WARN, "Unexpected null data macro endkey", K(macro_meta), K(ret));
 | |
|   } else if (OB_UNLIKELY(macro_meta.meta_->rowkey_column_number_ < schema_rowkey_column_cnt)) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     STORAGE_LOG(WARN,
 | |
|         "Unexpected mis matched rowkey column number",
 | |
|         K(macro_meta.meta_->rowkey_column_number_),
 | |
|         K(schema_rowkey_column_cnt),
 | |
|         K(ret));
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::build_macro_endkeys(const ObIArray<MacroBlockId>& macro_ids, ObIAllocator& allocator,
 | |
|     const int64_t schema_rowkey_column_cnt, const bool need_build_collation_free)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(macro_ids.count() == 0 || schema_rowkey_column_cnt <= 0)) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to build macro endkeys", K(macro_ids), K(schema_rowkey_column_cnt), K(ret));
 | |
|   } else {
 | |
|     int64_t macro_block_count = macro_ids.count();
 | |
|     ObFullMacroBlockMeta full_meta;
 | |
|     ObStoreRowkey rowkey;
 | |
| 
 | |
|     endkeys_.set_allocator(&allocator);
 | |
|     endkeys_.set_capacity(static_cast<uint32_t>(macro_block_count));
 | |
|     for (int64_t i = 0; OB_SUCC(ret) && i < macro_block_count; i++) {
 | |
|       if (OB_FAIL(get_macro_block_meta(macro_ids.at(i), full_meta, schema_rowkey_column_cnt))) {
 | |
|         STORAGE_LOG(WARN, "Failed to get macro block meta", K(i), K(ret));
 | |
|       } else {
 | |
|         const ObMacroBlockMetaV2* macro_meta = full_meta.meta_;
 | |
|         rowkey.assign(macro_meta->endkey_, macro_meta->rowkey_column_number_);
 | |
|         // TODO consider column order
 | |
|         if (rowkey.contains_min_or_max_obj() || (!use_cmp_nullsafe_ && rowkey.contains_null_obj())) {
 | |
|           ret = OB_ERR_SYS;
 | |
|           STORAGE_LOG(WARN, "Unexpected max or min macro endkey", K(rowkey), K(ret));
 | |
|         } else if (0 == i) {
 | |
|           rowkey_column_cnt_ = macro_meta->rowkey_column_number_;
 | |
|           column_type_array_ = full_meta.schema_->column_type_array_;
 | |
|           exist_collation_free_ = false;
 | |
|           if (need_build_collation_free) {
 | |
|             for (int64_t i = 0; !exist_collation_free_ && i < rowkey_column_cnt_; i++) {
 | |
|               if (column_type_array_[i].is_collation_free_compatible()) {
 | |
|                 exist_collation_free_ = true;
 | |
|               }
 | |
|             }
 | |
|             if (exist_collation_free_) {
 | |
|               collation_free_endkeys_.set_allocator(&allocator);
 | |
|               collation_free_endkeys_.set_capacity(static_cast<uint32_t>(macro_block_count));
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|         if (OB_FAIL(ret)) {
 | |
|         } else if (OB_FAIL(endkeys_.push_back(rowkey))) {
 | |
|           STORAGE_LOG(WARN, "Failed to push back macroblock endkey", K(rowkey), K(ret));
 | |
|         } else if (exist_collation_free_) {
 | |
|           if (OB_ISNULL(macro_meta->collation_free_endkey_)) {
 | |
|             // defend code to check null collation free endkey
 | |
|             for (int64_t i = 0; i < rowkey_column_cnt_; i++) {
 | |
|               // original varchar or char should be null now
 | |
|               if (rowkey.get_obj_ptr()[i].is_collation_free_compatible()) {
 | |
|                 ret = OB_ERR_UNEXPECTED;
 | |
|                 STORAGE_LOG(WARN, "Unexpected null collation freekey with valid rowkey", K(i), K(*macro_meta), K(ret));
 | |
|               }
 | |
|             }
 | |
|           } else {
 | |
|             rowkey.assign(macro_meta->collation_free_endkey_, macro_meta->rowkey_column_number_);
 | |
|           }
 | |
|           if (OB_SUCC(ret)) {
 | |
|             if (OB_FAIL(collation_free_endkeys_.push_back(rowkey))) {
 | |
|               STORAGE_LOG(WARN, "Failed to push back macroblock endkey", K(rowkey), K(ret));
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (OB_SUCC(ret)) {
 | |
|       if (endkeys_.count() != macro_block_count ||
 | |
|           (exist_collation_free_ && collation_free_endkeys_.count() != macro_block_count)) {
 | |
|         ret = OB_ERR_UNEXPECTED;
 | |
|         STORAGE_LOG(WARN,
 | |
|             "Unexpected macro block endkeys count",
 | |
|             K(macro_block_count),
 | |
|             K_(exist_collation_free),
 | |
|             K(endkeys_.count()),
 | |
|             K(collation_free_endkeys_.count()),
 | |
|             K(ret));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| int ObSSTableRowkeyHelper::make_rowkey_cmp_funcs(ObIAllocator& allocator)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_ISNULL(column_type_array_) || rowkey_column_cnt_ <= 0) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     STORAGE_LOG(WARN,
 | |
|         "Unexpected null column type array or rowkey column cnt",
 | |
|         KP_(column_type_array),
 | |
|         K_(rowkey_column_cnt),
 | |
|         K(ret));
 | |
|   } else {
 | |
|     void* buf = NULL;
 | |
|     T* cmp_funcs = NULL;
 | |
|     cmp_funcs_.set_allocator(&allocator);
 | |
|     cmp_funcs_.set_capacity(rowkey_column_cnt_);
 | |
|     if (OB_ISNULL(buf = allocator.alloc(sizeof(T) * rowkey_column_cnt_))) {
 | |
|       ret = OB_ALLOCATE_MEMORY_FAILED;
 | |
|       STORAGE_LOG(WARN, "Failed to allocate memory for cmopare func", K_(rowkey_column_cnt), K(ret));
 | |
|     } else {
 | |
|       cmp_funcs = reinterpret_cast<T*>(new (buf) T[rowkey_column_cnt_]);
 | |
|       for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_column_cnt_; i++) {
 | |
|         if (OB_FAIL(cmp_funcs[i].init_compare_func(column_type_array_[i]))) {
 | |
|           STORAGE_LOG(WARN, "Failed to init compare func", K(i), K(ret));
 | |
|         } else if (OB_FAIL(cmp_funcs_.push_back(&cmp_funcs[i]))) {
 | |
|           STORAGE_LOG(WARN, "Failed to push back compare func", K(i), K(ret));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (OB_SUCC(ret) && exist_collation_free_) {
 | |
|       collation_free_cmp_funcs_.set_allocator(&allocator);
 | |
|       collation_free_cmp_funcs_.set_capacity(rowkey_column_cnt_);
 | |
|       if (OB_ISNULL(buf = allocator.alloc(sizeof(T) * rowkey_column_cnt_))) {
 | |
|         ret = OB_ALLOCATE_MEMORY_FAILED;
 | |
|         STORAGE_LOG(WARN, "Failed to allocate memory for cmopare func", K_(rowkey_column_cnt), K(ret));
 | |
|       } else {
 | |
|         cmp_funcs = reinterpret_cast<T*>(new (buf) T[rowkey_column_cnt_]);
 | |
|         for (int64_t i = 0; OB_SUCC(ret) && i < rowkey_column_cnt_; i++) {
 | |
|           if (column_type_array_[i].is_collation_free_compatible()) {
 | |
|             if (OB_FAIL(cmp_funcs[i].init_compare_func_collation_free(column_type_array_[i]))) {
 | |
|               STORAGE_LOG(WARN, "Failed to init compare func", K(i), K(ret));
 | |
|             }
 | |
|           } else if (OB_FAIL(cmp_funcs[i].init_compare_func(column_type_array_[i]))) {
 | |
|             STORAGE_LOG(WARN, "Failed to init compare func", K(i), K(ret));
 | |
|           }
 | |
|           if (OB_SUCC(ret) && OB_FAIL(collation_free_cmp_funcs_.push_back(&cmp_funcs[i]))) {
 | |
|             STORAGE_LOG(WARN, "Failed to push back compare func", K(i), K(ret));
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::init(const ObIArray<MacroBlockId>& macro_ids, const ObSSTableMeta& sstable_meta,
 | |
|     const bool need_build_collation_free, ObSSTable* sstable, ObIAllocator& allocator)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   reset();
 | |
|   if (OB_UNLIKELY(!sstable_meta.is_valid()) || OB_ISNULL(sstable)) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to init sstable rowkey helper", K(sstable_meta), KP(sstable), K(ret));
 | |
|   } else if (macro_ids.count() > 0) {
 | |
|     sstable_ = sstable;
 | |
|     ObWorker::CompatMode mode;
 | |
|     if (OB_FAIL(ObCompatModeGetter::get_tenant_mode(extract_tenant_id(sstable_meta.index_id_), mode))) {
 | |
|       STORAGE_LOG(WARN, "Failed to get compat mode", K(sstable_meta), K(ret));
 | |
|       // rewrite ret for caller deal with
 | |
|       ret = OB_TENANT_NOT_EXIST;
 | |
|     } else {
 | |
|       is_oracle_mode_ = (mode == ObWorker::CompatMode::ORACLE) && !is_sys_table(sstable_meta.index_id_);
 | |
|       use_cmp_nullsafe_ = ObTableSchema::is_index_table(static_cast<ObTableType>(sstable_meta.table_type_)) ||
 | |
|                           TPKM_NEW_NO_PK == sstable_meta.table_mode_.pk_mode_;
 | |
|       if (OB_FAIL(build_macro_endkeys(
 | |
|               macro_ids, allocator, sstable_meta.rowkey_column_count_, need_build_collation_free))) {
 | |
|         STORAGE_LOG(WARN, "Failed to build macro endkeys", K(ret));
 | |
|       } else if (OB_FAIL(build_rowkey_cmp_funcs(allocator))) {
 | |
|         STORAGE_LOG(WARN, "Failed to build endkey cmp funcs", K(ret));
 | |
|       } else {
 | |
|         is_inited_ = true;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::build_rowkey_cmp_funcs(ObIAllocator& allocator)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_ISNULL(column_type_array_) || rowkey_column_cnt_ <= 0) {
 | |
|     ret = OB_ERR_UNEXPECTED;
 | |
|     STORAGE_LOG(WARN,
 | |
|         "Unexpected null column type array or rowkey column cnt",
 | |
|         KP_(column_type_array),
 | |
|         K_(rowkey_column_cnt),
 | |
|         K(ret));
 | |
|   } else if (is_oracle_mode_ && use_cmp_nullsafe_) {
 | |
|     ret = make_rowkey_cmp_funcs<ObRowkeyObjComparerNullsafeOracle>(allocator);
 | |
|   } else if (is_oracle_mode_) {
 | |
|     ret = make_rowkey_cmp_funcs<ObRowkeyObjComparerOracle>(allocator);
 | |
|   } else if (use_cmp_nullsafe_) {
 | |
|     ret = make_rowkey_cmp_funcs<ObRowkeyObjComparerNullsafeMysql>(allocator);
 | |
|   } else {
 | |
|     ret = make_rowkey_cmp_funcs<ObRowkeyObjComparer>(allocator);
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::locate_block_idx_(const ObExtStoreRowkey& ext_rowkey, const int64_t cmp_rowkey_col_cnt,
 | |
|     const bool use_lower_bound, const int64_t last_block_idx, int64_t& block_idx)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(cmp_rowkey_col_cnt > ext_rowkey.get_store_rowkey().get_obj_cnt())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "Invalid argument to locate block index", K(ext_rowkey), K(cmp_rowkey_col_cnt), K(ret));
 | |
|   } else {
 | |
|     RowkeyArray* rowkey_array = NULL;
 | |
|     const ObStoreRowkey* cmp_rowkey = NULL;
 | |
|     RowkeyCmpFuncArray* cmp_funcs = NULL;
 | |
|     block_idx = -1;
 | |
|     if (!exist_collation_free_) {
 | |
|       cmp_rowkey = &(ext_rowkey.get_store_rowkey());
 | |
|       rowkey_array = &endkeys_;
 | |
|       cmp_funcs = &cmp_funcs_;
 | |
|     } else {
 | |
|       bool use_collation_free = false;
 | |
|       if (OB_FAIL(ext_rowkey.check_use_collation_free(!exist_collation_free_, use_collation_free))) {
 | |
|         STORAGE_LOG(WARN, "Fail to check use collation free, ", K(ret), K(ext_rowkey));
 | |
|       } else if (use_collation_free && collation_free_cmp_funcs_.count() > 0) {
 | |
|         cmp_rowkey = &(ext_rowkey.get_collation_free_store_rowkey());
 | |
|         rowkey_array = &collation_free_endkeys_;
 | |
|         cmp_funcs = &collation_free_cmp_funcs_;
 | |
|       } else {
 | |
|         cmp_rowkey = &(ext_rowkey.get_store_rowkey());
 | |
|         rowkey_array = &endkeys_;
 | |
|         cmp_funcs = &cmp_funcs_;
 | |
|         use_collation_free = false;
 | |
|       }
 | |
|     }
 | |
|     if (OB_SUCC(ret)) {
 | |
|       if (cmp_rowkey->get_obj_cnt() == rowkey_column_cnt_ && last_block_idx >= 0 &&
 | |
|           last_block_idx < rowkey_array->count()) {
 | |
|         // the rowkey may be in the same macro block, so check last macro block first
 | |
|         if (compare_nullsafe(rowkey_array->at(last_block_idx), *cmp_rowkey, *cmp_funcs) >= 0) {
 | |
|           if (0 == last_block_idx ||
 | |
|               compare_nullsafe(rowkey_array->at(last_block_idx - 1), *cmp_rowkey, *cmp_funcs) < 0) {
 | |
|             block_idx = last_block_idx;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       if (-1 == block_idx) {  // binary search
 | |
|         RowkeyComparor comparor(*cmp_funcs, cmp_rowkey_col_cnt < rowkey_column_cnt_);
 | |
|         ObStoreRowkey refine_cmp_rowkey((const_cast<ObStoreRowkey*>(cmp_rowkey))->get_obj_ptr(), cmp_rowkey_col_cnt);
 | |
|         RowkeyArray::iterator begin = rowkey_array->begin();
 | |
|         RowkeyArray::iterator end = rowkey_array->end();
 | |
|         RowkeyArray::iterator iter;
 | |
|         if (use_lower_bound) {
 | |
|           iter = std::lower_bound(begin, end, &refine_cmp_rowkey, comparor);
 | |
|         } else {
 | |
|           iter = std::upper_bound(begin, end, &refine_cmp_rowkey, comparor);
 | |
|         }
 | |
|         if (iter < end) {
 | |
|           block_idx = iter - begin;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::locate_block_idx_index(
 | |
|     const ObExtStoreRowkey& ext_rowkey, const int64_t last_block_idx, int64_t& block_idx)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(!is_inited_)) {
 | |
|     ret = OB_NOT_INIT;
 | |
|     STORAGE_LOG(WARN, "ObSSTableRowkeyHelper is not inited", K(ret));
 | |
|   } else if (OB_UNLIKELY(!ext_rowkey.is_range_cutoffed())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "ExtRowkey is not range cutted", K(ext_rowkey), K(ret));
 | |
|   } else if (OB_UNLIKELY(ext_rowkey.get_range_cut_pos() == 0)) {
 | |
|     block_idx = ext_rowkey.is_range_check_min() ? 0 : -1;
 | |
|   } else {
 | |
|     ret = locate_block_idx_(
 | |
|         ext_rowkey, ext_rowkey.get_range_cut_pos(), ext_rowkey.is_range_check_min(), last_block_idx, block_idx);
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int ObSSTableRowkeyHelper::locate_block_idx_table(
 | |
|     const ObExtStoreRowkey& ext_rowkey, const int64_t last_block_idx, int64_t& block_idx)
 | |
| {
 | |
|   int ret = OB_SUCCESS;
 | |
| 
 | |
|   if (OB_UNLIKELY(!is_inited_)) {
 | |
|     ret = OB_NOT_INIT;
 | |
|     STORAGE_LOG(WARN, "ObSSTableRowkeyHelper is not inited", K(ret));
 | |
|   } else if (OB_UNLIKELY(!ext_rowkey.is_range_cutoffed())) {
 | |
|     ret = OB_INVALID_ARGUMENT;
 | |
|     STORAGE_LOG(WARN, "ExtRowkey is not range cutted", K(ext_rowkey), K(ret));
 | |
|   } else if (OB_UNLIKELY(ext_rowkey.get_range_cut_pos() == 0)) {
 | |
|     block_idx = ext_rowkey.is_range_check_min() ? 0 : -1;
 | |
|   } else if (OB_UNLIKELY(ext_rowkey.get_first_null_pos() == 0)) {
 | |
|     block_idx = is_oracle_mode_ ? -1 : 0;
 | |
|   } else {
 | |
|     int64_t cmp_rowkey_col_cnt = ext_rowkey.get_range_cut_pos();
 | |
|     bool use_lower_bound = ext_rowkey.is_range_check_min();
 | |
|     if (ext_rowkey.get_first_null_pos() > 0 && ext_rowkey.get_first_null_pos() < cmp_rowkey_col_cnt) {
 | |
|       cmp_rowkey_col_cnt = ext_rowkey.get_first_null_pos();
 | |
|       use_lower_bound = !is_oracle_mode_;
 | |
|     }
 | |
|     ret = locate_block_idx_(ext_rowkey, cmp_rowkey_col_cnt, use_lower_bound, last_block_idx, block_idx);
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| }  // end namespace storage
 | |
| }  // end namespace oceanbase
 | 
