-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🔥 Feature: Add max size to cache (#1892)
* Cache middleware size limit * Replace MaxInt with MaxInt32. Add comments to benchmark * Avoid allocation in heap push. Small fixes * Count body sizes instead of entries * Update cache/readme
- Loading branch information
Showing
7 changed files
with
348 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package cache | ||
|
||
import ( | ||
"container/heap" | ||
) | ||
|
||
type heapEntry struct { | ||
key string | ||
exp uint64 | ||
bytes uint | ||
idx int | ||
} | ||
|
||
// indexedHeap is a regular min-heap that allows finding | ||
// elements in constant time. It does so by handing out special indices | ||
// and tracking entry movement. | ||
// | ||
// indexdedHeap is used for quickly finding entries with the lowest | ||
// expiration timestamp and deleting arbitrary entries. | ||
type indexedHeap struct { | ||
// Slice the heap is built on | ||
entries []heapEntry | ||
// Mapping "index" to position in heap slice | ||
indices []int | ||
// Max index handed out | ||
maxidx int | ||
} | ||
|
||
func (h indexedHeap) Len() int { | ||
return len(h.entries) | ||
} | ||
|
||
func (h indexedHeap) Less(i, j int) bool { | ||
return h.entries[i].exp < h.entries[j].exp | ||
} | ||
|
||
func (h indexedHeap) Swap(i, j int) { | ||
h.entries[i], h.entries[j] = h.entries[j], h.entries[i] | ||
h.indices[h.entries[i].idx] = i | ||
h.indices[h.entries[j].idx] = j | ||
} | ||
|
||
func (h *indexedHeap) Push(x interface{}) { | ||
h.pushInternal(x.(heapEntry)) | ||
} | ||
|
||
func (h *indexedHeap) Pop() interface{} { | ||
n := len(h.entries) | ||
h.entries = h.entries[0 : n-1] | ||
return h.entries[0:n][n-1] | ||
} | ||
|
||
func (h *indexedHeap) pushInternal(entry heapEntry) { | ||
h.indices[entry.idx] = len(h.entries) | ||
h.entries = append(h.entries, entry) | ||
} | ||
|
||
// Returns index to track entry | ||
func (h *indexedHeap) put(key string, exp uint64, bytes uint) int { | ||
idx := 0 | ||
if len(h.entries) < h.maxidx { | ||
// Steal index from previously removed entry | ||
// capacity > size is guaranteed | ||
n := len(h.entries) | ||
idx = h.entries[:n+1][n].idx | ||
} else { | ||
idx = h.maxidx | ||
h.maxidx += 1 | ||
h.indices = append(h.indices, idx) | ||
} | ||
// Push manually to avoid allocation | ||
h.pushInternal(heapEntry{ | ||
key: key, exp: exp, idx: idx, bytes: bytes, | ||
}) | ||
heap.Fix(h, h.Len()-1) | ||
return idx | ||
} | ||
|
||
func (h *indexedHeap) removeInternal(realIdx int) (string, uint) { | ||
x := heap.Remove(h, realIdx).(heapEntry) | ||
return x.key, x.bytes | ||
} | ||
|
||
// Remove entry by index | ||
func (h *indexedHeap) remove(idx int) (string, uint) { | ||
return h.removeInternal(h.indices[idx]) | ||
} | ||
|
||
// Remove entry with lowest expiration time | ||
func (h *indexedHeap) removeFirst() (string, uint) { | ||
return h.removeInternal(0) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
aa22928
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold
2
.Benchmark_AcquireCtx
1270
ns/op 1440 B/op 5 allocs/op543.3
ns/op 1440 B/op 5 allocs/op2.34
This comment was automatically generated by workflow using github-action-benchmark.