You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
1.5 KiB
94 lines
1.5 KiB
3 years ago
|
package memory
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"gitoa.ru/go-4devs/cache"
|
||
|
)
|
||
|
|
||
|
// NewEncoding create new provider.
|
||
|
func NewEncoding() cache.Provider {
|
||
|
items := make(map[cache.Key]encodedEntry)
|
||
|
mu := sync.RWMutex{}
|
||
|
|
||
|
return func(ctx context.Context, operation string, item *cache.Item) error {
|
||
|
switch operation {
|
||
|
case cache.OperationSet:
|
||
|
i, err := newEncodedEntry(item)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
mu.Lock()
|
||
|
items[item.Key] = i
|
||
|
mu.Unlock()
|
||
|
|
||
|
return nil
|
||
|
case cache.OperationDelete:
|
||
|
mu.Lock()
|
||
|
delete(items, item.Key)
|
||
|
mu.Unlock()
|
||
|
|
||
|
return nil
|
||
|
case cache.OperationGet:
|
||
|
mu.RLock()
|
||
|
i, ok := items[item.Key]
|
||
|
mu.RUnlock()
|
||
|
|
||
|
if !ok {
|
||
|
return wrapErr(cache.ErrCacheMiss)
|
||
|
}
|
||
|
|
||
|
return resolveEncodedEntry(i, item)
|
||
|
}
|
||
|
|
||
|
return wrapErr(cache.ErrOperationNotAllwed)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type encodedEntry struct {
|
||
|
data []byte
|
||
|
expired time.Time
|
||
|
}
|
||
|
|
||
|
func wrapErr(err error) error {
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("%w: encoding", err)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func newEncodedEntry(item *cache.Item) (encodedEntry, error) {
|
||
|
var (
|
||
|
e encodedEntry
|
||
|
err error
|
||
|
)
|
||
|
|
||
|
e.data, err = item.Marshal()
|
||
|
if err != nil {
|
||
|
return e, wrapErr(err)
|
||
|
}
|
||
|
|
||
|
if item.TTL > 0 {
|
||
|
e.expired = item.Expired()
|
||
|
}
|
||
|
|
||
|
return e, nil
|
||
|
}
|
||
|
|
||
|
func resolveEncodedEntry(e encodedEntry, item *cache.Item) error {
|
||
|
if !e.expired.IsZero() {
|
||
|
item.TTL = time.Until(e.expired)
|
||
|
}
|
||
|
|
||
|
if item.IsExpired() {
|
||
|
return wrapErr(cache.ErrCacheExpired)
|
||
|
}
|
||
|
|
||
|
return wrapErr(item.Unmarshal(e.data))
|
||
|
}
|