Add NewFrom, and deprecate Save, SaveFile, Load, and LoadFile
This commit is contained in:
parent
ffd0b9e3ec
commit
73a30b2033
70
cache.go
70
cache.go
|
@ -821,6 +821,9 @@ func (c *cache) DeleteExpired() {
|
|||
}
|
||||
|
||||
// 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
|
||||
// documentation for NewFrom.)
|
||||
func (c *cache) Save(w io.Writer) (err error) {
|
||||
enc := gob.NewEncoder(w)
|
||||
defer func() {
|
||||
|
@ -839,6 +842,9 @@ func (c *cache) Save(w io.Writer) (err error) {
|
|||
|
||||
// Save the cache's items to the given filename, creating the file if it
|
||||
// doesn't exist, and overwriting it if it does.
|
||||
//
|
||||
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
|
||||
// documentation for NewFrom.)
|
||||
func (c *cache) SaveFile(fname string) error {
|
||||
fp, err := os.Create(fname)
|
||||
if err != nil {
|
||||
|
@ -854,6 +860,9 @@ func (c *cache) SaveFile(fname string) error {
|
|||
|
||||
// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
|
||||
// keys that already exist (and haven't expired) in the current cache.
|
||||
//
|
||||
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
|
||||
// documentation for NewFrom.)
|
||||
func (c *cache) Load(r io.Reader) error {
|
||||
dec := gob.NewDecoder(r)
|
||||
items := map[string]*Item{}
|
||||
|
@ -873,6 +882,9 @@ func (c *cache) Load(r io.Reader) error {
|
|||
|
||||
// Load and add cache items from the given filename, excluding any items with
|
||||
// keys that already exist in the current cache.
|
||||
//
|
||||
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
|
||||
// documentation for NewFrom.)
|
||||
func (c *cache) LoadFile(fname string) error {
|
||||
fp, err := os.Open(fname)
|
||||
if err != nil {
|
||||
|
@ -943,33 +955,63 @@ func runJanitor(c *cache, ci time.Duration) {
|
|||
go j.Run(c)
|
||||
}
|
||||
|
||||
func newCache(de time.Duration) *cache {
|
||||
func newCache(de time.Duration, m map[string]*Item) *cache {
|
||||
if de == 0 {
|
||||
de = -1
|
||||
}
|
||||
c := &cache{
|
||||
defaultExpiration: de,
|
||||
items: map[string]*Item{},
|
||||
items: m,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]*Item) *Cache {
|
||||
c := newCache(de, m)
|
||||
// This trick ensures that the janitor goroutine (which--granted it
|
||||
// was enabled--is running DeleteExpired on c forever) does not keep
|
||||
// the returned C object from being garbage collected. When it is
|
||||
// garbage collected, the finalizer stops the janitor goroutine, after
|
||||
// which c can be collected.
|
||||
C := &Cache{c}
|
||||
if ci > 0 {
|
||||
runJanitor(c, ci)
|
||||
runtime.SetFinalizer(C, stopJanitor)
|
||||
}
|
||||
return C
|
||||
}
|
||||
|
||||
// Return a new cache with a given default expiration duration and cleanup
|
||||
// interval. If the expiration duration is less than 1, the items in the cache
|
||||
// never expire (by default), and must be deleted manually. If the cleanup
|
||||
// interval is less than one, expired items are not deleted from the cache
|
||||
// before calling DeleteExpired.
|
||||
func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
|
||||
c := newCache(defaultExpiration)
|
||||
// This trick ensures that the janitor goroutine (which--granted it
|
||||
// was enabled--is running DeleteExpired on c forever) does not keep
|
||||
// the returned C object from being garbage collected. When it is
|
||||
// garbage collected, the finalizer stops the janitor goroutine, after
|
||||
// which c can be collected.
|
||||
C := &Cache{c}
|
||||
if cleanupInterval > 0 {
|
||||
runJanitor(c, cleanupInterval)
|
||||
runtime.SetFinalizer(C, stopJanitor)
|
||||
}
|
||||
return C
|
||||
items := make(map[string]*Item)
|
||||
return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
|
||||
}
|
||||
|
||||
// Return a new cache with a given default expiration duration and cleanup
|
||||
// interval. If the expiration duration is less than 1, the items in the cache
|
||||
// never expire (by default), and must be deleted manually. If the cleanup
|
||||
// interval is less than one, expired items are not deleted from the cache
|
||||
// before calling DeleteExpired.
|
||||
//
|
||||
// NewFrom also accepts an items map which will serve as the underlying map
|
||||
// for the cache. This is useful for deserializing a cache (serialized using
|
||||
// e.g. gob.Encode on c.Items()), or setting a starting size by passing in e.g.
|
||||
// make(map[string]*Item, 500) to avoid repeat initial resizing of a map that's
|
||||
// expected to reach a certain minimum size.
|
||||
//
|
||||
// Only the cache's methods synchronize access to this map, so it is not
|
||||
// recommended to keep any references to the map around after creating a cache.
|
||||
// If need be, the map can be accessed at a later point using c.Items() (with
|
||||
// the same caveats.)
|
||||
//
|
||||
// Note regarding serialization: When using e.g. gob, make sure to gob.Register
|
||||
// the individual types stored in the cache before encoding a map retrieved with
|
||||
// c.Items(), and to register those same types before decoding a blob containing
|
||||
// an items map.
|
||||
func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]*Item) *Cache {
|
||||
return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
|
||||
}
|
||||
|
|
|
@ -106,6 +106,34 @@ func TestCacheTimes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewFrom(t *testing.T) {
|
||||
m := map[string]*Item{
|
||||
"a": &Item{
|
||||
Object: 1,
|
||||
Expiration: nil,
|
||||
},
|
||||
"b": &Item{
|
||||
Object: 2,
|
||||
Expiration: nil,
|
||||
},
|
||||
}
|
||||
tc := NewFrom(0, 0, m)
|
||||
a, found := tc.Get("a")
|
||||
if !found {
|
||||
t.Fatal("Did not find a")
|
||||
}
|
||||
if a.(int) != 1 {
|
||||
t.Fatal("a is not 1")
|
||||
}
|
||||
b, found := tc.Get("b")
|
||||
if !found {
|
||||
t.Fatal("Did not find b")
|
||||
}
|
||||
if b.(int) != 2 {
|
||||
t.Fatal("b is not 2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStorePointerToStruct(t *testing.T) {
|
||||
tc := New(0, 0)
|
||||
tc.Set("foo", &TestStruct{Num: 1}, 0)
|
||||
|
|
Loading…
Reference in New Issue