master
go 298 lines 6.09 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package funcctl
4
5 import (
6 "sort"
7 "sync"
8
9 "github.com/netdata/netdata/go/plugins/pkg/funcapi"
10 "github.com/netdata/netdata/go/plugins/plugin/framework/collectorapi"
11 )
12
13 type moduleFuncRegistry struct {
14 mu sync.RWMutex
15 modules map[string]*moduleFunc
16 }
17
18 type moduleFunc struct {
19 creator collectorapi.Creator
20 methods []funcapi.MethodConfig
21 methodsByID map[string]funcapi.MethodConfig
22 jobs map[string]*jobEntry
23 nextGeneration uint64
24 jobMethods map[string][]funcapi.MethodConfig
25 }
26
27 type jobEntry struct {
28 job collectorapi.RuntimeJob
29 generation uint64
30 }
31
32 func newModuleFuncRegistry() *moduleFuncRegistry {
33 return &moduleFuncRegistry{
34 modules: make(map[string]*moduleFunc),
35 }
36 }
37
38 func (r *moduleFuncRegistry) registerModule(name string, creator collectorapi.Creator) {
39 r.mu.Lock()
40 defer r.mu.Unlock()
41
42 var methods []funcapi.MethodConfig
43 if creator.Methods != nil {
44 methods = creator.Methods()
45 }
46
47 r.modules[name] = &moduleFunc{
48 creator: creator,
49 methods: methods,
50 methodsByID: indexMethods(methods),
51 jobs: make(map[string]*jobEntry),
52 jobMethods: make(map[string][]funcapi.MethodConfig),
53 }
54 }
55
56 func indexMethods(methods []funcapi.MethodConfig) map[string]funcapi.MethodConfig {
57 if len(methods) == 0 {
58 return nil
59 }
60
61 idx := make(map[string]funcapi.MethodConfig, len(methods))
62 for _, method := range methods {
63 if method.ID == "" {
64 continue
65 }
66 idx[method.ID] = method
67 }
68 return idx
69 }
70
71 func (r *moduleFuncRegistry) addJob(moduleName, jobName string, job collectorapi.RuntimeJob) {
72 r.mu.Lock()
73 defer r.mu.Unlock()
74
75 module, ok := r.modules[moduleName]
76 if !ok {
77 return
78 }
79
80 module.nextGeneration++
81 newGen := module.nextGeneration
82 module.jobs[jobName] = &jobEntry{
83 job: job,
84 generation: newGen,
85 }
86 }
87
88 func (r *moduleFuncRegistry) removeJob(moduleName, jobName string) {
89 r.mu.Lock()
90 defer r.mu.Unlock()
91
92 if module, ok := r.modules[moduleName]; ok {
93 delete(module.jobs, jobName)
94 }
95 }
96
97 func (r *moduleFuncRegistry) getJobWithGeneration(moduleName, jobName string) (collectorapi.RuntimeJob, uint64) {
98 r.mu.RLock()
99 defer r.mu.RUnlock()
100
101 module, ok := r.modules[moduleName]
102 if !ok {
103 return nil, 0
104 }
105 entry, ok := module.jobs[jobName]
106 if !ok {
107 return nil, 0
108 }
109 return entry.job, entry.generation
110 }
111
112 func (r *moduleFuncRegistry) verifyJobGeneration(moduleName, jobName string, expectedGen uint64) bool {
113 r.mu.RLock()
114 defer r.mu.RUnlock()
115
116 module, ok := r.modules[moduleName]
117 if !ok {
118 return false
119 }
120 entry, ok := module.jobs[jobName]
121 if !ok {
122 return false
123 }
124 if !entry.job.IsRunning() {
125 return false
126 }
127 return entry.generation == expectedGen
128 }
129
130 func (r *moduleFuncRegistry) getMethod(moduleName, methodID string) (*funcapi.MethodConfig, bool) {
131 r.mu.RLock()
132 defer r.mu.RUnlock()
133
134 module, ok := r.modules[moduleName]
135 if !ok || module.methodsByID == nil {
136 return nil, false
137 }
138 cfg, ok := module.methodsByID[methodID]
139 if !ok {
140 return nil, false
141 }
142 return &cfg, true
143 }
144
145 func (r *moduleFuncRegistry) getMethods(moduleName string) []funcapi.MethodConfig {
146 r.mu.RLock()
147 defer r.mu.RUnlock()
148
149 module, ok := r.modules[moduleName]
150 if !ok {
151 return nil
152 }
153 return module.methods
154 }
155
156 func (r *moduleFuncRegistry) getJobNames(moduleName string) []string {
157 r.mu.RLock()
158 defer r.mu.RUnlock()
159
160 module, ok := r.modules[moduleName]
161 if !ok {
162 return nil
163 }
164
165 names := make([]string, 0, len(module.jobs))
166 for name := range module.jobs {
167 names = append(names, name)
168 }
169 sort.Strings(names)
170 return names
171 }
172
173 func (r *moduleFuncRegistry) getJob(moduleName, jobName string) (collectorapi.RuntimeJob, bool) {
174 r.mu.RLock()
175 defer r.mu.RUnlock()
176
177 module, ok := r.modules[moduleName]
178 if !ok {
179 return nil, false
180 }
181 entry, ok := module.jobs[jobName]
182 if !ok {
183 return nil, false
184 }
185 return entry.job, true
186 }
187
188 func (r *moduleFuncRegistry) getCreator(moduleName string) (collectorapi.Creator, bool) {
189 r.mu.RLock()
190 defer r.mu.RUnlock()
191
192 module, ok := r.modules[moduleName]
193 if !ok {
194 return collectorapi.Creator{}, false
195 }
196 return module.creator, true
197 }
198
199 func (r *moduleFuncRegistry) isModuleRegistered(moduleName string) bool {
200 r.mu.RLock()
201 defer r.mu.RUnlock()
202
203 _, ok := r.modules[moduleName]
204 return ok
205 }
206
207 func (r *moduleFuncRegistry) registerJobMethods(moduleName, jobName string, methods []funcapi.MethodConfig) {
208 r.mu.Lock()
209 defer r.mu.Unlock()
210
211 module, ok := r.modules[moduleName]
212 if !ok {
213 return
214 }
215 module.jobMethods[jobName] = methods
216 }
217
218 func (r *moduleFuncRegistry) unregisterJobMethods(moduleName, jobName string) {
219 r.mu.Lock()
220 defer r.mu.Unlock()
221
222 module, ok := r.modules[moduleName]
223 if !ok {
224 return
225 }
226 delete(module.jobMethods, jobName)
227 }
228
229 func (r *moduleFuncRegistry) getJobMethods(moduleName, jobName string) []funcapi.MethodConfig {
230 r.mu.RLock()
231 defer r.mu.RUnlock()
232
233 module, ok := r.modules[moduleName]
234 if !ok {
235 return nil
236 }
237 return module.jobMethods[jobName]
238 }
239
240 func (r *moduleFuncRegistry) getJobMethod(moduleName, jobName, methodID string) (*funcapi.MethodConfig, bool) {
241 r.mu.RLock()
242 defer r.mu.RUnlock()
243
244 module, ok := r.modules[moduleName]
245 if !ok {
246 return nil, false
247 }
248 methods, ok := module.jobMethods[jobName]
249 if !ok {
250 return nil, false
251 }
252 for i := range methods {
253 if methods[i].ID == methodID {
254 return &methods[i], true
255 }
256 }
257 return nil, false
258 }
259
260 func (r *moduleFuncRegistry) findMethodCollision(moduleName, jobName, methodID string) (string, bool) {
261 r.mu.RLock()
262 defer r.mu.RUnlock()
263
264 module, ok := r.modules[moduleName]
265 if !ok {
266 return "", false
267 }
268
269 if module.methodsByID != nil {
270 if _, exists := module.methodsByID[methodID]; exists {
271 return "static method", true
272 }
273 }
274
275 for ownerJob, methods := range module.jobMethods {
276 if ownerJob == jobName {
277 continue
278 }
279 for _, method := range methods {
280 if method.ID == methodID {
281 return "job method on " + ownerJob, true
282 }
283 }
284 }
285
286 return "", false
287 }
288
289 func (r *moduleFuncRegistry) snapshotCreators() map[string]collectorapi.Creator {
290 r.mu.RLock()
291 defer r.mu.RUnlock()
292
293 out := make(map[string]collectorapi.Creator, len(r.modules))
294 for name, module := range r.modules {
295 out[name] = module.creator
296 }
297 return out
298 }