restcache

package
v0.0.0-...-e2a80a6 Latest Latest
Warning

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

Go to latest
Published: Nov 29, 2023 License: BSD-3-Clause Imports: 9 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func HitIndexes

func HitIndexes[T any](collection []T, missIndexes []int) []int

HitIndexes 根据未命中的索引,得到命中的索引

Types

type Caching

type Caching struct {
	// Storage 存储接口。
	Storage Storage

	// Query 如果没从Storage里找到,调用Query查询。
	Query QueryFunc

	// TTLRange 缓存生存时间区间。每次随机取一个区间内的值。
	TTLRange [2]time.Duration

	// SentinelTTL 哨兵和哨兵持有的临时缓存的生存时间。用来省去双重检查。一般1s即可。
	// “副作用”是可以避免高频查询找不到的数据。
	SentinelTTL time.Duration
	// contains filtered or unexported fields
}

Caching 缓存。

func (*Caching) Get

func (caching *Caching) Get(ctx context.Context, destPtr interface{}, key string, args interface{}) (found bool, err error)

Get 查询。destPtr为结果对象指针,key为缓存key,args为查询函数参数。 destPtr的值是共享的,内容数据不可修改。

Example
query := func(ctx context.Context, destPtr interface{}, args interface{}) (found bool, err error) {
	req := args.(string)
	resp := destPtr.(*string)
	*resp = "echo: " + req
	return true, nil
}

caching := Caching{
	Storage:     lrucache.NewLRUCache(10000, 10), // 一般是redis实现
	Query:       query,
	TTLRange:    [2]time.Duration{time.Minute * 4, time.Minute * 6},
	SentinelTTL: time.Second,
}

var resp string
found, err := caching.Get(context.TODO(), &resp, "key:hello", "hello")
if err != nil {
	fmt.Println(err)
	return
}
if found {
	fmt.Println(resp)
}
Output:

echo: hello

type MCaching

type MCaching struct {
	// MStorage 支持批量操作的缓存存储接口。
	MStorage MStorage

	// MQuery 没从MStorage里找到的,调用MQuery批量查询。
	MQuery MQueryFunc

	// TTLRange 缓存生存时间区间。每次随机取一个区间内的值。
	TTLRange [2]time.Duration

	// SentinelTTL 哨兵和哨兵持有的临时缓存的生存时间。用来省去双重检查。一般1s即可。
	// “副作用”是可以避免高频查询找不到的数据。
	SentinelTTL time.Duration
	// contains filtered or unexported fields
}
Example (PartialFound)
query := func(ctx context.Context, destSlicePtr interface{}, argsSlice interface{}) (missIndexes []int, err error) {
	req := argsSlice.([]string)
	resp := destSlicePtr.(*[]string)
	for index, r := range req {
		if r == "" {
			missIndexes = append(missIndexes, index)
			continue
		}
		*resp = append(*resp, "echo: "+r)
	}
	return missIndexes, nil
}

mcaching := MCaching{
	MStorage:    lrucache.NewLRUCache(10000, 10), // 一般是redis实现
	MQuery:      query,
	TTLRange:    [2]time.Duration{time.Minute * 4, time.Minute * 6},
	SentinelTTL: time.Second,
}

var keys = []string{"key_1", "key_2", "key_notfound", "key_3"}
var args = []string{"1", "2", "", "3"}
var resp []string
missIndexes, err := mcaching.MGet(context.TODO(), &resp, keys, args)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(strings.Join(resp, "; "))
for _, missIndex := range missIndexes {
	fmt.Println("not found:", keys[missIndex])
}
Output:

echo: 1; echo: 2; echo: 3
not found: key_notfound

func (*MCaching) MGet

func (mcaching *MCaching) MGet(ctx context.Context, destSlicePtr interface{}, keys []string, argsSlice interface{}) (missIndexes []int, err error)

MGet 批量查询。 destSlicePtr是结果切片指针,keys是缓存key,argsSlice是查询函数的参数序列。 如果全部没找到,或者部分没找到,返回没找到部分的下标,不返回错误。 destSlicePtr指向的切片的元素数据是共享的,内容不可修改。 可以使用restutils.HitIndexes函数,将没找到部分的下标,转为找到部分的下标。

Example
query := func(ctx context.Context, destSlicePtr interface{}, argsSlice interface{}) (missIndexes []int, err error) {
	req := argsSlice.([]string)
	resp := destSlicePtr.(*[]string)
	for _, r := range req {
		*resp = append(*resp, "echo: "+r)
	}
	return nil, nil
}

mcaching := MCaching{
	MStorage:    lrucache.NewLRUCache(10000, 10), // 一般是redis实现
	MQuery:      query,
	TTLRange:    [2]time.Duration{time.Minute * 4, time.Minute * 6},
	SentinelTTL: time.Second,
}

var keys = []string{"key_1", "key_2", "key_3"}
var args = []string{"1", "2", "3"}
var resp []string
_, err := mcaching.MGet(context.TODO(), &resp, keys, args)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(strings.Join(resp, "\n"))
Output:

echo: 1
echo: 2
echo: 3

type MQueryFunc

type MQueryFunc func(ctx context.Context, destSlicePtr interface{}, argsSlice interface{}) (missIndexes []int, err error)

MQueryFunc 批量查询函数。 destSlicePtr元素的顺序同argsSlice的顺序。如果argsSlice元素出现重复,destSlicePtr元素也必须相应重复。 如果全部没找到,或者部分没找到,返回没找到部分的下标,不返回错误。

type MStorage

type MStorage interface {
	// MGet 批量查询存储的数据。
	// 当key格式相同时,valueSlicePtr指针参数指向的切片类型,同MSet方法valueSlice参数类型。
	// valueSlicePtr指向的切片的元素顺序同keys的顺序。如果keys重复,valueSlicePtr元素也必须相应重复。
	// 如果全部没找到,或者部分没找到,返回没找到部分的下标,不返回错误。
	// 实现逻辑应该处理掉需要忽略的错误。
	// 可以使用restutils.HitIndexes函数,将没找到部分的下标,转为找到部分的下标。
	MGet(ctx context.Context, keys []string, valueSlicePtr interface{}) (missIndexes []int, err error)

	// MSet 批量存储数据。
	// keys和destSlice同长度同顺序。
	// 实现逻辑应该处理掉需要忽略的错误。
	MSet(ctx context.Context, keys []string, valueSlice interface{}, ttl time.Duration) error
}

MStorage 支持批量操作的缓存存储接口。一般是对接redis、lru,透明处理业务数据。 因为MStorage和Storage的数据可能存储在一起,当key格式相同时,MStorage数据元素类型,应该同Storage数据元素类型。

type QueryFunc

type QueryFunc func(ctx context.Context, destPtr interface{}, args interface{}) (found bool, err error)

QueryFunc 查询未缓存的数据。一般是调http/rpc接口、查持久化数据库。

type Resetable

type Resetable interface {
	// Reset 重置。
	Reset()
}

Resetable 支持重置的对象接口。

type Storage

type Storage interface {
	// Get 查询存储的数据。
	// 实现逻辑应该处理掉需要忽略的错误。
	// 当key格式相同时,valuePtr指针参数指向的类型,同Set方法的value参数的类型。
	Get(ctx context.Context, key string, valuePtr interface{}) (found bool, err error)

	// Set 存储数据。
	// 实现逻辑应该处理掉需要忽略的错误。
	Set(ctx context.Context, key string, value interface{}, TTL time.Duration) error
}

Storage 缓存存储接口。一般是对接redis、lru,透明处理业务数据。 因为MStorage和Storage的数据可能存储在一起,当key格式相同时,MStorage数据元素类型,应该同Storage数据元素类型。

Example (CommonStorage)
commonStorage := lrucache.NewLRUCache(10000, 10)

query := func(ctx context.Context, destPtr interface{}, args interface{}) (found bool, err error) {
	req := args.(string)
	resp := destPtr.(*string)
	*resp = "echo: " + req
	return true, nil
}
mquery := func(ctx context.Context, destSlicePtr interface{}, argsSlice interface{}) (missIndexes []int, err error) {
	req := argsSlice.([]string)
	resp := destSlicePtr.(*[]string)
	for _, r := range req {
		*resp = append(*resp, "echo: "+r)
	}
	return nil, nil
}

caching := Caching{
	Storage:     commonStorage,
	Query:       query,
	TTLRange:    [2]time.Duration{time.Minute * 4, time.Minute * 6},
	SentinelTTL: time.Second,
}
mcaching := MCaching{
	MStorage:    commonStorage,
	MQuery:      mquery,
	TTLRange:    [2]time.Duration{time.Minute * 4, time.Minute * 6},
	SentinelTTL: time.Second,
}

var resp string
key := "key:abc"
args := "abc"
found, err := caching.Get(context.TODO(), &resp, key, args)
if err != nil {
	fmt.Println(err)
	return
}
if found {
	fmt.Println(resp)
}

var keys = []string{"key:abc", "key:def"}
var argsSlice = []string{"abc", "def"}
var respSlice []string
_, err = mcaching.MGet(context.TODO(), &respSlice, keys, argsSlice)
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(strings.Join(respSlice, "\n"))
Output:

echo: abc
echo: abc
echo: def

type Validatable

type Validatable interface {
	// IsValidCache 判断缓存对象是否还有效。返回true表示有效。
	// 如果无效,等同没找到缓存存储数据。
	IsValidCache() bool
}

Validatable 缓存有效性检查接口。缓存对象可选实现。 警告:注意实现中ValidCache方法的接收者,一般应该是结构体对象,而不是结构体指针。 失效的缓存对象可能会影响结果,可选实现Resetable接口。

Directories

Path Synopsis
Package mock_restcache is a generated GoMock package.
Package mock_restcache is a generated GoMock package.

Jump to

Keyboard shortcuts

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