-
Notifications
You must be signed in to change notification settings - Fork 207
Description
When entries exit the unstable
log structure
Line 156 in 3e6cb62
u.entries = u.entries[num:] |
it shrinks itself based on the entries slice length and cap:
Lines 162 to 179 in 3e6cb62
// shrinkEntriesArray discards the underlying array used by the entries slice | |
// if most of it isn't being used. This avoids holding references to a bunch of | |
// potentially large entries that aren't needed anymore. Simply clearing the | |
// entries wouldn't be safe because clients might still be using them. | |
func (u *unstable) shrinkEntriesArray() { | |
// We replace the array if we're using less than half of the space in | |
// it. This number is fairly arbitrary, chosen as an attempt to balance | |
// memory usage vs number of allocations. It could probably be improved | |
// with some focused tuning. | |
const lenMultiple = 2 | |
if len(u.entries) == 0 { | |
u.entries = nil | |
} else if len(u.entries)*lenMultiple < cap(u.entries) { | |
newEntries := make([]pb.Entry, len(u.entries)) | |
copy(newEntries, u.entries) | |
u.entries = newEntries | |
} | |
} |
Firstly, the len(u.entries)*lenMultiple < cap(u.entries)
does not necessarily do a right thing. After shifting the slice start in u.entries = u.entries[num:]
, the first num
entries "disappear" from len
and cap
of this slice: https://go.dev/play/p/ao1xaL0Edla.
So it's possible that len >= cap/2
all the time, even though only a small portion of the backing slice is used. We should take the cap
of the entire backing slice into account instead.
Secondly, this heuristic only takes len/cap
of the slice into consideration, but not the size of the entries referenced by it. It could be beneficial to, in addition, shrink the slice if the sum size of the "garbage" entries is more than a half. This would keep the overall memory consumption more controlled. Doing so would require maintaining a running sum of entry sizes in the unstable
struct (which we do anyway in other places for rate limiting purposes).
The same heuristic could be applied in MemoryStorage.Compact method to smooth out the allocation/copying cost of log truncations. Frequent truncations may incur a quadratic cost here, while the heuristic allows capping it at O(N).