Fawkes API Fawkes Development Version
rrd_thread.cpp
1
2/***************************************************************************
3 * rrd_thread.cpp - RRD Thread
4 *
5 * Created: Fri Dec 17 00:32:57 2010
6 * Copyright 2006-2010 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "rrd_thread.h"
24
25#include <core/exceptions/system.h>
26#include <core/threading/scoped_rwlock.h>
27#include <utils/misc/string_conversions.h>
28#include <utils/system/file.h>
29
30#include <cstdarg>
31#include <cstdio>
32#include <cstdlib>
33#include <cstring>
34#include <rrd.h>
35
36using namespace fawkes;
37
38/** @class RRDThread "rrd_thread.h"
39 * RRD Thread.
40 * This thread maintains an active connection to RRD and provides an
41 * aspect to access RRD to make it convenient for other threads to use
42 * RRD.
43 *
44 * @author Tim Niemueller
45 */
46
47/** Constructor. */
49: Thread("RRDThread", Thread::OPMODE_CONTINUOUS),
50 AspectProviderAspect(&rrd_aspect_inifin_),
51 rrd_aspect_inifin_(this)
52{
54}
55
56/** Destructor. */
58{
59}
60
61void
63{
64 cfg_graph_interval_ = 30.;
65 try {
66 cfg_graph_interval_ = config->get_float("/plugins/rrd/graph_interval");
67 } catch (Exception &e) {
68 }
69
70 time_wait_ = new TimeWait(clock, time_sec_to_usec(cfg_graph_interval_));
71}
72
73void
75{
76 delete time_wait_;
77}
78
79void
81{
82 time_wait_->mark_start();
84 time_wait_->wait_systime();
85}
86
87/** Generate all graphs. */
88void
90{
91 ScopedRWLock lock(graphs_.rwlock(), ScopedRWLock::LOCK_READ);
92
93 std::vector<fawkes::RRDGraphDefinition *>::iterator g;
94 for (g = graphs_.begin(); g != graphs_.end(); ++g) {
95 size_t argc = 0;
96 const char **argv = (*g)->get_argv(argc);
97
98 //logger->log_debug(name(), "rrd_graph arguments:");
99 //for (size_t j = 0; j < argc; ++j) {
100 // logger->log_debug(name(), " %zu: %s", j, argv[j]);
101 //}
102
103 rrd_clear_error();
104 rrd_info_t *i = rrd_graph_v(argc, (char **)argv);
105 if (i == NULL) {
106 throw Exception("Creating graph %s (for RRD %s) failed: %s",
107 (*g)->get_name(),
108 (*g)->get_rrd_def()->get_name(),
109 rrd_get_error());
110 }
111 rrd_info_free(i);
112 }
113}
114
115void
117{
118 // generate filename
119 char *filename;
120 if (asprintf(&filename, "%s/%s.rrd", ".", rrd_def->get_name()) == -1) {
121 throw OutOfMemoryException("Failed to creat filename for RRD %s", rrd_def->get_name());
122 }
123 rrd_def->set_filename(filename);
124 free(filename);
125
126 if (!File::exists(rrd_def->get_filename()) || rrd_def->get_recreate()) {
127 std::string size_s = StringConversions::to_string(rrd_def->get_step_sec());
128
129 // build parameter array
130 // "create" filename --step STEP --start START DS... RRA...
131 size_t rrd_argc = 6 + rrd_def->get_ds().size() + rrd_def->get_rra().size();
132 const char *rrd_argv[rrd_argc];
133 size_t i = 0;
134 rrd_argv[i++] = "create";
135 rrd_argv[i++] = rrd_def->get_filename();
136 rrd_argv[i++] = "--step";
137 rrd_argv[i++] = size_s.c_str();
138 rrd_argv[i++] = "--start";
139 rrd_argv[i++] = "0";
140
141 std::vector<RRDDataSource>::const_iterator d;
142 for (d = rrd_def->get_ds().begin(); d != rrd_def->get_ds().end() && i < rrd_argc; ++d) {
143 rrd_argv[i++] = d->to_string();
144 }
145
146 std::vector<RRDArchive>::const_iterator a;
147 for (a = rrd_def->get_rra().begin(); a != rrd_def->get_rra().end() && i < rrd_argc; ++a) {
148 rrd_argv[i++] = a->to_string();
149 }
150
151 //logger->log_debug(name(), "rrd_create arguments:");
152 //for (size_t j = 0; j < i; ++j) {
153 // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]);
154 //}
155
156 // Create RRD file
157 rrd_clear_error();
158 if (rrd_create(i, (char **)rrd_argv) == -1) {
159 throw Exception("Creating RRD %s failed: %s", rrd_def->get_name(), rrd_get_error());
160 }
161 }
162
163 ScopedRWLock lock(rrds_.rwlock());
165 for (r = rrds_.begin(); r != rrds_.end(); ++r) {
166 if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) {
167 throw Exception("RRD with name %s has already been registered", rrd_def->get_name());
168 }
169 }
170
171 rrd_def->set_rrd_manager(this);
172 rrds_.push_back(rrd_def);
173}
174
175void
177{
178 ScopedRWLock rrds_lock(rrds_.rwlock());
180 for (r = rrds_.begin(); r != rrds_.end(); ++r) {
181 if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) {
182 rrds_.erase(r);
183 break;
184 }
185 }
186
187 ScopedRWLock graph_lock(graphs_.rwlock());
188 bool graphs_modified = false;
189 do {
190 graphs_modified = false;
192 for (g = graphs_.begin(); g != graphs_.end(); ++g) {
193 if (strcmp((*g)->get_rrd_def()->get_name(), rrd_def->get_name()) == 0) {
194 graphs_.erase(g);
195 graphs_modified = true;
196 break;
197 }
198 }
199 } while (graphs_modified);
200}
201
202void
204{
205 // generate filename
206 char *filename;
207 if (asprintf(&filename, "%s/%s.png", ".", rrd_graph_def->get_name()) == -1) {
208 throw OutOfMemoryException("Failed to create filename for PNG %s", rrd_graph_def->get_name());
209 }
210 rrd_graph_def->set_filename(filename);
211 free(filename);
212
213 ScopedRWLock lock(graphs_.rwlock());
215 for (g = graphs_.begin(); g != graphs_.end(); ++g) {
216 if (strcmp((*g)->get_name(), rrd_graph_def->get_name()) == 0) {
217 throw Exception("RRD graph with name %s has already been registered",
218 rrd_graph_def->get_name());
219 }
220 }
221 graphs_.push_back(rrd_graph_def);
222}
223
224void
225RRDThread::add_data(const char *rrd_name, const char *format, ...)
226{
227 ScopedRWLock lock(rrds_.rwlock(), ScopedRWLock::LOCK_READ);
228
229 std::vector<RRDDefinition *>::const_iterator d;
230 for (d = rrds_.begin(); d != rrds_.end(); ++d) {
231 RRDDefinition *rrd_def = *d;
232 if (strcmp(rrd_name, rrd_def->get_name()) == 0) {
233 char * data;
234 va_list arg;
235 va_start(arg, format);
236 if (vasprintf(&data, format, arg) == -1) {
237 va_end(arg);
238 throw OutOfMemoryException("Failed to create data string for %s", rrd_name);
239 }
240 va_end(arg);
241
242 // filename data
243 size_t rrd_argc = 3;
244 const char *rrd_argv[rrd_argc];
245 size_t i = 0;
246 rrd_argv[i++] = "update";
247 rrd_argv[i++] = rrd_def->get_filename();
248 rrd_argv[i++] = data;
249
250 //logger->log_debug(name(), "rrd_update arguments:");
251 //for (size_t j = 0; j < i; ++j) {
252 // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]);
253 //}
254
255 rrd_clear_error();
256 if (rrd_update(i, (char **)rrd_argv) == -1) {
257 free(data);
258 throw Exception("Failed to update RRD %s: %s", rrd_name, rrd_get_error());
259 }
260
261 free(data);
262 return;
263 }
264 }
265
266 throw Exception("No RRD named %s registered", rrd_name);
267}
268
271{
272 return rrds_;
273}
274
277{
278 return graphs_;
279}
virtual void add_data(const char *rrd_name, const char *format,...)
Add data.
Definition: rrd_thread.cpp:225
virtual void add_rrd(fawkes::RRDDefinition *rrd_def)
Add RRD.
Definition: rrd_thread.cpp:116
virtual ~RRDThread()
Destructor.
Definition: rrd_thread.cpp:57
virtual void remove_rrd(fawkes::RRDDefinition *rrd_def)
Remove RRD.
Definition: rrd_thread.cpp:176
void generate_graphs()
Generate all graphs.
Definition: rrd_thread.cpp:89
virtual void add_graph(fawkes::RRDGraphDefinition *rrd_graph_def)
Add graph.
Definition: rrd_thread.cpp:203
virtual void init()
Initialize the thread.
Definition: rrd_thread.cpp:62
RRDThread()
Constructor.
Definition: rrd_thread.cpp:48
virtual void loop()
Code to execute in the thread.
Definition: rrd_thread.cpp:80
virtual void finalize()
Finalize the thread.
Definition: rrd_thread.cpp:74
virtual const fawkes::RWLockVector< fawkes::RRDGraphDefinition * > & get_graphs() const
Get graphs.
Definition: rrd_thread.cpp:276
virtual const fawkes::RWLockVector< fawkes::RRDDefinition * > & get_rrds() const
Get RRDs.
Definition: rrd_thread.cpp:270
Thread aspect provide a new aspect.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
virtual float get_float(const char *path)=0
Get value from configuration which is of type float.
Base class for exceptions in Fawkes.
Definition: exception.h:36
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:32
void set_rrd_manager(RRDManager *rrd_manager)
Set RRD manager.
const char * get_filename() const
Get file name.
void set_filename(const char *filename)
Set filename.
const std::vector< RRDArchive > & get_rra() const
Get RRD archives.
const char * get_name() const
Get name.
bool get_recreate() const
Check recreation flag.
unsigned int get_step_sec() const
Get step size in sec.
const std::vector< RRDDataSource > & get_ds() const
Get data sources.
Class representing a graph definition.
const char * get_name() const
Get graph definition name.
void set_filename(const char *filename)
Set filename.
Vector with a lock.
Definition: rwlock_vector.h:36
RefPtr< ReadWriteLock > rwlock() const
Get access to the internal read/write lock.
Scoped read/write lock.
Definition: scoped_rwlock.h:34
Thread class encapsulation of pthreads.
Definition: thread.h:46
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:716
Time wait utility.
Definition: wait.h:33
void mark_start()
Mark start of loop.
Definition: wait.cpp:68
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:96
Fawkes library namespace.
long int time_sec_to_usec(double sec)
Convert seconds to micro seconds.
Definition: time.h:73