/** * 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. */ #ifndef OCEANBASE_STORAGE_OB_HANDLE_CACHE_H_ #define OCEANBASE_STORAGE_OB_HANDLE_CACHE_H_ #include "lib/list/ob_dlist.h" #include "lib/hash/ob_hashtable.h" namespace oceanbase { namespace storage { template class ObHandleCacheNode : public common::ObDLinkBase> { public: ObHandleCacheNode() : bucket_idx_(-1) {} virtual ~ObHandleCacheNode() { bucket_idx_ = -1; } void reset() { handle_.reset(); bucket_idx_ = -1; } Handle handle_; Key key_; int16_t bucket_idx_; }; template class ObHandleCache { typedef ObHandleCacheNode CacheNode; typedef common::ObDList LRUList; public: ObHandleCache() { STATIC_ASSERT(N <= 8192, "number of bucket is larger than 8192"); for (int64_t i = 0; i < N; ++i) { lru_list_.add_first(&nodes_[i]); } MEMSET(buckets_, -1, sizeof(buckets_)); MEMSET(chain_, -1, sizeof(chain_)); } virtual ~ObHandleCache() {} int get_handle(const Key& key, Handle& handle) { int ret = common::OB_SUCCESS; int16_t idx = buckets_[key.hash() & MASK]; while (-1 < idx) { if (nodes_[idx].key_ == key) { handle = nodes_[idx].handle_; break; } else { idx = chain_[idx]; } } if (-1 == idx) { STORAGE_LOG(DEBUG, "get handle from handle cache failed", K(key)); ret = common::OB_ENTRY_NOT_EXIST; } else { STORAGE_LOG(DEBUG, "get handle from handle cache succeed", K(key)); lru_list_.remove(&nodes_[idx]); lru_list_.add_first(&nodes_[idx]); } return ret; } int put_handle(const Key& key, Handle& handle) { int ret = common::OB_SUCCESS; CacheNode* node = lru_list_.remove_last(); const int16_t node_idx = static_cast(node - nodes_); int16_t* idx_ptr = NULL; int16_t idx = 0; if (-1 < node->bucket_idx_) { idx_ptr = &buckets_[node->bucket_idx_]; idx = buckets_[node->bucket_idx_]; while (OB_LIKELY(-1 < idx) && (node_idx != idx)) { idx_ptr = &chain_[idx]; idx = chain_[idx]; } if (OB_UNLIKELY(-1 == idx)) { ret = common::OB_ERR_UNEXPECTED; lru_list_.add_last(node); STORAGE_LOG(WARN, "idx can not be -1, the entry must exist", K(ret), K(key), K(node->bucket_idx_)); } else { *idx_ptr = chain_[idx]; chain_[idx] = -1; } } if (OB_SUCC(ret)) { node->reset(); node->key_ = key; node->handle_ = handle; node->bucket_idx_ = key.hash() & MASK; idx_ptr = &buckets_[node->bucket_idx_]; chain_[node_idx] = *idx_ptr; *idx_ptr = node_idx; lru_list_.add_first(node); STORAGE_LOG(DEBUG, "put handle succeed", K(key)); } return ret; } private: static const uint64_t BUCKET_SIZE = common::next_pow2(N * 2); static const uint64_t MASK = BUCKET_SIZE - 1; CacheNode nodes_[N]; int16_t buckets_[BUCKET_SIZE]; int16_t chain_[N]; LRUList lru_list_; }; } // namespace storage } // namespace oceanbase #endif /* OCEANBASE_STORAGE_OB_HANDLE_CACHE_H_ */