singleflight.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. // Package singleflight provides a duplicate function call suppression
  5. // mechanism.
  6. package singleflight // import "golang.org/x/sync/singleflight"
  7. import "sync"
  8. // call is an in-flight or completed singleflight.Do call
  9. type call struct {
  10. wg sync.WaitGroup
  11. // These fields are written once before the WaitGroup is done
  12. // and are only read after the WaitGroup is done.
  13. val interface{}
  14. err error
  15. // These fields are read and written with the singleflight
  16. // mutex held before the WaitGroup is done, and are read but
  17. // not written after the WaitGroup is done.
  18. dups int
  19. chans []chan<- Result
  20. }
  21. // Group represents a class of work and forms a namespace in
  22. // which units of work can be executed with duplicate suppression.
  23. type Group struct {
  24. mu sync.Mutex // protects m
  25. m map[string]*call // lazily initialized
  26. }
  27. // Result holds the results of Do, so they can be passed
  28. // on a channel.
  29. type Result struct {
  30. Val interface{}
  31. Err error
  32. Shared bool
  33. }
  34. // Do executes and returns the results of the given function, making
  35. // sure that only one execution is in-flight for a given key at a
  36. // time. If a duplicate comes in, the duplicate caller waits for the
  37. // original to complete and receives the same results.
  38. // The return value shared indicates whether v was given to multiple callers.
  39. func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
  40. g.mu.Lock()
  41. if g.m == nil {
  42. g.m = make(map[string]*call)
  43. }
  44. if c, ok := g.m[key]; ok {
  45. c.dups++
  46. g.mu.Unlock()
  47. c.wg.Wait()
  48. return c.val, c.err, true
  49. }
  50. c := new(call)
  51. c.wg.Add(1)
  52. g.m[key] = c
  53. g.mu.Unlock()
  54. g.doCall(c, key, fn)
  55. return c.val, c.err, c.dups > 0
  56. }
  57. // DoChan is like Do but returns a channel that will receive the
  58. // results when they are ready.
  59. func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
  60. ch := make(chan Result, 1)
  61. g.mu.Lock()
  62. if g.m == nil {
  63. g.m = make(map[string]*call)
  64. }
  65. if c, ok := g.m[key]; ok {
  66. c.dups++
  67. c.chans = append(c.chans, ch)
  68. g.mu.Unlock()
  69. return ch
  70. }
  71. c := &call{chans: []chan<- Result{ch}}
  72. c.wg.Add(1)
  73. g.m[key] = c
  74. g.mu.Unlock()
  75. go g.doCall(c, key, fn)
  76. return ch
  77. }
  78. // doCall handles the single call for a key.
  79. func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
  80. c.val, c.err = fn()
  81. c.wg.Done()
  82. g.mu.Lock()
  83. delete(g.m, key)
  84. for _, ch := range c.chans {
  85. ch <- Result{c.val, c.err, c.dups > 0}
  86. }
  87. g.mu.Unlock()
  88. }
  89. // Forget tells the singleflight to forget about a key. Future calls
  90. // to Do for this key will call the function rather than waiting for
  91. // an earlier call to complete.
  92. func (g *Group) Forget(key string) {
  93. g.mu.Lock()
  94. delete(g.m, key)
  95. g.mu.Unlock()
  96. }