Skip to content

Commit

Permalink
add expirable LRU implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
paskal committed Nov 18, 2022
1 parent efb1d5b commit 84dd31b
Show file tree
Hide file tree
Showing 5 changed files with 586 additions and 40 deletions.
75 changes: 66 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,74 @@ Documentation

Full docs are available on [Go Packages](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2)

Example
=======

Using the LRU is very simple:
LRU cache example
=================

```go
l, _ := New(128)
for i := 0; i < 256; i++ {
l.Add(i, nil)
package main

import (
"fmt"

"github.com/hashicorp/golang-lru/v2"
)

func main() {
l, _ := lru.New[int, *string](128)
for i := 0; i < 256; i++ {
l.Add(i, nil)
}

if l.Len() != 128 {
panic(fmt.Sprintf("bad len: %v", l.Len()))
}
}
if l.Len() != 128 {
panic(fmt.Sprintf("bad len: %v", l.Len()))
```

Expirable LRU cache example
===========================

```go
package main

import (
"fmt"
"time"

"github.com/hashicorp/golang-lru/v2/simplelru"
)

func main() {
// make cache with short TTL and 3 max keys, purgeEvery time.Millisecond * 10
cache := simplelru.NewExpirableLRU[string, string](3, nil, time.Millisecond*5, time.Millisecond*10)
// expirable cache need to be closed after used
defer cache.Close()

// set value under key1.
cache.Add("key1", "val1")

// get value under key1
r, ok := cache.Get("key1")

// check for OK value
if ok {
fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
}

// wait for cache to expire
time.Sleep(time.Millisecond * 16)

// get value under key1 after key expiration
r, ok = cache.Get("key1")
fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)

// set value under key2, would evict old entry because it is already expired.
cache.Add("key2", "val2")

fmt.Printf("Cache len: %d\n", cache.Len())
// Output:
// value before expiration is found: true, value: "val1"
// value after expiration is found: false, value: ""
// Cache len: 1
}
```
15 changes: 10 additions & 5 deletions simplelru/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

package simplelru

import "time"

// entry is an LRU entry
type entry[K comparable, V any] struct {
// Next and previous pointers in the doubly-linked list of elements.
Expand All @@ -21,6 +23,9 @@ type entry[K comparable, V any] struct {

// The value stored with this element.
value V

// The time this element would be cleaned up
expiresAt time.Time
}

// prevEntry returns the previous list element or nil.
Expand Down Expand Up @@ -79,9 +84,9 @@ func (l *lruList[K, V]) insert(e, at *entry[K, V]) *entry[K, V] {
return e
}

// insertValue is a convenience wrapper for insert(&Element{Value: v}, at).
func (l *lruList[K, V]) insertValue(k K, v V, at *entry[K, V]) *entry[K, V] {
return l.insert(&entry[K, V]{value: v, key: k}, at)
// insertValue is a convenience wrapper for insert(&entry{value: v, expiresAt: expiresAt}, at).
func (l *lruList[K, V]) insertValue(k K, v V, expiresAt time.Time, at *entry[K, V]) *entry[K, V] {
return l.insert(&entry[K, V]{value: v, key: k, expiresAt: expiresAt}, at)
}

// remove removes e from its list, decrements l.len
Expand Down Expand Up @@ -111,9 +116,9 @@ func (l *lruList[K, V]) move(e, at *entry[K, V]) {
}

// pushFront inserts a new element e with value v at the front of list l and returns e.
func (l *lruList[K, V]) pushFront(k K, v V) *entry[K, V] {
func (l *lruList[K, V]) pushFront(k K, v V, expiresAt time.Time) *entry[K, V] {
l.lazyInit()
return l.insertValue(k, v, &l.root)
return l.insertValue(k, v, expiresAt, &l.root)
}

// moveToFront moves element e to the front of list l.
Expand Down
Loading

0 comments on commit 84dd31b

Please sign in to comment.