Files
oceanbase/src/storage/ob_handle_cache.h

135 lines
3.6 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.
*/
#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 <typename Key, typename Handle>
class ObHandleCacheNode : public common::ObDLinkBase<ObHandleCacheNode<Key, Handle>> {
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 <typename Key, typename Handle, int64_t N>
class ObHandleCache {
typedef ObHandleCacheNode<Key, Handle> CacheNode;
typedef common::ObDList<CacheNode> 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<int16_t>(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_ */