-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathex03_eviction.go
More file actions
58 lines (47 loc) · 1.57 KB
/
ex03_eviction.go
File metadata and controls
58 lines (47 loc) · 1.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package garbagecollector
import (
"sync"
)
// Context: Unbounded Caches and OOM
// You are building a session store. Whenever a user logs in, you save their
// profile in a global `map[string]User{}` so you don't have to hit the DB again.
//
// Why this matters: A map in Go never shrinks. If you add 10,000,000 users
// over a month, the map will consume gigabytes of memory. Because the map
// holds active pointers to the `User` structs, the Garbage Collector can NEVER
// free them. Your server will inevitably OOM (Out Of Memory) crash.
//
// Requirements:
// 1. Refactor `SessionCache` into a bounded cache.
// 2. Simplest approach: Add a `MaxKeys int` field. If `Set()` is called and
// `len(c.store) >= c.MaxKeys`, you MUST evict an item.
// 3. For this exercise, simple random eviction is acceptable (just use a `for k := range c.store { delete(c.store, k); break }`).
// In the real world, you would use an LRU or a TTL.
// 4. Ensure it remains safe for concurrent access (Mutex).
type User struct {
ID string
Data [1024]byte // 1KB of data per user
}
type SessionCache struct {
mu sync.Mutex
store map[string]User
// TODO: Add MaxKeys to enforce a cap
}
func NewSessionCache() *SessionCache {
return &SessionCache{
store: make(map[string]User),
}
}
func (c *SessionCache) Set(id string, u User) {
c.mu.Lock()
defer c.mu.Unlock()
// BUG: Unbounded growth!
// TODO: If len >= MaxKeys, evict something before inserting!
c.store[id] = u
}
func (c *SessionCache) Get(id string) (User, bool) {
c.mu.Lock()
defer c.mu.Unlock()
u, ok := c.store[id]
return u, ok
}