@@ -105,7 +105,12 @@ cdef class LRU_K:
105105 old_value = self .slots[key]
106106 self .current_memory += len (value) - len (old_value)
107107
108+ # Insert/update the slot value. Do NOT update access history on set();
109+ # access history should reflect actual accesses (gets) only. This keeps
110+ # behaviour consistent with LRU-K expectations and existing tests.
108111 self .slots[key] = value
112+ # Update access history on set as well (insertion counts as an access)
113+ # This mirrors the previous behavior and keeps eviction semantics stable.
109114 self ._update_access_history(key)
110115
111116 # Move to end to maintain LRU order
@@ -181,21 +186,40 @@ cdef class LRU_K:
181186 return None , None
182187 return None , None
183188
184- # Find the key with the oldest kth access time
185- # For keys with < k accesses, use their first access time
189+ # Find the key with the oldest kth access time.
190+ # First prefer keys that have at least k accesses (full history). If
191+ # none exist, fall back to keys with fewer than k accesses. This
192+ # enforces LRU-K: items with insufficient access history are evicted
193+ # only as a last resort.
194+ cdef int found_full_history = 0
195+ cdef int64_t candidate_time = - 1
196+
197+ # First pass: look for keys with >= k accesses
186198 for key in self .slots:
187199 history = self .access_history.get(key)
188200 if history is None :
189- # No history means never accessed, evict immediately
190- candidate_key = key
191- break
192-
193- # Use the oldest (first) access time as the comparison point
194- kth_time = history[0 ]
195-
196- if oldest_kth_time == - 1 or kth_time < oldest_kth_time:
197- oldest_kth_time = kth_time
198- candidate_key = key
201+ continue
202+ if len (history) >= self .k:
203+ kth_time = history[0 ]
204+ if candidate_key is None or kth_time < candidate_time:
205+ candidate_key = key
206+ candidate_time = kth_time
207+ found_full_history = 1
208+
209+ if not found_full_history:
210+ # Second pass: consider keys with partial history (len < k)
211+ for key in self .slots:
212+ history = self .access_history.get(key)
213+ if history is None :
214+ # No history means never accessed; consider as last fallback
215+ if candidate_key is None :
216+ candidate_key = key
217+ break
218+ # use first access time
219+ kth_time = history[0 ]
220+ if candidate_key is None or kth_time < candidate_time:
221+ candidate_key = key
222+ candidate_time = kth_time
199223
200224 if candidate_key is None :
201225 if details:
0 commit comments