1
2
3
4
5 package main
6
7 import (
8 "os"
9 "runtime"
10 "runtime/pprof"
11 "sync"
12 "time"
13 )
14
15
16
17
18
19
20 func init() {
21 register("Grpc3017", Grpc3017)
22 }
23
24 type Address_grpc3017 int
25 type SubConn_grpc3017 int
26
27 type subConnCacheEntry_grpc3017 struct {
28 sc SubConn_grpc3017
29 cancel func()
30 abortDeleting bool
31 }
32
33 type lbCacheClientConn_grpc3017 struct {
34 mu sync.Mutex
35 timeout time.Duration
36 subConnCache map[Address_grpc3017]*subConnCacheEntry_grpc3017
37 subConnToAddr map[SubConn_grpc3017]Address_grpc3017
38 }
39
40 func (ccc *lbCacheClientConn_grpc3017) NewSubConn(addrs []Address_grpc3017) SubConn_grpc3017 {
41 if len(addrs) != 1 {
42 return SubConn_grpc3017(1)
43 }
44 addrWithoutMD := addrs[0]
45 ccc.mu.Lock()
46 defer ccc.mu.Unlock()
47 if entry, ok := ccc.subConnCache[addrWithoutMD]; ok {
48 entry.cancel()
49 delete(ccc.subConnCache, addrWithoutMD)
50 return entry.sc
51 }
52 scNew := SubConn_grpc3017(1)
53 ccc.subConnToAddr[scNew] = addrWithoutMD
54 return scNew
55 }
56
57 func (ccc *lbCacheClientConn_grpc3017) RemoveSubConn(sc SubConn_grpc3017) {
58 ccc.mu.Lock()
59 defer ccc.mu.Unlock()
60 addr, ok := ccc.subConnToAddr[sc]
61 if !ok {
62 return
63 }
64
65 if entry, ok := ccc.subConnCache[addr]; ok {
66 if entry.sc != sc {
67 delete(ccc.subConnToAddr, sc)
68 }
69 return
70 }
71
72 entry := &subConnCacheEntry_grpc3017{
73 sc: sc,
74 }
75 ccc.subConnCache[addr] = entry
76
77 timer := time.AfterFunc(ccc.timeout, func() {
78 runtime.Gosched()
79 ccc.mu.Lock()
80 if entry.abortDeleting {
81 return
82 }
83 delete(ccc.subConnToAddr, sc)
84 delete(ccc.subConnCache, addr)
85 ccc.mu.Unlock()
86 })
87
88 entry.cancel = func() {
89 if !timer.Stop() {
90 entry.abortDeleting = true
91 }
92 }
93 }
94
95 func Grpc3017() {
96 prof := pprof.Lookup("goroutineleak")
97 defer func() {
98 time.Sleep(100 * time.Millisecond)
99 prof.WriteTo(os.Stdout, 2)
100 }()
101
102 for i := 0; i < 100; i++ {
103 go func() {
104 done := make(chan struct{})
105
106 ccc := &lbCacheClientConn_grpc3017{
107 timeout: time.Nanosecond,
108 subConnCache: make(map[Address_grpc3017]*subConnCacheEntry_grpc3017),
109 subConnToAddr: make(map[SubConn_grpc3017]Address_grpc3017),
110 }
111
112 sc := ccc.NewSubConn([]Address_grpc3017{Address_grpc3017(1)})
113 go func() {
114 for i := 0; i < 10000; i++ {
115 ccc.RemoveSubConn(sc)
116 sc = ccc.NewSubConn([]Address_grpc3017{Address_grpc3017(1)})
117 }
118 close(done)
119 }()
120 <-done
121 }()
122 }
123 }
124
View as plain text