mirror of
https://github.com/lukaszraczylo/graphql-monitoring-proxy.git
synced 2026-10-21 06:37:21 +00:00
Improve cache mechanism using sync map
This commit is contained in:
@@ -11,7 +11,7 @@ help: ## display this help
|
|||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: build ## run application
|
run: build ## run application
|
||||||
@LOG_LEVEL=debug BLOCK_SCHEMA_INTROSPECTION=false JWT_ROLE_RATE_LIMIT=false JWT_ROLE_CLAIM_PATH="Hasura.x-hasura-default-role" JWT_USER_CLAIM_PATH="Hasura.x-hasura-user-id" HOST_GRAPHQL=https://hasura8.lan/ ./graphql-proxy
|
@LOG_LEVEL=debug BLOCK_SCHEMA_INTROSPECTION=false CACHE_TTL=10 JWT_ROLE_RATE_LIMIT=false JWT_ROLE_CLAIM_PATH="Hasura.x-hasura-default-role" JWT_USER_CLAIM_PATH="Hasura.x-hasura-user-id" HOST_GRAPHQL=https://hasura8.lan/ ./graphql-proxy
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build: ## build the binary
|
build: ## build the binary
|
||||||
|
|||||||
Vendored
+44
-22
@@ -12,16 +12,21 @@ type CacheEntry struct {
|
|||||||
|
|
||||||
type Cache struct {
|
type Cache struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
entries map[string]CacheEntry
|
entries sync.Map
|
||||||
globalTTL time.Duration
|
globalTTL time.Duration
|
||||||
|
bytePool sync.Pool
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(globalTTL time.Duration) *Cache {
|
func New(globalTTL time.Duration) *Cache {
|
||||||
cache := &Cache{
|
cache := &Cache{
|
||||||
entries: make(map[string]CacheEntry),
|
|
||||||
globalTTL: globalTTL,
|
globalTTL: globalTTL,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize the byte pool.
|
||||||
|
cache.bytePool.New = func() interface{} {
|
||||||
|
return make([]byte, 0)
|
||||||
|
}
|
||||||
|
|
||||||
// Start the cache cleanup.
|
// Start the cache cleanup.
|
||||||
go cache.cleanupRoutine(globalTTL)
|
go cache.cleanupRoutine(globalTTL)
|
||||||
return cache
|
return cache
|
||||||
@@ -46,47 +51,64 @@ func (c *Cache) Set(key string, value []byte, ttl time.Duration) {
|
|||||||
expiresAt = now.Add(c.globalTTL)
|
expiresAt = now.Add(c.globalTTL)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.entries[key] = CacheEntry{
|
// Allocate a byte slice from the pool.
|
||||||
Value: value,
|
entry := CacheEntry{
|
||||||
|
Value: c.bytePool.Get().([]byte),
|
||||||
ExpiresAt: expiresAt,
|
ExpiresAt: expiresAt,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy the value into the byte slice.
|
||||||
|
copy(entry.Value, value)
|
||||||
|
|
||||||
|
// Set the entry in the cache.
|
||||||
|
c.entries.Store(key, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) Get(key string) ([]byte, bool) {
|
func (c *Cache) Get(key string) ([]byte, bool) {
|
||||||
c.RLock()
|
c.RLock()
|
||||||
defer c.RUnlock()
|
defer c.RUnlock()
|
||||||
|
|
||||||
entry, ok := c.entries[key]
|
entry, ok := c.entries.Load(key)
|
||||||
if !ok || entry.ExpiresAt.Before(time.Now()) {
|
if !ok || entry.(CacheEntry).ExpiresAt.Before(time.Now()) {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry.Value, true
|
// Copy the value from the byte slice.
|
||||||
|
value := make([]byte, len(entry.(CacheEntry).Value))
|
||||||
|
copy(value, entry.(CacheEntry).Value)
|
||||||
|
|
||||||
|
return value, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) Delete(key string) {
|
func (c *Cache) Delete(key string) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
|
|
||||||
delete(c.entries, key)
|
entry, ok := c.entries.Load(key)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the byte slice to the pool.
|
||||||
|
c.bytePool.Put(entry.(CacheEntry).Value)
|
||||||
|
|
||||||
|
// Delete the entry from the cache.
|
||||||
|
c.entries.Delete(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cache) CleanExpiredEntries() {
|
func (c *Cache) CleanExpiredEntries() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
toDelete := make([]string, 0)
|
c.entries.Range(func(key, value interface{}) bool {
|
||||||
|
entry := value.(CacheEntry)
|
||||||
c.RLock()
|
|
||||||
for key, entry := range c.entries {
|
|
||||||
if entry.ExpiresAt.Before(now) {
|
if entry.ExpiresAt.Before(now) {
|
||||||
toDelete = append(toDelete, key)
|
// Return the byte slice to the pool.
|
||||||
}
|
c.bytePool.Put(entry.Value)
|
||||||
}
|
|
||||||
c.RUnlock()
|
|
||||||
|
|
||||||
// Separate the deletion to its own critical section to reduce lock contention.
|
// Delete the entry from the cache.
|
||||||
c.Lock()
|
c.entries.Delete(key)
|
||||||
for _, key := range toDelete {
|
}
|
||||||
delete(c.entries, key)
|
|
||||||
}
|
// Return true to continue iterating over the map.
|
||||||
c.Unlock()
|
return true
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user