LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-analytics/contrail-query-engine - stats_select.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 384 443 86.7 %
Date: 2026-11-09 02:10:49 Functions: 11 11 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : #include "viz_constants.h"
       6             : #include "stats_select.h"
       7             : #include "stats_query.h"
       8             : #include "query.h"
       9             : #include <cstdlib>
      10             : #include <boost/assign/list_of.hpp>
      11             : #include <boost/functional/hash.hpp>
      12             : #include "rapidjson/document.h"
      13             : #include "rapidjson/stringbuffer.h"
      14             : #include "rapidjson/writer.h"
      15             : 
      16             : using boost::assign::map_list_of; 
      17             : 
      18             : using std::string;
      19             : using std::map;
      20             : using std::vector;
      21             : using std::set;
      22             : using std::pair;
      23             : using std::make_pair;
      24             : 
      25             : struct Centroid {
      26             : };
      27             : 
      28             : void
      29           6 : StatsSelect::DeleteCentroid (Centroid *t) {
      30           6 :     free(t);
      31           6 : }
      32             : 
      33             : struct TDigest {
      34             : };
      35             : 
      36             : void 
      37           3 : StatsSelect::DeleteTDigest(TDigest *t) {
      38           3 :     TDigest_destroy(t);
      39           3 : }
      40             : 
      41             : bool
      42         194 : StatsSelect::Jsonify(const std::string& table,
      43             :         const std::map<std::string, StatVal>&  uniks,
      44             :         const QEOpServerProxy::AggRowT& aggs, std::string& jstr) {
      45             : 
      46         194 :     contrail_rapidjson::Document dd;
      47         194 :     dd.SetObject();  
      48             : 
      49             :     try {
      50         194 :         for (std::map<std::string, StatVal>::const_iterator it = uniks.begin();
      51         871 :                 it!= uniks.end(); it++) {
      52         677 :             switch (it->second.which()) {
      53         372 :                 case QEOpServerProxy::STRING : {
      54         372 :                         string mapit = boost::get<string>(it->second);
      55         372 :                         contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
      56         372 :                         val.SetString(mapit.c_str(), dd.GetAllocator());
      57         372 :                         contrail_rapidjson::Value vk;
      58         372 :                         dd.AddMember(vk.SetString(it->first.c_str(),
      59             :                                                   dd.GetAllocator()),
      60             :                                      val, dd.GetAllocator());
      61         372 :                     }
      62         372 :                     break;
      63          49 :                 case QEOpServerProxy::UUID : {
      64          49 :                         boost::uuids::uuid mapit = boost::get<boost::uuids::uuid>(it->second);
      65          49 :                         contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
      66          49 :                         std::string ustr = to_string(mapit);
      67          49 :                         val.SetString(ustr.c_str(), dd.GetAllocator());
      68          49 :                         contrail_rapidjson::Value vk;
      69          49 :                         dd.AddMember(vk.SetString(it->first.c_str(),
      70             :                                                   dd.GetAllocator()),
      71             :                                      val, dd.GetAllocator()); 
      72          49 :                     }
      73          49 :                     break;
      74         229 :                 case QEOpServerProxy::UINT64 : {
      75         229 :                         uint64_t mapit = boost::get<uint64_t>(it->second);
      76         229 :                         contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
      77         229 :                         val.SetUint64(mapit);
      78         229 :                         contrail_rapidjson::Value vk;
      79         229 :                         dd.AddMember(vk.SetString(it->first.c_str(),
      80             :                                                   dd.GetAllocator()),
      81             :                                      val, dd.GetAllocator());
      82         229 :                     }
      83         229 :                     break;
      84          27 :                 case QEOpServerProxy::DOUBLE : {
      85          27 :                         double mapit = boost::get<double>(it->second);
      86          27 :                         contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
      87          27 :                         val.SetDouble(mapit);
      88          27 :                         contrail_rapidjson::Value vk;
      89          27 :                         dd.AddMember(vk.SetString(it->first.c_str(),
      90             :                                                   dd.GetAllocator()),
      91             :                                      val, dd.GetAllocator());
      92          27 :                     }
      93          27 :                     break;
      94           0 :                 default:
      95           0 :                     QE_ASSERT(0);
      96             :             }
      97             :         }
      98         194 :         for (QEOpServerProxy::AggRowT::const_iterator it = aggs.begin();
      99         301 :                 it!= aggs.end(); it++) {
     100             :             
     101         107 :             string sname("");
     102         107 :             if (it->first.first == QEOpServerProxy::SUM) {
     103         159 :                 if (it->first.second == g_viz_constants.SESSION_FWD_TEARDOWN_BYTES ||
     104         150 :                     it->first.second == g_viz_constants.SESSION_FWD_TEARDOWN_PKTS ||
     105         141 :                     it->first.second == g_viz_constants.SESSION_REV_TEARDOWN_BYTES ||
     106         132 :                     it->first.second == g_viz_constants.SESSION_REV_TEARDOWN_PKTS ||
     107         225 :                     it->first.second == g_viz_constants.FLOW_TABLE_AGG_PKTS ||
     108          66 :                     it->first.second == g_viz_constants.FLOW_TABLE_AGG_BYTES) {
     109          18 :                     sname = it->first.second;
     110             :                 } else {
     111          66 :                     sname = string("SUM(") + it->first.second + string(")");
     112             :                 }
     113          23 :             } else if (it->first.first == QEOpServerProxy::COUNT) {
     114           7 :                 if (table == g_viz_constants.SESSION_SERIES_TABLE) {
     115           5 :                     sname = "sample_count";
     116             :                 } else {
     117           2 :                     sname = string("COUNT(") + it->first.second + string(")");
     118             :                 }
     119          16 :             } else if (it->first.first == QEOpServerProxy::CLASS) {
     120           9 :                 if (table == g_viz_constants.SESSION_SERIES_TABLE) {
     121           0 :                     sname = "session_class_id";
     122           9 :                 } else if (table == g_viz_constants.FLOW_SERIES_TABLE){
     123           0 :                     sname = "flow_class_id";
     124             :                 } else {
     125           9 :                     sname = string("CLASS(") + it->first.second + string(")");
     126             :                 }
     127           7 :             } else if (it->first.first == QEOpServerProxy::MAX) {
     128           1 :                 sname = string("MAX(") + it->first.second + string(")");
     129           6 :             } else if (it->first.first == QEOpServerProxy::MIN) {
     130           1 :                 sname = string("MIN(") + it->first.second + string(")");
     131           5 :             } else if (it->first.first == QEOpServerProxy::PERCENTILES) {
     132           1 :                 sname = string("PERCENTILES(") + it->first.second + string(")");
     133           4 :             } else if (it->first.first == QEOpServerProxy::AVG) {
     134           2 :                 sname = string("AVG(") + it->first.second + string(")");
     135           2 :             } else if (it->first.first == QEOpServerProxy::COUNT_DISTINCT) {
     136           2 :                 sname = string("COUNT_DISTINCT(") + it->first.second + string(")");
     137             :             } else {
     138           0 :                 QE_ASSERT(0);
     139             :             }
     140         107 :             switch (it->second.which()) {
     141             : 
     142         103 :                 case QEOpServerProxy::UINT64 : {
     143         103 :                         uint64_t mapit = boost::get<uint64_t>(it->second);
     144         103 :                         contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
     145         103 :                         val.SetUint64(mapit);
     146         103 :                         contrail_rapidjson::Value vk;
     147         103 :                         dd.AddMember(vk.SetString(sname.c_str(),
     148             :                                                   dd.GetAllocator()),
     149             :                                      val, dd.GetAllocator());
     150         103 :                     }
     151         103 :                     break;
     152           1 :                 case QEOpServerProxy::DOUBLE : {
     153           1 :                         double mapit = boost::get<double>(it->second);
     154           1 :                         contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
     155           1 :                         val.SetDouble(mapit);
     156           1 :                         contrail_rapidjson::Value vk;
     157           1 :                         dd.AddMember(vk.SetString(sname.c_str(),
     158             :                                                   dd.GetAllocator()),
     159             :                                      val, dd.GetAllocator());
     160           1 :                     }
     161           1 :                     break;
     162           1 :                 case QEOpServerProxy::TDIGEST : {
     163             :                         boost::shared_ptr<TDigest> mapit =
     164           1 :                             boost::get<boost::shared_ptr<TDigest> >(it->second);
     165             :                         
     166           1 :                         contrail_rapidjson::Value val(contrail_rapidjson::kObjectType);
     167           1 :                         float ptiles[7] = {.01,.05,.25,.5,.75,.95,.99};
     168           9 :                         std::string stiles[7] = {"01","05","25","50","75","95","99"};
     169             : #if 0
     170             :                         size_t jj = TDigest_get_ncentroids(mapit.get());
     171             :                         for (size_t kk=0; kk < jj; kk++) {
     172             :                             Centroid *c = TDigest_get_centroid(mapit.get(), kk);
     173             :                             std::cout << "Parse Centroid " <<
     174             :                                Centroid_get_mean(c) << " " <<
     175             :                                Centroid_get_count(c) << " " <<
     176             :                                Centroid_quantile(c, mapit.get()) << std::endl;
     177             :                         }
     178             : #endif
     179           8 :                         for (size_t idx=0; idx<7; idx++) {
     180           7 :                             contrail_rapidjson::Value sval(contrail_rapidjson::kNumberType);
     181           7 :                             sval.SetDouble(TDigest_percentile(mapit.get(), ptiles[idx]));
     182           7 :                             contrail_rapidjson::Value vk;
     183           7 :                             val.AddMember(vk.SetString(stiles[idx].c_str(),
     184             :                                                        dd.GetAllocator()),
     185             :                                           sval, dd.GetAllocator());
     186           7 :                         }
     187           1 :                         contrail_rapidjson::Value vk;
     188           1 :                         dd.AddMember(vk.SetString(sname.c_str(),
     189             :                                                   dd.GetAllocator()),
     190             :                                      val, dd.GetAllocator());
     191          10 :                     }
     192           1 :                     break;
     193           2 :                 case QEOpServerProxy::CENTROID : {
     194             :                         boost::shared_ptr<Centroid> mapit =
     195           2 :                             boost::get<boost::shared_ptr<Centroid> >(it->second);
     196           2 :                         contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
     197           2 :                         val.SetDouble(Centroid_get_mean(mapit.get()));
     198           2 :                         contrail_rapidjson::Value vk;
     199           2 :                         dd.AddMember(vk.SetString(sname.c_str(),
     200             :                                                   dd.GetAllocator()),
     201             :                                      val, dd.GetAllocator());
     202           2 :                     }
     203           2 :                     break;
     204           0 :                 default:
     205           0 :                     QE_ASSERT(0);
     206             :             }
     207         107 :         }
     208           0 :     } catch (boost::bad_get& ex) {
     209           0 :         QE_ASSERT(0);
     210           0 :     } catch (const std::out_of_range& oor) {
     211           0 :         QE_ASSERT(0);
     212             :     }
     213         388 :     contrail_rapidjson::StringBuffer sb;
     214         194 :     contrail_rapidjson::Writer<contrail_rapidjson::StringBuffer> writer(sb);
     215         194 :     dd.Accept(writer);
     216         194 :     jstr = sb.GetString();
     217             :     //QE_LOG_NOQID(INFO, "Jsonify row " << jstr);
     218         388 :     return true;
     219         194 : }
     220             : 
     221          63 : void StatsSelect::MergeFinal(const std::vector<boost::shared_ptr<MapBufT> >& inputs,
     222             :         MapBufT& output) {
     223          63 :     MapBufT temp;
     224         567 :     for (size_t idx = 0; idx < inputs.size(); idx++) {
     225         504 :         if (agg_sort_cols_.empty())
     226         496 :             Merge(count_distinct_field_, *inputs[idx], output);
     227             :         else
     228           8 :             Merge(count_distinct_field_, *inputs[idx], temp);
     229             :     }
     230          63 :     if (!agg_sort_cols_.empty()) {
     231           1 :         MapBufT::iterator jt = temp.end();
     232           4 :         for (MapBufT::iterator it = temp.begin(); it!= temp.end(); it++) {
     233           3 :             if (jt!=temp.end()) {
     234           2 :                 temp.erase(jt);
     235             :             }
     236           3 :             std::vector<StatVal> ukey = it->first;
     237           3 :             const StatMap& uniks = it->second.first;
     238           3 :             const QEOpServerProxy::AggRowT& narows = it->second.second;
     239           3 :             for (AggSortT::const_iterator xt = agg_sort_cols_.begin();
     240           6 :                     xt != agg_sort_cols_.end(); xt++) {
     241           3 :                 QE_ASSERT(narows.find(xt->first) != narows.end());
     242           3 :                 ukey[xt->second] = narows.at(xt->first);
     243             :             }
     244           3 :             MergeFullRow(ukey, uniks, narows, output);
     245           3 :             jt = it;
     246           3 :         }
     247           1 :         temp.clear();
     248             :     }
     249          63 : }
     250             : 
     251         920 : void StatsSelect::Merge(const std::string& count_distinct_field_, const MapBufT& input, MapBufT& output) {
     252         920 :     for (MapBufT::const_iterator it = input.begin();
     253        1470 :             it!=input.end(); it++) {
     254         550 :         std::vector<StatVal> ukey(it->first);
     255         550 :         StatMap uniks(it->second.first);
     256         550 :         QEOpServerProxy::AggRowT narows(it->second.second);
     257             : 
     258         550 :         StatMap::iterator itr = uniks.find(count_distinct_field_);
     259         550 :         if (itr != uniks.end()) {
     260             :             pair<QEOpServerProxy::AggOper, std::string> aggkey(
     261           3 :                 QEOpServerProxy::COUNT_DISTINCT, count_distinct_field_);
     262           3 :             narows.insert(make_pair(aggkey, (uint64_t) 1));
     263           3 :             uniks.erase(itr);
     264           3 :             size_t hash_slot = ukey.size() - 1;
     265           3 :             uint64_t hash_val = boost::hash_range(uniks.begin(), uniks.end());
     266           3 :             ukey[hash_slot] = hash_val;
     267           3 :         }
     268             : 
     269         550 :         MergeFullRow(ukey, uniks, narows, output);
     270             : 
     271         550 :     }
     272         920 : }
     273             : 
     274        1055 : StatsSelect::StatsSelect(AnalyticsQuery * m_query,
     275        1055 :                 const std::vector<std::string> & select_fields) :
     276        1055 :                         main_query(m_query), select_fields_(select_fields),
     277        1056 :                         ts_period_(0), isT_(false), count_field_() {
     278             : 
     279        1057 :     status_ = false;
     280             : 
     281        5109 :     for (size_t j=0; j<select_fields_.size(); j++) {
     282             : 
     283        4051 :         if (select_fields_[j] == g_viz_constants.STAT_TIME_FIELD) {
     284          89 :             if (ts_period_) {
     285           0 :                 QE_LOG(INFO, "StatsSelect cannot accept both T and T="); 
     286           0 :                 return;
     287             :             }
     288          89 :             isT_ = true;
     289          89 :             sort_cols_.insert(std::make_pair(select_fields_[j], 0));
     290          89 :             QE_TRACE(DEBUG, "StatsSelect T");
     291             : 
     292        3962 :         } else if (select_fields_[j].substr(0, g_viz_constants.STAT_TIMEBIN_FIELD.size()) ==
     293             :                 g_viz_constants.STAT_TIMEBIN_FIELD) {
     294          40 :             if (isT_) {
     295           0 :                 QE_LOG(INFO, "StatsSelect cannot accept both T and T="); 
     296           0 :                 return;
     297             :             }
     298          40 :             string tsstr = select_fields_[j].substr(g_viz_constants.STAT_TIMEBIN_FIELD.size());
     299          40 :             ts_period_ = strtoul(tsstr.c_str(), NULL, 10) * 1000000;
     300          40 :             if (!ts_period_) {
     301           0 :                 QE_LOG(INFO, "StatsSelect cannot accept T= for " << tsstr);
     302           0 :                 return;
     303             :             }
     304          40 :             sort_cols_.insert(std::make_pair(g_viz_constants.STAT_TIMEBIN_FIELD,0));
     305          40 :             QE_TRACE(DEBUG, "StatsSelect T=");
     306          40 :         } else {
     307        3922 :             std::string sfield = select_fields_[j];
     308             :             QEOpServerProxy::AggOper agg =
     309        3921 :                 StatsQuery::ParseAgg(select_fields_[j], sfield);
     310        3922 :             if (agg == QEOpServerProxy::INVALID) {
     311        3401 :                 unik_cols_.insert(select_fields_[j]);
     312        3402 :                 QE_TRACE(DEBUG, "StatsSelect unik field " << select_fields_[j]);
     313         521 :             } else if (agg == QEOpServerProxy::COUNT) {
     314          54 :                 count_field_ = sfield;
     315          54 :                 QE_TRACE(DEBUG, "StatsSelect COUNT " << sfield);
     316         467 :             } else if (agg == QEOpServerProxy::COUNT_DISTINCT) {
     317          18 :                 count_distinct_field_ = sfield;
     318          18 :                 unik_cols_.insert(sfield);
     319          18 :                 QE_TRACE(DEBUG, "StatsSelect COUNT_DISTINCT " << sfield);
     320         449 :             } else if (agg == QEOpServerProxy::SUM) {
     321         288 :                 sum_cols_.insert(sfield);
     322         288 :                 QE_TRACE(DEBUG, "StatsSelect SUM " << sfield);
     323         161 :             } else if (agg == QEOpServerProxy::CLASS) {
     324          17 :                 class_cols_.insert(sfield);
     325          17 :                 QE_TRACE(DEBUG, "StatsSelect CLASS " << sfield);
     326         144 :             } else if (agg == QEOpServerProxy::MAX) {
     327          36 :                 max_field_.insert(sfield);
     328          36 :                 QE_TRACE(DEBUG, "StatsSelect MAX " << sfield);
     329         108 :             } else if (agg == QEOpServerProxy::MIN) {
     330          18 :                 min_field_.insert(sfield);
     331          18 :                 QE_TRACE(DEBUG, "StatsSelect MIN " << sfield);
     332          90 :             } else if (agg == QEOpServerProxy::PERCENTILES) {
     333          36 :                 percentile_cols_.insert(sfield);
     334          36 :                 QE_TRACE(DEBUG, "StatsSelect PERCENTILES " << sfield);
     335          54 :             } else if (agg == QEOpServerProxy::AVG) {
     336          54 :                 avg_field_.insert(sfield);
     337          54 :                 QE_TRACE(DEBUG, "StatsSelect AVG " << sfield);
     338             :             } else {
     339           0 :                 QE_ASSERT(0);
     340             :             }
     341        3923 :         }
     342             :     }
     343             : 
     344        1057 :     status_ = true;
     345           0 : }
     346             : 
     347        1057 : void StatsSelect::SetSortOrder(const std::vector<sort_field_t>& sort_fields) {
     348        1057 :     if (sort_fields.size()) {
     349          24 :         sort_cols_.clear();
     350             :     } else {
     351        1033 :         QE_TRACE(DEBUG, "StatsSelect Sort By T/T=");
     352             :     }
     353        1081 :     for (size_t st = 0; st < sort_fields.size(); st++) {
     354             : 
     355          24 :         if (sort_fields[st].name.substr(0, g_viz_constants.STAT_TIMEBIN_FIELD.size()) ==
     356             :                 g_viz_constants.STAT_TIMEBIN_FIELD) {
     357           0 :             QE_TRACE(DEBUG, "StatsSelect Sort By T=");
     358           0 :             sort_cols_.insert(std::make_pair(g_viz_constants.STAT_TIMEBIN_FIELD,st));
     359          24 :         } else if (sort_fields[st].name == g_viz_constants.STAT_TIME_FIELD) {
     360           0 :             QE_TRACE(DEBUG, "StatsSelect Sort By " << sort_fields[st].name);
     361           0 :             sort_cols_.insert(std::make_pair(sort_fields[st].name, st));                
     362             :         } else {
     363          24 :             std::string sfield = sort_fields[st].name;
     364             :             QEOpServerProxy::AggOper agg =
     365          24 :                 StatsQuery::ParseAgg(sort_fields[st].name, sfield);
     366          24 :             if (main_query->is_stat_table_query(main_query->table()) &&
     367           0 :                     main_query->stats().is_stat_table_static()) {
     368           0 :                 StatsQuery::column_t c = main_query->stats().get_column_desc(sfield);
     369           0 :                 if (c.datatype == QEOpServerProxy::BLANK) {
     370           0 :                     QE_LOG(INFO, "StatsSelect unknown field " << sort_fields[st].name);
     371           0 :                     return;
     372             :                 }
     373           0 :             }
     374          24 :             if (agg == QEOpServerProxy::INVALID) {
     375          12 :                 QE_TRACE(DEBUG, "StatsSelect Sort By " << sort_fields[st].name);
     376          12 :                 sort_cols_.insert(std::make_pair(sort_fields[st].name,st));                
     377             :             } else  {
     378          12 :                 agg_sort_cols_.insert(make_pair(make_pair(agg, sfield), st));
     379          12 :                 QE_TRACE(DEBUG, "StatsSelect Sort Agg " << agg << " of " << sfield);
     380             :             }
     381          24 :         }
     382             :     }    
     383             : }
     384             : 
     385        1088 : void StatsSelect::MergeFullRow(
     386             :         const std::vector<StatVal>& ukey,
     387             :         const StatMap& uniks,
     388             :         const QEOpServerProxy::AggRowT& narows,
     389             :         MapBufT& output) {
     390             : 
     391        1088 :     MapBufT::iterator rt = output.find(ukey);
     392        1088 :     if (rt!= output.end()) {
     393         229 :         StatMap& rm = rt->second.first;
     394         229 :         if (rm!=uniks) {
     395           0 :             output.insert(make_pair(ukey, make_pair(uniks, narows)));
     396             :         } else {
     397         229 :             QEOpServerProxy::AggRowT &arows = rt->second.second;
     398         229 :             MergeAggRow(arows, narows);
     399             :         }
     400             :     } else {
     401         859 :         QEOpServerProxy::AggRowT arows;
     402         859 :         output.insert(make_pair(ukey, make_pair(uniks, narows)));
     403         859 :     }    
     404        1088 : }
     405             : 
     406             : 
     407         229 : void StatsSelect::MergeAggRow(QEOpServerProxy::AggRowT &arows,
     408             :         const QEOpServerProxy::AggRowT &narows) {
     409         229 :     if (arows.empty()) {
     410         119 :         arows = narows;
     411         119 :         return;
     412             :     }
     413         110 :     for (QEOpServerProxy::AggRowT::iterator jt = arows.begin();
     414         337 :             jt!= arows.end(); jt++) {
     415         227 :         QEOpServerProxy::AggRowT::const_iterator kt = narows.find(jt->first);
     416         227 :         if (kt!=narows.end()) {
     417             :             // Attribute name must match for aggregate and for the new value
     418         209 :             QE_ASSERT(jt->first.second == kt->first.second);
     419             : 
     420         209 :             if (jt->first.first == QEOpServerProxy::SUM) {
     421         175 :                 StatsSelect::StatVal & sv = jt->second;
     422             :                 try {
     423         175 :                     if (sv.which() == QEOpServerProxy::UINT64) {
     424         175 :                         sv = boost::get<uint64_t>(sv) + boost::get<uint64_t>(kt->second);
     425             :                     }
     426         175 :                     if (sv.which() == QEOpServerProxy::DOUBLE) {
     427           0 :                         sv = boost::get<double>(sv) + boost::get<double>(kt->second);
     428             :                     }                   
     429           0 :                 } catch (boost::bad_get& ex) {
     430           0 :                     QE_ASSERT(0);
     431           0 :                 } catch (const std::out_of_range& oor) {
     432           0 :                     QE_ASSERT(0);
     433             :                 }                        
     434             : 
     435             :             }
     436             : 
     437         395 :             if (jt->first.first == QEOpServerProxy::COUNT ||
     438         186 :                 jt->first.first == QEOpServerProxy::COUNT_DISTINCT) {
     439             :                 try {
     440          24 :                     uint64_t& sv =  boost::get<uint64_t>(jt->second);
     441          24 :                     sv = sv + boost::get<uint64_t>(kt->second);
     442           0 :                 } catch (boost::bad_get& ex) {
     443           0 :                     QE_ASSERT(0);
     444           0 :                 } catch (const std::out_of_range& oor) {
     445           0 :                     QE_ASSERT(0);
     446             :                 }     
     447             :             }
     448         209 :             if (jt->first.first == QEOpServerProxy::MAX) {
     449           2 :                 StatsSelect::StatVal & sv = jt->second;
     450             :                 try {
     451           2 :                     if (sv.which() == QEOpServerProxy::UINT64) {
     452           2 :                         uint64_t& existing_max = boost::get<uint64_t>(jt->second);
     453           2 :                         existing_max = (existing_max > (boost::get<uint64_t>(kt->second))) ? existing_max:(boost::get<uint64_t>(kt->second));
     454             :                     }
     455           2 :                     if (sv.which() == QEOpServerProxy::DOUBLE) {
     456           0 :                         double& existing_max = boost::get<double>(jt->second);
     457           0 :                         existing_max = (existing_max > (boost::get<double>(kt->second))) ? existing_max:(boost::get<double>(kt->second));
     458             :                     }                   
     459           0 :                 } catch (boost::bad_get& ex) {
     460           0 :                     QE_ASSERT(0);
     461             :                 }     
     462             :             }
     463         209 :             if (jt->first.first == QEOpServerProxy::MIN) {
     464           2 :                 StatsSelect::StatVal & sv = jt->second;
     465             :                 try {
     466           2 :                     if (sv.which() == QEOpServerProxy::UINT64) {
     467           0 :                         uint64_t& existing_min = boost::get<uint64_t>(jt->second);
     468           0 :                         existing_min = (existing_min < (boost::get<uint64_t>(kt->second))) ? existing_min:(boost::get<uint64_t>(kt->second));
     469             :                     }
     470           2 :                     if (sv.which() == QEOpServerProxy::DOUBLE) {
     471           2 :                         double& existing_min = boost::get<double>(jt->second);
     472           2 :                         existing_min = (existing_min < (boost::get<double>(kt->second))) ? existing_min:(boost::get<double>(kt->second));
     473             :                     }                   
     474           0 :                 } catch (boost::bad_get& ex) {
     475           0 :                     QE_ASSERT(0);
     476             :                 }     
     477             :             }
     478         209 :             if (jt->first.first == QEOpServerProxy::AVG) {
     479           4 :                 StatsSelect::StatVal & sv = jt->second;
     480             :                 try {
     481           4 :                     if (sv.which() == QEOpServerProxy::CENTROID) {
     482             :                         boost::shared_ptr<Centroid>& pt =
     483           4 :                             boost::get<boost::shared_ptr<Centroid> >(jt->second);
     484             : 
     485             :                         boost::shared_ptr<Centroid> pt2 =
     486           4 :                             boost::get<boost::shared_ptr<Centroid> >(kt->second);
     487           4 :                         Centroid_add(pt.get(),
     488             :                                 Centroid_get_mean(pt2.get()),
     489             :                                 Centroid_get_count(pt2.get()));
     490           4 :                     }
     491           0 :                 } catch (boost::bad_get& ex) {
     492           0 :                     QE_ASSERT(0);
     493             :                 }
     494             :             }
     495         209 :             if (jt->first.first == QEOpServerProxy::PERCENTILES) {
     496           2 :                 StatsSelect::StatVal & sv = jt->second;
     497             :                 try {
     498           2 :                     if (sv.which() == QEOpServerProxy::TDIGEST) {
     499             :                         boost::shared_ptr<TDigest>& pt =
     500           2 :                             boost::get<boost::shared_ptr<TDigest> >(jt->second);
     501             :                         
     502             :                         boost::shared_ptr<TDigest> pt2 =
     503           2 :                             boost::get<boost::shared_ptr<TDigest> >(kt->second);
     504           2 :                         size_t j, ncentroids = TDigest_get_ncentroids(pt2.get());
     505           4 :                         for (j = 0; j < ncentroids; j++) {
     506           2 :                             Centroid * c = TDigest_get_centroid(pt2.get(), j);
     507           2 :                             TDigest* nd = TDigest_add(pt.get(),
     508             :                                 Centroid_get_mean(c),
     509             :                                 Centroid_get_count(c));
     510           2 :                             if (nd) {
     511           0 :                                 pt.reset(nd);
     512             :                             }
     513             :                         }
     514           2 :                     }
     515           0 :                 } catch (boost::bad_get& ex) {
     516           0 :                     QE_ASSERT(0);
     517             :                 }     
     518             :             }
     519             :         }
     520             :     }
     521             : }
     522             : 
     523             : namespace boost {
     524             :    std::size_t hash_value(const StatsSelect::StatVal&); 
     525             : }
     526             : 
     527        1822 : std::size_t boost::hash_value(const StatsSelect::StatVal& sv) {
     528        1822 :     std::ostringstream ostr;
     529        1822 :     ostr << sv;
     530        3644 :     return boost::hash_value(ostr.str());
     531        1822 : }
     532             : 
     533         535 : bool StatsSelect::LoadRow(boost::uuids::uuid u,
     534             :                 uint64_t timestamp, const vector<StatEntry>& row, MapBufT& output) {
     535             : 
     536         535 :         if (!Status()) return false;
     537         535 :     uint64_t ts = 0;
     538             : 
     539             :     // Build Uniks map
     540         535 :     StatMap uniks;
     541             :     set<string>::const_iterator ukit =
     542         535 :         unik_cols_.find(g_viz_constants.STAT_UUID_FIELD);
     543         535 :     if (ukit!=unik_cols_.end()) {
     544          63 :         uniks.insert(make_pair(g_viz_constants.STAT_UUID_FIELD,u));
     545             :     }
     546             :     
     547         535 :     if (isT_) {
     548          50 :         ts = timestamp;
     549          50 :         uniks.insert(make_pair(g_viz_constants.STAT_TIME_FIELD,ts)); 
     550             :     }
     551             : 
     552         535 :     if (ts_period_) {
     553          54 :         ts = timestamp - (timestamp % ts_period_);
     554          54 :         uniks.insert(make_pair(g_viz_constants.STAT_TIMEBIN_FIELD,ts)); 
     555             :     }
     556             : 
     557         535 :     for (vector<StatEntry>::const_iterator it = row.begin();
     558       18092 :             it != row.end(); it++) {
     559       17558 :         set<string>::const_iterator uit = unik_cols_.find(it->name);
     560       17559 :         if (uit!=unik_cols_.end()) {
     561        1633 :             uniks.insert(make_pair(it->name, it->value));
     562             :         }
     563             :     }
     564             : 
     565             :     // Build sort vector
     566             :     // Last slot is reserved for the hash
     567         535 :     std::vector<StatVal> ukey(sort_cols_.size() + agg_sort_cols_.size() + 1);
     568         535 :     size_t hash_slot = sort_cols_.size() + agg_sort_cols_.size();
     569         535 :     uint64_t hash_val = boost::hash_range(uniks.begin(), uniks.end());
     570         535 :     ukey[hash_slot] = hash_val;
     571             : 
     572         535 :     for (map<string, size_t>::const_iterator st = sort_cols_.begin();
     573         666 :             st!=sort_cols_.end(); st++) {
     574         131 :         QE_ASSERT(uniks.find(st->first) != uniks.end());
     575         131 :         ukey[st->second] = uniks.at(st->first);
     576             :     }
     577             : 
     578         535 :     QEOpServerProxy::AggRowT narows;
     579         535 :     for (vector<StatEntry>::const_iterator it = row.begin();
     580       18122 :             it != row.end(); it++) {
     581       17587 :         set<string>::const_iterator uit = sum_cols_.find(it->name);
     582       17591 :         if (uit!=sum_cols_.end()) {
     583         271 :             pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::SUM,it->name);
     584         271 :             narows.insert(make_pair(aggkey, it->value)); 
     585         271 :         }
     586             :     }
     587             : 
     588         535 :     for (vector<StatEntry>::const_iterator it = row.begin();
     589       18115 :             it != row.end(); it++) {
     590       17580 :         set<string>::const_iterator uit = max_field_.find(it->name);
     591       17582 :         if (uit!=max_field_.end()) {
     592           3 :             pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::MAX,it->name);
     593           3 :             narows.insert(make_pair(aggkey, it->value)); 
     594           3 :         }
     595       17582 :         uit = min_field_.find(it->name);
     596       17591 :         if (uit!=min_field_.end()) {
     597           3 :             pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::MIN,it->name);
     598           3 :             narows.insert(make_pair(aggkey, it->value)); 
     599           3 :         }
     600       17587 :         uit = avg_field_.find(it->name);
     601       17594 :         if (uit!=avg_field_.end()) {
     602           6 :             pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::AVG,it->name);
     603             :             try {
     604           6 :                 Centroid *t = Centroid_create(0, 0);
     605           6 :                 StatsSelect::StatVal sv = it->value;
     606             :                 double val;
     607           6 :                 if (sv.which() == QEOpServerProxy::UINT64) {
     608           3 :                     val = boost::get<uint64_t>(sv);
     609             :                 } else {
     610           3 :                     val = boost::get<double>(sv);
     611             :                 }
     612           6 :                 Centroid_add(t, val, 1);
     613           6 :                 boost::shared_ptr<Centroid> pt(t, &StatsSelect::DeleteCentroid);
     614           6 :                 narows.insert(make_pair(aggkey, pt));
     615           6 :             } catch (boost::bad_get& ex) {
     616           0 :                 QE_ASSERT(0);
     617           0 :             } catch (const std::out_of_range& oor) {
     618           0 :                 QE_ASSERT(0);
     619             :             }
     620           6 :         }
     621       17587 :         uit = percentile_cols_.find(it->name);
     622       17584 :         if (uit!=percentile_cols_.end()) {
     623           3 :             pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::PERCENTILES,it->name);
     624             : 
     625             :             try {
     626           3 :                 TDigest *t = TDigest_create(0.01, 100);
     627           3 :                 StatsSelect::StatVal sv = it->value;
     628             :                 double val;
     629           3 :                 if (sv.which() == QEOpServerProxy::UINT64) {
     630           3 :                     val = boost::get<uint64_t>(sv);
     631             :                 } else {
     632           0 :                     val = boost::get<double>(sv);
     633             :                 }                   
     634           3 :                 TDigest_add(t, val, 1);
     635           3 :                 boost::shared_ptr<TDigest> pt(t, &StatsSelect::DeleteTDigest);
     636           3 :                 narows.insert(make_pair(aggkey, pt)); 
     637           3 :             } catch (boost::bad_get& ex) {
     638           0 :                 QE_ASSERT(0);
     639           0 :             } catch (const std::out_of_range& oor) {
     640           0 :                 QE_ASSERT(0);
     641             :             }                        
     642           3 :         }
     643             :     }
     644             :     
     645         535 :     for (std::set<std::string>::const_iterator ct = class_cols_.begin();
     646         544 :             ct!=class_cols_.end(); ct++) {
     647           9 :         pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::CLASS,*ct);
     648           9 :         StatMap huniks;
     649           9 :         for (vector<StatEntry>::const_iterator rit = row.begin();
     650          90 :                 rit != row.end(); rit++) {
     651          81 :             if (rit->name != *ct) {
     652          81 :                 if (uniks.find(rit->name) != uniks.end()) {
     653             :                     // For generating the hash, consider all attributes that 
     654             :                     // are in the row, and that do not match the CLASS attribute,
     655             :                     // and that are in non-aggregate attributes in the SELECT
     656          18 :                     huniks[rit->name] = rit->value;
     657             :                 }
     658             :             }
     659             :         }
     660           9 :         uint64_t hh = boost::hash_range(huniks.begin(), huniks.end());
     661           9 :         narows.insert(make_pair(aggkey, hh));
     662           9 :     }
     663             :  
     664         535 :     if (!count_field_.empty()) {
     665          30 :         pair<QEOpServerProxy::AggOper,string> aggkey(QEOpServerProxy::COUNT,count_field_);
     666          30 :         narows.insert(make_pair(aggkey, (uint64_t) 1));            
     667          30 :     }
     668             :     
     669         535 :     MergeFullRow(ukey, uniks, narows, output);
     670             : 
     671         535 :     return true;
     672         535 : }
     673             : 

Generated by: LCOV version 1.14