2019-05-10 14:36:20 -06:00
|
|
|
// Copyright 2019 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2019-06-11 19:16:35 -06:00
|
|
|
// Package memoize supports memoizing the return values of functions with
|
|
|
|
// idempotent results that are expensive to compute.
|
|
|
|
//
|
|
|
|
// The memoizied result is returned again the next time the function is invoked.
|
|
|
|
// To prevent excessive memory use, the return values are only remembered
|
|
|
|
// for as long as they still have a user.
|
|
|
|
//
|
2019-05-10 14:36:20 -06:00
|
|
|
// To use this package, build a store and use it to aquire handles with the
|
|
|
|
// Bind method.
|
2019-06-11 19:16:35 -06:00
|
|
|
//
|
2019-05-10 14:36:20 -06:00
|
|
|
package memoize
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Store binds keys to functions, returning handles that can be used to access
|
|
|
|
// the functions results.
|
|
|
|
type Store struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
// entries is the set of values stored.
|
|
|
|
entries map[interface{}]*entry
|
|
|
|
}
|
|
|
|
|
|
|
|
// Function is the type for functions that can be memoized.
|
|
|
|
// The result must be a pointer.
|
|
|
|
type Function func(ctx context.Context) interface{}
|
|
|
|
|
|
|
|
// Handle is returned from a store when a key is bound to a function.
|
|
|
|
// It is then used to access the results of that function.
|
|
|
|
type Handle struct {
|
|
|
|
mu sync.Mutex
|
|
|
|
function Function
|
|
|
|
entry *entry
|
|
|
|
value interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// entry holds the machinery to manage a function and its result such that
|
|
|
|
// there is only one instance of the result live at any given time.
|
|
|
|
type entry struct {
|
|
|
|
noCopy
|
2019-06-24 22:50:01 -06:00
|
|
|
key interface{}
|
2019-05-10 14:36:20 -06:00
|
|
|
// mu contols access to the typ and ptr fields
|
|
|
|
mu sync.Mutex
|
|
|
|
// the calculated value, as stored in an interface{}
|
|
|
|
typ, ptr uintptr
|
|
|
|
ready bool
|
|
|
|
// wait is used to block until the value is ready
|
|
|
|
// will only be non nil if the generator is already running
|
|
|
|
wait chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Has returns true if they key is currently valid for this store.
|
|
|
|
func (s *Store) Has(key interface{}) bool {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
_, found := s.entries[key]
|
|
|
|
return found
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete removes a key from the store, if present.
|
|
|
|
func (s *Store) Delete(key interface{}) {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
delete(s.entries, key)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bind returns a handle for the given key and function.
|
2019-06-11 19:16:35 -06:00
|
|
|
//
|
|
|
|
// Each call to bind will generate a new handle.
|
|
|
|
// All of of the handles for a single key will refer to the same value.
|
|
|
|
// Only the first handle to get the value will cause the function to be invoked.
|
|
|
|
// The value will be held for as long as there are handles through which it has been accessed.
|
2019-05-10 14:36:20 -06:00
|
|
|
// Bind does not cause the value to be generated.
|
|
|
|
func (s *Store) Bind(key interface{}, function Function) *Handle {
|
|
|
|
// panic early if the function is nil
|
|
|
|
// it would panic later anyway, but in a way that was much harder to debug
|
|
|
|
if function == nil {
|
2019-06-11 19:16:35 -06:00
|
|
|
panic("the function passed to bind must not be nil")
|
2019-05-10 14:36:20 -06:00
|
|
|
}
|
|
|
|
// check if we already have the key
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
e, found := s.entries[key]
|
|
|
|
if !found {
|
|
|
|
// we have not seen this key before, add a new entry
|
|
|
|
if s.entries == nil {
|
|
|
|
s.entries = make(map[interface{}]*entry)
|
|
|
|
}
|
2019-06-24 22:50:01 -06:00
|
|
|
e = &entry{key: key}
|
2019-05-10 14:36:20 -06:00
|
|
|
s.entries[key] = e
|
|
|
|
}
|
|
|
|
return &Handle{
|
|
|
|
entry: e,
|
|
|
|
function: function,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cached returns the value associated with a key.
|
2019-06-11 19:16:35 -06:00
|
|
|
//
|
|
|
|
// It cannot cause the value to be generated.
|
|
|
|
// It will return the cached value, if present.
|
2019-05-10 14:36:20 -06:00
|
|
|
func (s *Store) Cached(key interface{}) interface{} {
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
e, found := s.entries[key]
|
|
|
|
if !found {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
e.mu.Lock()
|
|
|
|
defer e.mu.Unlock()
|
|
|
|
return unref(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Cached returns the value associated with a handle.
|
2019-06-11 19:16:35 -06:00
|
|
|
//
|
|
|
|
// It will never cause the value to be generated.
|
|
|
|
// It will return the cached value, if present.
|
2019-05-10 14:36:20 -06:00
|
|
|
func (h *Handle) Cached() interface{} {
|
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
|
|
|
if h.value == nil {
|
|
|
|
h.entry.mu.Lock()
|
|
|
|
defer h.entry.mu.Unlock()
|
|
|
|
h.value = unref(h.entry)
|
|
|
|
}
|
|
|
|
return h.value
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the value associated with a handle.
|
2019-06-11 19:16:35 -06:00
|
|
|
//
|
2019-05-10 14:36:20 -06:00
|
|
|
// If the value is not yet ready, the underlying function will be invoked.
|
2019-06-11 19:16:35 -06:00
|
|
|
// This activates the handle, and it will remember the value for as long as it exists.
|
|
|
|
// This will cause any other handles for the same key to also return the same value.
|
2019-05-10 14:36:20 -06:00
|
|
|
func (h *Handle) Get(ctx context.Context) interface{} {
|
|
|
|
h.mu.Lock()
|
|
|
|
defer h.mu.Unlock()
|
|
|
|
if h.function != nil {
|
|
|
|
if v, ok := h.entry.get(ctx, h.function); ok {
|
|
|
|
h.value = v
|
|
|
|
h.function = nil
|
|
|
|
h.entry = nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return h.value
|
|
|
|
}
|
|
|
|
|
|
|
|
// get is the implementation of Get.
|
|
|
|
func (e *entry) get(ctx context.Context, f Function) (interface{}, bool) {
|
|
|
|
e.mu.Lock()
|
2019-06-11 19:16:35 -06:00
|
|
|
// Note: This defer is not paired with the above lock.
|
2019-05-10 14:36:20 -06:00
|
|
|
defer e.mu.Unlock()
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Fast path: If the entry is ready, it already has a value.
|
2019-05-10 14:36:20 -06:00
|
|
|
if e.ready {
|
|
|
|
return unref(e), true
|
|
|
|
}
|
2019-06-11 19:16:35 -06:00
|
|
|
// Only begin evaluating the function if no other goroutine is doing so.
|
2019-05-10 14:36:20 -06:00
|
|
|
var value interface{}
|
|
|
|
if e.wait == nil {
|
|
|
|
e.wait = make(chan struct{})
|
|
|
|
go func() {
|
2019-06-11 19:16:35 -06:00
|
|
|
// Note: We do not hold the lock on the entry in this goroutine.
|
|
|
|
//
|
|
|
|
// We immediately defer signaling that the entry is ready,
|
|
|
|
// since we cannot guarantee that the function, f, will not panic.
|
2019-05-10 14:36:20 -06:00
|
|
|
defer func() {
|
2019-06-11 19:16:35 -06:00
|
|
|
// Note: We have to hold the entry's lock before returning.
|
2019-05-10 14:36:20 -06:00
|
|
|
close(e.wait)
|
|
|
|
e.wait = nil
|
|
|
|
}()
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Use the background context to avoid canceling the function.
|
|
|
|
// The function cannot be canceled even if the context is canceled
|
|
|
|
// because multiple goroutines may depend on it.
|
2019-06-24 22:50:01 -06:00
|
|
|
value = f(detatchContext(ctx))
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// The function has completed. Update the value in the entry.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.mu.Lock()
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Note: Because this defer will execute before the first defer,
|
|
|
|
// we will hold the lock while we update the entry's wait channel.
|
2019-05-10 14:36:20 -06:00
|
|
|
defer e.mu.Unlock()
|
|
|
|
setref(e, value)
|
|
|
|
}()
|
|
|
|
}
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Get a local copy of wait while we still hold the lock.
|
2019-05-10 14:36:20 -06:00
|
|
|
wait := e.wait
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Release the lock while we wait for the value.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.mu.Unlock()
|
2019-06-11 19:16:35 -06:00
|
|
|
|
2019-05-10 14:36:20 -06:00
|
|
|
select {
|
|
|
|
case <-wait:
|
2019-06-11 19:16:35 -06:00
|
|
|
// We should now have a value. Lock the entry, and don't defer an unlock,
|
|
|
|
// since we already have done so at the beginning of this function.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.mu.Lock()
|
|
|
|
result := unref(e)
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// This keep alive makes sure that value is not garbage collected before
|
|
|
|
// we call unref and acquire a strong reference to it.
|
2019-05-10 14:36:20 -06:00
|
|
|
runtime.KeepAlive(value)
|
|
|
|
return result, true
|
|
|
|
case <-ctx.Done():
|
2019-06-11 19:16:35 -06:00
|
|
|
// The context was canceled, but we have to lock the entry again,
|
|
|
|
// since we already deferred an unlock at the beginning of this function.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.mu.Lock()
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-11 19:16:35 -06:00
|
|
|
// setref is called to store a weak reference to a value into an entry.
|
|
|
|
// It assumes that the caller is holding the entry's lock.
|
2019-05-10 14:36:20 -06:00
|
|
|
func setref(e *entry, value interface{}) interface{} {
|
|
|
|
// this is only called when the entry lock is already held
|
|
|
|
data := (*[2]uintptr)(unsafe.Pointer(&value))
|
|
|
|
// store the value back to the entry as a weak reference
|
|
|
|
e.typ, e.ptr = data[0], data[1]
|
|
|
|
e.ready = true
|
|
|
|
if e.ptr != 0 {
|
2019-06-11 19:16:35 -06:00
|
|
|
// Arrange to clear the weak reference when the object is garbage collected.
|
2019-05-10 14:36:20 -06:00
|
|
|
runtime.SetFinalizer(value, func(_ interface{}) {
|
|
|
|
e.mu.Lock()
|
|
|
|
defer e.mu.Unlock()
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Clear the now-invalid non-pointer.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.typ, e.ptr = 0, 0
|
2019-06-11 19:16:35 -06:00
|
|
|
// The value is no longer available.
|
2019-05-10 14:36:20 -06:00
|
|
|
e.ready = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
2019-06-11 19:16:35 -06:00
|
|
|
// unref returns a strong reference to value stored in the given entry.
|
|
|
|
// It assumes that the caller is holding the entry's lock.
|
2019-05-10 14:36:20 -06:00
|
|
|
func unref(e *entry) interface{} {
|
|
|
|
// this is only called when the entry lock is already held
|
|
|
|
var v interface{}
|
|
|
|
data := (*[2]uintptr)(unsafe.Pointer(&v))
|
2019-06-11 19:16:35 -06:00
|
|
|
|
|
|
|
// Note: This approach for computing weak references and converting between
|
|
|
|
// weak and strong references would be rendered invalid if Go's runtime
|
|
|
|
// changed to allow moving objects on the heap.
|
|
|
|
// If such a change were to occur, some modifications would need to be made
|
|
|
|
// to this library.
|
2019-05-10 14:36:20 -06:00
|
|
|
data[0], data[1] = e.typ, e.ptr
|
|
|
|
return v
|
|
|
|
}
|