/** * 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. */ #include "storage/ob_range_iterator.h" #include "lib/container/ob_se_array_iterator.h" #include "lib/profile/ob_perf_event.h" #include "common/ob_range.h" #include "share/ob_simple_batch.h" #include "storage/ob_dml_param.h" namespace oceanbase { using namespace common; namespace storage { int ObBatch::get_storage_batch(const ObSimpleBatch& sql_batch, ObIAllocator& allocator, ObBatch& batch) { int ret = OB_SUCCESS; ObStoreRange store_range; batch.type_ = static_cast(sql_batch.type_); if (ObBatch::T_NONE == static_cast(sql_batch.type_)) { batch.rowkey_ = NULL; } else if (ObBatch::T_SCAN == static_cast(sql_batch.type_)) { ObExtStoreRange* ext_store_range = NULL; if (OB_ISNULL(sql_batch.range_)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "NULL range", K(ret), K(sql_batch)); } else { store_range.assign(*sql_batch.range_); } if (OB_FAIL(ret)) { } else if (OB_ISNULL(ext_store_range = static_cast(allocator.alloc(sizeof(ObExtStoreRange))))) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "Failed to allocate ObStoreRange", K(ret)); } else { batch.range_ = new (ext_store_range) ObExtStoreRange(store_range); if (OB_FAIL(ext_store_range->to_collation_free_range_on_demand_and_cutoff_range(allocator))) { STORAGE_LOG(WARN, "Failed to transform collation free and cutoff range", K(store_range), K(ret)); } } } else if (ObBatch::T_MULTI_SCAN == static_cast(sql_batch.type_)) { ScanRangeArray* scan_range_arr = NULL; if (OB_ISNULL(sql_batch.ranges_)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "NULL ranges", K(ret), K(sql_batch)); } else if (OB_ISNULL(scan_range_arr = static_cast(allocator.alloc(sizeof(ScanRangeArray))))) { ret = OB_ALLOCATE_MEMORY_FAILED; STORAGE_LOG(WARN, "Failed to allocate ScanRangeArray", K(ret)); } else { batch.ranges_ = new (scan_range_arr) ScanRangeArray(); } for (int64_t i = 0; OB_SUCC(ret) && i < sql_batch.ranges_->count(); i++) { store_range.assign(sql_batch.ranges_->at(i)); if (OB_FAIL(scan_range_arr->push_back(ObExtStoreRange(store_range)))) { STORAGE_LOG(WARN, "Failed to push back store range", K(ret)); } } for (int64_t i = 0; OB_SUCC(ret) && i < scan_range_arr->count(); i++) { if (OB_FAIL(scan_range_arr->at(i).to_collation_free_range_on_demand_and_cutoff_range(allocator))) { STORAGE_LOG( WARN, "Failed to transform collation free and cutoff range", K(i), K(scan_range_arr->at(i)), K(ret)); } } } else { STORAGE_LOG(WARN, "invalid sql batch", K(sql_batch)); } return ret; } OB_INLINE static bool order_specified(const ObTableScanParam* scan_param) { return NULL != scan_param && scan_param->scan_flag_.scan_order_ > common::ObQueryFlag::ImplementedOrder; } OB_INLINE static int always_false(const ObStoreRange& range, const ObIArray* column_orders, bool& is_false) { int ret = OB_SUCCESS; int32_t cmp = 0; if (OB_ISNULL(column_orders)) { cmp = range.get_start_key().compare(range.get_end_key()); } else if (OB_FAIL(range.get_start_key().compare(range.get_end_key(), *column_orders, cmp))) { STORAGE_LOG(WARN, "start/end key comparison failed", K(ret), K(range.get_start_key()), K(range.get_end_key())); } if (OB_SUCC(ret)) { is_false = (cmp > 0) || (0 == cmp && (!range.get_border_flag().inclusive_start() || !range.get_border_flag().inclusive_end())); } return ret; } class RangeCmp { public: RangeCmp(const ObIArray* column_orders) : column_orders_(column_orders) {} // caller ensures no intersection between any two rangs OB_INLINE bool operator()(const ObExtStoreRange& a, const ObExtStoreRange& b) { int cmp = 0; if (OB_SUCCESS != a.get_range().compare_with_startkey(b.get_range(), column_orders_, cmp)) { right_to_die_or_duty_to_live(); } return cmp < 0; } OB_INLINE bool operator()(const ObExtStoreRowkey& a, const ObExtStoreRowkey& b) const { int32_t cmp = 0; if (OB_LIKELY(NULL == column_orders_)) { cmp = a.get_store_rowkey().compare(b.get_store_rowkey()); } else if (OB_SUCCESS != a.get_store_rowkey().compare(b.get_store_rowkey(), *column_orders_, cmp)) { right_to_die_or_duty_to_live(); } return cmp < 0; } private: const ObIArray* column_orders_; }; void ObRangeIterator::reset() { is_inited_ = false; scan_param_ = NULL; cur_idx_ = 0; order_ranges_.reset(); rowkey_.reset(); rowkeys_.reset(); range_.reset(); rowkey_column_orders_ = nullptr; rowkey_column_cnt_ = 0; } void ObRangeIterator::reuse() { is_inited_ = false; scan_param_ = NULL; cur_idx_ = 0; order_ranges_.reuse(); rowkey_.reset(); rowkeys_.reuse(); range_.reset(); rowkey_column_orders_ = nullptr; rowkey_column_cnt_ = 0; } // set scan parameter and do range comparison currently int ObRangeIterator::set_scan_param(ObTableScanParam& scan_param) { int ret = OB_SUCCESS; int64_t array_cnt = scan_param.range_array_pos_.count(); const int64_t range_cnt = scan_param.key_ranges_.count(); if (OB_UNLIKELY(is_inited_)) { ret = OB_INIT_TWICE; STORAGE_LOG(WARN, "init twice", K(ret)); } else if (FALSE_IT(rowkey_column_orders_ = scan_param.get_rowkey_column_orders())) { STORAGE_LOG(WARN, "get column order failed", K(ret)); } else if (scan_param.is_get_) { if (OB_UNLIKELY(range_cnt <= 0)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid key ranges", K(ret), K(scan_param.key_ranges_)); } else { scan_param_ = &scan_param; if (range_cnt > 1) { for (int64_t i = 0; OB_SUCC(ret) && i < range_cnt; ++i) { const ObRowkey& rowkey = scan_param_->key_ranges_.at(i).get_start_key(); if (OB_FAIL(rowkeys_.push_back( ObExtStoreRowkey(ObStoreRowkey(const_cast(rowkey.get_obj_ptr()), rowkey.get_obj_cnt()))))) { STORAGE_LOG(WARN, "fail to push back rowkey", K(ret), K(rowkey)); } } } if (OB_SUCC(ret) && array_cnt > 1) { int64_t curr_range_start_pos = 0; int64_t curr_range_end_pos = 0; for (int64_t i = 0; OB_SUCC(ret) && i < array_cnt; ++i) { curr_range_end_pos = scan_param.range_array_pos_.at(i) + 1; for (int64_t j = curr_range_start_pos; OB_SUCC(ret) && j < curr_range_end_pos; ++j) { set_range_array_idx(i, rowkeys_.at(j)); } curr_range_start_pos = curr_range_end_pos; } } } } else { scan_param_ = &scan_param; array_cnt = 0 == array_cnt ? 1 : array_cnt; if (1 == array_cnt) { if (0 == range_cnt) { ObStoreRange whole_range; if (OB_FAIL(whole_range.set_whole_range(rowkey_column_orders_, *scan_param_->allocator_))) { STORAGE_LOG(WARN, "set_whole_range failed.", K(ret)); } else if (OB_SUCCESS != (ret = order_ranges_.push_back(ObExtStoreRange(whole_range)))) { STORAGE_LOG(WARN, "push whole range error", K(ret)); } } else { if (OB_FAIL(order_ranges_.reserve(range_cnt))) { STORAGE_LOG(WARN, "fail to reserve order ranges", K(ret), K(range_cnt)); } else if (OB_FAIL(convert_key_ranges(0, range_cnt, 0, *scan_param_->allocator_, order_ranges_))) { STORAGE_LOG(WARN, "convert_key_ranges railed", K(ret)); } else { // sort the ranges if ((ObQueryFlag::Forward == scan_param_->scan_flag_.scan_order_ || ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_) && range_cnt > 1) { std::sort(order_ranges_.begin(), order_ranges_.end(), RangeCmp(rowkey_column_orders_)); } } } } else { int64_t range_array_idx = 0; int64_t curr_range_start_pos = 0; int64_t curr_range_end_pos = 0; if (ObQueryFlag::Forward == scan_param_->scan_flag_.scan_order_ || ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_) { ret = OB_NOT_SUPPORTED; STORAGE_LOG(WARN, "sort multiple range array is not supported", K(ret)); } if (OB_FAIL(ret)) { } else if (OB_FAIL(order_ranges_.reserve(range_cnt))) { STORAGE_LOG(WARN, "fail to reserve order ranges", K(ret), K(range_cnt)); } for (int64_t i = 0; OB_SUCC(ret) && i < array_cnt; ++i) { curr_range_end_pos = scan_param_->range_array_pos_.at(i) + 1; if (OB_FAIL(convert_key_ranges( curr_range_start_pos, curr_range_end_pos, range_array_idx, *scan_param_->allocator_, order_ranges_))) { STORAGE_LOG(WARN, "fail to convert key ranges", K(ret)); } else { ++range_array_idx; curr_range_start_pos = curr_range_end_pos; } } } STORAGE_LOG(DEBUG, "set_scan_param returned", KP_(rowkey_column_orders), K(scan_param), K(scan_param_->key_ranges_), K(order_ranges_), K(ret)); } if (OB_SUCC(ret) && OB_NOT_NULL(scan_param_)) { is_inited_ = true; } else { reset(); } return ret; } int ObRangeIterator::convert_key_ranges(const int64_t range_begin_pos, const int64_t range_end_pos, const int64_t range_array_idx, ObIAllocator& allocator, ObIArray& store_ranges) { int ret = OB_SUCCESS; ObStoreRange store_range; for (int64_t i = range_begin_pos; OB_SUCC(ret) && i < range_end_pos; i++) { bool is_always_false = false; ObNewRange& cur_range = scan_param_->key_ranges_.at(i); if (OB_ISNULL(rowkey_column_orders_)) { store_range.assign(cur_range); } else if (OB_FAIL(cur_range.to_store_range(*rowkey_column_orders_, store_range, allocator))) { STORAGE_LOG(WARN, "convert to store range failed", K(ret), K(cur_range), K(rowkey_column_orders_)); } if (OB_FAIL(ret)) { } else if (OB_FAIL(always_false(store_range, rowkey_column_orders_, is_always_false))) { STORAGE_LOG(WARN, "fail to check range always false", K(ret), K(store_range), K(rowkey_column_orders_)); } else if (OB_UNLIKELY(is_always_false)) { STORAGE_LOG(INFO, "range is always false, skip it", K(store_range), K(rowkey_column_orders_)); } else { ObExtStoreRange ext_range(store_range); set_range_array_idx(range_array_idx, ext_range); if (OB_FAIL(store_ranges.push_back(ext_range))) { STORAGE_LOG(WARN, "fail to push back store range", K(ret)); } } } return ret; } int ObRangeIterator::get_next(ObBatch& batch) { int ret = OB_SUCCESS; int64_t cnt = 0; batch.type_ = ObBatch::T_NONE; bool is_always_false = false; if (OB_UNLIKELY(!is_inited_)) { ret = OB_NOT_INIT; STORAGE_LOG(WARN, "ObRangeIterator is not initiated", K(ret)); } else if (scan_param_->is_get_) { const int64_t range_count = scan_param_->key_ranges_.count(); if (cur_idx_ >= range_count) { ret = OB_ITER_END; } else if (1 == range_count) { batch.type_ = ObBatch::T_GET; const ObRowkey& rowkey = scan_param_->key_ranges_.at(0).get_start_key(); rowkey_ = ObExtStoreRowkey(ObStoreRowkey(const_cast(rowkey.get_obj_ptr()), rowkey.get_obj_cnt())); batch.rowkey_ = &rowkey_; ++cur_idx_; } else { batch.type_ = ObBatch::T_MULTI_GET; const int64_t array_cnt = scan_param_->range_array_pos_.count(); if ((0 == array_cnt || 1 == array_cnt) && (ObQueryFlag::Forward == scan_param_->scan_flag_.scan_order_ || ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_)) { std::sort(rowkeys_.begin(), rowkeys_.end(), RangeCmp(rowkey_column_orders_)); } if (OB_SUCC(ret)) { if (ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_) { std::reverse(rowkeys_.begin(), rowkeys_.end()); } batch.rowkeys_ = &rowkeys_; cur_idx_ += range_count; } } } else if (cur_idx_ >= (cnt = order_ranges_.count())) { ret = OB_ITER_END; } else if (1 == cnt) { const ObExtStoreRange& range = order_ranges_.at(cur_idx_++); if (OB_FAIL(always_false(range.get_range(), rowkey_column_orders_, is_always_false))) { STORAGE_LOG(WARN, "check range always false failed.", K(range), K(ret)); } else if (is_always_false) { STORAGE_LOG(INFO, "range is always false, skip it", K(range)); ret = OB_ITER_END; } else if (range.is_single_rowkey()) { batch.type_ = ObBatch::T_GET; rowkey_ = ObExtStoreRowkey(range.get_range().get_start_key()); batch.rowkey_ = &rowkey_; } else { batch.type_ = ObBatch::T_SCAN; range_ = ObExtStoreRange(range); batch.range_ = &range_; } STORAGE_LOG(DEBUG, "next range", K(batch.type_), K(range), K(scan_param_->table_param_->get_table_id())); } else { // 1. skip always false range while (OB_SUCCESS == ret && cur_idx_ < cnt) { ObExtStoreRange& cur_ext_range = order_ranges_.at(cur_idx_); if (!cur_ext_range.get_range().is_single_rowkey()) { break; } else { ObExtStoreRowkey ext_rowkey(cur_ext_range.get_range().get_start_key()); set_range_array_idx(cur_ext_range.get_range_array_idx(), ext_rowkey); if (OB_FAIL(rowkeys_.push_back(ext_rowkey))) { STORAGE_LOG(WARN, "fail to push back rowkey", K(ret)); } } ++cur_idx_; } STORAGE_LOG(DEBUG, "range_iterator", "order", order_specified(scan_param_), "rowkey count", rowkeys_.count()); if (OB_SUCC(ret)) { if (rowkeys_.count() > 0 && cur_idx_ == cnt) { // all ranges are get if (ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_) { std::reverse(rowkeys_.begin(), rowkeys_.end()); } batch.type_ = ObBatch::T_MULTI_GET; batch.rowkeys_ = &rowkeys_; STORAGE_LOG(DEBUG, "multi get", K(batch.type_), K(rowkeys_)); } else { // use multi scan batch.type_ = ObBatch::T_MULTI_SCAN; batch.ranges_ = &order_ranges_; if (ObQueryFlag::Reverse == scan_param_->scan_flag_.scan_order_) { std::reverse(order_ranges_.begin(), order_ranges_.end()); } STORAGE_LOG(DEBUG, "multi scan", K(batch.type_), K(order_ranges_)); } cur_idx_ = scan_param_->key_ranges_.count(); } } return ret; } } // namespace storage } // namespace oceanbase