diff --git a/README.md b/README.md index 985d743..872d3df 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,14 @@ Generic cache use and cache manager for golang. Provide a unified usage API by p - `gocache` https://github.com/patrickmn/go-cache - `bigcache` https://github.com/allegro/bigcache -internal: +Internal: - file internal driver [driver_file.go](driver_file.go) - memory internal driver [driver_memory.go](driver_memory.go) +> Notice: The built-in implementation is relatively simple and is not recommended for production environments; +> the production environment recommends using the third-party drivers listed above. + ## GoDoc - [doc on gowalker](https://gowalker.org/github.com/gookit/cache) @@ -53,8 +56,6 @@ type Cache interface { // basic operation Has(key string) bool Get(key string) interface{} - // GetAs get cache value and unmarshal to an object ptr. - GetAs(key string, ptr interface{}) error Set(key string, val interface{}, ttl time.Duration) (err error) Del(key string) error // multi operation diff --git a/README_cn.md b/README_cn.md index 39f06f8..a069ef2 100644 --- a/README_cn.md +++ b/README_cn.md @@ -26,11 +26,13 @@ Golang 通用的缓存管理使用库。 - `gocache` https://github.com/patrickmn/go-cache - `bigcache` https://github.com/allegro/bigcache -internal: +Internal: - file 简单的文件缓存(_当前包的内置实现_) - memory 简单的内存缓存(_当前包的内置实现_) +> 注意:内置实现比较简单,不推荐生产环境使用;生产环境推荐使用上面列出的三方驱动。 + ## GoDoc - [doc on gowalker](https://gowalker.org/github.com/gookit/cache) @@ -53,8 +55,6 @@ type Cache interface { // basic op Has(key string) bool Get(key string) interface{} - // GetAs get cache value and unmarshal to an object ptr. - GetAs(key string, ptr interface{}) error Set(key string, val interface{}, ttl time.Duration) (err error) Del(key string) error // multi op diff --git a/boltdb/boltdb.go b/boltdb/boltdb.go index 0ad5f15..60a5289 100644 --- a/boltdb/boltdb.go +++ b/boltdb/boltdb.go @@ -8,6 +8,7 @@ import ( "go.etcd.io/bbolt" ) +// Name driver name const Name = "boltDB" // BoltDB definition diff --git a/buntdb/buntdb.go b/buntdb/buntdb.go index 02d1c91..3249f58 100644 --- a/buntdb/buntdb.go +++ b/buntdb/buntdb.go @@ -10,6 +10,7 @@ import ( // Memory open a file that does not persist to disk. const Memory = ":memory:" +// Name driver name const Name = "buntDB" // BuntDB definition. diff --git a/cache.go b/cache.go index 586ef07..0a6ff1a 100644 --- a/cache.go +++ b/cache.go @@ -88,13 +88,13 @@ func Register(name string, driver Cache) *Manager { } // Unregister an cache driver -func Unregister(name string) { - std.Unregister(name) +func Unregister(name string) int { + return std.Unregister(name) } // UnregisterAll cache drivers -func UnregisterAll(fn ...func(cache Cache)) { - std.UnregisterAll(fn...) +func UnregisterAll(fn ...func(cache Cache)) int { + return std.UnregisterAll(fn...) } // SetDefName set default driver name. @@ -124,6 +124,11 @@ func Driver(driverName string) Cache { return std.Driver(driverName) } +// Std get default cache manager instance +func Std() *Manager { + return std +} + // DefManager get default cache manager instance func DefManager() *Manager { return std @@ -139,6 +144,11 @@ func Close() error { return std.Close() } +// ClearAll all drivers caches +func ClearAll() error { + return std.ClearAll() +} + /************************************************************* * quick use by default cache driver *************************************************************/ diff --git a/driver_file.go b/driver_file.go index 44f140c..aa23279 100644 --- a/driver_file.go +++ b/driver_file.go @@ -49,15 +49,9 @@ func NewFileCache(dir string, pfxAndKey ...string) *FileCache { return c } -// Has cache key. -// TODO decode value, and check expire time +// Has cache key. will check expire time func (c *FileCache) Has(key string) bool { - if c.MemoryCache.Has(key) { - return true - } - - path := c.GetFilename(key) - return fileExists(path) + return c.get(key) != nil } // Get value by key @@ -87,15 +81,14 @@ func (c *FileCache) get(key string) interface{} { return nil } - // check expire time - if item.Exp == 0 || item.Exp > time.Now().Unix() { - c.caches[key] = item // save to memory. - return item.Val + // check expired + if item.Expired() { + c.SetLastErr(c.del(key)) + return nil } - // has been expired. delete it. - c.SetLastErr(c.del(key)) - return nil + c.caches[key] = item // save to memory. + return item.Val } // Set value by key @@ -107,8 +100,8 @@ func (c *FileCache) Set(key string, val interface{}, ttl time.Duration) (err err } func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err error) { - if err = c.MemoryCache.set(key, val, ttl); err != nil { - c.SetLastErr(err) + err = c.MemoryCache.set(key, val, ttl) + if err != nil { return } @@ -132,10 +125,7 @@ func (c *FileCache) set(key string, val interface{}, ttl time.Duration) (err err } defer f.Close() - if _, err = f.Write(bs); err != nil { - return err - } - + _, err = f.Write(bs) return } @@ -165,12 +155,12 @@ func (c *FileCache) GetMulti(keys []string) map[string]interface{} { c.lock.RLock() defer c.lock.RUnlock() - values := make(map[string]interface{}, len(keys)) + data := make(map[string]interface{}, len(keys)) for _, key := range keys { - values[key] = c.get(key) + data[key] = c.get(key) } - return values + return data } // SetMulti values by multi key diff --git a/driver_memory.go b/driver_memory.go index 5f199ba..edee8ba 100644 --- a/driver_memory.go +++ b/driver_memory.go @@ -5,16 +5,6 @@ import ( "time" ) -// MemoryCache definition. -type MemoryCache struct { - // locker - lock sync.RWMutex - // cache data in memory. or use sync.Map - caches map[string]*Item - // TODO set max cache number - MaxCacheNum int -} - // Item for memory cache type Item struct { // Exp expire time @@ -23,9 +13,19 @@ type Item struct { Val interface{} } -// Invalid check whether expired -func (item Item) Invalid() bool { - return item.Exp != 0 && item.Exp < time.Now().Unix() +// Expired check whether expired +func (item Item) Expired() bool { + return item.Exp > 1 && item.Exp < time.Now().Unix() +} + +// MemoryCache definition. +type MemoryCache struct { + // locker + lock sync.RWMutex + // cache data in memory. or use sync.Map + caches map[string]*Item + // CacheSize TODO set max cache size + CacheSize int } // NewMemoryCache create a memory cache instance @@ -53,9 +53,8 @@ func (c *MemoryCache) Get(key string) interface{} { func (c *MemoryCache) get(key string) interface{} { if item, ok := c.caches[key]; ok { - // check expire time - // if has been expired, remove it. - if item.Invalid() { + // check expire time. if has been expired, remove it. + if item.Expired() { _ = c.del(key) } diff --git a/driver_test.go b/driver_test.go index e3c3f50..dcdad8b 100644 --- a/driver_test.go +++ b/driver_test.go @@ -122,3 +122,33 @@ func TestFileCache_object(t *testing.T) { // val2 := c.GetAs() // dump.P("cache get:", val) } + +func TestDefManager(t *testing.T) { + is := assert.New(t) + num := cache.UnregisterAll() + is.Equal(0, num) + is.Equal(0, cache.Unregister("not_exist")) + + cache.Register(cache.DvrMemory, cache.NewMemoryCache()) + is.Equal(cache.DvrMemory, cache.Std().DefName()) + + key := "name" + + // set + err := cache.Set(key, "cache value", cache.TwoMinutes) + is.NoError(err) + is.True(cache.Has(key)) + + // get + val := cache.Get(key) + is.Equal("cache value", val) + + // del + is.NoError(cache.Del(key)) + is.False(cache.Has(key)) + + is.NoError(cache.Clear()) + + num = cache.UnregisterAll() + is.GreaterOrEqual(1, num) +} diff --git a/example_test.go b/example_test.go index f7ee45b..c8dc7f1 100644 --- a/example_test.go +++ b/example_test.go @@ -17,7 +17,7 @@ func Example() { cache.Register(goredis.Name, goredis.Connect("127.0.0.1:6379", "", 0)) // setting default driver name - cache.DefaultUse(cache.DvrRedis) + cache.DefaultUse(goredis.Name) // quick use.(it is default driver) // diff --git a/gcache/gcache.go b/gcache/gcache.go index e0ccb13..e933c27 100644 --- a/gcache/gcache.go +++ b/gcache/gcache.go @@ -7,6 +7,9 @@ import ( "github.com/bluele/gcache" ) +// Name driver name +const Name = "gcache" + // GCache driver definition type GCache struct { // cache.BaseDriver diff --git a/gcache/gcache_test.go b/gcache/gcache_test.go new file mode 100644 index 0000000..accc35a --- /dev/null +++ b/gcache/gcache_test.go @@ -0,0 +1,122 @@ +package gcache_test + +import ( + "fmt" + "testing" + "time" + + "github.com/gookit/cache" + "github.com/gookit/cache/gcache" + "github.com/gookit/goutil/dump" + "github.com/gookit/goutil/strutil" + "github.com/stretchr/testify/assert" +) + +func Example() { + c := gcache.New(12) + key := "name" + + // set + c.Set(key, "cache value", cache.Seconds2) + fmt.Println(c.Has(key)) + + // get + val := c.Get(key) + fmt.Println(val) + + time.Sleep(2 * time.Second) + + // get expired + val2 := c.Get(key) + fmt.Println(val2) + + // del + c.Del(key) + fmt.Println(c.Has(key)) + + // Output: + // true + // cache value + // + // false +} + +func ExampleGCache_in_cachePkg() { + cache.Register(gcache.Name, gcache.New(12)) + defer cache.UnregisterAll() + + key := "name1" + + // set + cache.Set(key, "cache value", cache.Seconds2) + fmt.Println(cache.Has(key)) + + // get + val := cache.Get(key) + fmt.Println(val) + + time.Sleep(2 * time.Second) + + // get expired + val2 := cache.Get(key) + fmt.Println(val2) + + // del + cache.Del(key) + fmt.Println(cache.Has(key)) + + // Output: + // true + // cache value + // + // false +} + +func TestGCache_usage(t *testing.T) { + is := assert.New(t) + c := gcache.New(12) + defer c.Clear() + + key := strutil.RandomCharsV2(12) + is.False(c.Has(key)) + + err := c.Set(key, "value", cache.Seconds3) + is.NoError(err) + is.True(c.Has(key)) + + val := c.Get(key) + is.Equal("value", val) + + // del + err = c.Del(key) + is.NoError(err) + is.False(c.Has(key)) +} + +type user struct { + Age int + Name string +} + +func TestGCache_object(t *testing.T) { + is := assert.New(t) + c := gcache.New(12) + defer c.Clear() + + b1 := user { + Age: 1, + Name: "inhere", + } + + key := strutil.RandomCharsV2(12) + dump.P("cache key: " + key) + is.False(c.Has(key)) + + err := c.Set(key, b1, cache.Seconds3) + is.NoError(err) + is.True(c.Has(key)) + + b2 := c.Get(key).(user) + dump.P(b2) + is.Equal("inhere", b2.Name) +} \ No newline at end of file diff --git a/gocache/gocache_test.go b/gocache/gocache_test.go index faff630..94ece35 100644 --- a/gocache/gocache_test.go +++ b/gocache/gocache_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" ) -func ExampleGoCache() { +func Example() { c := gocache.New() key := "name" @@ -41,7 +41,7 @@ func ExampleGoCache() { // false } -func ExampleNewGoCache_cachePkg() { +func ExampleGoCache_in_cachePkg() { c1 := gocache.NewGoCache(cache.OneDay, cache.FiveMinutes) cache.Register(gocache.Name, c1) defer cache.UnregisterAll() diff --git a/leveldb/leveldb.go b/leveldb/leveldb.go index 3f19eb8..56aef77 100644 --- a/leveldb/leveldb.go +++ b/leveldb/leveldb.go @@ -7,6 +7,9 @@ import ( "github.com/syndtr/goleveldb/leveldb" ) +// Name driver name +const Name = "leveldb" + // LevelDB definition type LevelDB struct { // cache.BaseDriver diff --git a/manager.go b/manager.go index 03be13b..b56872e 100644 --- a/manager.go +++ b/manager.go @@ -43,13 +43,18 @@ func (m *Manager) Register(name string, driver Cache) *Manager { } // Unregister an cache driver -func (m *Manager) Unregister(name string) { +func (m *Manager) Unregister(name string) int { + if _, ok := m.drivers[name]; !ok { + return 0 + } + delete(m.drivers, name) // reset default driver name. if m.defName == name { m.defName = "" } + return 1 } // SetDefName set default driver name. alias of DefaultUse() @@ -106,10 +111,20 @@ func (m *Manager) Close() (err error) { return err } -// UnregisterAll cache drivers -func (m *Manager) UnregisterAll(fn ...func(cache Cache)) { - m.defName = "" +// ClearAll all drivers caches +func (m *Manager) ClearAll() (err error) { + for _, cache := range m.drivers { + err = cache.Clear() + } + return err +} +// UnregisterAll cache drivers +func (m *Manager) UnregisterAll(fn ...func(cache Cache)) int { + num := len(m.drivers) + + // unregister + m.defName = "" for name, driver := range m.drivers { if len(fn) > 0 { fn[0](driver) @@ -117,6 +132,7 @@ func (m *Manager) UnregisterAll(fn ...func(cache Cache)) { delete(m.drivers, name) } + return num } /************************************************************* diff --git a/memcached/memcached.go b/memcached/memcached.go index 9d4a8c4..c6ac3e2 100644 --- a/memcached/memcached.go +++ b/memcached/memcached.go @@ -8,6 +8,9 @@ import ( "github.com/gookit/cache" ) +// Name driver name +const Name = "memCached" + // MemCached definition type MemCached struct { cache.BaseDriver diff --git a/nutsdb/nutsdb.go b/nutsdb/nutsdb.go index e40ca95..9451ee3 100644 --- a/nutsdb/nutsdb.go +++ b/nutsdb/nutsdb.go @@ -5,6 +5,9 @@ import ( "time" ) +// Name driver name +const Name = "nutsdb" + // NutsDB definition TODO type NutsDB struct { // cache.BaseDriver diff --git a/redis/redigo.go b/redis/redigo.go index 48c6e34..036de31 100644 --- a/redis/redigo.go +++ b/redis/redigo.go @@ -11,6 +11,7 @@ import ( "github.com/gookit/cache" ) +// Name driver name const Name = "redigo" // RedisCache fallback alias