1 /*- 2 * Copyright 2016 Vsevolod Stakhov 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #ifndef RRD_H_ 17 #define RRD_H_ 18 19 #include "config.h" 20 21 /** 22 * This file contains basic structure and functions to operate with round-robin databases 23 */ 24 25 #define RRD_COOKIE "RRD" 26 #define RRD_VERSION "0003" 27 #define RRD_FLOAT_COOKIE ((double)8.642135E130) 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 typedef union { 34 unsigned long lv; 35 double dv; 36 } rrd_value_t; 37 38 struct rrd_file_head { 39 /* Data Base Identification Section ** */ 40 gchar cookie[4]; /* RRD */ 41 gchar version[5]; /* version of the format */ 42 gdouble float_cookie; /* is it the correct double representation ? */ 43 44 /* Data Base Structure Definition **** */ 45 gulong ds_cnt; /* how many different ds provid input to the rrd */ 46 gulong rra_cnt; /* how many rras will be maintained in the rrd */ 47 gulong pdp_step; /* pdp interval in seconds */ 48 49 rrd_value_t par[10]; /* global parameters ... unused 50 at the moment */ 51 }; 52 53 enum rrd_dst_type { 54 RRD_DST_INVALID = -1, 55 RRD_DST_COUNTER = 0, /* data source types available */ 56 RRD_DST_ABSOLUTE, 57 RRD_DST_GAUGE, 58 RRD_DST_DERIVE, 59 RRD_DST_CDEF 60 }; 61 enum rrd_ds_param { 62 RRD_DS_mrhb_cnt = 0, /* minimum required heartbeat */ 63 RRD_DS_min_val, /* the processed input of a ds must */ 64 RRD_DS_max_val, /* be between max_val and min_val 65 * both can be set to UNKNOWN if you 66 * do not care. Data outside the limits 67 * set to UNKNOWN */ 68 RRD_DS_cdef = RRD_DS_mrhb_cnt 69 }; /* pointer to encoded rpn expression only applies to DST_CDEF */ 70 71 72 /* The magic number here is one less than DS_NAM_SIZE */ 73 #define RRD_DS_NAM_SIZE 20 74 75 #define RRD_DST_SIZE 20 76 77 struct rrd_ds_def { 78 gchar ds_nam[RRD_DS_NAM_SIZE]; /* Name of the data source (null terminated) */ 79 gchar dst[RRD_DST_SIZE]; /* Type of data source (null terminated) */ 80 rrd_value_t par[10]; /* index of this array see ds_param_en */ 81 }; 82 83 /* RRA definition */ 84 85 enum rrd_cf_type { 86 RRD_CF_INVALID = -1, 87 RRD_CF_AVERAGE = 0, /* data consolidation functions */ 88 RRD_CF_MINIMUM, 89 RRD_CF_MAXIMUM, 90 RRD_CF_LAST, 91 }; 92 93 94 #define MAX_RRA_PAR_EN 10 95 96 enum rrd_rra_param { 97 RRA_cdp_xff_val = 0, /* what part of the consolidated 98 * datapoint must be known, to produce a 99 * valid entry in the rra */ 100 }; 101 102 103 #define RRD_CF_NAM_SIZE 20 104 105 struct rrd_rra_def { 106 gchar cf_nam[RRD_CF_NAM_SIZE]; /* consolidation function (null term) */ 107 gulong row_cnt; /* number of entries in the store */ 108 gulong pdp_cnt; /* how many primary data points are 109 * required for a consolidated data point?*/ 110 rrd_value_t par[MAX_RRA_PAR_EN]; /* index see rra_param_en */ 111 112 }; 113 114 struct rrd_live_head { 115 time_t last_up; /* when was rrd last updated */ 116 glong last_up_usec; /* micro seconds part of the update timestamp. Always >= 0 */ 117 }; 118 119 #define RRD_LAST_DS_LEN 30 120 121 enum rrd_pdp_param { 122 PDP_unkn_sec_cnt = 0, /* how many seconds of the current 123 * pdp value is unknown data? */ 124 PDP_val 125 }; /* current value of the pdp. 126 this depends on dst */ 127 128 struct rrd_pdp_prep { 129 gchar last_ds[RRD_LAST_DS_LEN]; /* the last reading from the data 130 * source. this is stored in ASCII 131 * to cater for very large counters 132 * we might encounter in connection 133 * with SNMP. */ 134 rrd_value_t scratch[10]; /* contents according to pdp_par_en */ 135 }; 136 137 #define RRD_MAX_CDP_PAR_EN 10 138 #define RRD_MAX_CDP_FAILURES_IDX 8 139 /* max CDP scratch entries avail to record violations for a FAILURES RRA */ 140 #define RRD_MAX_FAILURES_WINDOW_LEN 28 141 142 enum rrd_cdp_param { 143 CDP_val = 0, 144 /* the base_interval is always an 145 * average */ 146 CDP_unkn_pdp_cnt, 147 /* how many unknown pdp were 148 * integrated. This and the cdp_xff 149 * will decide if this is going to 150 * be a UNKNOWN or a valid value */ 151 CDP_hw_intercept, 152 /* Current intercept coefficient for the Holt-Winters 153 * prediction algorithm. */ 154 CDP_hw_last_intercept, 155 /* Last iteration intercept coefficient for the Holt-Winters 156 * prediction algorihtm. */ 157 CDP_hw_slope, 158 /* Current slope coefficient for the Holt-Winters 159 * prediction algorithm. */ 160 CDP_hw_last_slope, 161 /* Last iteration slope coeffient. */ 162 CDP_null_count, 163 /* Number of sequential Unknown (DNAN) values + 1 preceding 164 * the current prediction. 165 * */ 166 CDP_last_null_count, 167 /* Last iteration count of Unknown (DNAN) values. */ 168 CDP_primary_val = 8, 169 /* optimization for bulk updates: the value of the first CDP 170 * value to be written in the bulk update. */ 171 CDP_secondary_val = 9, 172 /* optimization for bulk updates: the value of subsequent 173 * CDP values to be written in the bulk update. */ 174 CDP_hw_seasonal = CDP_hw_intercept, 175 /* Current seasonal coefficient for the Holt-Winters 176 * prediction algorithm. This is stored in CDP prep to avoid 177 * redundant seek operations. */ 178 CDP_hw_last_seasonal = CDP_hw_last_intercept, 179 /* Last iteration seasonal coefficient. */ 180 CDP_seasonal_deviation = CDP_hw_intercept, 181 CDP_last_seasonal_deviation = CDP_hw_last_intercept, 182 CDP_init_seasonal = CDP_null_count 183 }; 184 185 struct rrd_cdp_prep { 186 rrd_value_t scratch[RRD_MAX_CDP_PAR_EN]; 187 /* contents according to cdp_par_en * 188 * init state should be NAN */ 189 }; 190 191 struct rrd_rra_ptr { 192 gulong cur_row; /* current row in the rra */ 193 }; 194 195 /* Final rrd file structure */ 196 struct rspamd_rrd_file { 197 struct rrd_file_head *stat_head; /* the static header */ 198 struct rrd_ds_def *ds_def; /* list of data source definitions */ 199 struct rrd_rra_def *rra_def; /* list of round robin archive def */ 200 struct rrd_live_head *live_head; /* rrd v >= 3 last_up with us */ 201 struct rrd_pdp_prep *pdp_prep; /* pdp data prep area */ 202 struct rrd_cdp_prep *cdp_prep; /* cdp prep area */ 203 struct rrd_rra_ptr *rra_ptr; /* list of rra pointers */ 204 gdouble *rrd_value; /* list of rrd values */ 205 206 gchar *filename; 207 guint8 *map; /* mmapped area */ 208 gsize size; /* its size */ 209 gboolean finalized; 210 gchar *id; 211 gint fd; 212 }; 213 214 215 /* Public API */ 216 217 /** 218 * Open (and mmap) existing RRD file 219 * @param filename path 220 * @param err error pointer 221 * @return rrd file structure 222 */ 223 struct rspamd_rrd_file *rspamd_rrd_open (const gchar *filename, GError **err); 224 225 /** 226 * Create basic header for rrd file 227 * @param filename file path 228 * @param ds_count number of data sources 229 * @param rra_count number of round robin archives 230 * @param pdp_step step of primary data points 231 * @param err error pointer 232 * @return TRUE if file has been created 233 */ 234 struct rspamd_rrd_file *rspamd_rrd_create (const gchar *filename, 235 gulong ds_count, 236 gulong rra_count, 237 gulong pdp_step, 238 gdouble initial_ticks, 239 GError **err); 240 241 /** 242 * Add data sources to rrd file 243 * @param filename path to file 244 * @param ds array of struct rrd_ds_def 245 * @param err error pointer 246 * @return TRUE if data sources were added 247 */ 248 gboolean rspamd_rrd_add_ds (struct rspamd_rrd_file *file, 249 GArray *ds, 250 GError **err); 251 252 /** 253 * Add round robin archives to rrd file 254 * @param filename path to file 255 * @param ds array of struct rrd_rra_def 256 * @param err error pointer 257 * @return TRUE if archives were added 258 */ 259 gboolean rspamd_rrd_add_rra (struct rspamd_rrd_file *file, 260 GArray *rra, 261 GError **err); 262 263 /** 264 * Finalize rrd file header and initialize all RRA in the file 265 * @param filename file path 266 * @param err error pointer 267 * @return TRUE if rrd file is ready for use 268 */ 269 gboolean rspamd_rrd_finalize (struct rspamd_rrd_file *file, GError **err); 270 271 /** 272 * Add record to rrd file 273 * @param file rrd file object 274 * @param points points (must be row suitable for this RRA, depending on ds count) 275 * @param err error pointer 276 * @return TRUE if a row has been added 277 */ 278 gboolean rspamd_rrd_add_record (struct rspamd_rrd_file *file, 279 GArray *points, 280 gdouble ticks, 281 GError **err); 282 283 /** 284 * Close rrd file 285 * @param file 286 * @return 287 */ 288 gint rspamd_rrd_close (struct rspamd_rrd_file *file); 289 290 /* 291 * Conversion functions 292 */ 293 294 /** 295 * Convert rrd dst type from string to numeric value 296 */ 297 enum rrd_dst_type rrd_dst_from_string (const gchar *str); 298 299 /** 300 * Convert numeric presentation of dst to string 301 */ 302 const gchar *rrd_dst_to_string (enum rrd_dst_type type); 303 304 /** 305 * Convert rrd consolidation function type from string to numeric value 306 */ 307 enum rrd_cf_type rrd_cf_from_string (const gchar *str); 308 309 /** 310 * Convert numeric presentation of cf to string 311 */ 312 const gchar *rrd_cf_to_string (enum rrd_cf_type type); 313 314 /* Default RRA and DS */ 315 316 /** 317 * Create default RRA 318 */ 319 void rrd_make_default_rra (const gchar *cf_name, 320 gulong pdp_cnt, 321 gulong rows, 322 struct rrd_rra_def *rra); 323 324 /** 325 * Create default DS 326 */ 327 void rrd_make_default_ds (const gchar *name, 328 const gchar *type, 329 gulong pdp_step, 330 struct rrd_ds_def *ds); 331 332 /** 333 * Open or create the default rspamd rrd file 334 */ 335 struct rspamd_rrd_file *rspamd_rrd_file_default (const gchar *path, 336 GError **err); 337 338 /** 339 * Returned by querying rrd database 340 */ 341 struct rspamd_rrd_query_result { 342 gulong rra_rows; 343 gulong pdp_per_cdp; 344 gulong ds_count; 345 gdouble last_update; 346 gulong cur_row; 347 const gdouble *data; 348 }; 349 350 /** 351 * Return RRA data 352 * @param file rrd file 353 * @param rra_num number of rra to return data for 354 * @return query result structure, that should be freed (using g_slice_free1) after usage 355 */ 356 struct rspamd_rrd_query_result *rspamd_rrd_query (struct rspamd_rrd_file *file, 357 gulong rra_num); 358 359 #ifdef __cplusplus 360 } 361 #endif 362 363 #endif /* RRD_H_ */ 364