|
|
@@ -0,0 +1,101 @@
|
|
|
+// package store_mem -- хранилище-кеш в памяти
|
|
|
+package store_mem
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "sync"
|
|
|
+
|
|
|
+ "git.p78su.freemyip.com/svi/gostore/internal/store_mem/mem_pool_record"
|
|
|
+ "git.p78su.freemyip.com/svi/gostore/pkg/types"
|
|
|
+)
|
|
|
+
|
|
|
+// StoreMem -- хранилище-кеш в памяти
|
|
|
+type StoreMem struct {
|
|
|
+ dict map[string]types.IMemRecord // Кеш в памяти с данными
|
|
|
+ pool types.IMemPoolRecord // Пул доступных записей
|
|
|
+ lifeTime types.ILifeTime // Счётчик жизни для очистки кеша
|
|
|
+ block sync.Mutex
|
|
|
+ cap int // Предельная ёмкость кеша
|
|
|
+}
|
|
|
+
|
|
|
+// NewStoreMem -- возвращает новое хранилище в памяти
|
|
|
+func NewStoreMem() (types.IMemStore, error) {
|
|
|
+ pool, err := mem_pool_record.NewMemPoolRecord()
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("NewStoreMem(): in create IMemPoolRecord, err=\n\t%w", err)
|
|
|
+ }
|
|
|
+ sf := &StoreMem{
|
|
|
+ dict: map[string]types.IMemRecord{},
|
|
|
+ pool: pool,
|
|
|
+ cap: pool.Cap() - pool.Cap()/10,
|
|
|
+ }
|
|
|
+ return sf, nil
|
|
|
+}
|
|
|
+
|
|
|
+// Сбрасывает словарь по требованию
|
|
|
+func (sf *StoreMem) reset() {
|
|
|
+ for _, rec := range sf.dict {
|
|
|
+ sf.pool.Put(rec)
|
|
|
+ }
|
|
|
+ sf.dict = map[string]types.IMemRecord{}
|
|
|
+}
|
|
|
+
|
|
|
+// Put -- размещает запись в памяти
|
|
|
+func (sf *StoreMem) Put(key string, val []byte) {
|
|
|
+ sf.block.Lock()
|
|
|
+ defer sf.block.Unlock()
|
|
|
+ nextTime := sf.lifeTime.Next()
|
|
|
+ if nextTime <= 0 {
|
|
|
+ sf.reset()
|
|
|
+ nextTime = sf.lifeTime.Next()
|
|
|
+ }
|
|
|
+ // Проверить что такая запись есть в памяти
|
|
|
+ rec := sf.dict[key]
|
|
|
+ if rec != nil {
|
|
|
+ rec.Set(val, nextTime)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // Такой записи нет, проверить что словарь не переполнен
|
|
|
+ if len(sf.dict) > sf.cap {
|
|
|
+ sf.clear()
|
|
|
+ }
|
|
|
+ rec = sf.pool.Get()
|
|
|
+ rec.Set(val, nextTime)
|
|
|
+ sf.dict[key] = rec
|
|
|
+}
|
|
|
+
|
|
|
+// Снижает уровень заполнения словаря меньше 90% по требованию
|
|
|
+func (sf *StoreMem) clear() {
|
|
|
+ nextTime := sf.lifeTime.Next()
|
|
|
+ if nextTime <= 0 {
|
|
|
+ sf.reset()
|
|
|
+ nextTime = sf.lifeTime.Next()
|
|
|
+ }
|
|
|
+ nextTime -= sf.cap
|
|
|
+ for key, rec := range sf.dict {
|
|
|
+ if rec.IsOld(nextTime) {
|
|
|
+ delete(sf.dict, key)
|
|
|
+ }
|
|
|
+ if len(sf.dict) < sf.cap {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Get -- возвращает хранимую запись (если есть)
|
|
|
+func (sf *StoreMem) Get(key string) []byte {
|
|
|
+ sf.block.Lock()
|
|
|
+ defer sf.block.Unlock()
|
|
|
+ rec := sf.dict[key]
|
|
|
+ if rec == nil {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ nextTime := sf.lifeTime.Next()
|
|
|
+ if nextTime <= 0 {
|
|
|
+ sf.reset()
|
|
|
+ nextTime = sf.lifeTime.Next()
|
|
|
+ }
|
|
|
+ rec.Update(nextTime)
|
|
|
+ return rec.Get()
|
|
|
+
|
|
|
+}
|