Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 #include <cstdio>
30 #include <cstdlib>
31 #include <cstdarg>
32 #include <cstring>
33 #include <rrd.h>
34 
35 using namespace fawkes;
36 
37 /** @class RRDThread "rrd_thread.h"
38  * RRD Thread.
39  * This thread maintains an active connection to RRD and provides an
40  * aspect to access RRD to make it convenient for other threads to use
41  * RRD.
42  *
43  * @author Tim Niemueller
44  */
45 
46 /** Constructor. */
48  : Thread("RRDThread", Thread::OPMODE_CONTINUOUS),
49  AspectProviderAspect("RRDAspect", &__rrd_aspect_inifin),
50  __rrd_aspect_inifin(this)
51 {
53 }
54 
55 
56 /** Destructor. */
58 {
59 }
60 
61 
62 void
64 {
65  __cfg_graph_interval = 30.;
66  try {
67  __cfg_graph_interval = config->get_float("/plugins/rrd/graph_interval");
68  } catch (Exception &e) {}
69 
70  __time_wait = new TimeWait(clock, time_sec_to_usec(__cfg_graph_interval));
71 }
72 
73 
74 void
76 {
77 }
78 
79 
80 void
82 {
83  __time_wait->mark_start();
85  __time_wait->wait_systime();
86 }
87 
88 
89 /** Generate all graphs. */
90 void
92 {
93  ScopedRWLock lock(__graphs.rwlock(), ScopedRWLock::LOCK_READ);
94 
95  std::vector<fawkes::RRDGraphDefinition *>::iterator g;
96  for (g = __graphs.begin(); g != __graphs.end(); ++g) {
97  size_t argc = 0;
98  const char **argv = (*g)->get_argv(argc);
99 
100  //logger->log_debug(name(), "rrd_graph arguments:");
101  //for (size_t j = 0; j < argc; ++j) {
102  // logger->log_debug(name(), " %zu: %s", j, argv[j]);
103  //}
104 
105  rrd_clear_error();
106  rrd_info_t *i = rrd_graph_v(argc, (char **)argv);
107  if (i == NULL) {
108  throw Exception("Creating graph %s (for RRD %s) failed: %s",
109  (*g)->get_name(), (*g)->get_rrd_def()->get_name(),
110  rrd_get_error());
111  }
112  rrd_info_free(i);
113  }
114 }
115 
116 void
118 {
119  // generate filename
120  char *filename;
121  if (asprintf(&filename, "%s/%s.rrd", ".", rrd_def->get_name()) == -1) {
122  throw OutOfMemoryException("Failed to creat filename for RRD %s",
123  rrd_def->get_name());
124  }
125  rrd_def->set_filename(filename);
126  free(filename);
127 
128  if (! File::exists(rrd_def->get_filename()) || rrd_def->get_recreate()) {
129  std::string size_s = StringConversions::to_string(rrd_def->get_step_sec());
130 
131  // build parameter array
132  // "create" filename --step STEP --start START DS... RRA...
133  size_t rrd_argc = 6 + rrd_def->get_ds().size() + rrd_def->get_rra().size();
134  const char *rrd_argv[rrd_argc];
135  size_t i = 0;
136  rrd_argv[i++] = "create";
137  rrd_argv[i++] = rrd_def->get_filename();
138  rrd_argv[i++] = "--step";
139  rrd_argv[i++] = size_s.c_str();
140  rrd_argv[i++] = "--start";
141  rrd_argv[i++] = "0";
142 
143  std::vector<RRDDataSource>::const_iterator d;
144  for (d = rrd_def->get_ds().begin();
145  d != rrd_def->get_ds().end() && i < rrd_argc;
146  ++d)
147  {
148  rrd_argv[i++] = d->to_string();
149  }
150 
151  std::vector<RRDArchive>::const_iterator a;
152  for (a = rrd_def->get_rra().begin();
153  a != rrd_def->get_rra().end() && i < rrd_argc;
154  ++a)
155  {
156  rrd_argv[i++] = a->to_string();
157  }
158 
159  //logger->log_debug(name(), "rrd_create arguments:");
160  //for (size_t j = 0; j < i; ++j) {
161  // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]);
162  //}
163 
164  // Create RRD file
165  rrd_clear_error();
166  if (rrd_create(i, (char **)rrd_argv) == -1) {
167  throw Exception("Creating RRD %s failed: %s",
168  rrd_def->get_name(), rrd_get_error());
169  }
170  }
171 
172  ScopedRWLock lock(__rrds.rwlock());
174  for (r = __rrds.begin(); r != __rrds.end(); ++r) {
175  if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) {
176  throw Exception("RRD with name %s has already been registered",
177  rrd_def->get_name());
178  }
179  }
180 
181  rrd_def->set_rrd_manager(this);
182  __rrds.push_back(rrd_def);
183 }
184 
185 void
187 {
188  ScopedRWLock rrds_lock(__rrds.rwlock());
190  for (r = __rrds.begin(); r != __rrds.end(); ++r) {
191  if (strcmp((*r)->get_name(), rrd_def->get_name()) == 0) {
192  __rrds.erase(r);
193  break;
194  }
195  }
196 
197  ScopedRWLock graph_lock(__graphs.rwlock());
198  bool graphs_modified = false;
199  do {
200  graphs_modified = false;
202  for (g = __graphs.begin(); g != __graphs.end(); ++g) {
203  if (strcmp((*g)->get_rrd_def()->get_name(), rrd_def->get_name()) == 0) {
204  __graphs.erase(g);
205  graphs_modified = true;
206  break;
207  }
208  }
209  } while (graphs_modified);
210 }
211 
212 void
214 {
215  // generate filename
216  char *filename;
217  if (asprintf(&filename, "%s/%s.png", ".",
218  rrd_graph_def->get_name()) == -1) {
219  throw OutOfMemoryException("Failed to create filename for PNG %s",
220  rrd_graph_def->get_name());
221  }
222  rrd_graph_def->set_filename(filename);
223  free(filename);
224 
225  ScopedRWLock lock(__graphs.rwlock());
227  for (g = __graphs.begin(); g != __graphs.end(); ++g) {
228  if (strcmp((*g)->get_name(), rrd_graph_def->get_name()) == 0) {
229  throw Exception("RRD graph with name %s has already been registered",
230  rrd_graph_def->get_name());
231  }
232  }
233  __graphs.push_back(rrd_graph_def);
234 }
235 
236 void
237 RRDThread::add_data(const char *rrd_name, const char *format, ...)
238 {
239  ScopedRWLock lock(__rrds.rwlock(), ScopedRWLock::LOCK_READ);
240 
241  std::vector<RRDDefinition *>::const_iterator d;
242  for (d = __rrds.begin(); d != __rrds.end(); ++d) {
243  RRDDefinition *rrd_def = *d;
244  if (strcmp(rrd_name, rrd_def->get_name()) == 0) {
245  char *data;
246  va_list arg;
247  va_start(arg, format);
248  if (vasprintf(&data, format, arg) == -1) {
249  va_end(arg);
250  throw OutOfMemoryException("Failed to create data string for %s",
251  rrd_name);
252  }
253  va_end(arg);
254 
255  // filename data
256  size_t rrd_argc = 3;
257  const char *rrd_argv[rrd_argc];
258  size_t i = 0;
259  rrd_argv[i++] = "update";
260  rrd_argv[i++] = rrd_def->get_filename();
261  rrd_argv[i++] = data;
262 
263  //logger->log_debug(name(), "rrd_update arguments:");
264  //for (size_t j = 0; j < i; ++j) {
265  // logger->log_debug(name(), " %zu: %s", j, rrd_argv[j]);
266  //}
267 
268  rrd_clear_error();
269  if (rrd_update(i, (char **)rrd_argv) == -1) {
270  free(data);
271  throw Exception("Failed to update RRD %s: %s", rrd_name, rrd_get_error());
272  }
273 
274  free(data);
275  return;
276  }
277  }
278 
279  throw Exception("No RRD named %s registered", rrd_name);
280 }
281 
282 
285 {
286  return __rrds;
287 }
288 
289 
292 {
293  return __graphs;
294 }
long int time_sec_to_usec(double sec)
Convert seconds to micro seconds.
Definition: time.h:72
const std::vector< RRDDataSource > & get_ds() const
Get data sources.
unsigned int get_step_sec() const
Get step size in sec.
const std::vector< RRDArchive > & get_rra() const
Get RRD archives.
Scoped read/write lock.
Definition: scoped_rwlock.h:33
virtual void add_rrd(fawkes::RRDDefinition *rrd_def)
Add RRD.
Definition: rrd_thread.cpp:117
void set_filename(const char *filename)
Set filename.
Thread class encapsulation of pthreads.
Definition: thread.h:42
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:715
virtual const fawkes::RWLockVector< fawkes::RRDGraphDefinition * > & get_graphs() const
Get graphs.
Definition: rrd_thread.cpp:291
virtual void finalize()
Finalize the thread.
Definition: rrd_thread.cpp:75
const char * get_filename() const
Get file name.
void wait_systime()
Wait until minimum loop time has been reached in real time.
Definition: wait.cpp:100
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:45
virtual void loop()
Code to execute in the thread.
Definition: rrd_thread.cpp:81
virtual void add_graph(fawkes::RRDGraphDefinition *rrd_graph_def)
Add graph.
Definition: rrd_thread.cpp:213
virtual ~RRDThread()
Destructor.
Definition: rrd_thread.cpp:57
virtual void remove_rrd(fawkes::RRDDefinition *rrd_def)
Remove RRD.
Definition: rrd_thread.cpp:186
const char * get_name() const
Get name.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Class representing a graph definition.
void set_filename(const char *filename)
Set filename.
bool get_recreate() const
Check recreation flag.
Thread aspect provide a new aspect.
virtual const fawkes::RWLockVector< fawkes::RRDDefinition * > & get_rrds() const
Get RRDs.
Definition: rrd_thread.cpp:284
void mark_start()
Mark start of loop.
Definition: wait.cpp:70
virtual void init()
Initialize the thread.
Definition: rrd_thread.cpp:63
RefPtr< ReadWriteLock > rwlock() const
Get access to the internal read/write lock.
const char * get_name() const
Get graph definition name.
RRDThread()
Constructor.
Definition: rrd_thread.cpp:47
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
virtual float get_float(const char *path)=0
Get value from configuration which is of type float.
Time wait utility.
Definition: wait.h:32
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.
Vector with a lock.
Definition: rwlock_vector.h:37
void generate_graphs()
Generate all graphs.
Definition: rrd_thread.cpp:91
virtual void add_data(const char *rrd_name, const char *format,...)
Add data.
Definition: rrd_thread.cpp:237