| 264 | } |
| 265 | |
| 266 | Cache::Handle* LRUCache::Insert(const Slice& key, uint32_t hash, void* value, |
| 267 | size_t charge, |
| 268 | void (*deleter)(const Slice& key, |
| 269 | void* value)) { |
| 270 | MutexLock l(&mutex_); |
| 271 | |
| 272 | LRUHandle* e = |
| 273 | reinterpret_cast<LRUHandle*>(malloc(sizeof(LRUHandle) - 1 + key.size())); |
| 274 | e->value = value; |
| 275 | e->deleter = deleter; |
| 276 | e->charge = charge; |
| 277 | e->key_length = key.size(); |
| 278 | e->hash = hash; |
| 279 | e->in_cache = false; |
| 280 | e->refs = 1; // for the returned handle. |
| 281 | memcpy(e->key_data, key.data(), key.size()); |
| 282 | |
| 283 | if (capacity_ > 0) { |
| 284 | e->refs++; // for the cache's reference. |
| 285 | e->in_cache = true; |
| 286 | LRU_Append(&in_use_, e); |
| 287 | usage_ += charge; |
| 288 | FinishErase(table_.Insert(e)); |
| 289 | } else { // don't cache. (capacity_==0 is supported and turns off caching.) |
| 290 | // next is read by key() in an assert, so it must be initialized |
| 291 | e->next = nullptr; |
| 292 | } |
| 293 | while (usage_ > capacity_ && lru_.next != &lru_) { |
| 294 | LRUHandle* old = lru_.next; |
| 295 | assert(old->refs == 1); |
| 296 | bool erased = FinishErase(table_.Remove(old->key(), old->hash)); |
| 297 | if (!erased) { // to avoid unused variable when compiled NDEBUG |
| 298 | assert(erased); |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | return reinterpret_cast<Cache::Handle*>(e); |
| 303 | } |
| 304 | |
| 305 | // If e != nullptr, finish removing *e from the cache; it has already been |
| 306 | // removed from the hash table. Return whether e != nullptr. |