@@ -16,7 +16,8 @@ import (
16
16
)
17
17
18
18
type dgramStream struct {
19
- ctx context.Context
19
+ cancel context.CancelFunc
20
+
20
21
lines chan <- * logline.LogLine
21
22
22
23
scheme string // Datagram scheme, either "unixgram" or "udp".
@@ -25,17 +26,15 @@ type dgramStream struct {
25
26
mu sync.RWMutex // protects following fields
26
27
completed bool // This pipestream is completed and can no longer be used.
27
28
lastReadTime time.Time // Last time a log line was read from this named pipe
28
-
29
- stopOnce sync.Once // Ensure stopChan only closed once.
30
- stopChan chan struct {} // Close to start graceful shutdown.
31
29
}
32
30
33
- func newDgramStream (ctx context.Context , wg * sync.WaitGroup , waker waker.Waker , scheme , address string , lines chan <- * logline.LogLine ) (LogStream , error ) {
31
+ func newDgramStream (ctx context.Context , wg * sync.WaitGroup , waker waker.Waker , scheme , address string , lines chan <- * logline.LogLine , oneShot OneShotMode ) (LogStream , error ) {
34
32
if address == "" {
35
33
return nil , ErrEmptySocketAddress
36
34
}
37
- ss := & dgramStream {ctx : ctx , scheme : scheme , address : address , lastReadTime : time .Now (), lines : lines , stopChan : make (chan struct {})}
38
- if err := ss .stream (ctx , wg , waker ); err != nil {
35
+ ctx , cancel := context .WithCancel (ctx )
36
+ ss := & dgramStream {cancel : cancel , scheme : scheme , address : address , lastReadTime : time .Now (), lines : lines }
37
+ if err := ss .stream (ctx , wg , waker , oneShot ); err != nil {
39
38
return nil , err
40
39
}
41
40
return ss , nil
@@ -50,22 +49,22 @@ func (ss *dgramStream) LastReadTime() time.Time {
50
49
// The read buffer size for datagrams.
51
50
const datagramReadBufferSize = 131072
52
51
53
- func (ss * dgramStream ) stream (ctx context.Context , wg * sync.WaitGroup , waker waker.Waker ) error {
52
+ func (ss * dgramStream ) stream (ctx context.Context , wg * sync.WaitGroup , waker waker.Waker , oneShot OneShotMode ) error {
54
53
c , err := net .ListenPacket (ss .scheme , ss .address )
55
54
if err != nil {
56
55
logErrors .Add (ss .address , 1 )
57
56
return err
58
57
}
59
- glog .V (2 ).Infof ("opened new datagram socket %v" , c )
58
+ glog .V (2 ).Infof ("stream(%s:%s): opened new datagram socket %v" , ss . scheme , ss . address , c )
60
59
b := make ([]byte , datagramReadBufferSize )
61
60
partial := bytes .NewBufferString ("" )
62
61
var total int
63
62
wg .Add (1 )
64
63
go func () {
65
64
defer wg .Done ()
66
65
defer func () {
67
- glog .V (2 ).Infof ("%v: read total %d bytes from %s " , c , total , ss .address )
68
- glog .V (2 ).Infof ("%v: closing connection" , c )
66
+ glog .V (2 ).Infof ("stream(%s:%s): read total %d bytes" , ss . scheme , ss .address , total )
67
+ glog .V (2 ).Infof ("stream(%s:%s): closing connection" , ss . scheme , ss . address )
69
68
err := c .Close ()
70
69
if err != nil {
71
70
logErrors .Add (ss .address , 1 )
@@ -83,15 +82,25 @@ func (ss *dgramStream) stream(ctx context.Context, wg *sync.WaitGroup, waker wak
83
82
84
83
for {
85
84
n , _ , err := c .ReadFrom (b )
86
- glog .V (2 ).Infof ("%v: read %d bytes, err is %v" , c , n , err )
85
+ glog .V (2 ).Infof ("stream(%s:%s): read %d bytes, err is %v" , ss . scheme , ss . address , n , err )
87
86
88
87
// This is a test-only trick that says if we've already put this
89
88
// logstream in graceful shutdown, then a zero-byte read is
90
89
// equivalent to an "EOF" in connection and file oriented streams.
91
90
if n == 0 {
91
+ if oneShot {
92
+ glog .V (2 ).Infof ("stream(%s:%s): exiting because zero byte read and one shot" , ss .scheme , ss .address )
93
+ if partial .Len () > 0 {
94
+ sendLine (ctx , ss .address , partial , ss .lines )
95
+ }
96
+ return
97
+ }
92
98
select {
93
- case <- ss .stopChan :
94
- glog .V (2 ).Infof ("%v: exiting because zero byte read after Stop" , c )
99
+ case <- ctx .Done ():
100
+ glog .V (2 ).Infof ("stream(%s:%s): exiting because zero byte read after cancellation" , ss .scheme , ss .address )
101
+ if partial .Len () > 0 {
102
+ sendLine (ctx , ss .address , partial , ss .lines )
103
+ }
95
104
return
96
105
default :
97
106
}
@@ -100,7 +109,7 @@ func (ss *dgramStream) stream(ctx context.Context, wg *sync.WaitGroup, waker wak
100
109
if n > 0 {
101
110
total += n
102
111
//nolint:contextcheck
103
- decodeAndSend (ss . ctx , ss .lines , ss .address , n , b [:n ], partial )
112
+ decodeAndSend (ctx , ss .lines , ss .address , n , b [:n ], partial )
104
113
ss .mu .Lock ()
105
114
ss .lastReadTime = time .Now ()
106
115
ss .mu .Unlock ()
@@ -110,28 +119,23 @@ func (ss *dgramStream) stream(ctx context.Context, wg *sync.WaitGroup, waker wak
110
119
if partial .Len () > 0 {
111
120
sendLine (ctx , ss .address , partial , ss .lines )
112
121
}
113
- glog .V (2 ).Infof ("%v: exiting, stream has error %s" , c , err )
122
+ glog .V (2 ).Infof ("stream(%s:%s): exiting, stream has error %s" , ss . scheme , ss . address , err )
114
123
return
115
124
}
116
125
117
126
// Yield and wait
118
- glog .V (2 ).Infof ("%v: waiting" , c )
127
+ glog .V (2 ).Infof ("stream(%s:%s): waiting" , ss . scheme , ss . address )
119
128
select {
120
- case <- ss . stopChan :
129
+ case <- ctx . Done () :
121
130
// We may have started waiting here when the stop signal
122
131
// arrives, but since that wait the file may have been
123
132
// written to. The file is not technically yet at EOF so
124
133
// we need to go back and try one more read. We'll exit
125
134
// the stream in the zero byte handler above.
126
- glog .V (2 ).Infof ("%v: Stopping after next zero byte read" , c )
127
- case <- ctx .Done ():
128
- // Exit immediately; a cancelled context will set an immediate
129
- // deadline on the next read which will cause us to exit then,
130
- // so don't bother going around the loop again.
131
- return
135
+ glog .V (2 ).Infof ("stream(%s:%s): Stopping after next zero byte read" , ss .scheme , ss .address )
132
136
case <- waker .Wake ():
133
137
// sleep until next Wake()
134
- glog .V (2 ).Infof ("%v: Wake received" , c )
138
+ glog .V (2 ).Infof ("stream(%s:%s): Wake received" , ss . scheme , ss . address )
135
139
}
136
140
}
137
141
}()
@@ -145,8 +149,6 @@ func (ss *dgramStream) IsComplete() bool {
145
149
}
146
150
147
151
func (ss * dgramStream ) Stop () {
148
- glog .V (2 ).Infof ("Stop received on datagram stream." )
149
- ss .stopOnce .Do (func () {
150
- close (ss .stopChan )
151
- })
152
+ glog .V (2 ).Infof ("stream(%s:%s): Stop received on datagram stream." , ss .scheme , ss .address )
153
+ ss .cancel ()
152
154
}
0 commit comments