in lru.go [358:437]
func (lru *LRU[K, V]) addWithLifetime(hash uint32, key K, value V,
lifetime time.Duration) (evicted bool) {
bucketPos, startPos := lru.hashToPos(hash)
if startPos == emptyBucket {
pos := lru.len
if pos == lru.cap {
// Capacity reached, evict the oldest entry and
// store the new entry at evicted position.
pos = lru.elements[lru.head].next
lru.evict(pos)
lru.metrics.Evictions++
evicted = true
}
// insert new (first) entry into the bucket
lru.buckets[bucketPos] = pos
lru.elements[pos].bucketPos = bucketPos
lru.elements[pos].nextBucket = pos
lru.elements[pos].prevBucket = pos
lru.insert(pos, key, value, lifetime)
return evicted
}
// Walk through the bucket list to see whether key already exists.
pos := startPos
for {
if lru.elements[pos].key == key {
// Key exists, replace the value and update element to be the head element.
lru.elements[pos].value = value
lru.elements[pos].expire = expire(lifetime)
if pos != lru.head {
lru.unlinkElement(pos)
lru.setHead(pos)
}
// count as insert, even if it's just an update
lru.metrics.Inserts++
return false
}
pos = lru.elements[pos].nextBucket
if pos == startPos {
// Key not found
break
}
}
pos = lru.len
if pos == lru.cap {
// Capacity reached, evict the oldest entry and
// store the new entry at evicted position.
pos = lru.elements[lru.head].next
lru.evict(pos)
lru.metrics.Evictions++
evicted = true
startPos = lru.buckets[bucketPos]
if startPos == emptyBucket {
startPos = pos
}
}
// insert new entry into the existing bucket before startPos
lru.buckets[bucketPos] = pos
lru.elements[pos].bucketPos = bucketPos
lru.elements[pos].nextBucket = startPos
lru.elements[pos].prevBucket = lru.elements[startPos].prevBucket
lru.elements[lru.elements[startPos].prevBucket].nextBucket = pos
lru.elements[startPos].prevBucket = pos
lru.insert(pos, key, value, lifetime)
if lru.elements[pos].prevBucket != pos {
// The bucket now contains more than 1 element.
// That means we have a collision.
lru.metrics.Collisions++
}
return evicted
}