localcache

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 20, 2024 License: Apache-2.0, BSD-2-Clause, BSD-3-Clause, + 1 more Imports: 8 Imported by: 0

README

English | 中文

tRPC-Go localcache plugin

Go Reference Go Report Card Tests Coverage

localcache is a standalone local K-V cache component that allows multiple goroutines to access it concurrently and supports LRU and expiration time based elimination policy. After the capacity of localcache reaches the upper limit, it will carry out data elimination based on LRU, and the deletion of expired key-value is realized based on time wheel.

applies to readcache scenarios, not to writecache scenarios.

Quick Start

Use the functions directly from the localcache package.

package main

import (
    "trpc.group/trpc-go/trpc-database/localcache"
)

func LoadData(ctx context.Context, key string) (interface{}, error) {
    return "cat", nil
}

func main() {
    // Cache the key-value, and set the expiration time to 5 seconds.
    localcache.Set("foo", "bar", 5)

    // Get the value corresponding to the key
    value, found := localcache.Get("foo")

    // Get the value corresponding to the key.
    // If the key does not exist in the cache, it is loaded from the data source using the custom LoadData function
    // and cached in the cache.
    // And Set an expiration time of 5 seconds.
    value, err := localcache.GetWithLoad(context.TODO(), "tom", LoadData, 5)

    // Delete key
    localcache.Del("foo")

    // Clear cache
    localcache.Clear()
}

Configuring Usage

New() generates a Cache instance and calls the functional functions of that instance

Optional parameters
WithCapacity(capacity int)

Sets the maximum size of the cache, with a minimum value of 1 and a maximum value of 1e30. When the cache is full, the last element of the queue is eliminated based on LRU. Default value is 1e30.

WithExpiration(ttl int64)

Sets the expiration time of the element in seconds. The default value is 60 seconds.

WithLoad(f LoadFunc)
type LoadFunc func(ctx context.Context, key string) (interface{}, error)

Set data load function, when the key does not exist in cache, use this function to load the corresponding value, and cache it in cache. Use with GetWithLoad().

WithMLoad(f MLoadFunc)
type MLoadFunc func(ctx context.Context, keys []string) (map[string]interface{}, error)

Set bulk data loading function, use this function to bulk load keys that don't exist in cache. Use with MGetWithLoad().

WithDelay(duration int64)

Sets the interval in seconds for delayed deletion of expired keys in cache. The default value is 0, the key is deleted immediately after it expires.

Usage Scenario: When the key expires, at the same time the data downstream service exception of the business, I hope to be able to get the expired value from the cache in the business as the backing data.

WithOnDel(delCallBack ItemCallBackFunc)
type ItemCallBackFunc func(item *Item)

Setting the callback function when an element is deleted: expired deletions, active deletions, and LRU deletions all trigger this callback function.

WithOnExpire(expireCallback ItemCallbackFunc)
type ItemCallBackFunc func(item *Item)

Set the callback function when an element expires. Two callback functions are triggered when an element expires: the expiration callback and the deletion callback.

Cache Interface
type Cache interface {
    // Get returns the value of the key, bool returns true. bool returns false if the key does not exist or is expired.
    Get(key string) (interface{}, bool)

    // GetWithLoad returns the value corresponding to the key, if the key does not exist, use the customized load function
    // to get the data and cache it.
    GetWithLoad(ctx context.Context, key string) (interface{}, error)

    // MGetWithLoad returns values corresponding to multiple keys. when some keys don't exist, use a customized bulk load
    // function to fetch the data and cache it.
    // For a key that does not exist in the cache, and does not exist in the result of the mLoad function call, the return 
    // result of MGetWithLoad will contain the key, and the corresponding value will be nil.
    MGetWithLoad(ctx context.Context, keys []string) (map[string]interface{}, error)

    // GetWithCustomLoad returns the value corresponding to the key. If the key does not exist, it is loaded using the load
    // function passed in and caches the ttl time.
    // load function does not exist will return err, if you do not need to pass in the load function every time you get
    // please use the option to set load when new cache, and use the GetWithLoad method to get the cache value.
    GetWithCustomLoad(ctx context.Context, key string, customLoad LoadFunc, ttl int64) (interface{}, error)

    // MGetWithCustomLoad returns values corresponding to multiple keys. when some keys don't exist, they are loaded using the 
    // load function passed in and cached ttl time. For a key that does not exist in the cache, and does not exist in the result
    // of the mLoad function call, the result of MGetWithLoad contains the key, and the corresponding value is nil. oad function
    // does not exist will return err, if you do not need to pass in the load function every time you get please use the option
    // to set load when new cache, and use the MGetWithLoad method to get the cache value.
    MGetWithCustomLoad(ctx context.Context, keys []string, customLoad MLoadFunc, ttl int64) (map[string]interface{}, error)

    // Set cache key-value
    Set(key string, value interface{}) bool

    // SetWithExpire caches key-values, and sets a specific ttl (expiration time in seconds) for a key.
    SetWithExpire(key string, value interface{}, ttl int64) bool

    // Delete key
    Del(key string)

    // Clear all queues and caches
    Clear()

    // Close cache
    Close()
}

Example

Setting capacity and expiration time
func main() {
    var lc localcache.Cache

    // Create a cache with a size of 100 and an element expiration time of 5 seconds.
    lc = localcache.New(localcache.WithCapacity(100), localcache.WithExpiration(5))

    // Set key-value, expiration time 5 seconds
    lc.Set("foo", "bar")

    // Set a specific expiration time (10 seconds) for the key, without using the expiration parameter in the New() method
    lc.SetWithExpire("tom", "cat", 10)

    // Short wait for asynchronous processing to complete from cache
    time.Sleep(time.Millisecond)

    // Get value
    val, found := lc.Get("foo")
    
    // Delete key: "foo"
    lc.Del("foo")
}
Delayed deletion
func main() {
	// Set the delayed deletion interval to 3 seconds
	lc := localcache.New(localcache.WithDelay(3))
	// Set key expiration time to 1 second: key expires after 1 second and is removed from cache after 4 seconds
	lc.SetWithExpire("tom", "cat", 1)
	// sleep 2s
	time.Sleep(time.Second * 2)

	value, ok := lc.Get("tom")
	if !ok {
		// key has expired after 2 seconds of sleep.
		fmt.Printf("key:%s is expired or empty\n", "tom")
	}

	if s, ok := value.(string); ok && s == "cat" {
		// Expired values are still returned, and the business side can decide whether or not to use them.
		fmt.Printf("get expired value: %s\n", "cat")
	}
}
Custom Load Functions

Set up a custom data loading function and use GetWithLoad(key) to get the value

func main() {
    loadFunc := func(ctx context.Context, key string) (interface{}, error) {
        return "cat", nil
    }

    lc := localcache.New(localcache.WithLoad(loadFunc), localcache.WithExpiration(5))

    // err is the error message returned directly by the loadFunc function.
    val, err := lc.GetWithLoad(context.TODO(), "tom")

    // Or you can pass in the load function at get time
    otherLoadFunc := func(ctx context.Context, key string) (interface{}, error) {
        return "dog", nil
    }

    val,err := lc.GetWithCustomLoad(context.TODO(),"tom",otherLoadFunc,10)
}

Set the bulk data load function and use MGetWithLoad(keys) to get values

func main() {
    mLoadFunc := func(ctx context.Context, keys []string) (map[string]interface{}, error) {
        return map[string]interface{} {
            "foo": "bar",
            "tom": "cat",
        }, nil
    }

    lc := localcache.New(localcache.WithMLoad(mLoadFunc), localcache.WithExpiration(5))

    // err is the error message returned directly by the mLoadFunc function.
    val, err := lc.MGetWithLoad(context.TODO(), []string{"foo", "tom"})

    // Or you can pass in the load function at get time
    val,err := lc.MGetWithCustomLoad(context.TODO(),"tom",mLoadFunc,10)
}
Customizing the callback on expiration/deletion of deleted elements
func main() {
	delCount := map[string]int{"A": 0, "B": 0, "": 0}
	expireCount := map[string]int{"A": 0, "B": 0, "": 0}
	c := localcache.New(
		localcache.WithCapacity(4),
		localcache.WithOnExpire(func(item *localcache.Item) {
			if item.Flag != localcache.ItemDelete {
				return
			}
			if _, ok := expireCount[item.Key]; ok {
				expireCount[item.Key]++
			}
		}),
		localcache.WithOnDel(func(item *localcache.Item) {
			if item.Flag != localcache.ItemDelete {
				return
			}
			if _, ok := delCount[item.Key]; ok {
				delCount[item.Key]++
			}
		}))

	defer c.Close()

	elems := []struct {
		key string
		val string
		ttl int64
	}{
		{"A", "a", 1},
		{"B", "b", 300},
		{"C", "c", 300},
	}

	for _, elem := range elems {
		c.SetWithExpire(elem.key, elem.val, elem.ttl)
	}
	time.Sleep(1001 * time.Millisecond)
	fmt.Printf("del info:%v\n", delCount)
	fmt.Printf("expire info:%v\n", expireCount)
}
TODO
  1. Add Metrics statistics
  2. increase the control of memory usage
  3. Introduce an upgraded version of LRU: W-tinyLRU, which controls key writing and elimination more efficiently.

Documentation

Overview

Package localcache is a stand-alone local K-V cache component that allows concurrent access by multiple goroutines. The cache eliminates elements based on LRU and expiration time strategies.

Index

Constants

This section is empty.

Variables

View Source
var ErrCacheExpire = errors.New("cache exist, but expired")

ErrCacheExpire the cache exists but has expired

Functions

func Clear

func Clear()

Clear all queues and caches

func Del

func Del(key string)

Del Delete key

func Get

func Get(key string) (interface{}, bool)

Get returns the value corresponding to key, bool returns true. If the key does not exist or expires, bool returns false

func GetWithLoad

func GetWithLoad(ctx context.Context, key string, load LoadFunc, ttl int64) (interface{}, error)

GetWithLoad returns the value corresponding to the key. If the key does not exist, use the load function to load the return and cache it for ttl seconds.

func Set

func Set(key string, value interface{}, ttl int64) bool

Set key, value, expiration time ttl (seconds)

Types

type Cache

type Cache interface {
	// Get returns the value corresponding to key, bool returns true.
	// If the key does not exist or expires, bool returns false
	Get(key string) (interface{}, bool)
	// GetWithStatus returns the value corresponding to the key and returns the cache status
	GetWithStatus(key string) (interface{}, CachedStatus)
	// GetWithLoad returns the value corresponding to the key.
	// If the key does not exist, use the user-defined loading function to obtain the data and cache it.
	GetWithLoad(ctx context.Context, key string) (interface{}, error)
	// MGetWithLoad returns values corresponding to multiple keys.
	// When some keys do not exist, use a custom batch loading function to obtain data and cache it
	// For a key that does not exist in the cache and does not exist in the calling result of the mLoad function,
	// the return result of MGetWithLoad includes the key and the corresponding value is nil.
	MGetWithLoad(ctx context.Context, keys []string) (map[string]interface{}, error)
	// GetWithCustomLoad returns the value corresponding to the key.
	// If the key does not exist, the passed in load function is used to load and cache the ttl time.
	// If the load function does not exist, err will be returned.
	// If you do not need to pass in the load function every time you get it, please use the option method
	// to set the load in the new cache, and use the GetWithLoad method to obtain the cache value.
	GetWithCustomLoad(ctx context.Context, key string, customLoad LoadFunc, ttl int64) (interface{}, error)
	// MGetWithCustomLoad returns values corresponding to multiple keys.
	// When some keys do not exist, the passed in load function is used to load and cache the ttl time.
	// For a key that does not exist in the cache and does not exist in the calling result of the mLoad function,
	// the return result of MGetWithLoad includes the key and the corresponding value is nil.
	// If the load function does not exist, err will be returned.
	// If you do not need to pass in the load function every time you get it, please use the option method to set
	// the load in the new cache, and use the MGetWithLoad method to obtain the cache value.
	MGetWithCustomLoad(ctx context.Context, keys []string, customLoad MLoadFunc, ttl int64) (map[string]interface{}, error)
	// Set key and value
	Set(key string, value interface{}) bool
	// SetWithExpire sets key, value, and sets different ttl (expiration time in seconds) for different keys
	SetWithExpire(key string, value interface{}, ttl int64) bool
	// Del delete key
	Del(key string)
	// Len key quantity
	Len() int
	// Clear clears all queues and caches
	Clear()
	// Close Close cache
	Close()
}

Cache is a local K-V memory store that supports expiration time

func New

func New(opts ...Option) Cache

New generate cache object

type CachedStatus

type CachedStatus int

CachedStatus cache status

const (
	// CacheNotExist cache data does not exist
	CacheNotExist CachedStatus = 1
	// CacheExist cache data exists
	CacheExist CachedStatus = 2
	// CacheExpire cache data exists but has expired. You can choose whether to use it
	CacheExpire CachedStatus = 3
)

type Item

type Item struct {
	Flag  ItemFlag
	Key   string
	Value interface{}
}

Item The element that triggered the callback event

type ItemCallBackFunc

type ItemCallBackFunc func(*Item)

ItemCallBackFunc callback function triggered when the element expires/deletes

type ItemFlag

type ItemFlag int

ItemFlag The event type that triggers the callback

const (
	// ItemDelete Triggered when actively deleted/expired
	ItemDelete ItemFlag = iota
	// ItemLruDel LRU triggered deletion
	ItemLruDel
)

type LoadFunc

type LoadFunc func(ctx context.Context, key string) (interface{}, error)

LoadFunc loads the value data corresponding to the key and is used to fill the cache

type MLoadFunc

type MLoadFunc func(ctx context.Context, keys []string) (map[string]interface{}, error)

MLoadFunc loads the value data of multiple keys in batches to fill the cache

type Option

type Option func(*cache)

Option parameter tool function

func WithCapacity

func WithCapacity(capacity int) Option

WithCapacity sets the maximum number of keys

func WithDelay

func WithDelay(duration int64) Option

WithDelay delay deletion interval of expired keys (unit seconds)

func WithExpiration

func WithExpiration(ttl int64) Option

WithExpiration sets the expiration time of the element (in seconds). If the expiration time is not set, the default is 60 seconds.

func WithLoad

func WithLoad(f LoadFunc) Option

WithLoad sets a custom data loading function

func WithMLoad

func WithMLoad(f MLoadFunc) Option

WithMLoad sets a custom data batch loading function

func WithOnDel

func WithOnDel(delCallBack ItemCallBackFunc) Option

WithOnDel sets the callback function when the element is deleted

func WithOnExpire

func WithOnExpire(expireCallback ItemCallBackFunc) Option

WithOnExpire sets the callback function triggered when the element expires

func WithSettingTimeout

func WithSettingTimeout(t time.Duration) Option

WithSettingTimeout causes elements to be written to the store synchronously, and a timeout needs to be set.

func WithSyncDelFlag

func WithSyncDelFlag(flag bool) Option

WithSyncDelFlag sets the synchronous method to delete elements in the store when deleting elements.

Directories

Path Synopsis
examples
Package mocklocalcache is a generated GoMock package.
Package mocklocalcache is a generated GoMock package.

Jump to

Keyboard shortcuts

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