129 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package cache
 | 
						|
 | 
						|
import (
 | 
						|
	"github.com/micro/go-micro/v3/store"
 | 
						|
	"github.com/micro/go-micro/v3/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,
 | 
						|
	}
 | 
						|
	return cf
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
func (c *cache) init(opts ...store.Option) error {
 | 
						|
	for _, o := range opts {
 | 
						|
		o(&c.options)
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Init initialises the underlying stores
 | 
						|
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"
 | 
						|
}
 |