candycache/simplecache.go

133 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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)
}
}