1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H 17 #define OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H 18 19 #include <list> 20 #include <map> 21 #include <mutex> 22 23 namespace OHOS { 24 template<typename _Key, typename _Tp> 25 class LRUBucket { 26 public: LRUBucket(size_t capacity)27 LRUBucket(size_t capacity) : size_(0), capacity_(capacity) 28 { 29 } 30 31 LRUBucket(LRUBucket &&bucket) noexcept = delete; 32 LRUBucket(const LRUBucket &bucket) = delete; 33 LRUBucket &operator=(LRUBucket &&bucket) noexcept = delete; 34 LRUBucket &operator=(const LRUBucket &bucket) = delete; 35 ~LRUBucket()36 ~LRUBucket() 37 { 38 std::lock_guard<decltype(mutex_)> lock(mutex_); 39 while (size_ > 0) { 40 PopBack(); 41 } 42 } 43 Size()44 size_t Size() const 45 { 46 return size_; 47 } 48 Capacity()49 size_t Capacity() const 50 { 51 return capacity_; 52 } 53 ResetCapacity(size_t capacity)54 bool ResetCapacity(size_t capacity) 55 { 56 std::lock_guard<decltype(mutex_)> lock(mutex_); 57 capacity_ = capacity; 58 while (capacity_ < size_) { 59 PopBack(); 60 } 61 return capacity_ == capacity; 62 } 63 64 /** 65 * The time complexity is O(log(index size)) 66 **/ 67 bool Get(const _Key &key, _Tp &value, bool isLRU = true) 68 { 69 std::lock_guard<decltype(mutex_)> lock(mutex_); 70 auto it = indexes_.find(key); 71 if (it != indexes_.end()) { 72 if (isLRU) { 73 // move node from the list; 74 Remove(it->second); 75 // insert node to the head 76 Insert(&head_, it->second); 77 } 78 value = it->second->value_; 79 return true; 80 } 81 return false; 82 } 83 84 /** 85 * The time complexity is O(log(index size)) 86 **/ Set(const _Key & key,const _Tp & value)87 bool Set(const _Key &key, const _Tp &value) 88 { 89 std::lock_guard<decltype(mutex_)> lock(mutex_); 90 if (capacity_ == 0) { 91 return false; 92 } 93 94 auto it = indexes_.find(key); 95 if (it != indexes_.end()) { 96 Update(it->second, value); 97 Remove(it->second); 98 Insert(&head_, it->second); 99 return true; 100 } 101 102 while (capacity_ <= size_) { 103 PopBack(); 104 } 105 106 auto *node = new (std::nothrow) Node(value); 107 if (node == nullptr) { 108 return false; 109 } 110 111 Insert(&head_, node); 112 auto pair = indexes_.emplace(key, node); 113 node->iterator_ = pair.first; 114 return true; 115 } 116 117 /** 118 * Just update the values, not change the lru 119 **/ Update(const _Key & key,const _Tp & value)120 bool Update(const _Key &key, const _Tp &value) 121 { 122 std::lock_guard<decltype(mutex_)> lock(mutex_); 123 auto it = indexes_.find(key); 124 if (it != indexes_.end()) { 125 Update(it->second, value); 126 return true; 127 } 128 return false; 129 } 130 131 /** 132 * The time complexity is O(min(indexes, values)) 133 * Just update the values, not change the lru chain 134 */ Update(const std::map<_Key,_Tp> & values)135 bool Update(const std::map<_Key, _Tp> &values) 136 { 137 std::lock_guard<decltype(mutex_)> lock(mutex_); 138 auto idx = indexes_.begin(); 139 auto val = values.begin(); 140 bool updated = false; 141 auto comp = indexes_.key_comp(); 142 while (idx != indexes_.end() && val != values.end()) { 143 if (comp(idx->first, val->first)) { 144 ++idx; 145 continue; 146 } 147 if (comp(val->first, idx->first)) { 148 ++val; 149 continue; 150 } 151 updated = true; 152 Update(idx->second, val->second); 153 ++idx; 154 ++val; 155 } 156 return updated; 157 } 158 159 /** 160 * The time complexity is O(log(index size)) 161 * */ Delete(const _Key & key)162 bool Delete(const _Key &key) 163 { 164 std::lock_guard<decltype(mutex_)> lock(mutex_); 165 auto it = indexes_.find(key); 166 if (it != indexes_.end()) { 167 Remove(it->second); 168 Delete(it->second); 169 return true; 170 } 171 return false; 172 } 173 174 private: 175 struct Node final { 176 using iterator = typename std::map<_Key, Node *>::iterator; Nodefinal177 Node(const _Tp &value) : value_(value) {} Nodefinal178 Node() : value_() {} 179 ~Node() = default; 180 _Tp value_; 181 iterator iterator_; 182 Node *prev_ = this; 183 Node *next_ = this; 184 }; 185 PopBack()186 void PopBack() 187 { 188 auto *node = head_.prev_; 189 Remove(node); 190 Delete(node); 191 } 192 Update(Node * node,const _Tp & value)193 void Update(Node *node, const _Tp &value) 194 { 195 node->value_ = value; 196 } 197 Remove(Node * node)198 void Remove(Node *node) 199 { 200 node->prev_->next_ = node->next_; 201 node->next_->prev_ = node->prev_; 202 size_--; 203 } 204 Insert(Node * prev,Node * node)205 void Insert(Node *prev, Node *node) 206 { 207 prev->next_->prev_ = node; 208 node->next_ = prev->next_; 209 prev->next_ = node; 210 node->prev_ = prev; 211 size_++; 212 } 213 Delete(Node * node)214 void Delete(Node *node) 215 { 216 indexes_.erase(node->iterator_); 217 delete node; 218 } 219 220 mutable std::recursive_mutex mutex_; 221 std::map<_Key, Node *> indexes_; 222 Node head_; 223 size_t size_; 224 size_t capacity_; 225 }; 226 } // namespace OHOS 227 #endif // OHOS_DISTRIBUTED_DATA_FRAMEWORKS_COMMON_LRU_BUCKET_H 228