@@ -36,38 +36,44 @@ type Factory struct {
36
36
handlerRegistrations map [string ]cache.ResourceEventHandlerRegistration
37
37
ctx context.Context
38
38
cancel context.CancelFunc
39
+ // done is closed when the underlying informer.Run returns
40
+ done chan struct {}
39
41
}
40
42
41
43
type FactoryStore struct {
42
44
mu sync.Mutex
43
- data map [FactoryIndex ]Factory
45
+ cond * sync.Cond
46
+ data map [FactoryIndex ]* Factory
44
47
}
45
48
46
49
func NewFactoryStore () * FactoryStore {
47
- return & FactoryStore {
48
- data : make (map [FactoryIndex ]Factory ),
50
+ fs := & FactoryStore {
51
+ data : make (map [FactoryIndex ]* Factory ),
49
52
}
53
+ fs .cond = sync .NewCond (& fs .mu )
54
+ return fs
50
55
}
51
56
52
57
func (c * FactoryStore ) Reset () {
53
58
c .mu .Lock ()
54
59
defer c .mu .Unlock ()
55
- c .data = make (map [FactoryIndex ]Factory )
60
+ c .data = make (map [FactoryIndex ]* Factory )
56
61
}
57
62
58
63
func (c * FactoryStore ) add (index FactoryIndex , f dynamicinformer.DynamicSharedInformerFactory ) {
59
64
ctx , cancel := context .WithCancel (context .Background ())
60
- c .data [index ] = Factory {
65
+ c .data [index ] = & Factory {
61
66
shared : f ,
62
67
handlerRegistrations : make (map [string ]cache.ResourceEventHandlerRegistration ),
63
68
ctx : ctx ,
64
69
cancel : cancel ,
70
+ done : nil ,
65
71
}
66
72
log .Debug ("Factory store: added a new factory for index" ,
67
73
slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
68
74
}
69
75
70
- func (c * FactoryStore ) get (client dynamic.Interface , index FactoryIndex ) Factory {
76
+ func (c * FactoryStore ) get (client dynamic.Interface , index FactoryIndex ) * Factory {
71
77
f , ok := c .data [index ]
72
78
if ok {
73
79
log .Debug ("Factory store: the factory with index found" ,
@@ -115,9 +121,18 @@ func (c *FactoryStore) Start(ctx context.Context, informerId string, client dyna
115
121
slog .Int ("value" , len (factory .handlerRegistrations )),
116
122
slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
117
123
118
- if ! informer .HasSynced () {
119
- go informer .Run (factory .ctx .Done ())
124
+ // Ensure informer.Run is started once and tracked
125
+ if factory .done == nil {
126
+ factory .done = make (chan struct {})
127
+ go func () {
128
+ informer .Run (factory .ctx .Done ())
129
+ close (factory .done )
130
+ log .Debug ("Factory store: informer goroutine exited" ,
131
+ slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
132
+ }()
133
+ }
120
134
135
+ if ! informer .HasSynced () {
121
136
if err := wait .PollUntilContextCancel (ctx , DefaultSyncTime , true , func (_ context.Context ) (bool , error ) {
122
137
return informer .HasSynced (), nil
123
138
}); err != nil {
@@ -131,11 +146,10 @@ func (c *FactoryStore) Start(ctx context.Context, informerId string, client dyna
131
146
132
147
func (c * FactoryStore ) Stop (informerId string , index FactoryIndex ) {
133
148
c .mu .Lock ()
134
- defer c .mu .Unlock ()
135
-
136
149
f , ok := c .data [index ]
137
150
if ! ok {
138
151
// already deleted
152
+ c .mu .Unlock ()
139
153
return
140
154
}
141
155
@@ -152,10 +166,32 @@ func (c *FactoryStore) Stop(informerId string, index FactoryIndex) {
152
166
slog .Int ("value" , len (f .handlerRegistrations )),
153
167
slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
154
168
if len (f .handlerRegistrations ) == 0 {
169
+ log .Debug ("Factory store: last handler removed, canceling shared informer" ,
170
+ slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
171
+ done := f .done
155
172
f .cancel ()
173
+ c .mu .Unlock ()
174
+ if done != nil {
175
+ <- done
176
+ }
177
+ c .mu .Lock ()
156
178
delete (c .data , index )
157
179
log .Debug ("Factory store: deleted factory" ,
158
180
slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
181
+ c .cond .Broadcast ()
182
+ }
183
+ }
184
+ c .mu .Unlock ()
185
+ }
186
+
187
+ // WaitStopped blocks until there is no factory for the index
188
+ func (c * FactoryStore ) WaitStopped (index FactoryIndex ) {
189
+ c .mu .Lock ()
190
+ for {
191
+ if _ , ok := c .data [index ]; ! ok {
192
+ c .mu .Unlock ()
193
+ return
159
194
}
195
+ c .cond .Wait ()
160
196
}
161
197
}
0 commit comments