singleinflight.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Adapted for dns package usage by Miek Gieben.
  5. package dns
  6. import "sync"
  7. import "time"
  8. // call is an in-flight or completed singleflight.Do call
  9. type call struct {
  10. wg sync.WaitGroup
  11. val *Msg
  12. rtt time.Duration
  13. err error
  14. dups int
  15. }
  16. // singleflight represents a class of work and forms a namespace in
  17. // which units of work can be executed with duplicate suppression.
  18. type singleflight struct {
  19. sync.Mutex // protects m
  20. m map[string]*call // lazily initialized
  21. dontDeleteForTesting bool // this is only to be used by TestConcurrentExchanges
  22. }
  23. // Do executes and returns the results of the given function, making
  24. // sure that only one execution is in-flight for a given key at a
  25. // time. If a duplicate comes in, the duplicate caller waits for the
  26. // original to complete and receives the same results.
  27. // The return value shared indicates whether v was given to multiple callers.
  28. func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
  29. g.Lock()
  30. if g.m == nil {
  31. g.m = make(map[string]*call)
  32. }
  33. if c, ok := g.m[key]; ok {
  34. c.dups++
  35. g.Unlock()
  36. c.wg.Wait()
  37. return c.val, c.rtt, c.err, true
  38. }
  39. c := new(call)
  40. c.wg.Add(1)
  41. g.m[key] = c
  42. g.Unlock()
  43. c.val, c.rtt, c.err = fn()
  44. c.wg.Done()
  45. if !g.dontDeleteForTesting {
  46. g.Lock()
  47. delete(g.m, key)
  48. g.Unlock()
  49. }
  50. return c.val, c.rtt, c.err, c.dups > 0
  51. }