Browse Source

Fix up cachenode

pull/1/head
Stephanie Gredell 7 months ago
parent
commit
f60495ab40
  1. 93
      internal/simulation/cachenode.go

93
internal/simulation/cachenode.go

@ -1,5 +1,17 @@ @@ -1,5 +1,17 @@
package simulation
import (
"math/rand"
"sort"
)
type CacheEntry struct {
Value interface{}
Timestamp int
ExpireAt int
AccessCount int
}
type CacheNode struct {
ID string
Label string
@ -7,10 +19,11 @@ type CacheNode struct { @@ -7,10 +19,11 @@ type CacheNode struct {
MaxEntries int
EvictionPolicy string
CurrentLoad int
Queue []Request
Cache map[string]interface{}
Queue []*Request
Cache map[string]CacheEntry
Alive bool
Targets []string
Output []*Request
}
func (c *CacheNode) GetID() string {
@ -21,42 +34,74 @@ func (c *CacheNode) Type() string { @@ -21,42 +34,74 @@ func (c *CacheNode) Type() string {
return "cache"
}
func (c *CacheNode) GetQueue() []Request {
return c.Queue
func (c *CacheNode) IsAlive() bool {
return c.Alive
}
func (c *CacheNode) Tick(tick int) {
func (c *CacheNode) Tick(tick int, currentTimeMs int) {
for key, entry := range c.Cache {
if currentTimeMs > entry.ExpireAt {
delete(c.Cache, key)
}
}
if len(c.Cache) > c.MaxEntries {
evictCount := len(c.Cache) - c.MaxEntries
keys := make([]string, 0, len(c.Cache))
for k := range c.Cache {
keys = append(keys, k)
}
i := 0
switch c.EvictionPolicy {
case "Random":
rand.Shuffle(len(keys), func(i, j int) { keys[i], keys[j] = keys[j], keys[i] })
case "LRU":
sort.Slice(keys, func(i, j int) bool {
return c.Cache[keys[i]].Timestamp < c.Cache[keys[j]].Timestamp
})
case "LFU":
sort.Slice(keys, func(i, j int) bool {
return c.Cache[keys[i]].AccessCount < c.Cache[keys[j]].AccessCount
})
}
for k := range c.Cache {
delete(c.Cache, k)
i++
if i >= evictCount {
break
for i := 0; i < evictCount && i < len(keys); i++ {
delete(c.Cache, keys[i])
}
}
toProcess := min(len(c.Queue), 10)
for i := 0; i < toProcess; i++ {
req := c.Queue[i]
if entry, found := c.Cache[req.ID]; found && currentTimeMs <= entry.ExpireAt {
// Cache hit
req.LatencyMS += 2
req.Path = append(req.Path, c.ID+"(hit)")
} else {
// Cache miss
req.LatencyMS += 5
req.Path = append(req.Path, c.ID+"(miss)")
c.Cache[req.ID] = CacheEntry{
Value: req,
Timestamp: currentTimeMs,
ExpireAt: currentTimeMs + c.CacheTTL*1000,
}
c.Output = append(c.Output, req)
}
}
c.Queue = c.Queue[toProcess:]
}
func (c *CacheNode) Receive(req *Request) {
c.Queue = append(c.Queue, *req)
c.Queue = append(c.Queue, req)
}
func (c *CacheNode) Emit() []*Request {
var out []*Request
// emit everything in a single tick.
for _, req := range c.Queue {
// check cache
if _, ok := c.Cache[req.ID]; !ok {
c.Cache[req.ID] = struct{}{}
out = append(out, &req)
}
}
c.Queue = nil
out := append([]*Request(nil), c.Output...)
c.Output = c.Output[:0]
return out
}
func (c *CacheNode) IsAlive() bool { return c.Alive }
func (c *CacheNode) AddTarget(targetID string) {
c.Targets = append(c.Targets, targetID)
}

Loading…
Cancel
Save