Add OnMissing callback
This commit is contained in:
parent
5633e08626
commit
f3b182e5bf
|
@ -7,3 +7,4 @@ Dustin Sallings <dustin@spy.net>
|
||||||
Jason Mooberry <jasonmoo@me.com>
|
Jason Mooberry <jasonmoo@me.com>
|
||||||
Sergey Shepelev <temotor@gmail.com>
|
Sergey Shepelev <temotor@gmail.com>
|
||||||
Alex Edwards <ajmedwards@gmail.com>
|
Alex Edwards <ajmedwards@gmail.com>
|
||||||
|
Andrew Regner <andrew@aregner.com>
|
||||||
|
|
19
cache.go
19
cache.go
|
@ -42,6 +42,7 @@ type cache struct {
|
||||||
items map[string]Item
|
items map[string]Item
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
onEvicted func(string, interface{})
|
onEvicted func(string, interface{})
|
||||||
|
onMissing func(string) (*Item, error)
|
||||||
janitor *janitor
|
janitor *janitor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +124,16 @@ func (c *cache) Get(k string) (interface{}, bool) {
|
||||||
item, found := c.items[k]
|
item, found := c.items[k]
|
||||||
if !found {
|
if !found {
|
||||||
c.mu.RUnlock()
|
c.mu.RUnlock()
|
||||||
|
// try to generate the missing value
|
||||||
|
if c.onMissing != nil {
|
||||||
|
item, err := c.onMissing(k)
|
||||||
|
if err == nil {
|
||||||
|
c.mu.Lock()
|
||||||
|
c.items[k] = *item
|
||||||
|
c.mu.Unlock()
|
||||||
|
return item.Object, true
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
if item.Expiration > 0 {
|
if item.Expiration > 0 {
|
||||||
|
@ -956,6 +967,14 @@ func (c *cache) OnEvicted(f func(string, interface{})) {
|
||||||
c.mu.Unlock()
|
c.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets an (optional) function that is called to optionally generate a value for
|
||||||
|
// a key that was not found when calling Get.
|
||||||
|
func (c *cache) OnMissing(f func(string) (*Item, error)) {
|
||||||
|
c.mu.Lock()
|
||||||
|
c.onMissing = f
|
||||||
|
c.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
// Write the cache's items (using Gob) to an io.Writer.
|
// Write the cache's items (using Gob) to an io.Writer.
|
||||||
//
|
//
|
||||||
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
|
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
|
||||||
|
|
|
@ -2,6 +2,7 @@ package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -1247,6 +1248,41 @@ func TestOnEvicted(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOnMissing(t *testing.T) {
|
||||||
|
tc := New(DefaultExpiration, 0)
|
||||||
|
tc.Set("foo", 3, DefaultExpiration)
|
||||||
|
if tc.onMissing != nil {
|
||||||
|
t.Fatal("tc.onMissing is not nil")
|
||||||
|
}
|
||||||
|
tc.OnMissing(func(k string) (*Item, error) {
|
||||||
|
return &Item{
|
||||||
|
Object: 42,
|
||||||
|
Expiration: 0,
|
||||||
|
}, nil
|
||||||
|
})
|
||||||
|
x, _ := tc.Get("foo")
|
||||||
|
if x != 3 {
|
||||||
|
t.Error("getting a set item with a generator set produced unexpected result:", x)
|
||||||
|
}
|
||||||
|
x, found := tc.Get("potato")
|
||||||
|
if !found {
|
||||||
|
t.Error("item was not generated for missing key")
|
||||||
|
} else if x.(int) != 42 {
|
||||||
|
t.Error("generated item was not expected; value:", x)
|
||||||
|
}
|
||||||
|
tc.OnMissing(func(k string) (*Item, error) {
|
||||||
|
return nil, fmt.Errorf("some error")
|
||||||
|
})
|
||||||
|
x, found = tc.Get("apples")
|
||||||
|
if found || x != nil {
|
||||||
|
t.Error("onMissing should not have generated this:", x)
|
||||||
|
}
|
||||||
|
x, found = tc.Get("potato")
|
||||||
|
if !found || x != 42 {
|
||||||
|
t.Error("prior generated value should still have been set")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCacheSerialization(t *testing.T) {
|
func TestCacheSerialization(t *testing.T) {
|
||||||
tc := New(DefaultExpiration, 0)
|
tc := New(DefaultExpiration, 0)
|
||||||
testFillAndSerialize(t, tc)
|
testFillAndSerialize(t, tc)
|
||||||
|
|
Loading…
Reference in New Issue