#pragma once #include // I keep these declaration here because of following error: // error: there are no arguments to ‘increment_outgoing_counters’ that depend on a template parameter, so a declaration of ‘increment_outgoing_counters’ must be available [-fpermissive] // increment_outgoing_counters(counter_ptr, current_packet, sampled_number_of_packets, sampled_number_of_bytes); void increment_incoming_counters(map_element_t* current_element, simple_packet_t& current_packet, uint64_t sampled_number_of_packets, uint64_t sampled_number_of_bytes); void build_speed_counters_from_packet_counters(map_element_t& new_speed_element, map_element_t* vector_itr, double speed_calc_period); void increment_outgoing_counters(map_element_t* current_element, simple_packet_t& current_packet, uint64_t sampled_number_of_packets, uint64_t sampled_number_of_bytes); void build_average_speed_counters_from_speed_counters(map_element_t* current_average_speed_element, map_element_t& new_speed_element, double exp_value, double exp_power); // Class for abstract per key counters template class abstract_subnet_counters_t { public: std::unordered_map counter_map; std::mutex counter_map_mutex; std::unordered_map speed_map; std::unordered_map average_speed_map; // Increments outgoing counters for specified key void increment_outgoing_counters_for_key(T key, simple_packet_t& current_packet, uint64_t sampled_number_of_packets, uint64_t sampled_number_of_bytes) { std::lock_guard lock_guard(counter_map_mutex); subnet_counter_t* counter_ptr = &counter_map[key]; increment_outgoing_counters(counter_ptr, current_packet, sampled_number_of_packets, sampled_number_of_bytes); } // Increments incoming counters for specified key void increment_incoming_counters_for_key(T key, simple_packet_t& current_packet, uint64_t sampled_number_of_packets, uint64_t sampled_number_of_bytes) { std::lock_guard lock_guard(counter_map_mutex); subnet_counter_t* counter_ptr = &counter_map[key]; increment_incoming_counters(counter_ptr, current_packet, sampled_number_of_packets, sampled_number_of_bytes); } uint64_t purge_old_data(unsigned int automatic_data_cleanup_threshold) { std::lock_guard lock_guard(this->counter_map_mutex); std::vector keys_to_remove; time_t current_time = 0; time(¤t_time); for (auto itr = this->counter_map.begin(); itr != this->counter_map.end(); ++itr) { if ((int64_t)itr->second.last_update_time < int64_t((int64_t)current_time - (int64_t)automatic_data_cleanup_threshold)) { keys_to_remove.push_back(itr->first); } } for (const auto& key : keys_to_remove) { counter_map.erase(key); speed_map.erase(key); average_speed_map.erase(key); } // Report number of removed records return keys_to_remove.size(); } void recalculate_speed(double speed_calc_period, double average_calculation_time_for_subnets, std::function speed_check_callback) { std::lock_guard lock_guard(this->counter_map_mutex); for (auto itr = this->counter_map.begin(); itr != this->counter_map.end(); ++itr) { T current_key = itr->first; subnet_counter_t* subnet_traffic = &itr->second; subnet_counter_t new_speed_element; build_speed_counters_from_packet_counters(new_speed_element, subnet_traffic, speed_calc_period); /* Moving average recalculation for subnets */ /* http://en.wikipedia.org/wiki/Moving_average#Application_to_measuring_computer_performance */ double exp_power_subnet = -speed_calc_period / average_calculation_time_for_subnets; double exp_value_subnet = exp(exp_power_subnet); map_element_t* current_average_speed_element = &average_speed_map[current_key]; build_average_speed_counters_from_speed_counters(current_average_speed_element, new_speed_element, exp_value_subnet, exp_power_subnet); // Update speed calculation structure in single step this->speed_map[current_key] = new_speed_element; subnet_traffic->zeroify(); // Check thresholds speed_check_callback(¤t_key, current_average_speed_element); } } // Returns all non zero average speed elements void get_all_non_zero_average_speed_elements_as_pairs(std::vector>& all_elements) { std::lock_guard lock_guard(this->counter_map_mutex); for (auto itr = this->average_speed_map.begin(); itr != this->average_speed_map.end(); ++itr) { if (itr->second.is_zero()) { continue; } all_elements.push_back(std::make_pair(itr->first, itr->second)); } } void get_sorted_average_speed(std::vector>& vector_for_sort, sort_type_t sorter_type, direction_t sort_direction) { std::lock_guard lock_guard(this->counter_map_mutex); vector_for_sort.reserve(average_speed_map.size()); std::copy(average_speed_map.begin(), average_speed_map.end(), std::back_inserter(vector_for_sort)); std::sort(vector_for_sort.begin(), vector_for_sort.end(), TrafficComparatorClass>(sort_direction, sorter_type)); } // Retrieves average speed for specified key with all locks bool get_average_speed_subnet(T key, map_element_t& average_speed_element) { std::lock_guard lock_guard(this->counter_map_mutex); auto average_speed_itr = this->average_speed_map.find(key); if (average_speed_itr == this->average_speed_map.end()) { return false; } average_speed_element = average_speed_itr->second; return true; } // Please create vector_for_sort this way on callers side: top_four(4); void get_top_k_average_speed(std::vector>& vector_for_sort, sort_type_t sorter_type, direction_t sort_direction) { std::lock_guard lock_guard(this->counter_map_mutex); std::partial_sort_copy(average_speed_map.begin(), average_speed_map.end(), vector_for_sort.begin(), vector_for_sort.end(), TrafficComparatorClass>(sort_direction, sorter_type)); } };