Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
161
pkg/cache/ringmap.go
vendored
Normal file
161
pkg/cache/ringmap.go
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/elliotchance/orderedmap/v2"
|
||||
)
|
||||
|
||||
type RingMapInterface interface {
|
||||
Exists(key string, value interface{}) bool
|
||||
}
|
||||
|
||||
// Copied from https://github.com/prgsmall/ringmap to use orderedmap v2
|
||||
|
||||
type RingMap struct {
|
||||
orderedMap *orderedmap.OrderedMap[string, interface{}]
|
||||
capacity int
|
||||
writeLock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewRingMap(capacity int) *RingMap {
|
||||
return &RingMap{
|
||||
orderedMap: orderedmap.NewOrderedMap[string, interface{}](),
|
||||
capacity: capacity,
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience function to check if key and value already exists
|
||||
// If key and value does not exists, it is added
|
||||
// If key exists with different value, it is replaced with new value
|
||||
func (m *RingMap) Exists(key string, value interface{}) bool {
|
||||
m.writeLock.RLock()
|
||||
el := m.orderedMap.GetElement(key)
|
||||
m.writeLock.RUnlock()
|
||||
exists := el != nil
|
||||
|
||||
if exists && el.Value != value {
|
||||
m.Delete(key)
|
||||
exists = false
|
||||
} else {
|
||||
m.clearLast()
|
||||
}
|
||||
m.writeLock.Lock()
|
||||
defer m.writeLock.Unlock()
|
||||
m.orderedMap.Set(key, value)
|
||||
|
||||
return exists
|
||||
}
|
||||
|
||||
// Get returns the value for a key. If the key does not exist, the second return
|
||||
// parameter will be false and the value will be nil.
|
||||
func (m *RingMap) Get(key string) (interface{}, bool) {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Get(key)
|
||||
}
|
||||
|
||||
// Set will set (or replace) a value for a key. If the key was new, then true
|
||||
// will be returned. The returned value will be false if the value was replaced
|
||||
// (even if the value was the same). If a new key is being added and the map is
|
||||
// full, then the front element will be deleted to make room for the new element.
|
||||
func (m *RingMap) Set(key string, value interface{}) bool {
|
||||
_, didExist := m.Get(key)
|
||||
|
||||
if !didExist {
|
||||
m.clearLast()
|
||||
}
|
||||
m.writeLock.Lock()
|
||||
defer m.writeLock.Unlock()
|
||||
m.orderedMap.Set(key, value)
|
||||
|
||||
return !didExist
|
||||
}
|
||||
|
||||
// Put will set a value for a key. If the key already exists, it will be deleted
|
||||
// from and a recreated at the end of the list. If the key was new, then true
|
||||
// will be returned. The returned value will be false if the value was replaced
|
||||
// (even if the value was the same). If a new key is being added and the map is
|
||||
// full, then the front element will be deleted to make room for the new element.
|
||||
func (m *RingMap) Put(key string, value interface{}) bool {
|
||||
_, didExist := m.Get(key)
|
||||
|
||||
if didExist {
|
||||
m.Delete(key)
|
||||
} else {
|
||||
m.clearLast()
|
||||
}
|
||||
m.writeLock.Lock()
|
||||
defer m.writeLock.Unlock()
|
||||
m.orderedMap.Set(key, value)
|
||||
|
||||
return !didExist
|
||||
}
|
||||
|
||||
// GetOrDefault returns the value for a key. If the key does not exist, returns
|
||||
// the default value instead.
|
||||
func (m *RingMap) GetOrDefault(key string, defaultValue interface{}) interface{} {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.GetOrDefault(key, defaultValue)
|
||||
}
|
||||
|
||||
// Len returns the number of elements in the map.
|
||||
func (m *RingMap) Len() int {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Len()
|
||||
}
|
||||
|
||||
// Capacity returns the capacity of the map
|
||||
func (m *RingMap) Capacity() int {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.capacity
|
||||
}
|
||||
|
||||
// IsFull returns true if the number of elements in the map is Capacity()
|
||||
func (m *RingMap) IsFull() bool {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Len() == m.capacity
|
||||
}
|
||||
|
||||
// Keys returns all of the keys in the order they were inserted. If a key was
|
||||
// replaced it will retain the same position. To ensure most recently set keys
|
||||
// are always at the end you must always Delete before Set.
|
||||
func (m *RingMap) Keys() (keys []string) {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Keys()
|
||||
}
|
||||
|
||||
// Delete will remove a key from the map. It will return true if the key was
|
||||
// removed (the key did exist).
|
||||
func (m *RingMap) Delete(key string) (didDelete bool) {
|
||||
m.writeLock.Lock()
|
||||
defer m.writeLock.Unlock()
|
||||
return m.orderedMap.Delete(key)
|
||||
}
|
||||
|
||||
// Front will return the element that is the first (oldest Set element). If
|
||||
// there are no elements this will return nil.
|
||||
func (m *RingMap) Front() *orderedmap.Element[string, interface{}] {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Front()
|
||||
}
|
||||
|
||||
// Back will return the element that is the last (most recent Set element). If
|
||||
// there are no elements this will return nil.
|
||||
func (m *RingMap) Back() *orderedmap.Element[string, interface{}] {
|
||||
m.writeLock.RLock()
|
||||
defer m.writeLock.RUnlock()
|
||||
return m.orderedMap.Back()
|
||||
}
|
||||
|
||||
func (m *RingMap) clearLast() {
|
||||
if m.IsFull() {
|
||||
m.Delete(m.Front().Key)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user