| 1021 | } |
| 1022 | |
| 1023 | HandleBase* LIRSCacheShard::Insert(HandleBase* e_in, |
| 1024 | Cache::EvictionCallback *eviction_callback) { |
| 1025 | DCHECK(initialized_); |
| 1026 | LIRSHandle* e = static_cast<LIRSHandle*>(e_in); |
| 1027 | CHECK_EQ(e->state(), UNINITIALIZED); |
| 1028 | // Set the remaining LIRSHandle members which were not already set in the constructor. |
| 1029 | e->eviction_callback_ = eviction_callback; |
| 1030 | // The caller has already stored the value in the handle (and any underlying storage). |
| 1031 | // Whether the Insert() is ultimately successful or not, this handle is currently |
| 1032 | // resident. |
| 1033 | e->set_resident(); |
| 1034 | |
| 1035 | // Insert() can fail. A failed insert is equivalent to a successful insert followed |
| 1036 | // by an immediate eviction of that entry, so much of the setup code is identical. |
| 1037 | bool success = true; |
| 1038 | LIRSThreadState tstate; |
| 1039 | { |
| 1040 | std::lock_guard<MutexType> l(mutex_); |
| 1041 | |
| 1042 | // Cases: |
| 1043 | // 1. There is no existing entry. |
| 1044 | // 2. There is a tombstone entry. |
| 1045 | // 3. There is a non-tombstone entry (rare) |
| 1046 | // In any case, the existing entry will be replaced, so go ahead and remove it. |
| 1047 | LIRSHandle* existing_entry = |
| 1048 | static_cast<LIRSHandle*>(table_.Remove(e->key(), e->hash())); |
| 1049 | |
| 1050 | // The entry is always resident at the start of Insert(), so incorporate this |
| 1051 | // entry's charge into the memtracker. If Insert() fails, this is decremented as |
| 1052 | // part of eviction. |
| 1053 | UpdateMemTracker(e->charge()); |
| 1054 | // All of these paths can result in evictions |
| 1055 | if (existing_entry != nullptr) { |
| 1056 | // Priorities are modified in Lookup, but priorities are not changed in Insert. |
| 1057 | // The exception is TOMBSTONE entries, which are not impacted by Lookup. |
| 1058 | // So: |
| 1059 | // 1. TOMBSTONE becomes PROTECTED. |
| 1060 | // 2. PROTECTED remains PROTECTED. |
| 1061 | // 3. UNPROTECTED remains UNPROTECTED. |
| 1062 | LIRSState existing_state = existing_entry->state(); |
| 1063 | ToUninitialized(&tstate, existing_entry); |
| 1064 | if (existing_state == PROTECTED || existing_state == TOMBSTONE) { |
| 1065 | UninitializedToProtected(&tstate, e); |
| 1066 | } else { |
| 1067 | DCHECK_EQ(existing_state, UNPROTECTED); |
| 1068 | // UninitializedToUnprotected can fail (i.e. the entry inserted may not remain |
| 1069 | // in the cache). |
| 1070 | success = UninitializedToUnprotected(&tstate, e); |
| 1071 | } |
| 1072 | } else if (protected_usage_ + e->charge() <= protected_capacity_) { |
| 1073 | // There is available space in the protected area, so add it directly there. |
| 1074 | UninitializedToProtected(&tstate, e); |
| 1075 | } else { |
| 1076 | // UninitializedToUnprotected can fail (i.e. the entry inserted may not remain in |
| 1077 | // the cache). |
| 1078 | success = UninitializedToUnprotected(&tstate, e); |
| 1079 | } |
| 1080 | // If success=false, the entry is scheduled for eviction and won't be returned. |
no test coverage detected