function output_rrd_data($start_time, $force = FALSE) { global $start, $max_run_duration, $config, $debug, $get_memory, $memory_used; global $rrdtool_pipe, $rrdtool_read_pipe; include_once $config['base_path'] . '/lib/rrd.php'; $boost_poller_status = read_config_option('boost_poller_status'); $rrd_updates = 0; /* implement process lock control for boost */ if (!db_fetch_cell("SELECT GET_LOCK('poller_boost', 1)")) { if ($debug) { cacti_log('DEBUG: Found lock, so another boost process is running'); } return -1; } /* detect a process that has overrun it's warning time */ if (substr_count($boost_poller_status, 'running')) { $status_array = explode(':', $boost_poller_status); if (!empty($status_array[1])) { $previous_start_time = strtotime($status_array[1]); /* if the runtime was exceeded, allow the next process to run */ if ($previous_start_time + $max_run_duration < $start_time) { cacti_log('WARNING: Detected Poller Boost Overrun, Possible Boost Poller Crash', FALSE, 'BOOST SVR'); } } } /* if the poller is not running, or has never run, start */ /* mark the boost server as running */ db_execute("REPLACE INTO settings (name, value) VALUES ('boost_poller_status', 'running - start time:" . date('Y-m-d G:i:s') . "')"); $current_time = date('Y-m-d G:i:s', $start_time); $rrdtool_pipe = rrd_init(); $rrdtool_read_pipe = rrd_init(); $runtime_exceeded = false; /* let's set and track memory usage will we */ if (!function_exists('memory_get_peak_usage')) { $get_memory = true; $memory_used = memory_get_usage(); } else { $get_memory = false; } $delayed_inserts = db_fetch_row("SHOW STATUS LIKE 'Not_flushed_delayed_rows'"); while ($delayed_inserts['Value']) { cacti_log('BOOST WAIT: Waiting 1s for delayed inserts are made', true, 'SYSTEM'); usleep(1000000); $delayed_inserts = db_fetch_row("SHOW STATUS LIKE 'Not_flushed_delayed_rows'"); } /* split poller_output_boost */ $archive_table = 'poller_output_boost_arch_' . time(); db_execute("RENAME TABLE poller_output_boost TO {$archive_table}"); db_execute("CREATE TABLE poller_output_boost LIKE {$archive_table}"); $more_arch_tables = db_fetch_assoc("SELECT table_name AS name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema=SCHEMA()\n\t\tAND table_name LIKE 'poller_output_boost_arch_%'\n\t\tAND table_name!='{$archive_table}'\n\t\tAND table_rows>0;"); if (count($more_arch_tables)) { foreach ($more_arch_tables as $table) { $table_name = $table['name']; db_execute("INSERT INTO {$archive_table} SELECT * FROM {$table_name}"); db_execute("TRUNCATE TABLE {$table_name}"); } } if (!strlen($archive_table)) { cacti_log('ERROR: Failed to retrieve archive table name'); return -1; } while (1) { $rows = db_fetch_cell("SELECT count(*) FROM {$archive_table}"); if ($rows > 0) { $rrd_updates += boost_process_poller_output(FALSE, '', $current_time); if ($get_memory) { $cur_memory = memory_get_usage(); if ($cur_memory > $memory_used) { $memory_used = $cur_memory; } } } else { break; } if (time() - $start > $max_run_duration && !$runtime_exceeded) { cacti_log('WARNING: RRD On Demand Updater Exceeded Runtime Limits. Continuing to Process!!!'); $runtime_exceeded = true; } } /* tell the main poller that we are done */ db_execute("REPLACE INTO settings (name, value) VALUES ('boost_poller_status', 'complete - end time:" . date('Y-m-d G:i:s') . "')"); /* log memory usage */ if (function_exists('memory_get_peak_usage')) { db_execute("REPLACE INTO settings (name, value) VALUES ('boost_peak_memory', '" . memory_get_peak_usage() . "')"); } else { db_execute("REPLACE INTO settings (name, value) VALUES ('boost_peak_memory', '" . $memory_used . "')"); } rrd_close($rrdtool_pipe); rrd_close($rrdtool_read_pipe); /* cleanup - remove empty arch tables */ $tables = db_fetch_assoc("SELECT table_name AS name\n\t\tFROM information_schema.tables\n\t\tWHERE table_schema=SCHEMA()\n\t\tAND table_name LIKE 'poller_output_boost_arch_%'\n\t\tAND table_rows=0;"); if (count($tables)) { foreach ($tables as $table) { db_execute('DROP TABLE ' . $table['name']); } } db_execute("SELECT RELEASE_LOCK('poller_boost');"); return $rrd_updates; }
function boost_process_poller_output($use_server = FALSE, $local_data_id = "") { global $config, $boost_sock, $boost_timeout, $debug, $get_memory, $memory_used; global $rrdtool_pipe, $rrdtool_read_pipe; include_once $config["library_path"] . "/rrd.php"; /* suppress warnings */ if (defined("E_DEPRECATED")) { error_reporting(E_ALL ^ E_DEPRECATED); } else { error_reporting(E_ALL); } /* install the boost error handler */ set_error_handler("boost_error_handler"); /* load system variables needed */ $log_verbosity = read_config_option("log_verbosity"); $upd_string_len = read_config_option("boost_rrd_update_string_length"); /* tiny SQL where addendum for boost */ if (strlen($local_data_id)) { /* we can simplify the delete process if only one local_data_id */ $single_local_data_id = TRUE; $orig_local_data_id = $local_data_id; /* aquire lock in order to prevent race conditions */ while (!db_fetch_cell("SELECT GET_LOCK('boost.single_ds.{$local_data_id}', 1)")) { usleep(50000); } } else { $single_local_data_id = FALSE; $poller_interval = read_config_option("poller_interval"); $rrd_update_interval = read_config_option("boost_rrd_update_interval"); $data_ids_to_get = read_config_option("boost_rrd_update_max_records_per_select"); $archive_table = boost_get_arch_table_name(); if ($archive_table === FALSE) { cacti_log("Failed to determine archive table", FALSE, "BOOST"); return 0; } } /* get the records */ if ($single_local_data_id) { $query_string = ""; $arch_tables = db_fetch_assoc("\tSELECT table_name AS name\r\n\t\t\t\t\t\tFROM information_schema.tables\r\n\t\t\t\t\t\t\tWHERE table_schema=SCHEMA()\r\n\t\t\t\t\t\t\tAND table_name LIKE 'poller_output_boost_arch_%'\r\n\t\t\t\t\t\t\tAND table_rows>0;\r\n\t\t\t\t\t\t"); if (count($arch_tables)) { foreach ($arch_tables as $table) { if (strlen($query_string)) { $query_string .= " UNION "; } $query_string .= " ( SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM " . $table["name"] . " WHERE local_data_id='{$local_data_id}' ) "; } } if (strlen($query_string)) { $query_string .= " UNION "; } $timestamp = time(); $query_string .= " ( SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM poller_output_boost WHERE local_data_id='{$local_data_id}' AND time < FROM_UNIXTIME('{$timestamp}') ) "; $query_string .= " ORDER BY local_data_id ASC, timestamp ASC, rrd_name ASC "; } else { $query_string = "SELECT local_data_id, UNIX_TIMESTAMP(time) AS timestamp, rrd_name, output FROM {$archive_table} FORCE INDEX (PRIMARY)\r\n\t\t\t\tORDER BY local_data_id ASC, time ASC, rrd_name ASC\r\n\t\t\t\tLIMIT {$data_ids_to_get} "; } boost_timer("get_records", BOOST_TIMER_START); $results = db_fetch_assoc($query_string); boost_timer("get_records", BOOST_TIMER_END); /* log memory */ if ($get_memory) { $cur_memory = memory_get_usage(); if ($cur_memory > $memory_used) { $memory_used = $cur_memory; } } if ($single_local_data_id && ($debug || $log_verbosity >= POLLER_VERBOSITY_MEDIUM)) { cacti_log("NOTE: Updating Local Data ID:'{$local_data_id}', Total of '" . sizeof($results) . "' Updates to Process", FALSE, "BOOST"); } if (sizeof($results) > 0) { /* open the boost socket connection if applicable */ if (read_config_option("boost_server_enable") == "on" && $local_data_id != "" && $use_server) { $boost_timeout = read_config_option("boost_server_timeout"); $boost_sock = boost_server_connect(); if ($boost_sock < 0) { /* restore original error handler */ restore_error_handler(); return 0; } } /* create an array keyed off of each .rrd file */ $local_data_id = -1; $time = -1; $outbuf = ""; $last_update = -1; $last_item = array("local_data_id" => -1, "timestamp" => -1, "rrd_name" => ""); /* we are going to blow away all record if ok */ $vals_in_buffer = 0; /* cut last DS (likely to be incomplete due to LIMIT)*/ if (!$single_local_data_id) { reset($results); $first_ds = $results[key($results)]; $first_ds = intval($first_ds["local_data_id"]); end($results); $last_ds = $results[key($results)]; $last_ds = intval($last_ds["local_data_id"]); reset($results); if ($first_ds == $last_ds) { if (sizeof($results) == $data_ids_to_get) { cacti_log("FALURE: Current LIMIT ({$data_ids_to_get}) is too low to run multiple DS RRD writes, consider raising it", FALSE, "BOOST"); } restore_error_handler(); return boost_process_poller_output($use_server, $first_ds); } } boost_timer("results_cycle", BOOST_TIMER_START); /* go through each poller_output_boost entries and process */ foreach ($results as $item) { $item["timestamp"] = trim($item["timestamp"]); if ($single_local_data_id && $last_item["local_data_id"] == $item["local_data_id"] && $last_item["timestamp"] == $item["timestamp"] && strcmp($last_item["rrd_name"], $item["rrd_name"]) == 0) { continue; } if (!$single_local_data_id && $first_ds != $last_ds && $last_ds == $item["local_data_id"]) { /* we faced last and possibly incomplete DS, bail out */ break; } /* if the local_data_id changes, we need to flush the buffer */ if ($local_data_id != $item["local_data_id"]) { /* update the rrd for the previous local_data_id */ if ($vals_in_buffer) { if ($debug || $log_verbosity >= POLLER_VERBOSITY_MEDIUM) { cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST"); } boost_timer("rrdupdate", BOOST_TIMER_START); $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe); boost_timer("rrdupdate", BOOST_TIMER_END); $outbuf = ""; $vals_in_buffer = 0; /* check return status for delete operation */ if (trim($return_value) != "OK") { cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST"); } } /* reset the rrd file path and templates, assume non multi output */ boost_timer("rrd_filename_and_template", BOOST_TIMER_START); $rrd_data = boost_get_rrd_filename_and_template($item["local_data_id"]); $rrd_tmpl = $rrd_data["rrd_template"]; $rrd_path = $rrd_data["rrd_path"]; boost_timer("rrd_filename_and_template", BOOST_TIMER_END); $pipe = is_resource($rrdtool_read_pipe) || is_array($rrdtool_read_pipe) ? $rrdtool_read_pipe : $rrdtool_pipe; boost_timer("rrd_lastupdate", BOOST_TIMER_START); $last_update = boost_rrdtool_get_last_update_time($rrd_path, $pipe); boost_timer("rrd_lastupdate", BOOST_TIMER_END); $local_data_id = $item["local_data_id"]; $time = $item["timestamp"]; $initial_time = $time; $outbuf = " " . $time; $multi_vals_set = FALSE; } /* don't generate error messages if the RRD has already been updated */ if ($time <= $last_update) { cacti_log("WARNING: Stale Poller Data Found! Item Time:'" . $time . "', RRD Time:'" . $last_update . "' Ignoring Value!", FALSE, "BOOST"); $value = 'DNP'; } else { $value = trim($item["output"]); } if ($time != $item["timestamp"]) { if (strlen($outbuf) > $upd_string_len) { if ($log_verbosity >= POLLER_VERBOSITY_MEDIUM) { cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST"); } boost_timer("rrdupdate", BOOST_TIMER_START); $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe); boost_timer("rrdupdate", BOOST_TIMER_END); $outbuf = ""; $vals_in_buffer = 0; /* check return status for delete operation */ if (trim($return_value) != "OK") { cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST"); } } $outbuf .= " " . $item["timestamp"]; $time = $item["timestamp"]; } /* single one value output */ if (strcmp($value, 'DNP') == 0) { /* continue, bad time */ } elseif (is_numeric($value) || strcmp($value, "U") == 0) { $outbuf .= ":" . $value; $vals_in_buffer++; } elseif (function_exists("is_hexadecimal") && is_hexadecimal($value)) { $outbuf .= ":" . hexdec($value); $vals_in_buffer++; } elseif (strlen($value)) { /* break out multiple value output to an array */ $values = explode(" ", $value); if (!$multi_vals_set) { $rrd_field_names = array_rekey(db_fetch_assoc("SELECT\r\n\t\t\t\t\t\tdata_template_rrd.data_source_name,\r\n\t\t\t\t\t\tdata_input_fields.data_name\r\n\t\t\t\t\t\tFROM (data_template_rrd,data_input_fields)\r\n\t\t\t\t\t\tWHERE data_template_rrd.data_input_field_id=data_input_fields.id\r\n\t\t\t\t\t\tAND data_template_rrd.local_data_id=" . $item["local_data_id"]), "data_name", "data_source_name"); $rrd_tmpl = ""; } $first_tmpl = 1; $multi_ok = FALSE; for ($i = 0; $i < count($values); $i++) { if (preg_match("/^([a-zA-Z0-9_\\.-]+):([eE0-9\\+\\.-]+)\$/", $values[$i], $matches)) { if (isset($rrd_field_names[$matches[1]])) { $multi_ok = TRUE; if ($log_verbosity == POLLER_VERBOSITY_DEBUG) { cacti_log("Parsed MULTI output field '" . $matches[0] . "' [map " . $matches[1] . "->" . $rrd_field_names[$matches[1]] . "]", FALSE, "BOOST"); } if (!$multi_vals_set) { if (!$first_tmpl) { $rrd_tmpl .= ":"; } $rrd_tmpl .= $rrd_field_names[$matches[1]]; $first_tmpl = 0; } if (is_numeric($matches[2]) || $matches[2] == "U") { $outbuf .= ":" . $matches[2]; } elseif (function_exists("is_hexadecimal") && is_hexadecimal($matches[2])) { $outbuf .= ":" . hexdec($matches[2]); } else { $outbuf .= ":U"; } } } } /* we only want to process the template and gather the fields once */ $multi_vals_set = TRUE; if ($multi_ok) { $vals_in_buffer++; } } else { cacti_log("WARNING: Local Data Id [" . $item["local_data_id"] . "] Contains an empty value", FALSE, "BOOST"); } } /* process the last rrdupdate if applicable */ if ($vals_in_buffer) { if ($log_verbosity >= POLLER_VERBOSITY_MEDIUM) { cacti_log("NOTE: Updating Local Data Id:'{$local_data_id}', Template:" . $rrd_tmpl . ", Output:" . $outbuf, FALSE, "BOOST"); } boost_timer("rrdupdate", BOOST_TIMER_START); $return_value = boost_rrdtool_function_update($local_data_id, $rrd_path, $rrd_tmpl, $initial_time, $outbuf, $rrdtool_pipe); boost_timer("rrdupdate", BOOST_TIMER_END); /* check return status for delete operation */ if (trim($return_value) != "OK") { cacti_log("WARNING: RRD Update Warning '" . $return_value . "' for Local Data ID '{$local_data_id}'", FALSE, "BOOST"); } } boost_timer("results_cycle", BOOST_TIMER_END); /* remove the entries from the table */ boost_timer("delete", BOOST_TIMER_START); if ($single_local_data_id) { $tables = db_fetch_assoc("SELECT table_name AS name\r\n\t\t\t\t\t\tFROM information_schema.tables\r\n\t\t\t\t\t\tWHERE table_schema=SCHEMA()\r\n\t\t\t\t\t\tAND ( table_name LIKE 'poller_output_boost_arch_%' OR table_name LIKE 'poller_output_boost' )\r\n\t\t\t\t\t\tAND table_rows>0;\r\n\t\t\t\t\t\t"); if (count($tables)) { foreach ($tables as $table) { db_execute("DELETE FROM " . $table["name"] . " WHERE local_data_id='{$local_data_id}' AND time < FROM_UNIXTIME('{$timestamp}')"); } } } else { db_execute("DELETE FROM {$archive_table} WHERE local_data_id BETWEEN '{$first_ds}' AND '" . ($last_ds - 1) . "'"); } boost_timer("delete", BOOST_TIMER_END); /* close the boost server connection, if applicable */ if (read_config_option("boost_server_enable") == "on" && $local_data_id != "" && $use_server) { boost_server_disconnect($boost_sock); } } if ($single_local_data_id) { db_execute("SELECT RELEASE_LOCK('boost.single_ds.{$orig_local_data_id}')"); } /* restore original error handler */ restore_error_handler(); return sizeof($results); }
function get_current_value($rra, $ds, $cdef = 0) { global $config; /* get the information to populate into the rrd files */ if (function_exists("boost_check_correct_enabled") && boost_check_correct_enabled()) { boost_process_poller_output(TRUE, $rra); } $last_time_entry = thold_rrd_last($rra); // This should fix and 'did you really mean month 899 errors', this is because your RRD has not polled yet if ($last_time_entry == -1) { $last_time_entry = time(); } $data_template_data = db_fetch_row("SELECT * FROM data_template_data WHERE local_data_id={$rra}"); $step = $data_template_data['rrd_step']; // Round down to the nearest 100 $last_time_entry = intval($last_time_entry / 100) * 100 - $step; $last_needed = $last_time_entry + $step; $result = rrdtool_function_fetch($rra, trim($last_time_entry), trim($last_needed)); // Return Blank if the data source is not found (Newly created?) if (!isset($result['data_source_names'])) { return ''; } $idx = array_search($ds, $result['data_source_names']); // Return Blank if the value was not found (Cache Cleared?) if (!isset($result['values'][$idx][0])) { return ''; } $value = $result['values'][$idx][0]; if ($cdef != 0) { $value = thold_build_cdef($cdef, $value, $rra, $ds); } return round($value, 4); }