corosync  2.3.2
mon.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2012 Red Hat, Inc.
3  *
4  * All rights reserved.
5  *
6  * Author: Angus Salkeld <asalkeld@redhat.com>
7  *
8  * This software licensed under BSD license, the text of which follows:
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * - Redistributions of source code must retain the above copyright notice,
14  * this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  * - Neither the name of the MontaVista Software, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32  * THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <config.h>
36 
37 #include <unistd.h>
38 #include <statgrab.h>
39 
40 #include <corosync/corotypes.h>
41 #include <corosync/corodefs.h>
42 #include <corosync/coroapi.h>
43 #include <corosync/list.h>
44 #include <corosync/logsys.h>
45 #include <corosync/icmap.h>
46 #include "fsm.h"
47 
48 #include "service.h"
49 
50 LOGSYS_DECLARE_SUBSYS ("MON");
51 
52 /*
53  * Service Interfaces required by service_message_handler struct
54  */
55 static char *mon_exec_init_fn (struct corosync_api_v1 *corosync_api);
56 
57 static struct corosync_api_v1 *api;
58 #define MON_DEFAULT_PERIOD 3000
59 #define MON_MIN_PERIOD 500
60 #define MON_MAX_PERIOD (120 * CS_TIME_MS_IN_SEC)
61 
63  .name = "corosync resource monitoring service",
64  .id = MON_SERVICE,
65  .priority = 1,
66  .private_data_size = 0,
67  .flow_control = CS_LIB_FLOW_CONTROL_NOT_REQUIRED,
68  .lib_init_fn = NULL,
69  .lib_exit_fn = NULL,
70  .lib_engine = NULL,
71  .lib_engine_count = 0,
72  .exec_engine = NULL,
73  .exec_engine_count = 0,
74  .confchg_fn = NULL,
75  .exec_init_fn = mon_exec_init_fn,
76  .exec_dump_fn = NULL
77 };
78 
79 static DECLARE_LIST_INIT (confchg_notify);
80 
81 
83  const char *icmap_path;
84  const char *name;
86  void (*update_stats_fn) (void *data);
87  struct cs_fsm fsm;
88  uint64_t period;
90  union {
91  int32_t int32;
92  double dbl;
93  } max;
94 };
95 
96 static void mem_update_stats_fn (void *data);
97 static void load_update_stats_fn (void *data);
98 
99 static struct resource_instance memory_used_inst = {
100  .name = "memory_used",
101  .icmap_path = "resources.system.memory_used.",
102  .update_stats_fn = mem_update_stats_fn,
103  .max_type = ICMAP_VALUETYPE_INT32,
104  .max.int32 = INT32_MAX,
105  .period = MON_DEFAULT_PERIOD,
106 };
107 
108 static struct resource_instance load_15min_inst = {
109  .name = "load_15min",
110  .icmap_path = "resources.system.load_15min.",
111  .update_stats_fn = load_update_stats_fn,
112  .max_type = ICMAP_VALUETYPE_DOUBLE,
113  .max.dbl = INT32_MAX,
114  .period = MON_DEFAULT_PERIOD,
115 };
116 
117 
118 /*
119  * F S M
120  */
121 static void mon_config_changed (struct cs_fsm* fsm, int32_t event, void * data);
122 static void mon_resource_failed (struct cs_fsm* fsm, int32_t event, void * data);
123 
124 const char * mon_running_str = "running";
125 const char * mon_failed_str = "failed";
126 const char * mon_failure_str = "failure";
127 const char * mon_stopped_str = "stopped";
128 const char * mon_config_changed_str = "config_changed";
129 
134 };
138 };
139 
141  { MON_S_STOPPED, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_STOPPED, MON_S_RUNNING, -1} },
142  { MON_S_STOPPED, MON_E_FAILURE, NULL, {-1} },
143  { MON_S_RUNNING, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_RUNNING, MON_S_STOPPED, -1} },
144  { MON_S_RUNNING, MON_E_FAILURE, mon_resource_failed, {MON_S_FAILED, -1} },
145  { MON_S_FAILED, MON_E_CONFIG_CHANGED, mon_config_changed, {MON_S_RUNNING, MON_S_STOPPED, -1} },
146  { MON_S_FAILED, MON_E_FAILURE, NULL, {-1} },
147 };
148 
150 {
151  return (&mon_service_engine);
152 }
153 
154 static const char * mon_res_state_to_str(struct cs_fsm* fsm,
155  int32_t state)
156 {
157  switch (state) {
158  case MON_S_STOPPED:
159  return mon_stopped_str;
160  break;
161  case MON_S_RUNNING:
162  return mon_running_str;
163  break;
164  case MON_S_FAILED:
165  return mon_failed_str;
166  break;
167  }
168  return NULL;
169 }
170 
171 static const char * mon_res_event_to_str(struct cs_fsm* fsm,
172  int32_t event)
173 {
174  switch (event) {
176  return mon_config_changed_str;
177  break;
178  case MON_E_FAILURE:
179  return mon_failure_str;
180  break;
181  }
182  return NULL;
183 }
184 
185 static void mon_fsm_cb (struct cs_fsm *fsm, int cb_event, int32_t curr_state,
186  int32_t next_state, int32_t fsm_event, void *data)
187 {
188  switch (cb_event) {
190  log_printf (LOGSYS_LEVEL_ERROR, "Fsm:%s could not find event \"%s\" in state \"%s\"",
191  fsm->name, fsm->event_to_str(fsm, fsm_event), fsm->state_to_str(fsm, curr_state));
193  break;
195  log_printf (LOGSYS_LEVEL_INFO, "Fsm:%s event \"%s\", state \"%s\" --> \"%s\"",
196  fsm->name,
197  fsm->event_to_str(fsm, fsm_event),
198  fsm->state_to_str(fsm, fsm->table[fsm->curr_entry].curr_state),
199  fsm->state_to_str(fsm, next_state));
200  break;
202  log_printf (LOGSYS_LEVEL_CRIT, "Fsm:%s Can't change state from \"%s\" to \"%s\" (event was \"%s\")",
203  fsm->name,
204  fsm->state_to_str(fsm, fsm->table[fsm->curr_entry].curr_state),
205  fsm->state_to_str(fsm, next_state),
206  fsm->event_to_str(fsm, fsm_event));
208  break;
209  default:
210  log_printf (LOGSYS_LEVEL_CRIT, "Fsm: Can't find callback event!");
212  break;
213  }
214 }
215 
216 static void mon_fsm_state_set (struct cs_fsm* fsm,
217  enum mon_resource_state next_state, struct resource_instance* inst)
218 {
219  enum mon_resource_state prev_state = fsm->curr_state;
220  const char *state_str;
221  char key_name[ICMAP_KEYNAME_MAXLEN];
222 
223  ENTER();
224 
225  cs_fsm_state_set(fsm, next_state, inst, mon_fsm_cb);
226 
227  if (prev_state == fsm->curr_state) {
228  return;
229  }
230  state_str = mon_res_state_to_str(fsm, fsm->curr_state);
231 
232  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "state");
233  icmap_set_string(key_name, state_str);
234 }
235 
236 
237 static void mon_config_changed (struct cs_fsm* fsm, int32_t event, void * data)
238 {
239  struct resource_instance * inst = (struct resource_instance *)data;
240  uint64_t tmp_value;
241  char key_name[ICMAP_KEYNAME_MAXLEN];
242  int run_updater;
243 
244  ENTER();
245 
246  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "poll_period");
247  if (icmap_get_uint64(key_name, &tmp_value) == CS_OK) {
248  if (tmp_value >= MON_MIN_PERIOD && tmp_value <= MON_MAX_PERIOD) {
250  "poll_period changing from:%"PRIu64" to %"PRIu64".",
251  inst->period, tmp_value);
252  inst->period = tmp_value;
253  } else {
255  "Could NOT use poll_period:%"PRIu64" ms for resource %s",
256  tmp_value, inst->name);
257  }
258  }
259 
260  if (inst->timer_handle) {
261  api->timer_delete(inst->timer_handle);
262  inst->timer_handle = 0;
263  }
264 
265  run_updater = 0;
266 
267  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "max");
268  if (inst->max_type == ICMAP_VALUETYPE_INT32) {
269  if (icmap_get_int32(key_name, &inst->max.int32) != CS_OK) {
270  inst->max.int32 = INT32_MAX;
271 
272  mon_fsm_state_set (fsm, MON_S_STOPPED, inst);
273  } else {
274  run_updater = 1;
275  }
276  }
277  if (inst->max_type == ICMAP_VALUETYPE_DOUBLE) {
278  if (icmap_get_double(key_name, &inst->max.dbl) != CS_OK) {
279  inst->max.dbl = INT32_MAX;
280 
281  mon_fsm_state_set (fsm, MON_S_STOPPED, inst);
282  } else {
283  run_updater = 1;
284  }
285  }
286 
287  if (run_updater) {
288  mon_fsm_state_set (fsm, MON_S_RUNNING, inst);
289  /*
290  * run the updater, incase the period has shortened
291  * and to start the timer.
292  */
293  inst->update_stats_fn (inst);
294  }
295 }
296 
297 void mon_resource_failed (struct cs_fsm* fsm, int32_t event, void * data)
298 {
299  struct resource_instance * inst = (struct resource_instance *)data;
300  ENTER();
301  mon_fsm_state_set (fsm, MON_S_FAILED, inst);
302 }
303 
304 static int32_t percent_mem_used_get(void)
305 {
306  sg_mem_stats *mem_stats;
307  sg_swap_stats *swap_stats;
308  long long total, freemem;
309 
310  mem_stats = sg_get_mem_stats();
311  swap_stats = sg_get_swap_stats();
312 
313  if (mem_stats == NULL || swap_stats != NULL) {
314  log_printf (LOGSYS_LEVEL_ERROR, "Unable to get memory stats: %s",
315  sg_str_error(sg_get_error()));
316  return -1;
317  }
318  total = mem_stats->total + swap_stats->total;
319  freemem = mem_stats->free + swap_stats->free;
320  return ((total - freemem) * 100) / total;
321 }
322 
323 static void mem_update_stats_fn (void *data)
324 {
325  struct resource_instance * inst = (struct resource_instance *)data;
326  int32_t new_value;
327  uint64_t timestamp;
328  char key_name[ICMAP_KEYNAME_MAXLEN];
329 
330  new_value = percent_mem_used_get();
331  if (new_value > 0) {
332  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "current");
333  icmap_set_uint32(key_name, new_value);
334 
335  timestamp = cs_timestamp_get();
336 
337  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "last_updated");
338  icmap_set_uint64(key_name, timestamp);
339 
340  if (new_value > inst->max.int32 && inst->fsm.curr_state != MON_S_FAILED) {
341  cs_fsm_process (&inst->fsm, MON_E_FAILURE, inst, mon_fsm_cb);
342  }
343  }
345  inst, inst->update_stats_fn, &inst->timer_handle);
346 }
347 
348 static double min15_loadavg_get(void)
349 {
350  sg_load_stats *load_stats;
351  load_stats = sg_get_load_stats ();
352  if (load_stats == NULL) {
353  log_printf (LOGSYS_LEVEL_ERROR, "Unable to get load stats: %s",
354  sg_str_error (sg_get_error()));
355  return -1;
356  }
357  return load_stats->min15;
358 }
359 
360 static void load_update_stats_fn (void *data)
361 {
362  struct resource_instance * inst = (struct resource_instance *)data;
363  uint64_t timestamp;
364  char key_name[ICMAP_KEYNAME_MAXLEN];
365  double min15 = min15_loadavg_get();
366 
367  if (min15 > 0) {
368  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "current");
369  icmap_set_double(key_name, min15);
370 
371  timestamp = cs_timestamp_get();
372 
373  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "last_updated");
374  icmap_set_uint64(key_name, timestamp);
375 
376  if (min15 > inst->max.dbl && inst->fsm.curr_state != MON_S_FAILED) {
377  cs_fsm_process (&inst->fsm, MON_E_FAILURE, &inst, mon_fsm_cb);
378  }
379  }
380 
382  inst, inst->update_stats_fn, &inst->timer_handle);
383 }
384 
385 static void mon_key_changed_cb (
386  int32_t event,
387  const char *key_name,
388  struct icmap_notify_value new_value,
389  struct icmap_notify_value old_value,
390  void *user_data)
391 {
392  struct resource_instance* inst = (struct resource_instance*)user_data;
393  char *last_key_part;
394 
395  if (event == ICMAP_TRACK_DELETE && inst) {
397  "resource \"%s\" deleted from cmap!",
398  inst->name);
399 
400  cs_fsm_process (&inst->fsm, MON_E_CONFIG_CHANGED, inst, mon_fsm_cb);
401  }
402 
403  if (event == ICMAP_TRACK_MODIFY) {
404  last_key_part = strrchr(key_name, '.');
405  if (last_key_part == NULL)
406  return ;
407 
408  last_key_part++;
409  if (strcmp(last_key_part, "max") == 0 ||
410  strcmp(last_key_part, "poll_period") == 0) {
411  ENTER();
412  cs_fsm_process (&inst->fsm, MON_E_CONFIG_CHANGED, inst, mon_fsm_cb);
413  }
414  }
415 }
416 
417 static void mon_instance_init (struct resource_instance* inst)
418 {
419  uint64_t tmp_value;
420  char key_name[ICMAP_KEYNAME_MAXLEN];
421  icmap_track_t icmap_track = NULL;
422 
423  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "current");
424  if (inst->max_type == ICMAP_VALUETYPE_INT32) {
425  icmap_set_int32(key_name, 0);
426  } else {
427  icmap_set_double(key_name, 0);
428  }
429 
430  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "last_updated");
431  icmap_set_uint64(key_name, 0);
432 
433  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "state");
435 
436  inst->fsm.name = inst->name;
437  inst->fsm.curr_entry = 0;
438  inst->fsm.curr_state = MON_S_STOPPED;
439  inst->fsm.table = mon_fsm_table;
440  inst->fsm.entries = sizeof(mon_fsm_table) / sizeof(struct cs_fsm_entry);
441  inst->fsm.state_to_str = mon_res_state_to_str;
442  inst->fsm.event_to_str = mon_res_event_to_str;
443 
444  snprintf(key_name, ICMAP_KEYNAME_MAXLEN, "%s%s", inst->icmap_path, "poll_period");
445  if (icmap_get_uint64(key_name, &tmp_value) != CS_OK) {
446  icmap_set_uint64(key_name, inst->period);
447  }
448  else {
449  if (tmp_value >= MON_MIN_PERIOD && tmp_value <= MON_MAX_PERIOD) {
450  inst->period = tmp_value;
451  } else {
453  "Could NOT use poll_period:%"PRIu64" ms for resource %s",
454  tmp_value, inst->name);
455  }
456  }
457  cs_fsm_process (&inst->fsm, MON_E_CONFIG_CHANGED, inst, mon_fsm_cb);
458 
461  mon_key_changed_cb, inst, &icmap_track);
462 }
463 
464 static char *mon_exec_init_fn (struct corosync_api_v1 *corosync_api)
465 {
466  sg_init();
467 
468  api = corosync_api;
469 
470  mon_instance_init (&memory_used_inst);
471  mon_instance_init (&load_15min_inst);
472 
473  return NULL;
474 }
475 
476 
const char * name
Definition: coroapi.h:432
const char * mon_running_str
Definition: mon.c:124
#define LOGSYS_LEVEL_INFO
Definition: logsys.h:73
int32_t curr_state
Definition: fsm.h:67
void(* timer_delete)(corosync_timer_handle_t timer_handle)
Definition: coroapi.h:193
double dbl
Definition: mon.c:92
struct cs_fsm fsm
Definition: mon.c:87
int(* timer_add_duration)(unsigned long long nanoseconds_in_future, void *data, void(*timer_nf)(void *data), corosync_timer_handle_t *handle)
Definition: coroapi.h:181
#define corosync_exit_error(err)
Definition: exec/util.h:69
Definition: fsm.h:65
corosync_timer_handle_t timer_handle
Definition: mon.c:85
icmap_value_types_t max_type
Definition: mon.c:89
struct cs_fsm_entry mon_fsm_table[]
Definition: mon.c:140
cs_fsm_event_to_str_fn event_to_str
Definition: fsm.h:72
#define MON_MAX_PERIOD
Definition: mon.c:60
cs_error_t icmap_set_string(const char *key_name, const char *value)
Definition: icmap.c:641
const char * icmap_path
Definition: mon.c:83
mon_resource_event
Definition: mon.c:135
#define log_printf(level, format, args...)
Definition: logsys.h:217
cs_error_t icmap_get_int32(const char *key_name, int32_t *i32)
Definition: icmap.c:860
#define ICMAP_TRACK_DELETE
Definition: icmap.h:77
#define ICMAP_KEYNAME_MAXLEN
Definition: icmap.h:48
size_t entries
Definition: fsm.h:69
void(* update_stats_fn)(void *data)
Definition: mon.c:86
#define LOGSYS_LEVEL_WARNING
Definition: logsys.h:71
#define ICMAP_TRACK_MODIFY
Definition: icmap.h:78
cs_error_t icmap_set_uint32(const char *key_name, uint32_t value)
Definition: icmap.c:611
void * user_data
Definition: sam.c:126
#define LOGSYS_DECLARE_SUBSYS(subsys)
Definition: logsys.h:197
#define ICMAP_TRACK_ADD
Definition: icmap.h:76
const char * name
Definition: fsm.h:66
#define LOGSYS_LEVEL_ERROR
Definition: logsys.h:70
Linked list API.
#define DECLARE_LIST_INIT(name)
Definition: list.h:51
#define LOGSYS_LEVEL_DEBUG
Definition: logsys.h:74
#define CS_FSM_CB_EVENT_STATE_SET
Definition: fsm.h:55
const char * name
Definition: mon.c:84
cs_error_t icmap_set_uint64(const char *key_name, uint64_t value)
Definition: icmap.c:623
struct corosync_service_engine mon_service_engine
Definition: mon.c:62
#define ENTER
Definition: logsys.h:218
cs_fsm_state_to_str_fn state_to_str
Definition: fsm.h:71
cs_error_t icmap_set_int32(const char *key_name, int32_t value)
Definition: icmap.c:605
#define MILLI_2_NANO_SECONDS
Definition: coroapi.h:92
Definition: fsm.h:58
const char * mon_failed_str
Definition: mon.c:125
#define CS_FSM_CB_EVENT_PROCESS_NF
Definition: fsm.h:54
cs_error_t icmap_get_uint64(const char *key_name, uint64_t *u64)
Definition: icmap.c:878
#define CS_FSM_CB_EVENT_STATE_SET_NF
Definition: fsm.h:56
#define MON_DEFAULT_PERIOD
Definition: mon.c:58
cs_error_t icmap_set_double(const char *key_name, double value)
Definition: icmap.c:635
qb_loop_timer_handle corosync_timer_handle_t
Definition: coroapi.h:64
mon_resource_state
Definition: mon.c:130
uint64_t period
Definition: mon.c:88
#define LOGSYS_LEVEL_CRIT
Definition: logsys.h:69
int32_t curr_entry
Definition: fsm.h:68
#define MON_MIN_PERIOD
Definition: mon.c:59
union resource_instance::@6 max
cs_error_t icmap_get_double(const char *key_name, double *dbl)
Definition: icmap.c:890
const char * mon_config_changed_str
Definition: mon.c:128
int32_t curr_state
Definition: fsm.h:59
struct cs_fsm_entry * table
Definition: fsm.h:70
icmap_value_types_t
Definition: icmap.h:58
struct corosync_service_engine * mon_get_service_engine_ver0(void)
Definition: mon.c:149
const char * mon_failure_str
Definition: mon.c:126
cs_error_t icmap_track_add(const char *key_name, int32_t track_type, icmap_notify_fn_t notify_fn, void *user_data, icmap_track_t *icmap_track)
Definition: icmap.c:1167
int32_t int32
Definition: mon.c:91
#define ICMAP_TRACK_PREFIX
Definition: icmap.h:84
const char * mon_stopped_str
Definition: mon.c:127