Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : /*
7 : * This file details various data structures used for query
8 : * engine processing
9 : *
10 : * Overall the data structure heirarchy is as following:
11 : *
12 : * AnalyticsQuery--
13 : * |
14 : * |--SelectQuery
15 : * |
16 : * |--PostProcessingQuery
17 : * |
18 : * |--WhereQuery (multiple ANDs)
19 : * |
20 : * |-DbQueryUnit
21 : * |
22 : * |-DbQueryUnit
23 : * ...
24 : *
25 : */
26 : #ifndef QUERY_H_
27 : #define QUERY_H_
28 :
29 : #include <atomic>
30 : #include <sstream>
31 : #include <iostream>
32 : #include <string>
33 : #include <map>
34 : #include <mutex>
35 : #include <vector>
36 : #include <set>
37 : #include <algorithm>
38 : #include <exception>
39 : #include <cstdlib>
40 : #include <utility>
41 : #include <list>
42 :
43 : #include <boost/uuid/uuid.hpp>
44 : #include <boost/uuid/uuid_generators.hpp>
45 : #include <boost/uuid/uuid_io.hpp>
46 : #include <boost/algorithm/string/predicate.hpp>
47 : #include <boost/lexical_cast.hpp>
48 : #include <boost/algorithm/string.hpp>
49 : #include "io/event_manager.h"
50 : #include <boost/bind/bind.hpp>
51 : #include <boost/assign/list_of.hpp>
52 : #include <boost/scoped_ptr.hpp>
53 : #include <boost/ptr_container/ptr_map.hpp>
54 : #include "base/util.h"
55 : #include "base/task.h"
56 : #include "base/address.h"
57 : #include "base/parse_object.h"
58 : #include <boost/asio.hpp>
59 : #include <boost/tuple/tuple.hpp>
60 : #include <boost/foreach.hpp>
61 : #include "base/logging.h"
62 : #include "hiredis/hiredis.h"
63 : #include "hiredis/boostasio.hpp"
64 : #include <contrail-collector/redis_connection.h>
65 : #include "base/regex.h"
66 : #include "base/work_pipeline.h"
67 : #include "database/gendb_if.h"
68 : #include "database/gendb_statistics.h"
69 : #include <contrail-collector/viz_message.h>
70 : #include "json_parse.h"
71 : #include "QEOpServerProxy.h"
72 : #include <sandesh/sandesh_ctrl_types.h>
73 : #include <sandesh/sandesh_trace.h>
74 : #include <sandesh/common/vns_constants.h>
75 : #include <analytics/viz_constants.h>
76 : #include <query_engine/qe_constants.h>
77 : #include <query_engine/qe_types.h>
78 : #include "rapidjson/document.h"
79 : #include <boost/shared_ptr.hpp>
80 :
81 : using namespace boost::placeholders;
82 :
83 : extern std::map< std::string, int > trace_enable_map;
84 : #define IS_TRACE_ENABLED(trace_flag_string) \
85 : ((trace_enable_map.find(trace_flag_string) != trace_enable_map.end()))
86 :
87 : // following is the list of trace flags
88 : #define WHERE_RESULT_TRACE "where_result_trace"
89 : #define SELECT_RESULT_TRACE "select_result_trace"
90 : #define POSTPROCESS_RESULT_TRACE "postprocess_result_trace"
91 :
92 : #define QE_ASSERT(cond) assert((cond))
93 :
94 : #define TIMESTAMP_FROM_T2T1(t2, t1) (((uint64_t)(t2)) << g_viz_constants.RowTimeInBits) |\
95 : ((t1) & g_viz_constants.RowTimeInMask);
96 :
97 : // for Sandesh trace
98 : #define QE_TRACE_BUF "QeTraceBuf"
99 :
100 : extern SandeshTraceBufferPtr QeTraceBuf;
101 :
102 : // fix this later
103 : #define QE_LOG(level, log_msg) { \
104 : std::string qid("");\
105 : std::string table("");\
106 : int batch_num = 0;\
107 : if ((AnalyticsQuery *)(this->main_query))\
108 : {\
109 : qid = (((AnalyticsQuery *)(this->main_query))->query_id);\
110 : table = (((AnalyticsQuery *)(this->main_query))->table());\
111 : batch_num = (((AnalyticsQuery *)(this->main_query))->parallel_batch_num);\
112 : }\
113 : std::stringstream ss; ss << ":" << batch_num << ":" << log_msg; \
114 : Q_E_QUERY_LOG_SEND(qid, table, ss.str());\
115 : }
116 :
117 : // Following log message will be printed for only one thread among all threads
118 : #define QE_LOG_GLOBAL(level, log_msg) { \
119 : std::string qid("");\
120 : std::string table("");\
121 : int batch_num = 0;\
122 : if ((AnalyticsQuery *)(this->main_query))\
123 : {\
124 : qid = (((AnalyticsQuery *)(this->main_query))->query_id);\
125 : table = (((AnalyticsQuery *)(this->main_query))->table());\
126 : batch_num = (((AnalyticsQuery *)(this->main_query))->parallel_batch_num);\
127 : }\
128 : if (batch_num == 0) {\
129 : std::stringstream ss; ss << ":" << batch_num << ":" << log_msg; \
130 : Q_E_QUERY_LOG_SEND(qid, table, ss.str());\
131 : }\
132 : }
133 :
134 : #define QE_LOG_NOQID(level, log_msg) { \
135 : std::stringstream ss; ss << log_msg; \
136 : Q_E_LOG_SEND(ss.str());\
137 : }
138 :
139 : #define QE_TRACE_NOQID(level, trace_msg) {\
140 : std::stringstream ss; ss << level << ":" << trace_msg; \
141 : QUERY_TRACE_TRACE(QeTraceBuf, std::string(""), ss.str());\
142 : }
143 :
144 : #define QE_TRACE(level, trace_msg) {\
145 : std::stringstream ss; ss << level << ":" << trace_msg; \
146 : QUERY_TRACE_TRACE(QeTraceBuf, \
147 : (((AnalyticsQuery *)(this->main_query))? \
148 : (((AnalyticsQuery *)(this->main_query))->query_id):\
149 : std::string("")), ss.str());\
150 : }
151 :
152 : #if !defined(DEBUG)
153 : #define DEBUG "DEBUG"
154 : #endif
155 :
156 : // this is to return errors from the member functions of the QueryUnit class
157 : // and its derived classes. These macros just set the status_details field
158 : // and return from the function
159 : #define QE_PARSE_ERROR(cond) if (!(cond)) \
160 : { QE_LOG(DEBUG, "EBADMSG"); this->status_details = EBADMSG; return;}
161 : #define QE_INVALIDARG_ERROR(cond) if (!(cond)) \
162 : { QE_LOG(DEBUG, "EINVAL"); this->status_details = EINVAL; return;}
163 : #define QE_IO_ERROR(cond) if (!(cond)) \
164 : { QE_LOG(DEBUG, "EIO"); this->status_details = EIO; return;}
165 : #define QE_NOENT_ERROR(cond) if (!(cond)) \
166 : { QE_LOG(DEBUG, "ENOENT"); this->status_details = ENOENT; return;}
167 : #define QE_PARSE_ERROR_RETURN(cond, ret_val) if (!(cond)) \
168 : { this->status_details = EBADMSG; return ret_val;}
169 : #define QE_INVALIDARG_ERROR_RETURN(cond, ret_val) if (!(cond)) \
170 : { this->status_details = EINVAL; return ret_val;}
171 : #define QE_IO_ERROR_RETURN(cond, ret_val) if (!(cond)) \
172 : { this->status_details = EIO; return ret_val;}
173 : #define QE_NOENT_ERROR_RETURN(cond, ret_val) if (!(cond)) \
174 : { this->status_details = ENOENT; return ret_val;}
175 : #define QE_QUERY_FETCH_ERROR() {\
176 : this->status_details = EIO; \
177 : AnalyticsQuery *m_query = (AnalyticsQuery *)main_query; \
178 : if (m_query) { \
179 : m_query->qperf_.error = status_details; \
180 : m_query->status_details = status_details; \
181 : m_query->query_status = QUERY_FAILURE; \
182 : } \
183 : QE_LOG(ERROR, "QUERY failed to get rows " << QUERY_FAILURE); \
184 : }
185 :
186 : extern bool oldDataExists;
187 :
188 : typedef boost::shared_ptr<GenDb::GenDbIf> GenDbIfPtr;
189 :
190 : // flow sample stats which is stored in Cassandra flow index tables
191 : struct flow_stats {
192 1992 : flow_stats(uint64_t ibytes=0, uint64_t ipkts=0, bool ishort_flow=false) :
193 1992 : bytes(ibytes), pkts(ipkts), short_flow(ishort_flow) {
194 1992 : }
195 : bool operator==(const flow_stats &rhs) const {
196 : return bytes == rhs.bytes &&
197 : pkts == rhs.pkts &&
198 : short_flow == rhs.short_flow &&
199 : flow_list == rhs.flow_list;
200 : }
201 : uint64_t bytes;
202 : uint64_t pkts;
203 : bool short_flow;
204 : std::set<boost::uuids::uuid> flow_list;
205 : };
206 :
207 : // 8-tuple corresponding to a flow
208 : struct flow_tuple {
209 : flow_tuple() : protocol(0), source_port(0), dest_port(0), direction(0) {
210 : }
211 :
212 : flow_tuple(const std::string& vr, const std::string& svn,
213 : const std::string& dvn, const IpAddress& sip,
214 : const IpAddress& dip, uint32_t proto,
215 : uint32_t sport, uint32_t dport, uint32_t dir) :
216 : vrouter(vr), source_vn(svn), dest_vn(dvn), source_ip(sip),
217 : dest_ip(dip), protocol(proto), source_port(sport),
218 : dest_port(dport), direction(dir) {
219 : }
220 :
221 : bool operator<(const flow_tuple& rhs) const {
222 : if (vrouter < rhs.vrouter) return true;
223 : if (vrouter > rhs.vrouter) return false;
224 :
225 : if (source_vn < rhs.source_vn) return true;
226 : if (source_vn > rhs.source_vn) return false;
227 :
228 : if (dest_vn < rhs.dest_vn) return true;
229 : if (dest_vn > rhs.dest_vn) return false;
230 :
231 : if (source_ip < rhs.source_ip) return true;
232 : if (source_ip > rhs.source_ip) return false;
233 :
234 : if (dest_ip < rhs.dest_ip) return true;
235 : if (dest_ip > rhs.dest_ip) return false;
236 :
237 : if (protocol < rhs.protocol) return true;
238 : if (protocol > rhs.protocol) return false;
239 :
240 : if (source_port < rhs.source_port) return true;
241 : if (source_port > rhs.source_port) return false;
242 :
243 : if (dest_port < rhs.dest_port) return true;
244 : if (dest_port > rhs.dest_port) return false;
245 :
246 : if (direction < rhs.direction) return true;
247 : if (direction > rhs.direction) return false;
248 :
249 : return false;
250 : }
251 :
252 : bool operator==(const flow_tuple& rhs) const {
253 : return (vrouter == rhs.vrouter) &&
254 : (source_vn == rhs.source_vn) &&
255 : (dest_vn == rhs.dest_vn) &&
256 : (source_ip == rhs.source_ip) &&
257 : (dest_ip == rhs.dest_ip) &&
258 : (protocol == rhs.protocol) &&
259 : (source_port == rhs.source_port) &&
260 : (dest_port == rhs.dest_port) &&
261 : (direction == rhs.direction);
262 : }
263 :
264 : friend std::ostream& operator<<(std::ostream& out, const flow_tuple& ft);
265 :
266 : std::string vrouter;
267 : std::string source_vn;
268 : std::string dest_vn;
269 : IpAddress source_ip;
270 : IpAddress dest_ip;
271 : uint32_t protocol;
272 : uint32_t source_port;
273 : uint32_t dest_port;
274 : uint32_t direction;
275 : };
276 :
277 : struct uuid_flow_stats {
278 : uuid_flow_stats(uint64_t t, flow_stats stats) :
279 : last_timestamp(t), last_stats(stats) {
280 : }
281 : // indiates the timestamp when the last_stats was updated
282 : uint64_t last_timestamp;
283 : // indicates the aggregate value of the stats seen @ last_ts
284 : flow_stats last_stats;
285 : };
286 :
287 : // Result of basic unit of any analytics event query
288 : struct query_result_unit_t {
289 : // timestamp of an analytics event (log, flow record sample etc..)
290 : uint64_t timestamp;
291 :
292 : // this string will be
293 : // UUID is in case of database queries for flow-records/flow-series
294 : // stats+UUID after database queries for flow-records WHERE queries
295 : // stats+UUID+8-tuple afer flow-series WHERE query
296 : // AttribJSON+UUID for StatsTable queries
297 : // key,key2,column1-column19,DATA for messagetablev2
298 : GenDb::DbDataValueVec info;
299 :
300 : // Following APIs will be invoked based on the table being queried
301 :
302 : void set_stattable_info(
303 : const std::string& attribstr,
304 : const boost::uuids::uuid& uuid);
305 :
306 : void get_stattable_info(
307 : std::string& attribstr,
308 : boost::uuids::uuid& uuid) const;
309 :
310 : // Get UUID from the info field
311 : void get_uuid(boost::uuids::uuid& u) const;
312 : // Get UUID and stats
313 : void get_uuid_stats(boost::uuids::uuid& u, flow_stats& stats) const;
314 : // Get UUID and stats and 8-tuple
315 : void get_objectid(std::string&) const;
316 : // for sorting and set operations
317 : bool operator<(const query_result_unit_t& rhs) const;
318 :
319 : // for printing
320 : friend std::ostream &operator<<(std::ostream &out,
321 : query_result_unit_t&);
322 : } ;
323 :
324 : typedef std::vector<query_result_unit_t> WhereResultT;
325 :
326 : // Different status codes of query processing
327 : enum query_status_t {
328 : QUERY_PROCESSING_NOT_STARTED = 0,
329 : QUERY_IN_PROGRESS = 1,
330 : QUERY_SUCCESS = 2,
331 : QUERY_FAILURE = 3
332 : };
333 :
334 : // basic query unit (other classes will inherit from this)
335 : class QueryUnit {
336 : public:
337 : QueryUnit(QueryUnit *p_query, QueryUnit *m_query);
338 : virtual ~QueryUnit();
339 : virtual query_status_t process_query() = 0;
340 :
341 : typedef QEOpServerProxy::BufferT BufT;
342 : typedef QEOpServerProxy::OutRowMultimapT MapBufT;
343 :
344 : // following callback function is called whenever a subquery
345 : // is prcoessed
346 2619 : virtual void subquery_processed(QueryUnit *subquery) {};
347 :
348 : // list of child queries
349 : std::vector<QueryUnit *> sub_queries;
350 :
351 : // if this is a child/sub query, then following is pointer to
352 : // the parent query
353 : QueryUnit *parent_query;
354 : // Pointer to the highest level query
355 : QueryUnit *main_query;
356 :
357 : int pending_subqueries;
358 : query_status_t query_status;
359 : uint32_t status_details;
360 :
361 : // After query is processed following vector is populated
362 : boost::shared_ptr<WhereResultT> query_result;
363 : };
364 :
365 : class QueryResultMetaData {
366 : public:
367 : QueryResultMetaData() {
368 : }
369 : virtual ~QueryResultMetaData() = 0;
370 : };
371 :
372 : class fsMetaData : public QueryResultMetaData {
373 : public:
374 : fsMetaData(const std::set<boost::uuids::uuid>& flows)
375 : : uuids(flows.begin(), flows.end()) {
376 : }
377 : ~fsMetaData() {
378 : }
379 : std::set<boost::uuids::uuid> uuids;
380 : };
381 :
382 : struct GetRowInput {
383 : GenDb::DbDataValueVec rowkey;
384 : std::string cfname;
385 : GenDb::ColumnNameRange crange;
386 : GenDb::WhereIndexInfoVec where_vec;
387 : int chunk_no;
388 : std::string qid;
389 : int sub_qid;
390 : int row_no;
391 : int inst;
392 : };
393 :
394 : // max number of entries to extract from db
395 : #define MAX_DB_QUERY_ENTRIES 100000000
396 : // This class provides interface for doing single index database query
397 : class DbQueryUnit : public QueryUnit {
398 : public:
399 4095 : DbQueryUnit(QueryUnit *p_query, QueryUnit *m_query):
400 4095 : QueryUnit(p_query, m_query)
401 4094 : { cr.count_ = MAX_DB_QUERY_ENTRIES;
402 4094 : t_only_col = false; t_only_row = false;
403 4094 : sub_query_id = (p_query->sub_queries.size())-1;
404 4094 : query_fetch_error = false;
405 4094 : };
406 : virtual query_status_t process_query();
407 :
408 :
409 : // portion of column family name other than T1
410 : std::string cfname;
411 : // all type of match operations can be representated as
412 : // getrangeslice operations on Cassandra DB. For e.g.
413 : // NOT_EQUAL operation will be two getrangeslice operation
414 : GenDb::ColumnNameRange cr;
415 : GenDb::WhereIndexInfoVec where_vec;
416 : // row key suffix will be used to append DIR to flow
417 : // series/records query
418 : GenDb::DbDataValueVec row_key_suffix;
419 : bool t_only_col; // only T is in column name
420 : bool t_only_row; // only T2 is in row key
421 : int sub_query_id;
422 : typedef std::vector<query_result_unit_t> q_result;
423 : struct Input {
424 : std::atomic<uint32_t> row_count;
425 : std::atomic<uint32_t> total_rows;
426 : std::string cf_name;
427 : GenDb::ColumnNameRange cr;
428 : GenDb::WhereIndexInfoVec where_vec;
429 : std::vector<GenDb::DbDataValueVec> keys;
430 : };
431 :
432 : struct Output {
433 : boost::shared_ptr<WhereResultT> query_result;
434 : };
435 : struct Stage0Out {
436 : WhereResultT query_result;
437 : uint32_t current_row;
438 : };
439 : ExternalBase::Efn QueryExec(uint32_t inst,
440 : const std::vector<q_result *> & exts,
441 : const Input & inp, Stage0Out & res);
442 : typedef WorkPipeline<Input, Output> QEPipeT;
443 : bool QueryMerge(const std::vector<boost::shared_ptr<Stage0Out> > & subs,
444 : const boost::shared_ptr<Input> & inp, Output & res);
445 : void cb(GenDb::DbOpResult::type dresult, std::auto_ptr<GenDb::ColList>
446 : columns, GetRowInput *get_row_ctx, void *privdata);
447 : void message_table_query_get_row(GenDb::DbDataValueVec const &val,
448 : GenDb::NewColVec::iterator const &res_it,
449 : query_result_unit_t &result_unit);
450 : void WPCompleteCb(QEPipeT *wp, bool ret_code);
451 : std::vector<GenDb::DbDataValueVec> populate_row_keys();
452 : bool PipelineCb(std::string &, GenDb::DbDataValueVec &,
453 : const GenDb::ColumnNameRange &, GenDb::WhereIndexInfoVec &,
454 : GetRowInput *, void *);
455 : bool query_fetch_error;
456 : };
457 :
458 : struct SetOperationUnit {
459 : static void op_and(std::string qi, WhereResultT& res,
460 : std::vector<WhereResultT*> inp);
461 : static void op_or(std::string qi, WhereResultT& res,
462 : std::vector<WhereResultT*> inp);
463 : };
464 :
465 : typedef boost::function<void (void *, QEOpServerProxy::QPerfInfo,
466 : std::auto_ptr<WhereResultT>)> WhereQueryCbT;
467 : // Where processing class
468 : // Result is available for SELECT processing in query_result field
469 : // It will be an array of timestamp and
470 : // UUID is in case of messages/object-trace WHERE queries
471 : // stats+UUID after database queries for flow-records WHERE queries
472 : // stats+UUID+8-tuple for flow-series WHERE query
473 :
474 : struct filter_match_t {
475 : std::string name; // column name of match and filter
476 : std::string value; // column value to compare with
477 : match_op op; // matching op
478 : bool ignore_col_absence; // ignore (i.e. do not delete) if col is absent
479 : contrail::regex match_e; // matching regex expression
480 :
481 780 : filter_match_t():ignore_col_absence(false) {};
482 : };
483 :
484 : class WhereQuery : public QueryUnit {
485 : public:
486 :
487 : bool StatTermParse(QueryUnit *main_query, const contrail_rapidjson::Value& where_term,
488 : std::string& pname, match_op& pop,
489 : GenDb::DbDataValue& pval, GenDb::DbDataValue& pval2,
490 : std::string& sname, match_op& sop,
491 : GenDb::DbDataValue& sval, GenDb::DbDataValue& sval2);
492 :
493 : bool StatTermProcess(const contrail_rapidjson::Value& where_term,
494 : QueryUnit* pnode, QueryUnit *main_query);
495 :
496 : WhereQuery(const std::string& where_json_string, int session_type,
497 : int is_si,int direction, int32_t or_number, QueryUnit *main_query);
498 : // construtor for UT
499 : WhereQuery(QueryUnit *mq);
500 : virtual query_status_t process_query();
501 : virtual void subquery_processed(QueryUnit *subquery);
502 : void handle_object_type_value(AnalyticsQuery *m_query,
503 : DbQueryUnit *db_query,
504 : bool object_id_specified);
505 : bool populate_where_vec(AnalyticsQuery *m_query,
506 : GenDb::WhereIndexInfoVec *where_vec,
507 : const std::string& query_col,
508 : const GenDb::Op::type db_op,
509 : const std::string& value);
510 : std::string query_column_to_cass_column(AnalyticsQuery *m_query,
511 : const std::string& query_column);
512 :
513 : // filter list to store filters converted from where cluase
514 : std::vector<std::vector<filter_match_t> > filter_list_;
515 : std::vector<std::string> additional_select_;
516 :
517 : // 0 is for egress and 1 for ingress
518 : int32_t direction_ing;
519 : const std::string json_string_;
520 : uint32_t wterms_;
521 : std::unique_ptr<WhereResultT> where_result_;
522 : // Used to store the sub_query(Each DbQueryUnits) results
523 : std::vector<WhereResultT*> inp;
524 : std::vector<WhereResultT*> inp_new_data;
525 : typedef boost::function<void(void *, QEOpServerProxy::QPerfInfo,
526 : std::auto_ptr<WhereResultT> )> WhereQueryCbT;
527 : WhereQueryCbT where_query_cb_;
528 :
529 : void populate_session_where_vec_list(std::vector<GenDb::WhereIndexInfoVec> *where_vec_list,
530 : const GenDb::WhereIndexInfoVec &rest_where_vec,
531 : const GenDb::WhereIndexInfoVec &labels_vec,
532 : const GenDb::WhereIndexInfoVec &remote_labels_vec,
533 : const GenDb::WhereIndexInfoVec &arbitrary_tags_vec,
534 : const GenDb::WhereIndexInfoVec &remote_arbitrary_tags_vec);
535 :
536 : private:
537 : std::mutex vector_push_mutex_;
538 : };
539 :
540 : typedef std::vector<std::string> final_result_row_t;
541 :
542 : struct final_result_t {
543 : // These are actual names used in the database
544 : std::vector<std::string> columns;
545 : std::vector<final_result_row_t> final_result_table;
546 : uint status;
547 : };
548 :
549 : enum agg_op_t {
550 : RAW = 1,
551 : SUM = 2,
552 : AGG_OP_INVALID = 3,
553 : };
554 :
555 : enum stat_type_t {
556 : PKT_STATS = 1,
557 : BYTE_STATS = 2,
558 : };
559 :
560 : // Aggregated stats
561 : struct agg_stats_t {
562 : agg_op_t agg_op;
563 : stat_type_t stat_type;
564 : };
565 :
566 : class StatsSelect;
567 :
568 : // following data structure does the processing of SELECT portion of query
569 : class SelectQuery : public QueryUnit {
570 : public:
571 : SelectQuery(QueryUnit *main_query,
572 : const std::map<std::string, std::string>& json_api_data);
573 :
574 : virtual query_status_t process_query();
575 :
576 : // Query related fields
577 : std::string json_string_;
578 : std::vector<std::string> select_column_fields;
579 : std::vector<agg_stats_t> agg_stats;
580 : // Whethere timestamp will be one of the columns
581 : bool provide_timeseries;
582 : // relevant only if provide_timeseries is set
583 : uint granularity;
584 :
585 : // column family name (column family to query to get column
586 : // fields/NULL for flow series)
587 : std::string cfname;
588 : bool unroll_needed;
589 :
590 : std::unique_ptr<BufT> result_;
591 : std::unique_ptr<MapBufT> mresult_;
592 :
593 : std::unique_ptr<StatsSelect> stats_;
594 :
595 : enum fs_query_type {
596 : FS_SELECT_INVALID = 0x0,
597 : FS_SELECT_T = 0x1,
598 : FS_SELECT_TS = 0x2,
599 : FS_SELECT_FLOW_TUPLE = 0x4,
600 : FS_SELECT_STATS = 0x8,
601 : FS_SELECT_T_FLOW_TUPLE = 0x5,
602 : FS_SELECT_T_STATS = 0x9,
603 : FS_SELECT_FLOW_TUPLE_STATS = 0xC,
604 : FS_SELECT_TS_FLOW_TUPLE = 0x6,
605 : FS_SELECT_TS_STATS = 0xA,
606 : FS_SELECT_T_FLOW_TUPLE_STATS = 0xD,
607 : FS_SELECT_TS_FLOW_TUPLE_STATS = 0xE
608 : };
609 :
610 : uint8_t flowseries_query_type() {
611 : return fs_query_type_;
612 : }
613 :
614 138 : bool is_present_in_select_column_fields(const std::string& field) {
615 138 : std::vector<std::string>::iterator it;
616 138 : it = std::find(select_column_fields.begin(),
617 : select_column_fields.end(),
618 : field);
619 138 : if (it == select_column_fields.end()) {
620 0 : return false;
621 : }
622 138 : return true;
623 : }
624 395 : bool ObjectIdQuery() {
625 739 : return ((select_column_fields.size() == 1 &&
626 739 : select_column_fields[0] == g_viz_constants.OBJECT_ID));
627 : }
628 : friend class SelectTest;
629 : private:
630 : bool is_valid_select_field(const std::string& select_field) const;
631 : //
632 : // Object table query
633 : //
634 : void get_query_column_value(const GenDb::DbDataValueVec &info,
635 : unsigned int index,
636 : std::string *query_column,
637 : GenDb::DbDataValue *value,
638 : std::string *object_id);
639 : bool process_object_query_specific_select_params(
640 : const std::string& sel_field,
641 : std::map<std::string, GenDb::DbDataValue>& col_res_map,
642 : std::map<std::string, std::string>& cmap,
643 : const boost::uuids::uuid& uuid,
644 : std::map<boost::uuids::uuid, std::string>&);
645 :
646 : // For flow class id in select field
647 :
648 : // flow class id to flow tuple map
649 : std::map<size_t, flow_tuple> flow_class_id_map;
650 :
651 : //
652 : // Flow Series Query
653 : //
654 : static const uint64_t kMicrosecInSec = 1000 * 1000;
655 :
656 : uint8_t fs_query_type_;
657 : bool is_flow_tuple_specified();
658 : void evaluate_fs_query_type();
659 : typedef void (SelectQuery::*process_fs_query_callback)(const uint64_t&,
660 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
661 : typedef void (SelectQuery::*populate_fs_result_callback)();
662 : typedef std::map<uint8_t, process_fs_query_callback>
663 : process_fs_query_cb_map_t;
664 : static process_fs_query_cb_map_t process_fs_query_cb_map_;
665 : static process_fs_query_cb_map_t process_fs_query_cb_map_init();
666 : typedef std::map<uint8_t, populate_fs_result_callback>
667 : populate_fs_result_cb_map_t;
668 : static populate_fs_result_cb_map_t populate_fs_result_cb_map_;
669 : static populate_fs_result_cb_map_t populate_fs_result_cb_map_init();
670 : typedef std::map<const boost::uuids::uuid, uuid_flow_stats>
671 : fs_uuid_stats_map_t;
672 :
673 : // Called from process_query() for FLOW SERIES Query
674 : query_status_t process_fs_query(process_fs_query_callback,
675 : populate_fs_result_callback);
676 :
677 : // flowclass is populated from tuple based on the
678 : // tuple fields in the select_column_fields
679 : void get_flow_class(const flow_tuple& tuple, flow_tuple& flowclass);
680 :
681 : void fs_write_final_result_row(const uint64_t *t, const flow_tuple *tuple,
682 : const flow_stats *raw_stats, const flow_stats *sum_stats,
683 : const flow_stats *avg_stats,
684 : const std::set<boost::uuids::uuid> *flow_list = NULL);
685 :
686 : uint64_t fs_get_time_slice(const uint64_t& t);
687 : // Common Flow series queries
688 :
689 : // 1. SELECT with T=<granularity>, stats fields
690 : typedef std::map<const uint64_t, flow_stats> fs_ts_stats_map_t;
691 : fs_ts_stats_map_t fs_ts_stats_map_;
692 : void process_fs_query_with_ts_stats_fields(const uint64_t&,
693 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
694 : void populate_fs_query_result_with_ts_stats_fields();
695 :
696 : // 2. SELECT with flow tuple fields, stats fields
697 : typedef std::map<const flow_tuple, flow_stats> fs_tuple_stats_map_t;
698 : fs_tuple_stats_map_t fs_tuple_stats_map_;
699 : void process_fs_query_with_tuple_stats_fields(const uint64_t&,
700 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
701 : void populate_fs_query_result_with_tuple_stats_fields();
702 :
703 : // 3. SELECT with T=<granularity>, flow tuple fields, stats fields
704 : typedef std::map<const flow_tuple, fs_ts_stats_map_t>
705 : fs_ts_tuple_stats_map_t;
706 : fs_ts_tuple_stats_map_t fs_ts_tuple_stats_map_;
707 : void process_fs_query_with_ts_tuple_stats_fields(const uint64_t&,
708 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
709 : void populate_fs_query_result_with_ts_tuple_stats_fields();
710 :
711 : // Rare Flow series queries
712 :
713 : // 1. SELECT with stats fields
714 : flow_stats fs_flow_stats_;
715 : void process_fs_query_with_stats_fields(const uint64_t&,
716 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
717 : void populate_fs_query_result_with_stats_fields();
718 :
719 : // 2. SELECT with T=<granularity>, flow tuple fields
720 : typedef std::map<const uint64_t, std::set<flow_tuple> > fs_ts_tuple_map_t;
721 : fs_ts_tuple_map_t fs_ts_tuple_map_;
722 : void process_fs_query_with_ts_tuple_fields(const uint64_t&,
723 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
724 : void populate_fs_query_result_with_ts_tuple_fields();
725 :
726 : // 3. SELECT with flow tuple fields
727 : void process_fs_query_with_tuple_fields(const uint64_t&,
728 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
729 : void populate_fs_query_result_with_tuple_fields();
730 :
731 : void process_fs_query_with_time(const uint64_t&,
732 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
733 : void populate_fs_query_result_with_time();
734 :
735 : // 4. SELECT with T=<granularity>
736 : typedef std::set<uint64_t> fs_ts_t;
737 : fs_ts_t fs_ts_list_;
738 : void process_fs_query_with_ts(const uint64_t&,
739 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
740 : void populate_fs_query_result_with_ts();
741 :
742 : // 5. SELECT with T
743 : // 6. SELECT with T, flow tuple fields
744 : // 7. SELECT with T, stats fields
745 : // 8. SELECT with T, flow tuple, stats
746 : void process_fs_query_with_time_tuple_stats_fields(const uint64_t&,
747 : const boost::uuids::uuid&, const flow_stats&, const flow_tuple&);
748 : void populate_fs_query_result_with_time_tuple_stats_fields();
749 : };
750 :
751 :
752 : struct sort_field_t {
753 126 : sort_field_t(const std::string& sort_name, const std::string& datatype) :
754 126 : name(sort_name), type(datatype) {
755 126 : }
756 : std::string name;
757 : std::string type;
758 : };
759 :
760 : // this data structure is passed on to post-processing module
761 : class PostProcessingQuery: public QueryUnit {
762 : public:
763 : // Initialize with the JSON string hashset received from REDIS
764 : PostProcessingQuery(const std::map<std::string, std::string>& json_api_data,
765 : QueryUnit *main_query);
766 :
767 : virtual query_status_t process_query();
768 :
769 : // Query related fields
770 :
771 : std::string json_string_;
772 :
773 : // filter list is an OR of ANDs
774 : std::vector<std::vector<filter_match_t> > filter_list;
775 :
776 : // Whether to sort the table or not
777 : bool sorted;
778 :
779 : // Type of sorting
780 : sort_op sorting_type;
781 : // fields to sort on (these are actual Cassandra column names)
782 : std::vector<sort_field_t> sort_fields;
783 : int limit; // number of entries
784 :
785 : // result after post processing
786 :
787 : std::unique_ptr<BufT> result_;
788 : std::unique_ptr<MapBufT> mresult_;
789 :
790 : bool sort_field_comparator(const QEOpServerProxy::ResultRowT& lhs,
791 : const QEOpServerProxy::ResultRowT& rhs);
792 :
793 : bool merge_processing(
794 : const QEOpServerProxy::BufferT& input,
795 : QEOpServerProxy::BufferT& output);
796 : bool final_merge_processing(
797 : const std::vector<boost::shared_ptr<QEOpServerProxy::BufferT> >& inputs,
798 : QEOpServerProxy::BufferT& output);
799 : };
800 :
801 : class StatsQuery;
802 :
803 : class AnalyticsQuery: public QueryUnit {
804 : public:
805 : AnalyticsQuery(const std::string& qid, std::map<std::string,
806 : std::string>& json_api_data,
807 : int or_number,
808 : const std::vector<query_result_unit_t> * where_info,
809 : const TtlMap& ttlmap,
810 : EventManager *evm, std::vector<std::string> cassandra_ips,
811 : std::vector<int> cassandra_ports, int batch,
812 : int total_batches, const std::string& cassandra_user,
813 : const std::string &cassandra_password,
814 : QueryEngine *qe, void * pipeline_handle = NULL);
815 : AnalyticsQuery(const std::string& qid, GenDbIfPtr dbif,
816 : std::map<std::string, std::string> json_api_data,
817 : int or_number,
818 : const std::vector<query_result_unit_t> * where_info,
819 : const TtlMap& ttlmap, int batch, int total_batches,
820 : QueryEngine *qe, void * pipeline_handle = NULL);
821 3990 : virtual ~AnalyticsQuery() {}
822 :
823 : virtual query_status_t process_query();
824 :
825 : // Interface to Cassandra
826 : GenDbIfPtr dbif_;
827 : void db_err_handler() {};
828 :
829 : //Query related fields
830 :
831 : // Query Id
832 : std::string query_id;
833 :
834 : // if the req is to get objectids, the following will contain the key
835 : std::string object_value_key;
836 :
837 : std::string sandesh_moduleid; // module id of the query engine itself
838 : bool filter_qe_logs; // whether to filter query engine logs
839 :
840 : // final result of the query
841 : std::unique_ptr<QEOpServerProxy::BufferT> final_result;
842 : std::unique_ptr<QEOpServerProxy::OutRowMultimapT> final_mresult;
843 :
844 : std::map<std::string, std::string> json_api_data_;
845 : const std::vector<query_result_unit_t> * where_info_;
846 :
847 : TtlMap ttlmap_;
848 : uint64_t where_start_;
849 : uint64_t select_start_;
850 : uint64_t postproc_start_;
851 : QEOpServerProxy::QPerfInfo qperf_;
852 :
853 : WhereQuery *wherequery_;
854 : SelectQuery *selectquery_;
855 : PostProcessingQuery *postprocess_;
856 :
857 : // For parallelization
858 : // Values from the original query
859 : // start time of the time range for the queried records
860 : uint64_t original_from_time;
861 : // end time of the time range for the queried records
862 : uint64_t original_end_time;
863 : // whether results from parallel instances need to be merged
864 : bool merge_needed; // whether sorting/limit operations are needed
865 : // which parallel batch number is this
866 : int parallel_batch_num;
867 : // total number of parallel batches
868 : int total_parallel_batches;
869 : // whether any processing is needed
870 : bool processing_needed;
871 : // time slice for each parallel instance
872 : uint64_t time_slice;
873 : // shared ptr to query engine needed when where_query winds up
874 : QueryEngine* qe_;
875 : // outer pipeline handle, needed while calling the QEResult from
876 : // where_query context
877 : void *handle_;
878 : // this is for merge between multiple instances running on same core
879 : bool merge_processing(const QEOpServerProxy::BufferT& input,
880 : QEOpServerProxy::BufferT& output);
881 : // this is for merge between instances running on multiple cores
882 : bool final_merge_processing(
883 : const std::vector<boost::shared_ptr<QEOpServerProxy::BufferT> >& inputs,
884 : QEOpServerProxy::BufferT& output);
885 :
886 : // this is to get parallelization details once the query is parsed
887 : void get_query_details(bool& is_merge_needed, bool& is_map_output,
888 : std::vector<uint64_t>& chunk_sizes,
889 : std::string& where, uint32_t& wterms,
890 : std::string& select,
891 : std::string& post,
892 : uint64_t& time_period,
893 : int& parse_status);
894 :
895 456566 : virtual std::string table() const {
896 456566 : return table_;
897 : }
898 0 : virtual uint64_t req_from_time() const {
899 0 : return req_from_time_;
900 : }
901 0 : virtual uint64_t req_end_time() const {
902 0 : return req_end_time_;
903 : }
904 8180 : virtual uint64_t from_time() const {
905 8180 : return from_time_;
906 : }
907 7943 : virtual uint64_t end_time() const {
908 7943 : return end_time_;
909 : }
910 0 : virtual const std::vector<query_result_unit_t>& where_query_result() {
911 0 : return *where_info_;
912 : }
913 0 : virtual uint32_t direction_ing() const {
914 0 : return wherequery_->direction_ing;
915 : }
916 :
917 : // validation functions
918 : virtual bool is_object_table_query(const std::string &tname);
919 : static bool is_message_table_query(const std::string &tname);
920 : bool is_message_table_query();
921 : static bool is_stat_table_query(const std::string& tname);
922 : static bool is_stat_fieldnames_table_query(const std::string& tname);
923 : static bool is_session_query(const std::string& tname); // either flow-series or flow-records query
924 : static bool is_flow_query(const std::string& tname); // either flow-series or flow-records query
925 : bool is_valid_where_field(const std::string& where_field);
926 : bool is_valid_sort_field(const std::string& sort_field);
927 : std::string get_column_field_datatype(const std::string& col_field);
928 15 : virtual bool is_query_parallelized() { return parallelize_query_; }
929 :
930 3336 : const StatsQuery& stats(void) const { return *stats_; }
931 : std::string stat_name_attr; // will be populated only for stats query
932 : private:
933 : std::unique_ptr<StatsQuery> stats_;
934 : // Analytics table to query
935 : std::string table_;
936 : // query start time requested by the user
937 : uint64_t req_from_time_;
938 : // query end time requested by the user
939 : uint64_t req_end_time_;
940 : // start time of the time range for the queried records.
941 : // If the start time requested by the user is earlier than the
942 : // analytics start time, then this field holds the analytics start time.
943 : // Else, from_time is same as req_from_time.
944 : uint64_t from_time_;
945 : // end time of the time range for the queried records.
946 : // If the end time requested by the user is later than the time @ which the
947 : // query was received, then this field holds the time @ which the query
948 : // was received. Else, end_time is same as req_end_time.
949 : uint64_t end_time_;
950 : bool parallelize_query_;
951 : // Init function
952 : void Init(const std::string& qid,
953 : const std::map<std::string, std::string>& json_api_data,
954 : int32_t or_number);
955 : bool can_parallelize_query();
956 : void ParseStatName(std::string &stat_table_name);
957 : };
958 :
959 : // limit on the size of query result we can handle
960 : static const int query_result_size_limit = 25000000;
961 :
962 : // main class
963 : class QueryEngine {
964 : public:
965 : static const uint64_t StartTimeDiffInSec = 12*3600;
966 : static int max_slice_;
967 :
968 : struct QueryParams {
969 126 : QueryParams(std::string qi,
970 : std::map<std::string, std::string> qu,
971 126 : uint32_t ch, uint64_t tm) :
972 126 : qid(qi), terms(qu), maxChunks(ch), query_starttm(tm) {}
973 1512 : QueryParams() {}
974 : std::string qid;
975 : std::map<std::string, std::string> terms;
976 : uint32_t maxChunks;
977 : uint64_t query_starttm;
978 : };
979 :
980 : uint64_t stime;
981 : int max_tasks_;
982 :
983 : QueryEngine(EventManager *evm,
984 : std::vector<std::string> cassandra_ips,
985 : std::vector<int> cassandra_ports,
986 : std::vector<std::string> redis_ip_ports,
987 : const std::string & redis_password,
988 : const bool redis_ssl_enable,
989 : const std::string & redis_keyfile,
990 : const std::string & redis_certfile,
991 : const std::string & redis_ca_cert,
992 : int max_tasks, int max_slice,
993 : const std::string & cassandra_name,
994 : const std::string & cassandra_password,
995 : bool cassandra_use_ssl,
996 : const std::string& cassandra_ca_certs,
997 : const std::string & cluster_id,
998 : const std::string &host_ip);
999 :
1000 : QueryEngine(EventManager *evm,
1001 : std::vector<std::string> redis_ip_ports,
1002 : const std::string & redis_password,
1003 : const bool redis_ssl_enable,
1004 : const std::string & redis_keyfile,
1005 : const std::string & redis_certfile,
1006 : const std::string & redis_ca_cert,
1007 : int max_tasks, int max_slice,
1008 : const std::string & cassandra_user,
1009 : const std::string & cassandra_password,
1010 : bool cassandra_use_ssl,
1011 : const std::string& cassandra_ca_certs,
1012 : const std::string &host_ip);
1013 :
1014 : // This constructor used only for test purpose
1015 5 : QueryEngine(){}
1016 :
1017 : virtual ~QueryEngine();
1018 :
1019 : int
1020 : QueryPrepare(QueryParams qp,
1021 : std::vector<uint64_t> &chunk_size,
1022 : bool & need_merge, bool & map_output,
1023 : std::string& where, uint32_t& wterms,
1024 : std::string& select, std::string& post,
1025 : uint64_t& time_period,
1026 : std::string &table);
1027 :
1028 : // Query Execution of WHERE term
1029 : bool
1030 : QueryExecWhere(void * handle, QueryParams qp, uint32_t chunk,
1031 : uint32_t or_number);
1032 :
1033 : void
1034 : WhereQueryResult(AnalyticsQuery *q);
1035 :
1036 : // Query Execution of SELECT and post-processing
1037 : bool
1038 : QueryExec(void * handle, QueryParams qp, uint32_t chunk,
1039 : const std::vector<query_result_unit_t> *wi);
1040 :
1041 : bool
1042 : QueryAccumulate(QueryParams qp,
1043 : const QEOpServerProxy::BufferT& input,
1044 : QEOpServerProxy::BufferT& output);
1045 :
1046 : bool
1047 : QueryFinalMerge(QueryParams qp,
1048 : const std::vector<boost::shared_ptr<QEOpServerProxy::BufferT> >& inputs,
1049 : QEOpServerProxy::BufferT& output);
1050 :
1051 : bool
1052 : QueryFinalMerge(QueryParams qp,
1053 : const std::vector<boost::shared_ptr<QEOpServerProxy::OutRowMultimapT> >& inputs,
1054 : QEOpServerProxy::OutRowMultimapT& output);
1055 :
1056 : // Unit test function
1057 : void QueryEngine_Test();
1058 :
1059 : void db_err_handler() {};
1060 : TtlMap& GetTTlMap() { return ttlmap_; }
1061 0 : const std::string & keyspace() { return keyspace_; }
1062 : GenDb::DbTableStatistics stable_stats_;
1063 : mutable std::mutex smutex_;
1064 : bool GetCumulativeStats(std::vector<GenDb::DbTableInfo> *vdbti,
1065 : GenDb::DbErrors *dbe, std::vector<GenDb::DbTableInfo> *vstats_dbti)
1066 : const;
1067 : bool GetDiffStats(std::vector<GenDb::DbTableInfo> *vdbti,
1068 : GenDb::DbErrors *dbe, std::vector<GenDb::DbTableInfo> *vstats_dbti);
1069 : bool GetCqlStats(cass::cql::DbStats *stats) const;
1070 : bool GetCqlMetrics(cass::cql::Metrics *matrics) const;
1071 39 : GenDbIfPtr GetDbHandler() { return dbif_; }
1072 :
1073 : private:
1074 : GenDbIfPtr dbif_;
1075 : boost::scoped_ptr<QEOpServerProxy> qosp_;
1076 : EventManager *evm_;
1077 : std::vector<int> cassandra_ports_;
1078 : std::vector<std::string> cassandra_ips_;
1079 : std::string cassandra_user_;
1080 : std::string cassandra_password_;
1081 : bool cassandra_use_ssl_;
1082 : std::string cassandra_ca_certs_;
1083 : TtlMap ttlmap_;
1084 : std::string keyspace_;
1085 : };
1086 :
1087 : #endif
|