* Two-level cache (L1 fast, L2 larger)
| 130 | * Two-level cache (L1 fast, L2 larger) |
| 131 | */ |
| 132 | class TwoLevelCache<K, V> { |
| 133 | private l1: LRUCache<K, V>; |
| 134 | private l2: LRUCache<K, V>; |
| 135 | private l1Hits = 0; |
| 136 | private l2Hits = 0; |
| 137 | private misses = 0; |
| 138 | |
| 139 | constructor(l1Size: number = 100, l2Size: number = 1000) { |
| 140 | this.l1 = new LRUCache<K, V>(l1Size); |
| 141 | this.l2 = new LRUCache<K, V>(l2Size); |
| 142 | } |
| 143 | |
| 144 | get(key: K): V | undefined { |
| 145 | // Check L1 first |
| 146 | let value = this.l1.get(key); |
| 147 | if (value !== undefined) { |
| 148 | this.l1Hits++; |
| 149 | return value; |
| 150 | } |
| 151 | |
| 152 | // Check L2 |
| 153 | value = this.l2.get(key); |
| 154 | if (value !== undefined) { |
| 155 | this.l2Hits++; |
| 156 | // Promote to L1 |
| 157 | this.l1.set(key, value); |
| 158 | return value; |
| 159 | } |
| 160 | |
| 161 | this.misses++; |
| 162 | return undefined; |
| 163 | } |
| 164 | |
| 165 | set(key: K, value: V): void { |
| 166 | this.l1.set(key, value); |
| 167 | this.l2.set(key, value); |
| 168 | } |
| 169 | |
| 170 | get stats(): { l1HitRate: number; l2HitRate: number; missRate: number } { |
| 171 | const total = this.l1Hits + this.l2Hits + this.misses; |
| 172 | return { |
| 173 | l1HitRate: total > 0 ? this.l1Hits / total : 0, |
| 174 | l2HitRate: total > 0 ? this.l2Hits / total : 0, |
| 175 | missRate: total > 0 ? this.misses / total : 0, |
| 176 | }; |
| 177 | } |
| 178 | |
| 179 | clear(): void { |
| 180 | this.l1.clear(); |
| 181 | this.l2.clear(); |
| 182 | this.l1Hits = 0; |
| 183 | this.l2Hits = 0; |
| 184 | this.misses = 0; |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * Memoization cache for function results |
nothing calls this directly
no outgoing calls
no test coverage detected