multiconn: map + close on children close
Juan Batiz-Benet committed
Oct 19, 2014 at 04:01 UTC
58fdcad971d4a029ec5fefa51c26d1e464583674
3 files changed
+39
-2
net/conn/multiconn.go
+8
@@ -10,6 +10,9 @@ import (
10
u "github.com/jbenet/go-ipfs/util"
11
)
12
13
+// MultiConnMap is for shorthand
14
+type MultiConnMap map[u.Key]*MultiConn
15
+
16
// Duplex is a simple duplex channel
17
type Duplex struct {
18
In chan []byte
@@ -160,10 +163,15 @@ func (c *MultiConn) fanInSingle(child Conn) {
163
// in case it still is in the map, remove it.
164
c.Lock()
165
delete(c.conns, child.ID())
166
+ connLen := len(c.conns)
167
c.Unlock()
168
169
c.Children().Done()
170
child.Children().Done()
171
+
172
+ if connLen == 0 {
173
+ c.Close() // close self if all underlying children are gone?
174
+ }
175
}()
176
177
for {
net/conn/multiconn_test.go
+29
@@ -293,3 +293,32 @@ func TestMulticonnSendUnderlying(t *testing.T) {
293
msgsFrom1.CheckDone(t)
294
msgsFrom2.CheckDone(t)
295
}
296
+
297
+func TestMulticonnClose(t *testing.T) {
298
+ // t.Skip("fooo")
299
+
300
+ log.Info("TestMulticonnSendUnderlying")
301
+ ctx := context.Background()
302
+ c1, c2 := setupMultiConns(t, ctx)
303
+
304
+ for _, c := range c1.conns {
305
+ c.Close()
306
+ }
307
+
308
+ for _, c := range c2.conns {
309
+ c.Close()
310
+ }
311
+
312
+ timeout := time.After(100 * time.Millisecond)
313
+ select {
314
+ case <-c1.Closed():
315
+ case <-timeout:
316
+ t.Fatal("timeout")
317
+ }
318
+
319
+ select {
320
+ case <-c2.Closed():
321
+ case <-timeout:
322
+ t.Fatal("timeout")
323
+ }
324
+}
net/conn/secure_conn_test.go
+2
-2
@@ -50,7 +50,7 @@ func TestSecureClose(t *testing.T) {
50
select {
51
case <-c1.Closed():
52
default:
53
- t.Fatal("not done after cancel")
53
+ t.Fatal("not done after close")
54
}
55
56
c2.Close()
@@ -58,7 +58,7 @@ func TestSecureClose(t *testing.T) {
58
select {
59
case <-c2.Closed():
60
default:
61
- t.Fatal("not done after cancel")
61
+ t.Fatal("not done after close")
62
}
63
64
cancel() // close the listener :P