@@ -22,6 +22,8 @@ import (
22
22
"time"
23
23
"unsafe"
24
24
25
+ "container/list"
26
+
25
27
"sigs.k8s.io/controller-runtime/pkg/log"
26
28
"sigs.k8s.io/gateway-api-inference-extension/pkg/epp/metrics"
27
29
logutil "sigs.k8s.io/gateway-api-inference-extension/pkg/epp/util/logging"
@@ -30,8 +32,8 @@ import (
30
32
func newIndexer (maxCacheSize int ) * indexer {
31
33
t := & indexer {
32
34
maxCacheSize : maxCacheSize ,
33
- table : make (map [BlockHash ]map [ServerID ]* node ),
34
- list : newLinkedList (),
35
+ table : make (map [BlockHash ]map [ServerID ]* list. Element ),
36
+ ll : list . New (),
35
37
}
36
38
go t .ReportCacheSize (time .Second )
37
39
return t
@@ -42,8 +44,14 @@ func newIndexer(maxCacheSize int) *indexer {
42
44
type indexer struct {
43
45
mu sync.RWMutex
44
46
maxCacheSize int
45
- table map [BlockHash ]map [ServerID ]* node // from any prefix cache to the cache entry to find the server
46
- list * linkedList // LRU list to keep track of the order of entries
47
+ table map [BlockHash ]map [ServerID ]* list.Element // from any prefix cache to the cache entry to find the server
48
+ ll * list.List // LinkedList to keep track of the order of entries
49
+ }
50
+
51
+ // value is the value stored in the linked list.
52
+ type value struct {
53
+ server ServerID
54
+ hash BlockHash
47
55
}
48
56
49
57
// Get returns the set of servers that have the given prefix hash cached.
@@ -68,49 +76,52 @@ func (i *indexer) Add(hashes []BlockHash, server ServerID) {
68
76
}
69
77
}
70
78
71
- func (i * indexer ) check (hash BlockHash , server ServerID ) (* node , bool ) {
79
+ func (i * indexer ) check (hash BlockHash , server ServerID ) (* list. Element , bool ) {
72
80
servers , ok := i .table [hash ]
73
81
if ! ok {
74
82
return nil , false
75
83
}
76
- n , ok := servers [server ]
77
- return n , ok
84
+ e , ok := servers [server ]
85
+ return e , ok
78
86
}
79
87
80
88
func (i * indexer ) add (hash BlockHash , server ServerID ) {
81
- node , exists := i .check (hash , server )
89
+ e , exists := i .check (hash , server )
82
90
if exists {
83
- i .list . moveToTail ( node )
91
+ i .ll . MoveToBack ( e )
84
92
} else {
85
93
i .create (hash , server )
86
94
}
87
95
}
88
96
89
97
func (i * indexer ) create (hash BlockHash , server ServerID ) {
90
- n := & node {
91
- hash : hash ,
92
- server : server ,
93
- }
94
-
95
- for i .list .size >= i .maxCacheSize {
98
+ for i .ll .Len () >= i .maxCacheSize {
96
99
// Evict the least recently used entry if we've exceeded the max cache size
97
100
i .evict ()
98
101
}
99
102
100
103
if _ , ok := i .table [hash ]; ! ok {
101
- i .table [hash ] = make (map [ServerID ]* node )
104
+ i .table [hash ] = make (map [ServerID ]* list. Element )
102
105
}
103
- i.table [hash ][server ] = n
104
- i .list .add (n )
106
+ v := & value {
107
+ server : server ,
108
+ hash : hash ,
109
+ }
110
+ e := i .ll .PushBack (v )
111
+ i.table [hash ][server ] = e
105
112
}
106
113
107
114
// evict removes the least recently used entry from the cache
108
115
func (i * indexer ) evict () {
109
- oldestNode := i .list .dummyHead .next
110
- i .list .delete (oldestNode )
116
+ oldestNode := i .ll .Front ()
117
+ if oldestNode == nil {
118
+ return
119
+ }
120
+ i .ll .Remove (oldestNode )
111
121
112
- hash := oldestNode .hash
113
- server := oldestNode .server
122
+ v := oldestNode .Value .(* value )
123
+ hash := v .hash
124
+ server := v .server
114
125
// Remove from the hash map
115
126
serverMap := i .table [hash ]
116
127
delete (serverMap , server )
@@ -129,8 +140,8 @@ func (i *indexer) ReportCacheSize(interval time.Duration) {
129
140
defer ticker .Stop ()
130
141
for range ticker .C {
131
142
i .mu .RLock ()
132
- metrics .RecordPrefixCacheSize (int64 (i .list . size ))
133
- log .FromContext (context .TODO ()).V (logutil .TRACE ).Info ("LRU" , "# entries" , i .list . size , "estimated size MB" , i .list . size * i .estimateEntrySize ()/ 1000000 )
143
+ metrics .RecordPrefixCacheSize (int64 (i .ll . Len () ))
144
+ log .FromContext (context .TODO ()).V (logutil .TRACE ).Info ("LRU" , "# entries" , i .ll . Len () , "estimated size MB" , i .ll . Len () * i .estimateEntrySize ()/ 1000000 )
134
145
i .mu .RUnlock ()
135
146
}
136
147
}
@@ -146,7 +157,7 @@ func (i *indexer) estimateEntrySize() int {
146
157
// The ServerID is a NamespacedName, which contains two strings (Name and Namespace).
147
158
// The headers for the strings are 16 bytes each (8 bytes for the pointer and 8 bytes for the length).
148
159
// So unsafe.Sizeof(node{}) should return 2*8 + 8 + 2*16 = 48 bytes.
149
- size += int (unsafe .Sizeof (node {}))
160
+ size += int (unsafe .Sizeof (value {}))
150
161
// Size of the Name and Namespace strings in ServerID, assuming 63 bytes each (max length for Kubernetes NamespacedName).
151
162
size += 2 * 63
152
163
0 commit comments