summaryrefslogtreecommitdiffstats
path: root/src/libutil/rrd.h
blob: 3d814771ac3584083146c9d1f422792b6c8844f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
/*-
 * Copyright 2016 Vsevolod Stakhov
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef RRD_H_
#define RRD_H_

#include "config.h"

/**
 * This file contains basic structure and functions to operate with round-robin databases
 */

#define RRD_COOKIE "RRD"
#define RRD_VERSION "0003"
#define RRD_FLOAT_COOKIE ((double) 8.642135E130)

#ifdef __cplusplus
extern "C" {
#endif

typedef union {
	unsigned long lv;
	double dv;
} rrd_value_t;

struct rrd_file_head {
	/* Data Base Identification Section ** */
	gchar cookie[4];      /* RRD */
	gchar version[5];     /* version of the format */
	gdouble float_cookie; /* is it the correct double representation ?  */

	/* Data Base Structure Definition **** */
	gulong ds_cnt;   /* how many different ds provide input to the rrd */
	gulong rra_cnt;  /* how many rras will be maintained in the rrd */
	gulong pdp_step; /* pdp interval in seconds */

	rrd_value_t par[10]; /* global parameters ... unused
	                           at the moment */
};

enum rrd_dst_type {
	RRD_DST_INVALID = -1,
	RRD_DST_COUNTER = 0, /* data source types available */
	RRD_DST_ABSOLUTE,
	RRD_DST_GAUGE,
	RRD_DST_DERIVE,
	RRD_DST_CDEF
};
enum rrd_ds_param {
	RRD_DS_mrhb_cnt = 0, /* minimum required heartbeat */
	RRD_DS_min_val,      /* the processed input of a ds must */
	RRD_DS_max_val,      /* be between max_val and min_val
	                         * both can be set to UNKNOWN if you
	                         * do not care. Data outside the limits
	                         * set to UNKNOWN */
	RRD_DS_cdef = RRD_DS_mrhb_cnt
}; /* pointer to encoded rpn expression only applies to DST_CDEF */


/* The magic number here is one less than DS_NAM_SIZE */
#define RRD_DS_NAM_SIZE 20

#define RRD_DST_SIZE 20

struct rrd_ds_def {
	gchar ds_nam[RRD_DS_NAM_SIZE]; /* Name of the data source (null terminated) */
	gchar dst[RRD_DST_SIZE];       /* Type of data source (null terminated) */
	rrd_value_t par[10];           /* index of this array see ds_param_en */
};

/* RRA definition */

enum rrd_cf_type {
	RRD_CF_INVALID = -1,
	RRD_CF_AVERAGE = 0, /* data consolidation functions */
	RRD_CF_MINIMUM,
	RRD_CF_MAXIMUM,
	RRD_CF_LAST,
};


#define MAX_RRA_PAR_EN 10

enum rrd_rra_param {
	RRA_cdp_xff_val = 0, /* what part of the consolidated
	                       * datapoint must be known, to produce a
	                       * valid entry in the rra */
};


#define RRD_CF_NAM_SIZE 20

struct rrd_rra_def {
	gchar cf_nam[RRD_CF_NAM_SIZE];   /* consolidation function (null term) */
	gulong row_cnt;                  /* number of entries in the store */
	gulong pdp_cnt;                  /* how many primary data points are
	                  * required for a consolidated data point?*/
	rrd_value_t par[MAX_RRA_PAR_EN]; /* index see rra_param_en */
};

struct rrd_live_head {
	time_t last_up;     /* when was rrd last updated */
	glong last_up_usec; /* micro seconds part of the update timestamp. Always >= 0 */
};

#define RRD_LAST_DS_LEN 30

enum rrd_pdp_param {
	PDP_unkn_sec_cnt = 0, /* how many seconds of the current
	                       * pdp value is unknown data? */
	PDP_val
}; /* current value of the pdp.
                           this depends on dst */

struct rrd_pdp_prep {
	gchar last_ds[RRD_LAST_DS_LEN]; /* the last reading from the data
	                                 * source.  this is stored in ASCII
	                                 * to cater for very large counters
	                                 * we might encounter in connection
	                                 * with SNMP. */
	rrd_value_t scratch[10];        /* contents according to pdp_par_en */
};

#define RRD_MAX_CDP_PAR_EN 10
#define RRD_MAX_CDP_FAILURES_IDX 8
/* max CDP scratch entries avail to record violations for a FAILURES RRA */
#define RRD_MAX_FAILURES_WINDOW_LEN 28

enum rrd_cdp_param {
	CDP_val = 0,
	/* the base_interval is always an
	 * average */
	CDP_unkn_pdp_cnt,
	/* how many unknown pdp were
	 * integrated. This and the cdp_xff
	 * will decide if this is going to
	 * be a UNKNOWN or a valid value */
	CDP_hw_intercept,
	/* Current intercept coefficient for the Holt-Winters
	 * prediction algorithm. */
	CDP_hw_last_intercept,
	/* Last iteration intercept coefficient for the Holt-Winters
	 * prediction algorithm. */
	CDP_hw_slope,
	/* Current slope coefficient for the Holt-Winters
	 * prediction algorithm. */
	CDP_hw_last_slope,
	/* Last iteration slope coefficient. */
	CDP_null_count,
	/* Number of sequential Unknown (DNAN) values + 1 preceding
	 * the current prediction.
	 * */
	CDP_last_null_count,
	/* Last iteration count of Unknown (DNAN) values. */
	CDP_primary_val = 8,
	/* optimization for bulk updates: the value of the first CDP
	 * value to be written in the bulk update. */
	CDP_secondary_val = 9,
	/* optimization for bulk updates: the value of subsequent
	 * CDP values to be written in the bulk update. */
	CDP_hw_seasonal = CDP_hw_intercept,
	/* Current seasonal coefficient for the Holt-Winters
	 * prediction algorithm. This is stored in CDP prep to avoid
	 * redundant seek operations. */
	CDP_hw_last_seasonal = CDP_hw_last_intercept,
	/* Last iteration seasonal coefficient. */
	CDP_seasonal_deviation = CDP_hw_intercept,
	CDP_last_seasonal_deviation = CDP_hw_last_intercept,
	CDP_init_seasonal = CDP_null_count
};

struct rrd_cdp_prep {
	rrd_value_t scratch[RRD_MAX_CDP_PAR_EN];
	/* contents according to cdp_par_en *
	 * init state should be NAN */
};

struct rrd_rra_ptr {
	gulong cur_row; /* current row in the rra */
};

/* Final rrd file structure */
struct rspamd_rrd_file {
	struct rrd_file_head *stat_head; /* the static header */
	struct rrd_ds_def *ds_def;       /* list of data source definitions */
	struct rrd_rra_def *rra_def;     /* list of round robin archive def */
	struct rrd_live_head *live_head; /* rrd v >= 3 last_up with us */
	struct rrd_pdp_prep *pdp_prep;   /* pdp data prep area */
	struct rrd_cdp_prep *cdp_prep;   /* cdp prep area */
	struct rrd_rra_ptr *rra_ptr;     /* list of rra pointers */
	gdouble *rrd_value;              /* list of rrd values */

	gchar *filename;
	guint8 *map; /* mmapped area */
	gsize size;  /* its size */
	gboolean finalized;
	gchar *id;
	gint fd;
};


/* Public API */

/**
 * Open (and mmap) existing RRD file
 * @param filename path
 * @param err error pointer
 * @return rrd file structure
 */
struct rspamd_rrd_file *rspamd_rrd_open(const gchar *filename, GError **err);

/**
 * Create basic header for rrd file
 * @param filename file path
 * @param ds_count number of data sources
 * @param rra_count number of round robin archives
 * @param pdp_step step of primary data points
 * @param err error pointer
 * @return TRUE if file has been created
 */
struct rspamd_rrd_file *rspamd_rrd_create(const gchar *filename,
										  gulong ds_count,
										  gulong rra_count,
										  gulong pdp_step,
										  gdouble initial_ticks,
										  GError **err);

/**
 * Add data sources to rrd file
 * @param filename path to file
 * @param ds array of struct rrd_ds_def
 * @param err error pointer
 * @return TRUE if data sources were added
 */
gboolean rspamd_rrd_add_ds(struct rspamd_rrd_file *file,
						   GArray *ds,
						   GError **err);

/**
 * Add round robin archives to rrd file
 * @param filename path to file
 * @param ds array of struct rrd_rra_def
 * @param err error pointer
 * @return TRUE if archives were added
 */
gboolean rspamd_rrd_add_rra(struct rspamd_rrd_file *file,
							GArray *rra,
							GError **err);

/**
 * Finalize rrd file header and initialize all RRA in the file
 * @param filename file path
 * @param err error pointer
 * @return TRUE if rrd file is ready for use
 */
gboolean rspamd_rrd_finalize(struct rspamd_rrd_file *file, GError **err);

/**
 * Add record to rrd file
 * @param file rrd file object
 * @param points points (must be row suitable for this RRA, depending on ds count)
 * @param err error pointer
 * @return TRUE if a row has been added
 */
gboolean rspamd_rrd_add_record(struct rspamd_rrd_file *file,
							   GArray *points,
							   gdouble ticks,
							   GError **err);

/**
 * Close rrd file
 * @param file
 * @return
 */
gint rspamd_rrd_close(struct rspamd_rrd_file *file);

/*
 * Conversion functions
 */

/**
 * Convert rrd dst type from string to numeric value
 */
enum rrd_dst_type rrd_dst_from_string(const gchar *str);

/**
 * Convert numeric presentation of dst to string
 */
const gchar *rrd_dst_to_string(enum rrd_dst_type type);

/**
 * Convert rrd consolidation function type from string to numeric value
 */
enum rrd_cf_type rrd_cf_from_string(const gchar *str);

/**
 * Convert numeric presentation of cf to string
 */
const gchar *rrd_cf_to_string(enum rrd_cf_type type);

/* Default RRA and DS */

/**
 * Create default RRA
 */
void rrd_make_default_rra(const gchar *cf_name,
						  gulong pdp_cnt,
						  gulong rows,
						  struct rrd_rra_def *rra);

/**
 * Create default DS
 */
void rrd_make_default_ds(const gchar *name,
						 const gchar *type,
						 gulong pdp_step,
						 struct rrd_ds_def *ds);

/**
 * Open or create the default rspamd rrd file
 */
struct rspamd_rrd_file *rspamd_rrd_file_default(const gchar *path,
												GError **err);

/**
 * Returned by querying rrd database
 */
struct rspamd_rrd_query_result {
	gulong rra_rows;
	gulong pdp_per_cdp;
	gulong ds_count;
	gdouble last_update;
	gulong cur_row;
	const gdouble *data;
};

/**
 * Return RRA data
 * @param file rrd file
 * @param rra_num number of rra to return data for
 * @return query result structure, that should be freed (using g_slice_free1) after usage
 */
struct rspamd_rrd_query_result *rspamd_rrd_query(struct rspamd_rrd_file *file,
												 gulong rra_num);

#ifdef __cplusplus
}
#endif

#endif /* RRD_H_ */