mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-06-05 22:44:17 +00:00
74c620ad51
Reduced connection timeouts from 30s to 15s Decreased idle connection limits from 100 to 30 Lowered keepalive duration from 90s to 30s Added MaxConnsPerHost limit of 50 to prevent connection flooding Optimized TLS handshake timeout to 5s Cache System Optimization: Implemented size-limited LRU cache with max 1000 items Added efficient eviction of least recently used items Improved cleanup process with batch operations Reduced lock contention by splitting read/write operations Optimized memory usage with access tracking Added immediate cleanup of expired items during access Connection Management: Enabled connection reuse with keepalives Reduced connection pool size to conserve memory Implemented more aggressive connection timeout Added connection limits per host to prevent resource exhaustion
170 lines
4.5 KiB
Go
170 lines
4.5 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// CacheItem represents an item stored in the cache with its associated metadata.
|
|
type CacheItem struct {
|
|
// Value is the cached data of any type
|
|
Value interface{}
|
|
|
|
// ExpiresAt is the timestamp when this item should be considered expired
|
|
// and removed from the cache during cleanup operations
|
|
ExpiresAt time.Time
|
|
}
|
|
|
|
// Cache provides a thread-safe in-memory caching mechanism with expiration support.
|
|
// It uses a read-write mutex to ensure safe concurrent access to the cached items.
|
|
type Cache struct {
|
|
// items stores the cached data with string keys
|
|
items map[string]CacheItem
|
|
|
|
// mutex protects concurrent access to the items map
|
|
// Use RLock/RUnlock for reads and Lock/Unlock for writes
|
|
mutex sync.RWMutex
|
|
|
|
// maxSize is the maximum number of items allowed in the cache
|
|
maxSize int
|
|
|
|
// accessList maintains the order of item access for eviction
|
|
accessList []string
|
|
}
|
|
|
|
// DefaultMaxSize is the default maximum number of items in the cache
|
|
const DefaultMaxSize = 1000
|
|
|
|
// NewCache creates a new empty cache instance.
|
|
// The cache is immediately ready for use and is thread-safe.
|
|
func NewCache() *Cache {
|
|
return &Cache{
|
|
items: make(map[string]CacheItem),
|
|
maxSize: DefaultMaxSize,
|
|
accessList: make([]string, 0, DefaultMaxSize),
|
|
}
|
|
}
|
|
|
|
// Set adds or updates an item in the cache with the specified expiration duration.
|
|
// Parameters:
|
|
// - key: Unique identifier for the cached item
|
|
// - value: The data to cache (can be of any type)
|
|
// - expiration: How long the item should remain in the cache
|
|
// Thread-safe: Uses write locking to ensure safe concurrent access.
|
|
func (c *Cache) Set(key string, value interface{}, expiration time.Duration) {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
// If key exists, update it
|
|
if _, exists := c.items[key]; exists {
|
|
c.items[key] = CacheItem{
|
|
Value: value,
|
|
ExpiresAt: time.Now().Add(expiration),
|
|
}
|
|
return
|
|
}
|
|
|
|
// If cache is full, remove oldest item
|
|
if len(c.items) >= c.maxSize {
|
|
c.evictOldest()
|
|
}
|
|
|
|
// Add new item
|
|
c.items[key] = CacheItem{
|
|
Value: value,
|
|
ExpiresAt: time.Now().Add(expiration),
|
|
}
|
|
c.accessList = append(c.accessList, key)
|
|
}
|
|
|
|
// Get retrieves an item from the cache if it exists and hasn't expired.
|
|
// Parameters:
|
|
// - key: The identifier of the item to retrieve
|
|
// Returns:
|
|
// - value: The cached data (nil if not found or expired)
|
|
// - found: true if the item was found and is valid, false otherwise
|
|
// Thread-safe: Uses read locking to ensure safe concurrent access.
|
|
func (c *Cache) Get(key string) (interface{}, bool) {
|
|
c.mutex.RLock()
|
|
item, found := c.items[key]
|
|
c.mutex.RUnlock()
|
|
|
|
if !found {
|
|
return nil, false
|
|
}
|
|
|
|
if time.Now().After(item.ExpiresAt) {
|
|
c.mutex.Lock()
|
|
c.removeItem(key)
|
|
c.mutex.Unlock()
|
|
return nil, false
|
|
}
|
|
|
|
// Update access order
|
|
c.mutex.Lock()
|
|
c.updateAccessOrder(key)
|
|
c.mutex.Unlock()
|
|
|
|
return item.Value, true
|
|
}
|
|
|
|
// Delete removes an item from the cache if it exists.
|
|
// If the item doesn't exist, this operation is a no-op.
|
|
// Thread-safe: Uses write locking to ensure safe concurrent access.
|
|
func (c *Cache) Delete(key string) {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
delete(c.items, key)
|
|
}
|
|
|
|
// Cleanup removes all expired items from the cache.
|
|
// This should be called periodically to prevent memory leaks from
|
|
// expired items that haven't been accessed (and thus not removed during Get operations).
|
|
// Thread-safe: Uses write locking to ensure safe concurrent access.
|
|
func (c *Cache) Cleanup() {
|
|
c.mutex.Lock()
|
|
defer c.mutex.Unlock()
|
|
|
|
now := time.Now()
|
|
var newAccessList []string
|
|
|
|
for _, key := range c.accessList {
|
|
if item, exists := c.items[key]; exists && !now.After(item.ExpiresAt) {
|
|
newAccessList = append(newAccessList, key)
|
|
} else {
|
|
delete(c.items, key)
|
|
}
|
|
}
|
|
|
|
c.accessList = newAccessList
|
|
}
|
|
|
|
// evictOldest removes the least recently used item from the cache
|
|
func (c *Cache) evictOldest() {
|
|
if len(c.accessList) > 0 {
|
|
oldest := c.accessList[0]
|
|
c.removeItem(oldest)
|
|
}
|
|
}
|
|
|
|
// removeItem removes an item from both the cache and access list
|
|
func (c *Cache) removeItem(key string) {
|
|
delete(c.items, key)
|
|
for i, k := range c.accessList {
|
|
if k == key {
|
|
c.accessList = append(c.accessList[:i], c.accessList[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// updateAccessOrder moves the accessed key to the end of the access list
|
|
func (c *Cache) updateAccessOrder(key string) {
|
|
for i, k := range c.accessList {
|
|
if k == key {
|
|
c.accessList = append(append(c.accessList[:i], c.accessList[i+1:]...), key)
|
|
break
|
|
}
|
|
}
|
|
}
|