| 793 | } |
| 794 | |
| 795 | void LIRSCacheShard::ToUninitialized(LIRSThreadState* tstate, LIRSHandle* e, |
| 796 | bool is_trim) { |
| 797 | DCHECK_NE(e->state(), UNINITIALIZED); |
| 798 | LIRSHandle* removed_elem = static_cast<LIRSHandle*>(table_.Remove(e->key(), e->hash())); |
| 799 | DCHECK(e == removed_elem || removed_elem == nullptr); |
| 800 | // Remove from the list (if it is in the list) |
| 801 | if (e->recency_list_hook_.is_linked()) { |
| 802 | // If we are removing the last entry on the recency list, then we may need to call |
| 803 | // TrimRecencyList to maintain our invariant that the last entry on the recency list |
| 804 | // is a PROTECTED element. TrimRecencyList itself calls this function while enforcing |
| 805 | // the invariant, so this passes is_trim=true from TrimRecencyList to avoid the |
| 806 | // unnecessary recursion. |
| 807 | bool need_trim = false; |
| 808 | // Is this the oldest entry in the list (the front)? |
| 809 | LIRSHandle* oldest = &recency_list_.front(); |
| 810 | if (!is_trim and oldest == e) { |
| 811 | DCHECK_EQ(e->state(), PROTECTED); |
| 812 | need_trim = true; |
| 813 | } |
| 814 | recency_list_.erase(recency_list_.iterator_to(*e)); |
| 815 | if (need_trim) { |
| 816 | TrimRecencyList(tstate); |
| 817 | } |
| 818 | } |
| 819 | if (e->state() == UNPROTECTED) { |
| 820 | if (e->unprotected_tombstone_list_hook_.is_linked()) { |
| 821 | // Remove from the unprotected list and decrement usage |
| 822 | RemoveFromUnprotectedList(e); |
| 823 | } |
| 824 | --num_unprotected_; |
| 825 | unprotected_usage_ -= e->charge(); |
| 826 | } else if (e->state() == TOMBSTONE) { |
| 827 | if (e->unprotected_tombstone_list_hook_.is_linked()) { |
| 828 | unprotected_tombstone_list_.erase(unprotected_tombstone_list_.iterator_to(*e)); |
| 829 | } |
| 830 | --num_tombstones_; |
| 831 | } else { |
| 832 | DCHECK(!e->unprotected_tombstone_list_hook_.is_linked()); |
| 833 | } |
| 834 | if (e->state() == PROTECTED) { |
| 835 | protected_usage_ -= e->charge(); |
| 836 | --num_protected_; |
| 837 | } |
| 838 | |
| 839 | auto state_transition = e->modify_atomic_state([](AtomicState& cur_state) { |
| 840 | cur_state.state = UNINITIALIZED; |
| 841 | // If it is not resident, there must be no references. |
| 842 | if (cur_state.residency == NOT_RESIDENT || cur_state.residency == EVICTING) { |
| 843 | DCHECK_EQ(cur_state.ref_count, 0); |
| 844 | } |
| 845 | // If this is resident without references, we can start eviction. |
| 846 | if (cur_state.residency == RESIDENT && cur_state.ref_count == 0) { |
| 847 | cur_state.residency = EVICTING; |
| 848 | } |
| 849 | }); |
| 850 | |
| 851 | if (state_transition.before.residency == RESIDENT && |
| 852 | state_transition.after.residency == EVICTING) { |