🤖
【Go】bigcacheの操作をラップしたインターフェースを作ってみた
概要
- Goのin-memory cache packageの
bigcache
パッケージを使用したサンプルコードと使用例- Get, Setなどの操作をインターフェース化
- encode / decodeは
gob
パッケージを使用
サンプルコード
package main
import (
"bytes"
"encoding/gob"
"errors"
"fmt"
"github.com/allegro/bigcache/v3"
)
// Cache bigcacheの操作を抽象化したインターフェース
type Cache interface {
Get(key string, mapper interface{}) error
Set(key string, value interface{}) error
Delete(key string) error
Reset() error
}
type BigCache struct {
Cache *bigcache.BigCache
}
// NewCache bigcacheのインスタンスを生成する関数
func NewCache(c *bigcache.BigCache) (Cache, error) {
if c == nil {
return nil, errors.New("cache instance is nil")
}
return &BigCache{
Cache: c,
}, nil
}
// 登録済みの型を保持するマップ
var registeredTypes = make(map[string]bool)
// registerType 型を一度だけ登録するための関数
func registerType(value interface{}) {
if value == nil {
return
}
typeName := fmt.Sprintf("%T", value)
if !registeredTypes[typeName] {
gob.Register(value)
registeredTypes[typeName] = true
}
}
// Get キャッシュからデータを取得する関数
func (c BigCache) Get(key string, mapper interface{}) error {
if key == "" {
return errors.New("key cannot be empty")
}
if mapper == nil {
return errors.New("mapper cannot be nil")
}
registerType(mapper)
entry, err := c.Cache.Get(key)
if err != nil {
return err
}
return gob.NewDecoder(bytes.NewReader(entry)).Decode(mapper)
}
func (c BigCache) Set(key string, value interface{}) error {
if key == "" {
return errors.New("key cannot be empty")
}
vb, err := serialize(value)
if err != nil {
return err
}
return c.Cache.Set(key, vb)
}
// serialize キャッシュに保存するデータをシリアライズする関数
func serialize(value interface{}) ([]byte, error) {
registerType(value)
buf := bytes.Buffer{}
enc := gob.NewEncoder(&buf)
err := enc.Encode(value)
if err != nil {
return nil, fmt.Errorf("failed to encode: %w", err)
}
return buf.Bytes(), nil
}
// Delete キャッシュからデータを削除する関数
func (c BigCache) Delete(key string) error {
if key == "" {
return errors.New("key cannot be empty")
}
return c.Cache.Delete(key)
}
// Reset キャッシュをリセットする関数
func (c BigCache) Reset() error {
return c.Cache.Reset()
}
使用例
package main
import (
"context"
"errors"
"log"
"math/big"
"time"
"github.com/allegro/bigcache/v3"
)
func main() {
// bigcacheの設定
cfg := bigcache.DefaultConfig(10 * time.Minute)
bigCa, err := bigcache.New(context.Background(), cfg)
if err != nil {
log.Fatal(err)
}
// bigcacheの操作を抽象化したインスタンスを生成
cache, err := NewCache(bigCa)
if err != nil {
log.Fatal(err)
}
// bigint型のデータをキャッシュに保存
var bigIntValue big.Int
bigIntValue.SetString("1234567890", 10)
cache.Set("test-key", &bigIntValue)
if err != nil {
log.Fatal(err)
}
// キャッシュからデータを取得
var result big.Int
err = cache.Get("test-key", &result)
if err != nil {
log.Fatal(err)
}
println("result:", result.String())
// キャッシュからデータを削除
err = cache.Delete("test-key")
if err != nil {
log.Fatal(err)
}
// Getでキャッシュが空かどうかを確認
var result2 big.Int
err = cache.Get("test-key", &result2)
if err != nil {
if errors.Is(err, bigcache.ErrEntryNotFound) {
println(err.Error())
} else {
println(err.Error())
}
}
println("result2:", result2.String())
}
// 出力
// result: 1234567890
// Entry not found
// result2: 0
Discussion