cache

package
v1.3.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2024 License: MIT Imports: 23 Imported by: 0

README

Read this in other languages: English, 中文.

cache

cache_test.go

TestCache

tc := New(0, 0)

a, found := tc.Get("a")
if found || a != nil {
	t.Error("Getting A found value that shouldn't exist:", a)
}

b, found := tc.Get("b")
if found || b != nil {
	t.Error("Getting B found value that shouldn't exist:", b)
}

c, found := tc.Get("c")
if found || c != nil {
	t.Error("Getting C found value that shouldn't exist:", c)
}

tc.Set("a", 1, 0)
tc.Set("b", "b", 0)
tc.Set("c", 3.5, 0)

x, found := tc.Get("a")
if !found {
	t.Error("a was not found while getting a2")
}
if x == nil {
	t.Error("x for a is nil")
} else if a2 := x.(int); a2+2 != 3 {
	t.Error("a2 (which should be 1) plus 2 does not equal 3; value:", a2)
}

x, found = tc.Get("b")
if !found {
	t.Error("b was not found while getting b2")
}
if x == nil {
	t.Error("x for b is nil")
} else if b2 := x.(string); b2+"B" != "bB" {
	t.Error("b2 (which should be b) plus B does not equal bB; value:", b2)
}

x, found = tc.Get("c")
if !found {
	t.Error("c was not found while getting c2")
}
if x == nil {
	t.Error("x for c is nil")
} else if c2 := x.(float64); c2+1.2 != 4.7 {
	t.Error("c2 (which should be 3.5) plus 1.2 does not equal 4.7; value:", c2)
}
TestCacheTimes

var found bool

tc := New(50*time.Millisecond, 1*time.Millisecond)
tc.Set("a", 1, 0)
tc.Set("b", 2, -1)
tc.Set("c", 3, 20*time.Millisecond)
tc.Set("d", 4, 70*time.Millisecond)

<-time.After(25 * time.Millisecond)
_, found = tc.Get("c")
if found {
	t.Error("Found c when it should have been automatically deleted")
}

<-time.After(30 * time.Millisecond)
_, found = tc.Get("a")
if found {
	t.Error("Found a when it should have been automatically deleted")
}

_, found = tc.Get("b")
if !found {
	t.Error("Did not find b even though it was set to never expire")
}

_, found = tc.Get("d")
if !found {
	t.Error("Did not find d even though it was set to expire later than the default")
}

<-time.After(20 * time.Millisecond)
_, found = tc.Get("d")
if found {
	t.Error("Found d when it should have been automatically deleted (later than the default)")
}
TestStorePointerToStruct

tc := New(0, 0)
tc.Set("foo", &TestStruct{Num: 1}, 0)
x, found := tc.Get("foo")
if !found {
	t.Fatal("*TestStruct was not found for foo")
}
foo := x.(*TestStruct)
foo.Num++

y, found := tc.Get("foo")
if !found {
	t.Fatal("*TestStruct was not found for foo (second time)")
}
bar := y.(*TestStruct)
if bar.Num != 2 {
	t.Fatal("TestStruct.Num is not 2")
}
TestIncrementUint

tc := New(0, 0)
tc.Set("tuint", uint(1), 0)
_, err := tc.Increment("tuint", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuint")
if !found {
	t.Error("tuint was not found")
}
if x.(uint) != 3 {
	t.Error("tuint is not 3:", x)
}
TestIncrementUintptr

tc := New(0, 0)
tc.Set("tuintptr", uintptr(1), 0)
_, err := tc.Increment("tuintptr", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuintptr")
if !found {
	t.Error("tuintptr was not found")
}
if x.(uintptr) != 3 {
	t.Error("tuintptr is not 3:", x)
}
TestIncrementUint8

tc := New(0, 0)
tc.Set("tuint8", uint8(1), 0)
_, err := tc.Increment("tuint8", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuint8")
if !found {
	t.Error("tuint8 was not found")
}
if x.(uint8) != 3 {
	t.Error("tuint8 is not 3:", x)
}
TestIncrementUint16

tc := New(0, 0)
tc.Set("tuint16", uint16(1), 0)
_, err := tc.Increment("tuint16", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuint16")
if !found {
	t.Error("tuint16 was not found")
}
if x.(uint16) != 3 {
	t.Error("tuint16 is not 3:", x)
}
TestIncrementUint32

tc := New(0, 0)
tc.Set("tuint32", uint32(1), 0)
_, err := tc.Increment("tuint32", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuint32")
if !found {
	t.Error("tuint32 was not found")
}
if x.(uint32) != 3 {
	t.Error("tuint32 is not 3:", x)
}
TestIncrementUint64

tc := New(0, 0)
tc.Set("tuint64", uint64(1), 0)
_, err := tc.Increment("tuint64", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}

x, found := tc.Get("tuint64")
if !found {
	t.Error("tuint64 was not found")
}
if x.(uint64) != 3 {
	t.Error("tuint64 is not 3:", x)
}
TestIncrementInt

tc := New(0, 0)
tc.Set("tint", 1, 0)
_, err := tc.Increment("tint", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}
x, found := tc.Get("tint")
if !found {
	t.Error("tint was not found")
}
if x.(int) != 3 {
	t.Error("tint is not 3:", x)
}
TestIncrementInt8

tc := New(0, 0)
tc.Set("tint8", int8(1), 0)
_, err := tc.Increment("tint8", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}
x, found := tc.Get("tint8")
if !found {
	t.Error("tint8 was not found")
}
if x.(int8) != 3 {
	t.Error("tint8 is not 3:", x)
}
TestIncrementInt16

tc := New(0, 0)
tc.Set("tint16", int16(1), 0)
_, err := tc.Increment("tint16", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}
x, found := tc.Get("tint16")
if !found {
	t.Error("tint16 was not found")
}
if x.(int16) != 3 {
	t.Error("tint16 is not 3:", x)
}
TestIncrementInt32

tc := New(0, 0)
tc.Set("tint32", int32(1), 0)
_, err := tc.Increment("tint32", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}
x, found := tc.Get("tint32")
if !found {
	t.Error("tint32 was not found")
}
if x.(int32) != 3 {
	t.Error("tint32 is not 3:", x)
}
TestIncrementInt64

tc := New(0, 0)
tc.Set("tint64", int64(1), 0)
_, err := tc.Increment("tint64", 2)
if err != nil {
	t.Error("Error incrementing:", err)
}
x, found := tc.Get("tint64")
if !found {
	t.Error("tint64 was not found")
}
if x.(int64) != 3 {
	t.Error("tint64 is not 3:", x)
}
TestDecrementInt64

tc := New(0, 0)
tc.Set("int64", int64(5), 0)
_, err := tc.Decrement("int64", 2)
if err != nil {
	t.Error("Error decrementing:", err)
}
x, found := tc.Get("int64")
if !found {
	t.Error("int64 was not found")
}
if x.(int64) != 3 {
	t.Error("int64 is not 3:", x)
}
TestAdd

tc := New(0, 0)
err := tc.Add("foo", "bar", 0)
if err != nil {
	t.Error("Couldn't add foo even though it shouldn't exist")
}
err = tc.Add("foo", "baz", 0)
if err == nil {
	t.Error("Successfully added another foo when it should have returned an error")
}
TestReplace

tc := New(0, 0)
err := tc.Replace("foo", "bar", 0)
if err == nil {
	t.Error("Replaced foo when it shouldn't exist")
}
tc.Set("foo", "bar", 0)
err = tc.Replace("foo", "bar", 0)
if err != nil {
	t.Error("Couldn't replace existing key foo")
}
TestDelete

tc := New(0, 0)
tc.Set("foo", "bar", 0)
tc.Delete("foo")
x, found := tc.Get("foo")
if found {
	t.Error("foo was found, but it should have been deleted")
}
if x != nil {
	t.Error("x is not nil:", x)
}
TestFlush

tc := New(0, 0)
tc.Set("foo", "bar", 0)
tc.Set("baz", "yes", 0)
tc.Flush()
x, found := tc.Get("foo")
if found {
	t.Error("foo was found, but it should have been deleted")
}
if x != nil {
	t.Error("x is not nil:", x)
}
x, found = tc.Get("baz")
if found {
	t.Error("baz was found, but it should have been deleted")
}
if x != nil {
	t.Error("x is not nil:", x)
}
TestIncrementOverflowInt

tc := New(0, 0)
tc.Set("int8", int8(127), 0)
_, err := tc.Increment("int8", 1)
if err != nil {
	t.Error("Error incrementing int8:", err)
}
x, _ := tc.Get("int8")
int8 := x.(int8)
if int8 != -128 {
	t.Error("int8 did not overflow as expected; value:", int8)
}

TestIncrementOverflowUint

tc := New(0, 0)
tc.Set("uint8", uint8(255), 0)
_, err := tc.Increment("uint8", 1)
if err != nil {
	t.Error("Error incrementing int8:", err)
}
x, _ := tc.Get("uint8")
uint8 := x.(uint8)
if uint8 != 0 {
	t.Error("uint8 did not overflow as expected; value:", uint8)
}
TestDecrementUnderflowUint

tc := New(0, 0)
tc.Set("uint8", uint8(0), 0)
_, err := tc.Decrement("uint8", 1)
if err != nil {
	t.Error("Error decrementing int8:", err)
}
x, _ := tc.Get("uint8")
uint8 := x.(uint8)
if uint8 != 0 {
	t.Error("uint8 was not capped at 0; value:", uint8)
}
TestCacheSerialization

tc := New(0, 0)
testFillAndSerialize(t, tc)

// Check if gob.Register behaves properly even after multiple gob.Register
// on c.Items (many of which will be the same type)
testFillAndSerialize(t, tc)
TestFileSerialization

tc := New(0, 0)
tc.Add("a", "a", 0)
tc.Add("b", "b", 0)
f, err := ioutil.TempFile("", "go-cache-cache.dat")
if err != nil {
	t.Fatal("Couldn't create cache file:", err)
}
fname := f.Name()
f.Close()
tc.SaveFile(fname)

oc := New(0, 0)
oc.Add("a", "aa", 0) // this should not be overwritten
err = oc.LoadFile(fname)
if err != nil {
	t.Error(err)
}
a, found := oc.Get("a")
if !found {
	t.Error("a was not found")
}
astr := a.(string)
if astr != "aa" {
	if astr == "a" {
		t.Error("a was overwritten")
	} else {
		t.Error("a is not aa")
	}
}
b, found := oc.Get("b")
if !found {
	t.Error("b was not found")
}
if b.(string) != "b" {
	t.Error("b is not b")
}
TestSerializeUnserializable

tc := New(0, 0)
ch := make(chan bool, 1)
ch <- true
tc.Set("chan", ch, 0)
fp := &bytes.Buffer{}
err := tc.Save(fp) // this should fail gracefully
if err.Error() != "gob NewTypeObject can't handle type: chan bool" {
	t.Error("Error from Save was not gob NewTypeObject can't handle type chan bool:", err)
}

mem_cache_test.go

TestMemCacheFunc

ctx := context.Background()

const cacheKey = "UT:%v:%v"

var lCache = New(5*time.Minute, 5*time.Minute)
result, err := MemCacheFunc(ctx, lCache, 60*time.Second, rawGetFunc0, cacheKey, "p1", "p2")
log.Info(ctx, "%v %v %v", result, err, printKind(result))

_memCacheFuncTestMore(ctx, lCache, cacheKey)

rds_cache_test.go

TestRdscCacheFunc

redisDao.InitRedises()
ctx := context.Background()

const cacheKey = "UT:%v:%v"
const RDSC_DB = "rdscdb"

rds := redisDao.Get(RDSC_DB)

result, err := RdsCacheFunc(ctx, rds, 60, rawGetFunc0, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

log.Info(ctx, "%v %v %v", result, err, printKind(result))
TestRdsDeleteCacheTestMore

redisDao.InitRedises()
ctx := context.Background()

const cacheKey = "UT:%v:%v"
const RDSC_DB = "rdscdb"

rds := redisDao.Get(RDSC_DB)

var result interface{}
var err error

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc0, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc1, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc1, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc2, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc2, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc3, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc3, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc4, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc4, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc5, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc5, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc6, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc6, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", drainToArray(result), err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc7, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc7, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", drainToMap(result), err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc8, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc8, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc9, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))

result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc9, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
log.Info(ctx, "%v %v %v", result, err, printKind(result))
err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}

//result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc10, cacheKey, "p1", "p2")
//log.Info(ctx, "%v %v %v", result, err, printKind(result))
//
//result, err = RdsCacheFunc(ctx, rds, 60, rawGetFunc10, cacheKey, "p1", "p2")
//log.Info(ctx, "%v %v %v", result, err, printKind(result))

err = RdsDeleteCache(ctx, rds, cacheKey, "p1", "p2")
if err != nil {
	t.Error(err)
}
TestRdsCacheMultiFunc

redisDao.InitRedises()
ctx := context.Background()
const RDSC_DB = "rdscdb"

rds := redisDao.Get(RDSC_DB)
result, err := RdsCacheMultiFunc(ctx, rds, 30, getThingsByIds, "multikey:%s", []string{"1", "2", "5", "3", "4", "10"})
if err == nil && result != nil {
	mapValue, ok := result.(map[string]*Thing)
	if ok {
		for key, value := range mapValue {
			log.Info(ctx, "%v===%v", key, value)
		}
	}
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrKeyExists = fmt.Errorf("item already exists")
	ErrCacheMiss = fmt.Errorf("item not found")
)

Functions

func MemCacheDelete

func MemCacheDelete(ctx context.Context, cc *Cache, keyFmt string, args ...interface{}) bool

func MemCacheFunc

func MemCacheFunc(ctx context.Context, cc *Cache, expire time.Duration, f interface{}, keyFmt string, args ...interface{}) (interface{}, error)

func RdsCacheFunc

func RdsCacheFunc(ctx context.Context, rds redis.UniversalClient, rdsExpire int, f interface{}, keyFmt string,
	args ...interface{}) (interface{}, error)

func RdsCacheMultiFunc

func RdsCacheMultiFunc(ctx context.Context, rds redis.UniversalClient, rdsExpire int, fMulti interface{}, keyFmt string,
	args []string) (interface{}, error)

通用场景过于复杂,限定参数,返回类型为 map[string]*struct fMulti示例: func getThingsByIds(ctx context.Context, ids []string) (map[string]*Thing, error)

func RdsDeleteCache

func RdsDeleteCache(ctx context.Context, rds redis.UniversalClient, keyFmt string, args ...interface{}) (err error)

Types

type Cache added in v1.1.35

type Cache struct {
	// contains filtered or unexported fields
}

func New added in v1.1.35

func New(defaultExpiration, cleanupInterval time.Duration) *Cache

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 their next lookup or before calling DeleteExpired.

func (Cache) Add added in v1.1.35

func (c Cache) Add(k string, x interface{}, d time.Duration) error

Add an item to the cache only if an item doesn't already exist for the given key, or if the existing item has expired. Returns an error otherwise.

func (Cache) Decrement added in v1.1.35

func (c Cache) Decrement(k string, n uint64) (uint64, error)

Decrement an item of type int, int8, int16, int32, int64, uintptr, uint, uint8, uint32, or uint64 by n. Returns an error if the item's value is not an integer, if it was not found, or if it is not possible to decrement it by n. Stops at 0 on underflow.

func (Cache) Delete added in v1.1.35

func (c Cache) Delete(k string) (found bool)

Delete an item from the cache. Does nothing if the key is not in the cache.

func (Cache) DeleteExpired added in v1.1.35

func (c Cache) DeleteExpired()

Delete all expired items from the cache.

func (Cache) Flush added in v1.1.35

func (c Cache) Flush()

Delete all items from the cache.

func (Cache) Get added in v1.1.35

func (c Cache) Get(k string) (interface{}, bool)

Get an item from the cache. Returns the item or nil, and a bool indicating whether the key was found.

func (Cache) Increment added in v1.1.35

func (c Cache) Increment(k string, n uint64) (uint64, error)

Increment an item of type int, int8, int16, int32, int64, uintptr, uint, uint8, uint32, or uint64 by n. Returns an error if the item's value is not an integer, if it was not found, or if it is not possible to increment it by n. Wraps around on overlow.

func (Cache) IncrementFloat added in v1.1.35

func (c Cache) IncrementFloat(k string, n float64) error

Increment an item of type float32 or float64 by n. Returns an error if the item's value is not floating point, if it was not found, or if it is not possible to increment it by n. Pass a negative number to decrement the value.

func (Cache) Load added in v1.1.35

func (c Cache) Load(r io.Reader) error

Add (Gob-serialized) cache items from an io.Reader, excluding any items with keys that already exist in the current cache.

func (Cache) LoadFile added in v1.1.35

func (c Cache) LoadFile(fname string) error

Load and add cache items from the given filename, excluding any items with keys that already exist in the current cache.

func (Cache) Replace added in v1.1.35

func (c Cache) Replace(k string, x interface{}, d time.Duration) error

Set a new value for the cache key only if it already exists. Returns an error if it does not.

func (Cache) Save added in v1.1.35

func (c Cache) Save(w io.Writer) (err error)

Write the cache's items (using Gob) to an io.Writer.

func (Cache) SaveFile added in v1.1.35

func (c Cache) SaveFile(fname string) error

Save the cache's items to the given filename, creating the file if it doesn't exist, and overwriting it if it does.

func (Cache) Set added in v1.1.35

func (c Cache) Set(k string, x interface{}, d time.Duration)

Add an item to the cache, replacing any existing item. If the duration is 0, the cache's default expiration time is used. If it is -1, the item never expires.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL