@@ -2,66 +2,104 @@ package subscribers
2
2
3
3
import (
4
4
"context"
5
+ "math"
6
+ "sync"
7
+ "sync/atomic"
5
8
6
9
"github.com/jjeffcaii/reactor-go"
7
10
"github.com/jjeffcaii/reactor-go/hooks"
8
11
)
9
12
10
- type blockSubscriber struct {
11
- done chan struct {}
12
- c chan <- reactor.Item
13
+ var globalBlockSubscriberPool blockSubscriberPool
14
+
15
+ func BorrowBlockSubscriber () * BlockSubscriber {
16
+ return globalBlockSubscriberPool .get ()
17
+ }
18
+
19
+ func ReturnBlockSubscriber (s * BlockSubscriber ) {
20
+ globalBlockSubscriberPool .put (s )
21
+ }
22
+
23
+ type blockSubscriberPool struct {
24
+ inner sync.Pool
25
+ }
26
+
27
+ func (bp * blockSubscriberPool ) get () * BlockSubscriber {
28
+ if exist , _ := bp .inner .Get ().(* BlockSubscriber ); exist != nil {
29
+ atomic .StoreInt32 (& exist .done , 0 )
30
+ return exist
31
+ }
32
+ return & BlockSubscriber {
33
+ doneChan : make (chan struct {}, 1 ),
34
+ }
13
35
}
14
36
15
- func NewBlockSubscriber (done chan struct {}, c chan reactor.Item ) reactor.Subscriber {
16
- return blockSubscriber {
17
- done : done ,
18
- c : c ,
37
+ func (bp * blockSubscriberPool ) put (s * BlockSubscriber ) {
38
+ if s == nil {
39
+ return
19
40
}
41
+ s .Reset ()
42
+ bp .inner .Put (s )
20
43
}
21
44
22
- func (b blockSubscriber ) OnComplete () {
23
- select {
24
- case <- b .done :
25
- default :
26
- close (b .done )
45
+ type BlockSubscriber struct {
46
+ reactor.Item
47
+ doneChan chan struct {}
48
+ ctxChan chan struct {}
49
+ done int32
50
+ }
51
+
52
+ func (b * BlockSubscriber ) Reset () {
53
+ b .V = nil
54
+ b .E = nil
55
+ b .ctxChan = nil
56
+ atomic .StoreInt32 (& b .done , math .MinInt32 )
57
+ }
58
+
59
+ func (b * BlockSubscriber ) Done () <- chan struct {} {
60
+ return b .doneChan
61
+ }
62
+
63
+ func (b * BlockSubscriber ) OnComplete () {
64
+ if atomic .CompareAndSwapInt32 (& b .done , 0 , 1 ) {
65
+ b .finish ()
27
66
}
28
67
}
29
68
30
- func (b blockSubscriber ) OnError (err error ) {
31
- select {
32
- case <- b .done :
69
+ func (b * BlockSubscriber ) OnError (err error ) {
70
+ if ! atomic .CompareAndSwapInt32 (& b .done , 0 , 1 ) {
33
71
hooks .Global ().OnErrorDrop (err )
34
- default :
35
- select {
36
- case b .c <- reactor.Item {E : err }:
37
- default :
38
- hooks .Global ().OnErrorDrop (err )
39
- }
40
- close (b .done )
72
+ return
73
+ }
74
+ b .E = err
75
+ b .finish ()
76
+ }
77
+
78
+ func (b * BlockSubscriber ) finish () {
79
+ if b .ctxChan != nil {
80
+ close (b .ctxChan )
41
81
}
82
+ b .doneChan <- struct {}{}
42
83
}
43
84
44
- func (b blockSubscriber ) OnNext (any reactor.Any ) {
45
- select {
46
- case <- b .done :
85
+ func (b * BlockSubscriber ) OnNext (any reactor.Any ) {
86
+ if atomic .LoadInt32 (& b .done ) != 0 || b .V != nil || b .E != nil {
47
87
hooks .Global ().OnNextDrop (any )
48
- default :
49
- select {
50
- case b .c <- reactor.Item {V : any }:
51
- default :
52
- hooks .Global ().OnNextDrop (any )
53
- }
88
+ return
54
89
}
90
+ b .V = any
55
91
}
56
92
57
- func (b blockSubscriber ) OnSubscribe (ctx context.Context , subscription reactor.Subscription ) {
93
+ func (b * BlockSubscriber ) OnSubscribe (ctx context.Context , subscription reactor.Subscription ) {
58
94
// workaround: watch context
59
95
if ctx != context .Background () && ctx != context .TODO () {
96
+ ctxChan := make (chan struct {})
97
+ b .ctxChan = ctxChan
60
98
go func () {
61
99
select {
62
100
case <- ctx .Done ():
63
101
b .OnError (reactor .NewContextError (ctx .Err ()))
64
- case <- b . done :
102
+ case <- ctxChan :
65
103
}
66
104
}()
67
105
}
0 commit comments