Skip to content

Commit

Permalink
signature of the WithMaxCost option changed
Browse files Browse the repository at this point in the history
  • Loading branch information
dadrus committed Nov 14, 2024
1 parent c4b0baa commit 2a04fee
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 18 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ of items it can hold, the `ttlcache.WithMaxCost` option allows for
implementing custom strategies. The following example demonstrates
how to limit the maximum memory usage of a cache to 5MB:
```go
import (
"github.com/jellydator/ttlcache"
"github.com/DmitriyVTitov/size"
)

func main() {
cache := ttlcache.New[string, string](
ttlcache.WithMaxCost[string, string](5120, func(key string, item string) uint64 {
// 72 (bytes) represent the memory occupied by the *ttlcache.Item structure
// used to store the new value.
// 16 (bytes) represent the memory footprint of a string header in Go,
// as determined by unsafe.Sizeof.
return 72 + 16 + len(key) + 16 + len(item)
ttlcache.WithMaxCost[string, string](5120, func(item *ttlcache.Item[string, string]) uint64 {
return size.Of(item)
}),
)

Expand Down
14 changes: 8 additions & 6 deletions cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,19 @@ func (c *Cache[K, V]) set(key K, value V, ttl time.Duration) *Item[K, V] {

elem := c.get(key, false, true)
if elem != nil {
var oldItemCosts uint64
// update/overwrite an existing item
item := elem.Value.(*Item[K, V])
oldValue := item.value
if c.options.maxCost != 0 {
oldItemCosts = c.options.costFunc(item)
}

item.update(value, ttl)

c.updateExpirations(false, elem)

if c.options.maxCost != 0 {
oldItemCosts := c.options.costFunc(key, oldValue)
newItemCosts := c.options.costFunc(key, value)

newItemCosts := c.options.costFunc(item)
c.cost = c.cost - oldItemCosts + newItemCosts

for c.cost > c.options.maxCost {
Expand All @@ -174,7 +176,7 @@ func (c *Cache[K, V]) set(key K, value V, ttl time.Duration) *Item[K, V] {
c.updateExpirations(true, elem)

if c.options.maxCost != 0 {
c.cost += c.options.costFunc(key, value)
c.cost += c.options.costFunc(item)

for c.cost > c.options.maxCost {
c.evict(EvictionReasonTotalCostExceeded, c.items.lru.Back())
Expand Down Expand Up @@ -283,7 +285,7 @@ func (c *Cache[K, V]) evict(reason EvictionReason, elems ...*list.Element) {
delete(c.items.values, item.key)

if c.options.maxCost != 0 {
c.cost -= c.options.costFunc(item.key, item.value)
c.cost -= c.options.costFunc(item)
}

c.items.lru.Remove(elems[i])
Expand Down
6 changes: 3 additions & 3 deletions cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1263,10 +1263,10 @@ func prepCache(maxCost uint64, ttl time.Duration, keys ...string) *Cache[string,
c.options.ttl = ttl
if maxCost != 0 {
c.options.maxCost = maxCost
c.options.costFunc = func(key string, item string) uint64 {
c.options.costFunc = func(item *Item[string, string]) uint64 {
// 72 bytes are used by the Item struct
// 2 * 16 bytes are used by the used string headers (key and item)
return uint64(len(item))
return uint64(len(item.value))
}
}
c.items.values = make(map[string]*list.Element)
Expand Down Expand Up @@ -1295,7 +1295,7 @@ func addToCache(c *Cache[string, string], ttl time.Duration, keys ...string) {
c.items.expQueue.push(elem)

if c.options.maxCost != 0 {
c.cost += c.options.costFunc(key, value)
c.cost += c.options.costFunc(item)
}
}
}
2 changes: 1 addition & 1 deletion options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (fn optionFunc[K, V]) apply(opts *options[K, V]) {

// CostFunc is used to calculate the cost of the key and the item to be
// inserted into the cache.
type CostFunc[K comparable, V any] func(key K, item V) uint64
type CostFunc[K comparable, V any] func(item *Item[K, V]) uint64

// options holds all available cache configuration options.
type options[K comparable, V any] struct {
Expand Down
4 changes: 2 additions & 2 deletions options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ func Test_WithDisableTouchOnHit(t *testing.T) {
func Test_WithMaxCost(t *testing.T) {
var opts options[string, string]

WithMaxCost[string, string](1024, func(key string, item string) uint64 { return 1 }).apply(&opts)
WithMaxCost[string, string](1024, func(item *Item[string, string]) uint64 { return 1 }).apply(&opts)

assert.Equal(t, uint64(1024), opts.maxCost)
assert.Equal(t, uint64(1), opts.costFunc("test", "foo"))
assert.Equal(t, uint64(1), opts.costFunc(&Item[string, string]{key: "test", value: "foo"}))
}

0 comments on commit 2a04fee

Please sign in to comment.