func (c *Channel) write(pkt *lob.Packet, p *Pipe) error { if pkt.TID == 0 { pkt.TID = tracer.NewID() } if c.broken { // When a channel is marked as broken the all writes // must return a BrokenChannelError. return c.traceWriteError(pkt, p, &BrokenChannelError{c.hashname, c.typ, c.id}) } if c.writeDeadlineReached { // When a channel reached a write deadline then all writes // must return a ErrTimeout. return c.traceWriteError(pkt, p, ErrTimeout) } if c.deliveredEnd { // When a channel sent a packet with the "end" header set // then all subsequent writes must return io.EOF return c.traceWriteError(pkt, p, io.EOF) } c.oSeq++ hdr := pkt.Header() hdr.C, hdr.HasC = c.id, true if c.reliable { hdr.Seq, hdr.HasSeq = c.oSeq, true } if !c.serverside && c.oSeq == cInitialSeq { hdr.Type, hdr.HasType = c.typ, true } end := hdr.HasEnd && hdr.End if end { c.deliveredEnd = true c.setCloseDeadline() } if c.reliable { if c.oSeq%30 == 0 || hdr.End { c.applyAckHeaders(pkt) } c.writeBuffer[c.oSeq] = &writeBufferEntry{pkt, end, time.Time{}, p} c.needsResend = false } err := c.x.deliverPacket(pkt, p) if err != nil { return c.traceWriteError(pkt, p, err) } statChannelSndPkt.Add(1) if pkt.Header().HasAck { statChannelSndAckInline.Add(1) } if c.oSeq == cInitialSeq && c.serverside { c.unsetOpenDeadline() } c.traceWrite(pkt, p) if !c.reliable { pkt.Free() } return nil }
func BenchmarkReadWriteUnreliable(b *testing.B) { defer dumpExpVar(b) logs.ResetLogger() withTwoEndpoints(b, func(A, B *Endpoint) { A.setOptions(DisableLog()) B.setOptions(DisableLog()) var ( c *Channel ident *Identity pkt *lob.Packet err error body = bytes.Repeat([]byte{'x'}, 1300) ) b.SetBytes(int64(len(body))) b.ResetTimer() go func() { c, err := A.Listen("flood", false).AcceptChannel() if err != nil { b.Fatal(err) } defer c.Close() pkt, err = c.ReadPacket() if err != nil { b.Fatal(err) } for i := 0; i < b.N; i++ { pkt := lob.New(body) err = c.WritePacket(pkt) if err != nil { b.Fatal(err) } // Give the other go routines some room to breath when GOMAXPROCS=1 runtime.Gosched() } }() ident, err = A.LocalIdentity() if err != nil { b.Fatal(err) } c, err = B.Open(ident, "flood", false) if err != nil { b.Fatal(err) } defer c.Close() err = c.WritePacket(lob.New(nil)) if err != nil { b.Fatal(err) } for { pkt, err = c.ReadPacket() if err == io.EOF { break } if err != nil { b.Fatal(err) } pkt.Free() } b.StopTimer() }) }