singleinflight.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  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. }
  22. // Do executes and returns the results of the given function, making
  23. // sure that only one execution is in-flight for a given key at a
  24. // time. If a duplicate comes in, the duplicate caller waits for the
  25. // original to complete and receives the same results.
  26. // The return value shared indicates whether v was given to multiple callers.
  27. func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
  28. g.Lock()
  29. if g.m == nil {
  30. g.m = make(map[string]*call)
  31. }
  32. if c, ok := g.m[key]; ok {
  33. c.dups++
  34. g.Unlock()
  35. c.wg.Wait()
  36. return c.val, c.rtt, c.err, true
  37. }
  38. c := new(call)
  39. c.wg.Add(1)
  40. g.m[key] = c
  41. g.Unlock()
  42. c.val, c.rtt, c.err = fn()
  43. c.wg.Done()
  44. g.Lock()
  45. delete(g.m, key)
  46. g.Unlock()
  47. return c.val, c.rtt, c.err, c.dups > 0
  48. }