Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(748)

Delta Between Two Patch Sets: src/net/singleflight.go

Issue 154610044: code review 154610044: net: if a DNS lookup times out, forget that it is in flight (Closed)
Left Patch Set: Created 9 years, 5 months ago
Right Patch Set: diff -r 207a56999953fec99622802b5002cc65c7a2f833 https://code.google.com/p/go Created 9 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « src/net/lookup.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2013 The Go Authors. All rights reserved. 1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package net 5 package net
6 6
7 import "sync" 7 import "sync"
8 8
9 // call is an in-flight or completed singleflight.Do call 9 // call is an in-flight or completed singleflight.Do call
10 type call struct { 10 type call struct {
11 » wg sync.WaitGroup 11 » wg sync.WaitGroup
12 » val interface{} 12
13 » err error 13 » // These fields are written once before the WaitGroup is done
14 » dups int 14 » // and are only read after the WaitGroup is done.
15 » val interface{}
16 » err error
17
18 » // These fields are read and written with the singleflight
19 » // mutex held before the WaitGroup is done, and are read but
20 » // not written after the WaitGroup is done.
21 » dups int
22 » chans []chan<- singleflightResult
15 } 23 }
16 24
17 // singleflight represents a class of work and forms a namespace in 25 // singleflight represents a class of work and forms a namespace in
18 // which units of work can be executed with duplicate suppression. 26 // which units of work can be executed with duplicate suppression.
19 type singleflight struct { 27 type singleflight struct {
20 mu sync.Mutex // protects m 28 mu sync.Mutex // protects m
21 m map[string]*call // lazily initialized 29 m map[string]*call // lazily initialized
30 }
31
32 // singleflightResult holds the results of Do, so they can be passed
33 // on a channel.
34 type singleflightResult struct {
35 v interface{}
36 err error
37 shared bool
22 } 38 }
23 39
24 // Do executes and returns the results of the given function, making 40 // Do executes and returns the results of the given function, making
25 // sure that only one execution is in-flight for a given key at a 41 // sure that only one execution is in-flight for a given key at a
26 // time. If a duplicate comes in, the duplicate caller waits for the 42 // time. If a duplicate comes in, the duplicate caller waits for the
27 // original to complete and receives the same results. 43 // original to complete and receives the same results.
28 // The return value shared indicates whether v was given to multiple callers. 44 // The return value shared indicates whether v was given to multiple callers.
29 func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa ce{}, err error, shared bool) { 45 func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interfa ce{}, err error, shared bool) {
30 g.mu.Lock() 46 g.mu.Lock()
31 if g.m == nil { 47 if g.m == nil {
32 g.m = make(map[string]*call) 48 g.m = make(map[string]*call)
33 } 49 }
34 if c, ok := g.m[key]; ok { 50 if c, ok := g.m[key]; ok {
35 c.dups++ 51 c.dups++
36 g.mu.Unlock() 52 g.mu.Unlock()
37 c.wg.Wait() 53 c.wg.Wait()
38 return c.val, c.err, true 54 return c.val, c.err, true
39 } 55 }
40 c := new(call) 56 c := new(call)
41 c.wg.Add(1) 57 c.wg.Add(1)
42 g.m[key] = c 58 g.m[key] = c
43 g.mu.Unlock() 59 g.mu.Unlock()
44 60
61 g.doCall(c, key, fn)
62 return c.val, c.err, c.dups > 0
63 }
64
65 // DoChan is like Do but returns a channel that will receive the
66 // results when they are ready.
67 func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
68 ch := make(chan singleflightResult, 1)
69 g.mu.Lock()
70 if g.m == nil {
71 g.m = make(map[string]*call)
72 }
73 if c, ok := g.m[key]; ok {
74 c.dups++
75 c.chans = append(c.chans, ch)
76 g.mu.Unlock()
77 return ch
78 }
79 c := &call{chans: []chan<- singleflightResult{ch}}
80 c.wg.Add(1)
81 g.m[key] = c
82 g.mu.Unlock()
83
84 go g.doCall(c, key, fn)
85
86 return ch
87 }
88
89 // doCall handles the single call for a key.
90 func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error )) {
45 c.val, c.err = fn() 91 c.val, c.err = fn()
46 c.wg.Done() 92 c.wg.Done()
47 93
48 g.mu.Lock() 94 g.mu.Lock()
49 delete(g.m, key) 95 delete(g.m, key)
96 for _, ch := range c.chans {
97 ch <- singleflightResult{c.val, c.err, c.dups > 0}
98 }
50 g.mu.Unlock() 99 g.mu.Unlock()
100 }
51 101
52 » return c.val, c.err, c.dups > 0 102 // Forget tells the singleflight to forget about a key. Future calls
103 // to Do for this key will call the function rather than waiting for
104 // an earlier call to complete.
105 func (g *singleflight) Forget(key string) {
106 » g.mu.Lock()
107 » delete(g.m, key)
108 » g.mu.Unlock()
53 } 109 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b