/** * 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 "ob_row_cache.h" #include "lib/stat/ob_diagnose_info.h" namespace oceanbase { using namespace common; using namespace storage; namespace blocksstable { /** * -----------------------------------------------------ObRowCacheKey------------------------------------------------------ */ ObRowCacheKey::ObRowCacheKey() : rowkey_size_(0), tenant_id_(0), tablet_id_(), data_version_(-1), table_type_(ObITable::MAX_TABLE_TYPE), rowkey_(), datum_utils_(nullptr) { } ObRowCacheKey::ObRowCacheKey(const uint64_t tenant_id, const ObTabletID &tablet_id, const ObDatumRowkey &rowkey, const ObStorageDatumUtils &datum_utils, const int64_t data_version, const ObITable::TableType table_type) { tenant_id_ = tenant_id; tablet_id_ = tablet_id; data_version_ = data_version; table_type_ = table_type; rowkey_ = rowkey; datum_utils_ = &datum_utils; rowkey_size_ = rowkey.get_deep_copy_size(); } ObRowCacheKey::~ObRowCacheKey() { } int ObRowCacheKey::hash(uint64_t &hash_val) const { int ret = OB_SUCCESS; hash_val = static_cast(table_type_); hash_val = common::murmurhash(&tenant_id_, sizeof(tenant_id_), hash_val); hash_val = common::murmurhash(&tablet_id_, sizeof(tablet_id_), hash_val); hash_val = common::murmurhash(&data_version_, sizeof(data_version_), hash_val); if (rowkey_.is_valid()) { if (OB_ISNULL(datum_utils_)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected error for null datum utils", K(ret), K(*this)); } else if (OB_FAIL(rowkey_.hash(*datum_utils_, hash_val))) { STORAGE_LOG(WARN, "Failed to calc hash value for datum rowkey", K(ret), K(rowkey_)); } } return ret; } int ObRowCacheKey::equal(const ObIKVCacheKey &other, bool &equal) const { int ret = OB_SUCCESS; const ObRowCacheKey &other_key = reinterpret_cast(other); equal = (rowkey_size_ == other_key.rowkey_size_); equal &= tenant_id_ == other_key.tenant_id_; equal &= tablet_id_ == other_key.tablet_id_; equal &= (data_version_ == other_key.data_version_); equal &= (table_type_ == other_key.table_type_); if (equal && rowkey_size_ > 0) { const ObStorageDatumUtils *datum_utils = (nullptr != datum_utils_) ? datum_utils_ : other_key.datum_utils_; if (OB_ISNULL(datum_utils)) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument to compare row cachekey", K(ret), K(*this), K(other_key)); } else if (OB_FAIL(rowkey_.equal(other_key.rowkey_, *datum_utils, equal))) { STORAGE_LOG(WARN, "Failed to check rowkey cache key equal", K(ret), K(rowkey_), K(other_key)); } } return ret; } uint64_t ObRowCacheKey::get_tenant_id() const { return tenant_id_; } int64_t ObRowCacheKey::size() const { return sizeof(*this) + rowkey_size_; } int ObRowCacheKey::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheKey *&key) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(NULL == buf || buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", K(buf), K(buf_len), K(ret)); } else if (OB_UNLIKELY(!is_valid())) { ret = OB_INVALID_DATA; STORAGE_LOG(WARN, "Invalid row cache key, ", K(*this), K(ret)); } else { blocksstable::ObRowCacheKey *pkey = new (buf) ObRowCacheKey(); pkey->tenant_id_ = tenant_id_; pkey->tablet_id_ = tablet_id_; pkey->data_version_ = data_version_; pkey->table_type_ = table_type_; pkey->datum_utils_ = nullptr; if (rowkey_.is_valid() && 0 < rowkey_size_) { ObRawBufAllocatorWrapper temp_buf(buf + sizeof(*this), rowkey_size_); if (OB_FAIL(rowkey_.deep_copy(pkey->rowkey_, temp_buf))) { STORAGE_LOG(WARN, "Fail to deep copy rowkey, ", K(ret)); } else { pkey->rowkey_size_ = rowkey_size_; key = pkey; } } if (OB_FAIL(ret)) { pkey->~ObRowCacheKey(); } } return ret; } bool ObRowCacheKey::is_valid() const { return OB_LIKELY(0 != tenant_id_ && tablet_id_.is_valid() && rowkey_size_ > 0 && data_version_ > -1 && (ObITable::is_minor_sstable(table_type_) || ObITable::is_major_sstable(table_type_) || ObITable::is_ddl_sstable(table_type_) || ObITable::is_meta_major_sstable(table_type_)) && rowkey_.is_valid()); } /** * -----------------------------------------------------ObRowCacheValue------------------------------------------------------ */ ObRowCacheValue::ObRowCacheValue() : datums_(nullptr), flag_(), size_(0), column_cnt_(0), start_log_ts_(0), block_id_() { } ObRowCacheValue::~ObRowCacheValue() { } int ObRowCacheValue::init(const int64_t start_log_ts, const ObDatumRow &row) { int ret = OB_SUCCESS; if (OB_UNLIKELY(!row.row_flag_.is_valid())) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected row", K(ret), K(row)); } else { datums_ = row.storage_datums_; column_cnt_ = row.get_column_count(); start_log_ts_ = start_log_ts; flag_ = row.row_flag_; size_ = sizeof(ObStorageDatum) * column_cnt_; for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt_; i ++) { size_ += datums_[i].get_deep_copy_size(); } } return ret; } int64_t ObRowCacheValue::size() const { return sizeof(*this) + size_; } int ObRowCacheValue::deep_copy(char *buf, const int64_t buf_len, ObIKVCacheValue *&value) const { int ret = OB_SUCCESS; if (OB_UNLIKELY(NULL == buf || buf_len < size())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "Invalid argument, ", K(buf), K(buf_len), K(ret)); } else if (OB_UNLIKELY(!is_valid())) { ret = OB_INVALID_DATA; STORAGE_LOG(WARN, "Invalid row cache value, ", K(*this), K(ret)); } else { ObRowCacheValue *pvalue = new (buf) ObRowCacheValue(); if (NULL == datums_) { pvalue->datums_ = NULL; } else { pvalue->size_ = size_; pvalue->datums_ = new (buf + sizeof(*this)) ObStorageDatum [column_cnt_]; pvalue->column_cnt_ = column_cnt_; pvalue->start_log_ts_ = start_log_ts_; pvalue->flag_ = flag_; pvalue->block_id_ = block_id_; int64_t pos = sizeof(ObRowCacheValue) + sizeof(ObStorageDatum) * column_cnt_; for (int64_t i = 0; OB_SUCC(ret) && i < column_cnt_; i ++) { if (OB_FAIL(pvalue->datums_[i].deep_copy(datums_[i], buf, buf_len, pos))) { STORAGE_LOG(WARN, "Failed to deepl copy datum", K(ret), K(i)); } } } value = pvalue; } return ret; } /** * -----------------------------------------------------ObRowCache------------------------------------------------------ */ ObRowCache::ObRowCache() { } ObRowCache::~ObRowCache() { } int ObRowCache::get_row(const ObRowCacheKey &key, ObRowValueHandle &handle) { int ret = OB_SUCCESS; const ObRowCacheValue *value = NULL; if (OB_UNLIKELY(!key.is_valid())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid row cache key.", K(key), K(ret)); } else if (OB_SUCCESS != (ret = get(key, value, handle.handle_))) { if (OB_UNLIKELY(OB_ENTRY_NOT_EXIST != ret)) { STORAGE_LOG(WARN, "Fail to get key from row cache, ", K(ret)); } EVENT_INC(ObStatEventIds::ROW_CACHE_MISS); } else { EVENT_INC(ObStatEventIds::ROW_CACHE_HIT); if (OB_ISNULL(value)) { ret = OB_ERR_UNEXPECTED; STORAGE_LOG(WARN, "Unexpected error, the value is NULL, ", K(ret)); } else { handle.row_value_ = const_cast(value); } } return ret; } int ObRowCache::put_row(const ObRowCacheKey &key, const ObRowCacheValue &value) { int ret = OB_SUCCESS; bool overwrite = true; if (OB_UNLIKELY(!key.is_valid() || !value.is_valid())) { ret = OB_INVALID_ARGUMENT; STORAGE_LOG(WARN, "invalid row cache input param.", K(key), K(value), K(ret)); } else if (OB_SUCCESS != (ret = put(key, value, overwrite))) { STORAGE_LOG(WARN, "Fail to put row to row cache, ", K(ret)); } return ret; } }//end namespace blocksstable }//end namespace oceanbase