feat: update store cache

This commit is contained in:
Steven 2023-02-28 07:29:12 +08:00
parent be7efdd8d4
commit a1f66e3df2
6 changed files with 42 additions and 168 deletions

View File

@ -1,20 +0,0 @@
package api
// CacheNamespace is the type of a cache.
type CacheNamespace string
const (
// UserCache is the cache type of workspaces.
WorkspaceCache CacheNamespace = "w"
// UserCache is the cache type of users.
UserCache CacheNamespace = "u"
// ShortcutCache is the cache type of shortcuts.
ShortcutCache CacheNamespace = "s"
)
// CacheService is the service for caches.
type CacheService interface {
FindCache(namespace CacheNamespace, id int, entry interface{}) (bool, error)
UpsertCache(namespace CacheNamespace, id int, entry interface{}) error
DeleteCache(namespace CacheNamespace, id int)
}

View File

@ -1,72 +1 @@
package store
import (
"bytes"
"encoding/binary"
"encoding/gob"
"fmt"
"github.com/VictoriaMetrics/fastcache"
"github.com/boojack/corgi/api"
)
var (
// 64 MiB.
cacheSize = 1024 * 1024 * 64
_ api.CacheService = (*CacheService)(nil)
)
// CacheService implements a cache.
type CacheService struct {
cache *fastcache.Cache
}
// NewCacheService creates a cache service.
func NewCacheService() *CacheService {
return &CacheService{
cache: fastcache.New(cacheSize),
}
}
// FindCache finds the value in cache.
func (s *CacheService) FindCache(namespace api.CacheNamespace, id int, entry interface{}) (bool, error) {
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint64(buf1, uint64(id))
buf2, has := s.cache.HasGet(nil, append([]byte(namespace), buf1...))
if has {
dec := gob.NewDecoder(bytes.NewReader(buf2))
if err := dec.Decode(entry); err != nil {
return false, fmt.Errorf("failed to decode entry for cache namespace: %s, error: %w", namespace, err)
}
return true, nil
}
return false, nil
}
// UpsertCache upserts the value to cache.
func (s *CacheService) UpsertCache(namespace api.CacheNamespace, id int, entry interface{}) error {
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint64(buf1, uint64(id))
var buf2 bytes.Buffer
enc := gob.NewEncoder(&buf2)
if err := enc.Encode(entry); err != nil {
return fmt.Errorf("failed to encode entry for cache namespace: %s, error: %w", namespace, err)
}
s.cache.Set(append([]byte(namespace), buf1...), buf2.Bytes())
return nil
}
// DeleteCache deletes the cache.
func (s *CacheService) DeleteCache(namespace api.CacheNamespace, id int) {
buf1 := []byte{0, 0, 0, 0, 0, 0, 0, 0}
binary.LittleEndian.PutUint64(buf1, uint64(id))
_, has := s.cache.HasGet(nil, append([]byte(namespace), buf1...))
if has {
s.cache.Del(append([]byte(namespace), buf1...))
}
}

View File

@ -76,12 +76,8 @@ func (s *Store) CreateShortcut(ctx context.Context, create *api.ShortcutCreate)
return nil, FormatError(err)
}
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
shortcut := shortcutRaw.toShortcut()
if err := s.cache.UpsertCache(api.ShortcutCache, shortcut.ID, shortcut); err != nil {
return nil, err
}
return shortcut, nil
}
@ -101,12 +97,8 @@ func (s *Store) PatchShortcut(ctx context.Context, patch *api.ShortcutPatch) (*a
return nil, FormatError(err)
}
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
shortcut := shortcutRaw.toShortcut()
if err := s.cache.UpsertCache(api.ShortcutCache, shortcut.ID, shortcut); err != nil {
return nil, err
}
return shortcut, nil
}
@ -123,8 +115,9 @@ func (s *Store) FindShortcutList(ctx context.Context, find *api.ShortcutFind) ([
}
list := []*api.Shortcut{}
for _, raw := range shortcutRawList {
list = append(list, raw.toShortcut())
for _, shortcutRaw := range shortcutRawList {
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
list = append(list, shortcutRaw.toShortcut())
}
return list, nil
@ -132,13 +125,8 @@ func (s *Store) FindShortcutList(ctx context.Context, find *api.ShortcutFind) ([
func (s *Store) FindShortcut(ctx context.Context, find *api.ShortcutFind) (*api.Shortcut, error) {
if find.ID != nil {
shortcut := &api.Shortcut{}
has, err := s.cache.FindCache(api.ShortcutCache, *find.ID, shortcut)
if err != nil {
return nil, err
}
if has {
return shortcut, nil
if cache, ok := s.shortcutCache.Load(*find.ID); ok {
return cache.(*shortcutRaw).toShortcut(), nil
}
}
@ -157,12 +145,9 @@ func (s *Store) FindShortcut(ctx context.Context, find *api.ShortcutFind) (*api.
return nil, &common.Error{Code: common.NotFound, Err: fmt.Errorf("not found")}
}
shortcut := list[0].toShortcut()
if err := s.cache.UpsertCache(api.ShortcutCache, shortcut.ID, shortcut); err != nil {
return nil, err
}
shortcutRaw := list[0]
s.shortcutCache.Store(shortcutRaw.ID, shortcutRaw)
shortcut := shortcutRaw.toShortcut()
return shortcut, nil
}
@ -183,7 +168,7 @@ func (s *Store) DeleteShortcut(ctx context.Context, delete *api.ShortcutDelete)
}
if delete.ID != nil {
s.cache.DeleteCache(api.ShortcutCache, *delete.ID)
s.shortcutCache.Delete(*delete.ID)
}
return nil

View File

@ -2,8 +2,8 @@ package store
import (
"database/sql"
"sync"
"github.com/boojack/corgi/api"
"github.com/boojack/corgi/server/profile"
)
@ -11,16 +11,16 @@ import (
type Store struct {
db *sql.DB
profile *profile.Profile
cache api.CacheService
userCache sync.Map // map[int]*userRaw
workspaceCache sync.Map // map[int]*memoRaw
shortcutCache sync.Map // map[int]*shortcutRaw
}
// New creates a new instance of Store.
func New(db *sql.DB, profile *profile.Profile) *Store {
cacheService := NewCacheService()
return &Store{
db: db,
profile: profile,
cache: cacheService,
}
}

View File

@ -58,12 +58,8 @@ func (s *Store) CreateUser(ctx context.Context, create *api.UserCreate) (*api.Us
return nil, FormatError(err)
}
s.userCache.Store(userRaw.ID, userRaw)
user := userRaw.toUser()
if err := s.cache.UpsertCache(api.UserCache, user.ID, user); err != nil {
return nil, err
}
return user, nil
}
@ -83,12 +79,8 @@ func (s *Store) PatchUser(ctx context.Context, patch *api.UserPatch) (*api.User,
return nil, FormatError(err)
}
s.userCache.Store(userRaw.ID, userRaw)
user := userRaw.toUser()
if err := s.cache.UpsertCache(api.UserCache, user.ID, user); err != nil {
return nil, err
}
return user, nil
}
@ -105,14 +97,21 @@ func (s *Store) FindUserList(ctx context.Context, find *api.UserFind) ([]*api.Us
}
list := []*api.User{}
for _, raw := range userRawList {
list = append(list, raw.toUser())
for _, userRaw := range userRawList {
s.userCache.Store(userRaw.ID, userRaw)
list = append(list, userRaw.toUser())
}
return list, nil
}
func (s *Store) FindUser(ctx context.Context, find *api.UserFind) (*api.User, error) {
if find.ID != nil {
if cache, ok := s.userCache.Load(*find.ID); ok {
return cache.(*userRaw).toUser(), nil
}
}
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return nil, err
@ -130,11 +129,9 @@ func (s *Store) FindUser(ctx context.Context, find *api.UserFind) (*api.User, er
return nil, &common.Error{Code: common.Conflict, Err: fmt.Errorf("found %d users with filter %+v, expect 1", len(list), find)}
}
user := list[0].toUser()
if err := s.cache.UpsertCache(api.UserCache, user.ID, user); err != nil {
return nil, err
}
userRaw := list[0]
s.userCache.Store(userRaw.ID, userRaw)
user := userRaw.toUser()
return user, nil
}
@ -154,8 +151,7 @@ func (s *Store) DeleteUser(ctx context.Context, delete *api.UserDelete) error {
return FormatError(err)
}
s.cache.DeleteCache(api.UserCache, delete.ID)
s.userCache.Delete(delete.ID)
return nil
}

View File

@ -58,12 +58,8 @@ func (s *Store) CreateWorkspace(ctx context.Context, create *api.WorkspaceCreate
return nil, FormatError(err)
}
s.workspaceCache.Store(workspaceRaw.ID, workspaceRaw)
workspace := workspaceRaw.toWorkspace()
if err := s.cache.UpsertCache(api.WorkspaceCache, workspace.ID, workspace); err != nil {
return nil, err
}
return workspace, nil
}
@ -83,12 +79,8 @@ func (s *Store) PatchWorkspace(ctx context.Context, patch *api.WorkspacePatch) (
return nil, FormatError(err)
}
s.workspaceCache.Store(workspaceRaw.ID, workspaceRaw)
workspace := workspaceRaw.toWorkspace()
if err := s.cache.UpsertCache(api.WorkspaceCache, workspace.ID, workspace); err != nil {
return nil, err
}
return workspace, nil
}
@ -105,8 +97,9 @@ func (s *Store) FindWordspaceList(ctx context.Context, find *api.WorkspaceFind)
}
list := []*api.Workspace{}
for _, raw := range workspaceRawList {
list = append(list, raw.toWorkspace())
for _, workspaceRaw := range workspaceRawList {
s.workspaceCache.Store(workspaceRaw.ID, workspaceRaw)
list = append(list, workspaceRaw.toWorkspace())
}
return list, nil
@ -114,13 +107,8 @@ func (s *Store) FindWordspaceList(ctx context.Context, find *api.WorkspaceFind)
func (s *Store) FindWorkspace(ctx context.Context, find *api.WorkspaceFind) (*api.Workspace, error) {
if find.ID != nil {
workspace := &api.Workspace{}
has, err := s.cache.FindCache(api.WorkspaceCache, *find.ID, workspace)
if err != nil {
return nil, err
}
if has {
return workspace, nil
if cache, ok := s.workspaceCache.Load(*find.ID); ok {
return cache.(*workspaceRaw).toWorkspace(), nil
}
}
@ -141,12 +129,9 @@ func (s *Store) FindWorkspace(ctx context.Context, find *api.WorkspaceFind) (*ap
return nil, &common.Error{Code: common.Conflict, Err: fmt.Errorf("found %d workspaces with filter %+v, expect 1", len(list), find)}
}
workspace := list[0].toWorkspace()
if err := s.cache.UpsertCache(api.WorkspaceCache, workspace.ID, workspace); err != nil {
return nil, err
}
workspaceRaw := list[0]
s.workspaceCache.Store(workspaceRaw.ID, workspaceRaw)
workspace := workspaceRaw.toWorkspace()
return workspace, nil
}
@ -166,8 +151,7 @@ func (s *Store) DeleteWorkspace(ctx context.Context, delete *api.WorkspaceDelete
return FormatError(err)
}
s.cache.DeleteCache(api.WorkspaceCache, delete.ID)
s.workspaceCache.Delete(delete.ID)
return nil
}