micro/store/cache/cache.go

129 lines
3.3 KiB
Go
Raw Normal View History

package cache
import (
"github.com/micro/go-micro/v2/store"
2020-04-11 12:10:19 +01:00
"github.com/micro/go-micro/v2/store/memory"
)
// cache store is a store with caching to reduce IO where applicable.
// A memory store is used to cache reads from the given backing store.
// Reads are read through, writes are write-through
type cache struct {
m store.Store // the memory store
b store.Store // the backing store, could be file, cockroach etc
options store.Options
}
// NewStore returns a new cache store
func NewStore(store store.Store, opts ...store.Option) store.Store {
cf := &cache{
m: memory.NewStore(opts...),
b: store,
2020-04-11 12:10:19 +01:00
}
return cf
2020-04-11 12:10:19 +01:00
}
func (c *cache) init(opts ...store.Option) error {
for _, o := range opts {
o(&c.options)
}
return nil
}
// Init initialises the underlying stores
2020-04-11 12:10:19 +01:00
func (c *cache) Init(opts ...store.Option) error {
if err := c.init(opts...); err != nil {
return err
}
if err := c.m.Init(opts...); err != nil {
return err
}
return c.b.Init(opts...)
}
// Options allows you to view the current options.
func (c *cache) Options() store.Options {
return c.options
}
// Read takes a single key name and optional ReadOptions. It returns matching []*Record or an error.
func (c *cache) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
recs, err := c.m.Read(key, opts...)
if err != nil && err != store.ErrNotFound {
return nil, err
}
if len(recs) > 0 {
return recs, nil
}
recs, err = c.b.Read(key, opts...)
if err == nil {
for _, rec := range recs {
if err := c.m.Write(rec); err != nil {
return nil, err
}
}
}
return recs, err
}
// Write() writes a record to the store, and returns an error if the record was not written.
// If the write succeeds in writing to memory but fails to write through to file, you'll receive an error
// but the value may still reside in memory so appropriate action should be taken.
func (c *cache) Write(r *store.Record, opts ...store.WriteOption) error {
if err := c.m.Write(r, opts...); err != nil {
return err
}
return c.b.Write(r, opts...)
}
// Delete removes the record with the corresponding key from the store.
// If the delete succeeds in writing to memory but fails to write through to file, you'll receive an error
// but the value may still reside in memory so appropriate action should be taken.
func (c *cache) Delete(key string, opts ...store.DeleteOption) error {
if err := c.m.Delete(key, opts...); err != nil {
return err
}
return c.b.Delete(key, opts...)
}
// List returns any keys that match, or an empty list with no error if none matched.
func (c *cache) List(opts ...store.ListOption) ([]string, error) {
keys, err := c.m.List(opts...)
if err != nil && err != store.ErrNotFound {
return nil, err
}
if len(keys) > 0 {
return keys, nil
}
keys, err = c.b.List(opts...)
if err == nil {
for _, key := range keys {
recs, err := c.b.Read(key)
if err != nil {
return nil, err
}
for _, r := range recs {
if err := c.m.Write(r); err != nil {
return nil, err
}
}
}
}
return keys, err
}
// Close the store and the underlying store
func (c *cache) Close() error {
if err := c.m.Close(); err != nil {
return err
}
return c.b.Close()
}
// String returns the name of the implementation.
func (c *cache) String() string {
return "cache"
}