vendor: resenje.org/singleflight v0.4.0

Fixes the context aware singleflight not preserving context values.

full diff: https://github.com/janos/singleflight/compare/v0.3.0...v0.4.0

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>
This commit is contained in:
Paweł Gronowski 2023-09-12 09:22:22 +02:00
parent cdb5947316
commit 5fa011dc0c
No known key found for this signature in database
GPG key ID: B85EFCFE26DEF92A
6 changed files with 119 additions and 24 deletions

View file

@ -108,7 +108,7 @@ require (
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4
google.golang.org/grpc v1.53.0
gotest.tools/v3 v3.5.0
resenje.org/singleflight v0.3.0
resenje.org/singleflight v0.4.0
)
require (

View file

@ -2140,8 +2140,8 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc=
pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4=
resenje.org/singleflight v0.3.0 h1:USJtsAN6HTUA827ksc+2Kcr7QZ4HBq/z/P8ugVbqKFY=
resenje.org/singleflight v0.3.0/go.mod h1:lAgQK7VfjG6/pgredbQfmV0RvG/uVhKo6vSuZ0vCWfk=
resenje.org/singleflight v0.4.0 h1:NdOEhCxEikK2S2WxGjZV9EGSsItolQKslOOi6pE1tJc=
resenje.org/singleflight v0.4.0/go.mod h1:lAgQK7VfjG6/pgredbQfmV0RvG/uVhKo6vSuZ0vCWfk=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

2
vendor/modules.txt vendored
View file

@ -1444,7 +1444,7 @@ k8s.io/klog/v2/internal/clock
k8s.io/klog/v2/internal/dbg
k8s.io/klog/v2/internal/serialize
k8s.io/klog/v2/internal/severity
# resenje.org/singleflight v0.3.0
# resenje.org/singleflight v0.4.0
## explicit; go 1.18
resenje.org/singleflight
# sigs.k8s.io/yaml v1.3.0

View file

@ -5,7 +5,7 @@
// Package singleflight provides a duplicate function call suppression
// mechanism similar to golang.org/x/sync/singleflight with support
// for context cancelation.
// for context cancellation.
package singleflight
import (
@ -17,7 +17,7 @@ import (
// which units of work can be executed with duplicate suppression.
type Group[K comparable, V any] struct {
calls map[K]*call[V] // lazily initialized
mu sync.Mutex // protects calls
mu sync.Mutex // protects calls
}
// Do executes and returns the results of the given function, making sure that
@ -25,10 +25,12 @@ type Group[K comparable, V any] struct {
// comes in, the duplicate caller waits for the original to complete and
// receives the same results.
//
// The context passed to the fn function is a new context which is canceled when
// contexts from all callers are canceled, so that no caller is expecting the
// result. If there are multiple callers, context passed to one caller does not
// effect the execution and returned values of others.
// The context passed to the fn function is a context that preserves all values
// from the passed context but is cancelled by the singleflight only when all
// awaiting caller's contexts are cancelled (no caller is awaiting the result).
// If there are multiple callers, context passed to one caller does not affect
// the execution and returned values of others except if the function result is
// dependent on the context values.
//
// The return value shared indicates whether v was given to multiple callers.
func (g *Group[K, V]) Do(ctx context.Context, key K, fn func(ctx context.Context) (V, error)) (v V, shared bool, err error) {
@ -45,7 +47,9 @@ func (g *Group[K, V]) Do(ctx context.Context, key K, fn func(ctx context.Context
return g.wait(ctx, key, c)
}
callCtx, cancel := context.WithCancel(context.Background())
// Replace cancellation from the user context with a cancellation
// controlled by the singleflight and preserve context values.
callCtx, cancel := context.WithCancel(withoutCancel(ctx))
c := &call[V]{
done: make(chan struct{}),
@ -76,8 +80,6 @@ func (g *Group[K, V]) wait(ctx context.Context, key K, c *call[V]) (v V, shared
c.counter--
if c.counter == 0 {
c.cancel()
}
if !c.forgotten {
delete(g.calls, key)
}
g.mu.Unlock()
@ -89,9 +91,6 @@ func (g *Group[K, V]) wait(ctx context.Context, key K, c *call[V]) (v V, shared
// an earlier call to complete.
func (g *Group[K, V]) Forget(key K) {
g.mu.Lock()
if c, ok := g.calls[key]; ok {
c.forgotten = true
}
delete(g.calls, key)
g.mu.Unlock()
}
@ -105,15 +104,12 @@ type call[V any] struct {
// done channel signals that the function call is done.
done chan struct{}
// forgotten indicates whether Forget was called with this call's key
// while the call was still in flight.
forgotten bool
// shared indicates if results val and err are passed to multiple callers.
shared bool
// Cancel function for the context passed to the executing function.
cancel context.CancelFunc
// Number of callers that are waiting for the result.
counter int
// Cancel function for the context passed to the executing function.
cancel context.CancelFunc
// shared indicates if results val and err are passed to multiple callers.
shared bool
}

87
vendor/resenje.org/singleflight/withoutcancel.go generated vendored Normal file
View file

@ -0,0 +1,87 @@
//go:build !go1.21
// Copyright (c) 2009 The Go Authors. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Source: https://cs.opensource.google/go/go/+/refs/tags/go1.21.1:src/context/context.go
// The only modifications to the original source were:
// - renaming WithoutCancel to withoutCancel
// - replacing the usage of internal reflectlite with reflect
// - replacing the usage of private value function with Value method call
package singleflight
import (
"context"
"reflect"
"time"
)
// withoutCancel returns a copy of parent that is not canceled when parent is canceled.
// The returned context returns no Deadline or Err, and its Done channel is nil.
// Calling [Cause] on the returned context returns nil.
func withoutCancel(parent context.Context) context.Context {
if parent == nil {
panic("cannot create context from nil parent")
}
return withoutCancelCtx{parent}
}
type withoutCancelCtx struct {
c context.Context
}
func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (withoutCancelCtx) Done() <-chan struct{} {
return nil
}
func (withoutCancelCtx) Err() error {
return nil
}
func (c withoutCancelCtx) Value(key any) any {
return c.c.Value(key)
}
func (c withoutCancelCtx) String() string {
return contextName(c.c) + ".WithoutCancel"
}
type stringer interface {
String() string
}
func contextName(c context.Context) string {
if s, ok := c.(stringer); ok {
return s.String()
}
return reflect.TypeOf(c).String()
}

12
vendor/resenje.org/singleflight/withoutcancel_go121.go generated vendored Normal file
View file

@ -0,0 +1,12 @@
//go:build go1.21
package singleflight
import "context"
// withoutCancel returns a copy of parent that is not canceled when parent is canceled.
// The returned context returns no Deadline or Err, and its Done channel is nil.
// Calling [Cause] on the returned context returns nil.
func withoutCancel(ctx context.Context) context.Context {
return context.WithoutCancel(ctx)
}