135 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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_ */
 | 
