master
h 312 lines 13.1 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_RRDDIM_H
4 #define NETDATA_RRDDIM_H
5
6 #include "libnetdata/libnetdata.h"
7 #include "rrd-algorithm.h"
8
9 typedef struct rrddim RRDDIM;
10 typedef struct rrddim_acquired RRDDIM_ACQUIRED;
11 typedef struct ml_dimension rrd_ml_dimension_t;
12 typedef struct rrdmetric_acquired RRDMETRIC_ACQUIRED;
13
14 // gcc with libstdc++ may require this,
15 // but with libc++ it does not work correctly.
16 #if defined(__cplusplus) && !defined(_LIBCPP_VERSION)
17 #include <cmath>
18 using std::isnan;
19 #endif
20
21 #include "rrdset.h"
22
23 // options are permanent configuration options (no atomics to alter/access them)
24 typedef enum __attribute__ ((__packed__)) rrddim_options {
25 RRDDIM_OPTION_NONE = 0,
26 RRDDIM_OPTION_HIDDEN = (1 << 0), // this dimension will not be offered to callers
27 RRDDIM_OPTION_DONT_DETECT_RESETS_OR_OVERFLOWS = (1 << 1), // do not offer RESET or OVERFLOW info to callers
28 RRDDIM_OPTION_BACKFILLED_HIGH_TIERS = (1 << 2), // when set, we have backfilled higher tiers
29 RRDDIM_OPTION_UPDATED = (1 << 3), // single-threaded collector updated flag
30 RRDDIM_OPTION_VALUE_FLOAT = (1 << 4), // collected_value lane should be treated as float
31
32 // this is 8-bit
33 } RRDDIM_OPTIONS;
34
35 #define rrddim_option_check(rd, option) ((rd)->collector.options & (option))
36 #define rrddim_option_set(rd, option) (rd)->collector.options |= (option)
37 #define rrddim_option_clear(rd, option) (rd)->collector.options &= ~(option)
38 #define rrddim_is_float(rd) ((rd)->collector.options & RRDDIM_OPTION_VALUE_FLOAT)
39 #define rrddim_is_int(rd) (!rrddim_is_float(rd))
40
41 // flags are runtime changing status flags (atomics are required to alter/access them)
42 typedef enum __attribute__ ((__packed__)) rrddim_flags {
43 RRDDIM_FLAG_NONE = 0,
44
45 RRDDIM_FLAG_OBSOLETE = (1 << 0), // this is marked by the collector/module as obsolete
46 // No new values have been collected for this dimension since agent start, or it was marked RRDDIM_FLAG_OBSOLETE at
47 // least rrdset_free_obsolete_time seconds ago.
48
49 RRDDIM_FLAG_METADATA_UPDATE = (1 << 1), // Metadata needs to go to the database
50
51 RRDDIM_FLAG_META_HIDDEN = (1 << 2), // Status of hidden option in the metadata database
52 RRDDIM_FLAG_ML_MODEL_LOAD = (1 << 3), // Do ML LOAD for this dimension
53
54 // this is 8 bit
55 } RRDDIM_FLAGS;
56
57 #define rrddim_flag_get(rd) atomic_flags_get(&((rd)->flags))
58 #define rrddim_flag_check(rd, flag) atomic_flags_check(&((rd)->flags), flag)
59 #define rrddim_flag_set(rd, flag) atomic_flags_set(&((rd)->flags), flag)
60 #define rrddim_flag_clear(rd, flag) atomic_flags_clear(&((rd)->flags), flag)
61 #define rrddim_flag_set_and_clear(rd, set, clear) atomic_flags_set_and_clear(&((rd)->flags), set, clear)
62
63 struct rrddim {
64 UUIDMAP_ID uuid;
65
66 // ------------------------------------------------------------------------
67 // dimension definition
68
69 STRING *id; // the id of this dimension (for internal identification)
70 STRING *name; // the name of this dimension (as presented to user)
71
72 RRD_ALGORITHM algorithm; // the algorithm that is applied to add new collected values
73 RRD_DB_MODE rrd_memory_mode; // the memory mode for this dimension
74 RRDDIM_FLAGS flags; // run time changing status flags
75
76 SPINLOCK destroy_lock;
77 int32_t multiplier; // the multiplier of the collected values
78 int32_t divisor; // the divider of the collected values
79
80 // ------------------------------------------------------------------------
81 // operational state members
82
83 struct rrdset *rrdset;
84 rrd_ml_dimension_t *ml_dimension; // machine learning data about this dimension
85
86 struct {
87 RRDMETRIC_ACQUIRED *rrdmetric; // the rrdmetric of this dimension
88 bool collected;
89 } rrdcontexts;
90
91 #ifdef NETDATA_LOG_COLLECTION_ERRORS
92 usec_t rrddim_store_metric_last_ut; // the timestamp we last called rrddim_store_metric()
93 size_t rrddim_store_metric_count; // the rrddim_store_metric() counter
94 const char *rrddim_store_metric_last_caller; // the name of the function that last called rrddim_store_metric()
95 #endif
96
97 // ------------------------------------------------------------------------
98 // db mode RAM, ALLOC, NONE specifics
99 // TODO - they should be managed by storage engine
100 // (RRDDIM_DB_STATE ptr to an undefined structure, and a call to clean this up during destruction)
101
102 struct {
103 size_t memsize; // the memory allocated for this dimension (without RRDDIM)
104 storage_number *data; // the array of values
105 } db;
106
107 // ------------------------------------------------------------------------
108 // streaming
109
110 struct {
111 struct {
112 uint32_t sent_version;
113 uint32_t dim_slot;
114 } snd;
115 } stream;
116
117 // ------------------------------------------------------------------------
118 // data collection members
119
120 struct {
121 RRDDIM_OPTIONS options; // permanent configuration options
122
123 uint32_t counter; // the number of times we added values to this rrddim
124
125 union {
126 struct {
127 collected_number collected_value; // legacy int lane
128 collected_number collected_value_max; // legacy int lane
129 collected_number last_collected_value; // legacy int lane
130 } i;
131 struct {
132 NETDATA_DOUBLE collected_value;
133 NETDATA_DOUBLE collected_value_max;
134 NETDATA_DOUBLE last_collected_value;
135 } f;
136 } collected; // type-aware storage (option bit selects lane)
137
138 struct timeval last_collected_time; // when was this dimension last updated
139 // this is actual date time we updated the last_collected_value
140 // THIS IS DIFFERENT FROM THE SAME MEMBER OF RRDSET
141
142 NETDATA_DOUBLE calculated_value; // the current calculated value, after applying the algorithm - resets to zero after being used
143 NETDATA_DOUBLE last_calculated_value; // the last calculated value processed
144
145 NETDATA_DOUBLE last_stored_value; // the last value as stored in the database (after interpolation)
146 } collector;
147
148 // ------------------------------------------------------------------------
149
150 struct rrddim_tier tiers[]; // our tiers of databases
151 };
152
153 size_t rrddim_size(void);
154
155 #define rrddim_id(rd) string2str((rd)->id)
156 #define rrddim_name(rd) string2str((rd) ->name)
157
158 #define rrddim_check_updated(rd) ((rd)->collector.options & RRDDIM_OPTION_UPDATED)
159 #define rrddim_set_updated(rd) (rd)->collector.options |= RRDDIM_OPTION_UPDATED
160 #define rrddim_clear_updated(rd) (rd)->collector.options &= ~RRDDIM_OPTION_UPDATED
161
162 #define rrddim_foreach_read(rd, st) \
163 dfe_start_read((st)->rrddim_root_index, rd)
164
165 #define rrddim_foreach_done(rd) \
166 dfe_done(rd)
167
168 struct pluginsd_rrddim {
169 RRDDIM_ACQUIRED *rda;
170 RRDDIM *rd;
171 const char *id;
172 };
173
174 static inline uint32_t rrddim_metadata_version(RRDDIM *rd) {
175 // the metadata version of the dimension, is the version of the chart
176 return rrdset_metadata_version(rd->rrdset);
177 }
178
179 static inline uint32_t rrddim_metadata_upstream_version(RRDDIM *rd) {
180 return __atomic_load_n(&rd->stream.snd.sent_version, __ATOMIC_RELAXED);
181 }
182
183 void rrddim_metadata_updated(RRDDIM *rd);
184
185 static inline void rrddim_metadata_exposed_upstream(RRDDIM *rd, uint32_t version) {
186 __atomic_store_n(&rd->stream.snd.sent_version, version, __ATOMIC_RELAXED);
187 }
188
189 static inline void rrddim_metadata_exposed_upstream_clear(RRDDIM *rd) {
190 __atomic_store_n(&rd->stream.snd.sent_version, 0, __ATOMIC_RELAXED);
191 }
192
193 static inline bool rrddim_check_upstream_exposed(RRDDIM *rd) {
194 return rrddim_metadata_upstream_version(rd) != 0;
195 }
196
197 // the collector sets the exposed flag, but anyone can remove it
198 // still, it can be removed, after the collector has finished
199 // so, it is safe to check it without atomics
200 static inline bool rrddim_check_upstream_exposed_collector(RRDDIM *rd) {
201 return rd->rrdset->version == rd->stream.snd.sent_version;
202 }
203
204 // ------------------------------------------------------------------------
205 // Type-aware accessors (Phase 1: int-only behavior preserved)
206
207 static inline void rrddim_set_collected_int(RRDDIM *rd, int64_t v) {
208 rd->collector.collected.i.collected_value = (collected_number)v;
209 }
210
211 static inline void rrddim_set_collected_float(RRDDIM *rd, NETDATA_DOUBLE v) {
212 rd->collector.collected.f.collected_value = v;
213 }
214
215 static inline void rrddim_set_collected_max_int(RRDDIM *rd, int64_t v) {
216 rd->collector.collected.i.collected_value_max = (collected_number)v;
217 }
218
219 static inline void rrddim_set_collected_max_float(RRDDIM *rd, NETDATA_DOUBLE v) {
220 rd->collector.collected.f.collected_value_max = v;
221 }
222
223 static inline void rrddim_set_last_collected_int(RRDDIM *rd, int64_t v) {
224 rd->collector.collected.i.last_collected_value = (collected_number)v;
225 }
226
227 static inline void rrddim_set_last_collected_float(RRDDIM *rd, NETDATA_DOUBLE v) {
228 rd->collector.collected.f.last_collected_value = v;
229 }
230
231 static inline NETDATA_DOUBLE rrddim_collected_as_double(RRDDIM *rd) {
232 return rrddim_is_float(rd) ? rd->collector.collected.f.collected_value
233 : (NETDATA_DOUBLE)rd->collector.collected.i.collected_value;
234 }
235
236 static inline NETDATA_DOUBLE rrddim_last_collected_as_double(RRDDIM *rd) {
237 return rrddim_is_float(rd) ? rd->collector.collected.f.last_collected_value
238 : (NETDATA_DOUBLE)rd->collector.collected.i.last_collected_value;
239 }
240
241 static inline NETDATA_DOUBLE rrddim_collected_max_as_double(RRDDIM *rd) {
242 return rrddim_is_float(rd) ? rd->collector.collected.f.collected_value_max
243 : (NETDATA_DOUBLE)rd->collector.collected.i.collected_value_max;
244 }
245
246 static inline int64_t rrddim_last_collected_raw_int(RRDDIM *rd) {
247 return rrddim_is_float(rd) ? (int64_t)rd->collector.collected.f.last_collected_value
248 : (int64_t)rd->collector.collected.i.last_collected_value;
249 }
250
251 void rrddim_index_init(RRDSET *st);
252 void rrddim_index_destroy(RRDSET *st);
253
254 time_t rrddim_first_entry_s(RRDDIM *rd);
255 time_t rrddim_first_entry_s_of_tier(RRDDIM *rd, size_t tier);
256 time_t rrddim_last_entry_s(RRDDIM *rd);
257 time_t rrddim_last_entry_s_of_tier(RRDDIM *rd, size_t tier);
258
259 RRDDIM *rrddim_add_custom(RRDSET *st
260 , const char *id
261 , const char *name
262 , collected_number multiplier
263 , collected_number divisor
264 , RRD_ALGORITHM algorithm
265 , RRD_DB_MODE memory_mode
266 );
267
268 #define rrddim_add(st, id, name, multiplier, divisor, algorithm) \
269 rrddim_add_custom(st, id, name, multiplier, divisor, algorithm, (st)->rrd_memory_mode)
270
271 int rrddim_reset_name(RRDSET *st, RRDDIM *rd, const char *name);
272 int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm);
273 int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, int32_t multiplier);
274 int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, int32_t divisor);
275
276 RRDDIM *rrddim_find(RRDSET *st, const char *id, bool include_obsolete);
277 RRDDIM_ACQUIRED *rrddim_find_and_acquire(RRDSET *st, const char *id, bool include_obsolete);
278 RRDDIM *rrddim_acquired_to_rrddim(RRDDIM_ACQUIRED *rda);
279 void rrddim_acquired_release(RRDDIM_ACQUIRED *rda);
280 #define rrddim_find_active(st, id) rrddim_find(st, id, false)
281
282 int rrddim_hide(RRDSET *st, const char *id);
283 int rrddim_unhide(RRDSET *st, const char *id);
284
285 void rrddim_is_obsolete___safe_from_collector_thread(RRDSET *st, RRDDIM *rd);
286 void rrddim_isnot_obsolete___safe_from_collector_thread(RRDSET *st, RRDDIM *rd);
287
288 collected_number rrddim_timed_set_by_pointer(RRDSET *st, RRDDIM *rd, struct timeval collected_time, collected_number value);
289 collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
290 NETDATA_DOUBLE rrddim_set_by_pointer_double(RRDSET *st, RRDDIM *rd, NETDATA_DOUBLE value);
291 collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
292
293 bool rrddim_finalize_collection_and_check_retention(RRDDIM *rd);
294
295 void rrddim_free(RRDSET *st, RRDDIM *rd);
296
297 static inline double rrddim_get_last_stored_value(RRDDIM *rd_dim, double *max_value, double div) {
298 if (!rd_dim)
299 return NAN;
300
301 if (isnan(div) || div == 0.0)
302 div = 1.0;
303
304 double value = rd_dim->collector.last_stored_value / div;
305 value = ABS(value);
306
307 *max_value = MAX(*max_value, value);
308
309 return value;
310 }
311
312 #endif //NETDATA_RRDDIM_H