internal/memoize: do not iterate all handles on generation destruction
This allows reducing critical section of `g.store.mu` as the vast
majority of entries do not rely on generation-based GC.
Change-Id: I985af0b38504ddedb22649290deac91797577b75
Reviewed-on: https://go-review.googlesource.com/c/tools/+/413656
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/internal/memoize/memoize.go b/internal/memoize/memoize.go
index a758dee..7fa5340 100644
--- a/internal/memoize/memoize.go
+++ b/internal/memoize/memoize.go
@@ -33,6 +33,8 @@
type Store struct {
handlesMu sync.Mutex // lock ordering: Store.handlesMu before Handle.mu
handles map[interface{}]*Handle
+ // handles which are bound to generations for GC purposes.
+ boundHandles map[*Handle]struct{}
}
// Generation creates a new Generation associated with s. Destroy must be
@@ -71,10 +73,7 @@
g.store.handlesMu.Lock()
defer g.store.handlesMu.Unlock()
- for _, h := range g.store.handles {
- if !h.trackGenerations {
- continue
- }
+ for h := range g.store.boundHandles {
h.mu.Lock()
if _, ok := h.generations[g]; ok {
delete(h.generations, g) // delete even if it's dead, in case of dangling references to the entry.
@@ -237,7 +236,11 @@
trackGenerations: trackGenerations,
}
if trackGenerations {
+ if g.store.boundHandles == nil {
+ g.store.boundHandles = map[*Handle]struct{}{}
+ }
h.generations = make(map[*Generation]struct{}, 1)
+ g.store.boundHandles[h] = struct{}{}
}
if g.store.handles == nil {
@@ -302,6 +305,9 @@
h.cleanup(h.value)
}
delete(store.handles, h.key)
+ if h.trackGenerations {
+ delete(store.boundHandles, h)
+ }
}
func (h *Handle) incrementRef(g *Generation) {