commit
c319e788e7
|
@ -0,0 +1,132 @@
|
||||||
|
package simplecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Элемент в кэше - это данные и время их жизни.
|
||||||
|
type Item struct {
|
||||||
|
destroyTimestamp int64 // Момент в Unix-секундах, когда элемент становится устаревшим
|
||||||
|
data interface{} // Данные
|
||||||
|
}
|
||||||
|
|
||||||
|
// Кэш - это хранилище элементов и инервал его очистки (ну и мьютекс на всякий случай).
|
||||||
|
// Интервал очистки хранилища укахывается в НАНОСЕКУНДАХ (используй множители для преобразования во что-то другое).
|
||||||
|
type Cache struct {
|
||||||
|
sync.RWMutex // Мьютекс ждя реализации безопасного доступа к общим данным
|
||||||
|
storage map[string]Item // Хранилище элементов
|
||||||
|
cleanupInterval time.Duration // Интервал очистки хранилища в наносекундах
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCache создает новый экземпляр Cache с интервалом очистки cleanupInterval.
|
||||||
|
// Если cleanupInterval < 0, то кэш не будет очищаться автоматически.
|
||||||
|
func NewCache(cleanupInterval time.Duration) *Cache {
|
||||||
|
cache := &Cache{
|
||||||
|
storage: make(map[string]Item),
|
||||||
|
cleanupInterval: cleanupInterval,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Запускаем Garbage Collector если интервал очистки больше 0
|
||||||
|
// Иначе (если он отрицательный) кэш будет жить до ручного вызова Cleanup
|
||||||
|
if cleanupInterval > 0 {
|
||||||
|
go cache.gc(cleanupInterval)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache
|
||||||
|
}
|
||||||
|
|
||||||
|
// gc = Garbage Collector.
|
||||||
|
func (c *Cache) gc(cleanupInterval time.Duration) {
|
||||||
|
ticker := time.NewTicker(cleanupInterval)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
for range ticker.C {
|
||||||
|
c.Cleanup()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Перебирает все элементы в кэше, удаляет устаревшие.
|
||||||
|
func (c *Cache) Cleanup() {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
for key, item := range c.storage {
|
||||||
|
if item.destroyTimestamp <= time.Now().Unix() {
|
||||||
|
delete(c.storage, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаление всех элементов из кэша.
|
||||||
|
func (c *Cache) Flush() {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
for key := range c.storage {
|
||||||
|
delete(c.storage, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение элемента из кэша по ключу.
|
||||||
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
item, found := c.storage[key]
|
||||||
|
|
||||||
|
// Элемент не найден в кэше
|
||||||
|
if !found {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.data, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Удаление элемента по ключу.
|
||||||
|
func (c *Cache) Delete(key string) error {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
if _, found := c.storage[key]; !found {
|
||||||
|
return errors.New("key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(c.storage, key)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавление элемента в кэш.
|
||||||
|
// key - ключ.
|
||||||
|
// data - данные.
|
||||||
|
// ttl - время жизни элемента (time to life) в наносекундах.
|
||||||
|
func (c *Cache) Add(key string, data interface{}, ttl time.Duration) {
|
||||||
|
c.Lock()
|
||||||
|
defer c.Unlock()
|
||||||
|
|
||||||
|
c.storage[key] = Item{
|
||||||
|
destroyTimestamp: time.Now().Unix() + int64(ttl.Seconds()),
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вернет количество элементов в кэше.
|
||||||
|
func (c *Cache) Count() int {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
return len(c.storage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Печать всех элементов кэша (ключ и время уничтожения).
|
||||||
|
func (c *Cache) Print() {
|
||||||
|
c.RLock()
|
||||||
|
defer c.RUnlock()
|
||||||
|
|
||||||
|
for key, item := range c.storage {
|
||||||
|
fmt.Printf("Key: %s, DestroyTimestamp: %d\n", key, item.destroyTimestamp)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue