// 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.IStoreMem, 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{} } // Del -- удаляет запись по ключу func (sf *StoreMem) Del(key string) { sf.block.Lock() defer sf.block.Unlock() rec := sf.dict[key] if rec == nil { return } delete(sf.dict, key) sf.pool.Put(rec) } // Put -- размещает запись в памяти func (sf *StoreMem) Put(key string, val []byte) error { 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 nil } // Такой записи нет, проверить что словарь не переполнен if len(sf.dict) > sf.cap { sf.clear() } rec = sf.pool.Get() rec.Set(val, nextTime) sf.dict[key] = rec return nil } // Снижает уровень заполнения словаря меньше 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, error) { sf.block.Lock() defer sf.block.Unlock() rec := sf.dict[key] if rec == nil { return nil, fmt.Errorf("StoreMem.Get(): not found") } nextTime := sf.lifeTime.Next() if nextTime <= 0 { sf.reset() nextTime = sf.lifeTime.Next() } rec.Update(nextTime) return rec.Get(), nil }