1
0
Просмотр исходного кода

Merge remote-tracking branch 'origin/master'

Dima 4 месяцев назад
Родитель
Сommit
b201b3d561

+ 84 - 0
cache/lru_memory_cache/cache.go

@@ -0,0 +1,84 @@
+package lru_memory_cache
+
+import (
+	"container/list"
+	"errors"
+	"sync"
+)
+
+type Cache struct {
+	capacity int
+
+	mu    sync.RWMutex
+	items map[string]*list.Element
+	queue *list.List
+}
+
+type Item struct {
+	Key   string
+	Value interface{}
+}
+
+func NewCache(c Config) (*Cache, error) {
+	if c.capacity == 0 {
+		return nil, errors.New("empty capacity")
+	}
+
+	return &Cache{
+		capacity: int(c.capacity),
+		items:    make(map[string]*list.Element),
+		queue:    list.New(),
+	}, nil
+}
+
+func (c *Cache) Set(key string, value interface{}) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if element, found := c.items[key]; found {
+		c.queue.MoveToFront(element)
+		element.Value.(*Item).Value = value
+		return
+	}
+
+	if c.queue.Len() == c.capacity {
+		c.clean()
+	}
+
+	item := &Item{
+		Key:   key,
+		Value: value,
+	}
+
+	element := c.queue.PushFront(item)
+	c.items[item.Key] = element
+}
+
+func (c *Cache) Get(key string) (interface{}, bool) {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+
+	if element, found := c.items[key]; found {
+		c.queue.MoveToFront(element)
+		return element.Value.(*Item).Value, true
+	}
+
+	return nil, false
+}
+
+func (c *Cache) Delete(key string) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if element, found := c.items[key]; found {
+		c.queue.Remove(element)
+		delete(c.items, key)
+	}
+}
+
+func (c *Cache) clean() {
+	if element := c.queue.Back(); element != nil {
+		item := c.queue.Remove(element).(*Item)
+		delete(c.items, item.Key)
+	}
+}

+ 28 - 0
cache/lru_memory_cache/cache_config.go

@@ -0,0 +1,28 @@
+package lru_memory_cache
+
+type Config struct {
+	capacity uint
+}
+
+type ConfigOption func(*Config)
+
+type ConfigOptions []ConfigOption
+
+func (s *ConfigOptions) Add(option ConfigOption) {
+	*s = append(*s, option)
+}
+
+func NewConfig(opts ...ConfigOption) Config {
+	c := &Config{}
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return *c
+}
+
+func WithCapacity(capacity uint) ConfigOption {
+	return func(s *Config) {
+		s.capacity = capacity
+	}
+}

+ 25 - 0
cache/lru_memory_cache/readme.md

@@ -0,0 +1,25 @@
+
+## Usage example
+
+```
+cache, err := NewCache(
+    NewConfig(
+        WithCapacity(3),
+    ),
+)
+
+if err != nil {
+    // TODO
+}
+
+cache.Set("1", "value 1")
+cache.Set("2", "value 2")
+cache.Set("3", "value 3")
+
+val2, found2 := cache.Get("2") // "value 2", true
+val3, found3 := cache.Get("3") // "value 3", true
+
+cache.Set("4", "value 4")
+
+val1, found1 := cache.Get("1") // nil, false
+```

+ 41 - 0
cache/memory_cache/cache.go

@@ -0,0 +1,41 @@
+package memory_cache
+
+import (
+	"sync"
+)
+
+type Cache struct {
+	mu    sync.RWMutex
+	items map[string]interface{}
+}
+
+func NewCache() *Cache {
+	return &Cache{
+		items: make(map[string]interface{}),
+	}
+}
+
+func (c *Cache) Set(key string, value interface{}) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	c.items[key] = value
+}
+
+func (c *Cache) Get(key string) (interface{}, bool) {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+
+	item, found := c.items[key]
+
+	return item, found
+}
+
+func (c *Cache) Delete(key string) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if _, found := c.items[key]; found {
+		delete(c.items, key)
+	}
+}

+ 11 - 0
cache/memory_cache/readme.md

@@ -0,0 +1,11 @@
+
+## Usage example
+
+```
+cache := NewCache()
+
+cache.Set("1", "value 1")
+
+val1, found1 := cache.Get("1") // "value 1", true
+val2, found2 := cache.Get("2") // nil, false
+```

+ 95 - 0
cache/ttl_memory_cache/cache.go

@@ -0,0 +1,95 @@
+package ttl_memory_cache
+
+import (
+	"sync"
+	"time"
+)
+
+type Cache struct {
+	expiration      *time.Duration
+	cleanupInterval *time.Duration
+
+	mu    sync.RWMutex
+	items map[string]Item
+}
+
+type Item struct {
+	Value     interface{}
+	ExpiredAt *time.Time
+}
+
+func NewCache(c Config) *Cache {
+	cache := Cache{
+		items:           make(map[string]Item),
+		expiration:      c.expiration,
+		cleanupInterval: c.cleanupInterval,
+	}
+
+	if c.cleanupInterval != nil {
+		go cache.cleanupWorker()
+	}
+
+	return &cache
+}
+
+func (c *Cache) Set(key string, value interface{}, expiration *time.Duration) {
+	item := Item{
+		Value: value,
+	}
+
+	if expiration != nil {
+		expiredAt := time.Now().Add(*expiration)
+		item.ExpiredAt = &expiredAt
+	} else if c.expiration != nil {
+		expiredAt := time.Now().Add(*c.expiration)
+		item.ExpiredAt = &expiredAt
+	}
+
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	c.items[key] = item
+}
+
+func (c *Cache) Get(key string) (interface{}, bool) {
+	c.mu.RLock()
+	defer c.mu.RUnlock()
+
+	item, found := c.items[key]
+	if !found {
+		return nil, false
+	}
+
+	if item.ExpiredAt != nil && time.Now().After(*item.ExpiredAt) {
+		c.Delete(key)
+		return nil, false
+	}
+
+	return item.Value, true
+}
+
+func (c *Cache) Delete(key string) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+
+	if _, found := c.items[key]; found {
+		delete(c.items, key)
+	}
+}
+
+func (c *Cache) cleanupWorker() {
+	for {
+		<-time.After(*c.cleanupInterval)
+
+		if len(c.items) == 0 {
+			return
+		}
+
+		now := time.Now()
+		for key, item := range c.items {
+			if item.ExpiredAt != nil && now.After(*item.ExpiredAt) {
+				c.Delete(key)
+			}
+		}
+	}
+}

+ 37 - 0
cache/ttl_memory_cache/cache_config.go

@@ -0,0 +1,37 @@
+package ttl_memory_cache
+
+import "time"
+
+type Config struct {
+	expiration      *time.Duration
+	cleanupInterval *time.Duration
+}
+
+type ConfigOption func(*Config)
+
+type ConfigOptions []ConfigOption
+
+func (s *ConfigOptions) Add(option ConfigOption) {
+	*s = append(*s, option)
+}
+
+func NewConfig(opts ...ConfigOption) Config {
+	c := &Config{}
+	for _, opt := range opts {
+		opt(c)
+	}
+
+	return *c
+}
+
+func WithExpiration(expiration time.Duration) ConfigOption {
+	return func(s *Config) {
+		s.expiration = &expiration
+	}
+}
+
+func WithCleanupInterval(cleanupInterval time.Duration) ConfigOption {
+	return func(s *Config) {
+		s.cleanupInterval = &cleanupInterval
+	}
+}

+ 18 - 0
cache/ttl_memory_cache/readme.md

@@ -0,0 +1,18 @@
+## Usage example
+
+```
+cache := NewCache(
+    NewConfig(
+        memoryCache.WithCleanupInterval(30*time.Minute),
+        memoryCache.WithExpiration(time.Hour),
+    ),
+)
+
+cache.Set("1", "value 1", nil)
+
+exp := 12*time.Hour
+cache.Set("2", "value 2", &exp)
+	
+val1, found1 := cache.Get("1") // "value 1", true
+val3, found3 := cache.Get("3") // nil, false
+```