Ver Fonte

Add LRU memory cache

Dmitriy Gnatenko há 6 meses atrás
pai
commit
1b9d3a6ed8

+ 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
+```

+ 8 - 8
cache/simple_cache/cache.go → cache/memory_cache/cache.go

@@ -1,11 +1,11 @@
-package simple_cache
+package memory_cache
 
 import (
 	"sync"
 )
 
 type Cache struct {
-	sync.RWMutex
+	mu    sync.RWMutex
 	items map[string]interface{}
 }
 
@@ -16,15 +16,15 @@ func NewCache() *Cache {
 }
 
 func (c *Cache) Set(key string, value interface{}) {
-	c.Lock()
-	defer c.Unlock()
+	c.mu.Lock()
+	defer c.mu.Unlock()
 
 	c.items[key] = value
 }
 
 func (c *Cache) Get(key string) (interface{}, bool) {
-	c.RLock()
-	defer c.RUnlock()
+	c.mu.RLock()
+	defer c.mu.RUnlock()
 
 	item, found := c.items[key]
 
@@ -32,8 +32,8 @@ func (c *Cache) Get(key string) (interface{}, bool) {
 }
 
 func (c *Cache) Delete(key string) {
-	c.Lock()
-	defer c.Unlock()
+	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
+```

+ 7 - 7
cache/ttl_memory_cache/cache.go

@@ -9,7 +9,7 @@ type Cache struct {
 	expiration      *time.Duration
 	cleanupInterval *time.Duration
 
-	sync.RWMutex
+	mu    sync.RWMutex
 	items map[string]Item
 }
 
@@ -45,15 +45,15 @@ func (c *Cache) Set(key string, value interface{}, expiration *time.Duration) {
 		item.ExpiredAt = &expiredAt
 	}
 
-	c.Lock()
-	defer c.Unlock()
+	c.mu.Lock()
+	defer c.mu.Unlock()
 
 	c.items[key] = item
 }
 
 func (c *Cache) Get(key string) (interface{}, bool) {
-	c.RLock()
-	defer c.RUnlock()
+	c.mu.RLock()
+	defer c.mu.RUnlock()
 
 	item, found := c.items[key]
 	if !found {
@@ -69,8 +69,8 @@ func (c *Cache) Get(key string) (interface{}, bool) {
 }
 
 func (c *Cache) Delete(key string) {
-	c.Lock()
-	defer c.Unlock()
+	c.mu.Lock()
+	defer c.mu.Unlock()
 
 	if _, found := c.items[key]; found {
 		delete(c.items, key)

+ 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
+```