@@ -36,38 +36,44 @@ type Factory struct {
3636 handlerRegistrations map [string ]cache.ResourceEventHandlerRegistration
3737 ctx context.Context
3838 cancel context.CancelFunc
39+ // done is closed when the underlying informer.Run returns
40+ done chan struct {}
3941}
4042
4143type FactoryStore struct {
4244 mu sync.Mutex
43- data map [FactoryIndex ]Factory
45+ cond * sync.Cond
46+ data map [FactoryIndex ]* Factory
4447}
4548
4649func NewFactoryStore () * FactoryStore {
47- return & FactoryStore {
48- data : make (map [FactoryIndex ]Factory ),
50+ fs := & FactoryStore {
51+ data : make (map [FactoryIndex ]* Factory ),
4952 }
53+ fs .cond = sync .NewCond (& fs .mu )
54+ return fs
5055}
5156
5257func (c * FactoryStore ) Reset () {
5358 c .mu .Lock ()
5459 defer c .mu .Unlock ()
55- c .data = make (map [FactoryIndex ]Factory )
60+ c .data = make (map [FactoryIndex ]* Factory )
5661}
5762
5863func (c * FactoryStore ) add (index FactoryIndex , f dynamicinformer.DynamicSharedInformerFactory ) {
5964 ctx , cancel := context .WithCancel (context .Background ())
60- c .data [index ] = Factory {
65+ c .data [index ] = & Factory {
6166 shared : f ,
6267 handlerRegistrations : make (map [string ]cache.ResourceEventHandlerRegistration ),
6368 ctx : ctx ,
6469 cancel : cancel ,
70+ done : nil ,
6571 }
6672 log .Debug ("Factory store: added a new factory for index" ,
6773 slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
6874}
6975
70- func (c * FactoryStore ) get (client dynamic.Interface , index FactoryIndex ) Factory {
76+ func (c * FactoryStore ) get (client dynamic.Interface , index FactoryIndex ) * Factory {
7177 f , ok := c .data [index ]
7278 if ok {
7379 log .Debug ("Factory store: the factory with index found" ,
@@ -115,8 +121,18 @@ func (c *FactoryStore) Start(ctx context.Context, informerId string, client dyna
115121 slog .Int ("value" , len (factory .handlerRegistrations )),
116122 slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
117123
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+ }
134+
118135 if ! informer .HasSynced () {
119- go informer .Run (factory .ctx .Done ())
120136
121137 if err := wait .PollUntilContextCancel (ctx , DefaultSyncTime , true , func (_ context.Context ) (bool , error ) {
122138 return informer .HasSynced (), nil
@@ -131,11 +147,10 @@ func (c *FactoryStore) Start(ctx context.Context, informerId string, client dyna
131147
132148func (c * FactoryStore ) Stop (informerId string , index FactoryIndex ) {
133149 c .mu .Lock ()
134- defer c .mu .Unlock ()
135-
136150 f , ok := c .data [index ]
137151 if ! ok {
138152 // already deleted
153+ c .mu .Unlock ()
139154 return
140155 }
141156
@@ -152,10 +167,32 @@ func (c *FactoryStore) Stop(informerId string, index FactoryIndex) {
152167 slog .Int ("value" , len (f .handlerRegistrations )),
153168 slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
154169 if len (f .handlerRegistrations ) == 0 {
170+ log .Debug ("Factory store: last handler removed, canceling shared informer" ,
171+ slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
172+ done := f .done
155173 f .cancel ()
174+ c .mu .Unlock ()
175+ if done != nil {
176+ <- done
177+ }
178+ c .mu .Lock ()
156179 delete (c .data , index )
157180 log .Debug ("Factory store: deleted factory" ,
158181 slog .String ("namespace" , index .Namespace ), slog .String ("gvr" , index .GVR .String ()))
182+ c .cond .Broadcast ()
183+ }
184+ }
185+ c .mu .Unlock ()
186+ }
187+
188+ // WaitStopped blocks until there is no factory for the index
189+ func (c * FactoryStore ) WaitStopped (index FactoryIndex ) {
190+ c .mu .Lock ()
191+ for {
192+ if _ , ok := c .data [index ]; ! ok {
193+ c .mu .Unlock ()
194+ return
159195 }
196+ c .cond .Wait ()
160197 }
161198}
0 commit comments