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 : #include <exception>
7 : #include <mutex>
8 : #include <string>
9 : #include <boost/bind/bind.hpp>
10 : #include <boost/foreach.hpp>
11 : #include <boost/assign/list_of.hpp>
12 : #include <boost/uuid/name_generator.hpp>
13 : #include <boost/system/error_code.hpp>
14 :
15 : #include <rapidjson/document.h>
16 : #include <rapidjson/stringbuffer.h>
17 : #include <rapidjson/writer.h>
18 :
19 : #include <base/string_util.h>
20 : #include <base/logging.h>
21 : #include <io/event_manager.h>
22 : #include <base/connection_info.h>
23 : #include <base/address_util.h>
24 : #include <sandesh/sandesh_message_builder.h>
25 : #include <sandesh/protocol/TXMLProtocol.h>
26 : #include <database/cassandra/cql/cql_if.h>
27 : #include <zookeeper/zookeeper_client.h>
28 :
29 : #include "sandesh/common/flow_constants.h"
30 : #include "sandesh/common/flow_types.h"
31 : #include "viz_constants.h"
32 : #include "vizd_table_desc.h"
33 : #include "viz_collector.h"
34 : #include "collector.h"
35 : #include "db_handler.h"
36 : #include "parser_util.h"
37 : #include "db_handler_impl.h"
38 : #include "viz_sandesh.h"
39 :
40 : using namespace boost::placeholders;
41 :
42 : #define DB_LOG(_Level, _Msg) \
43 : do { \
44 : if (LoggingDisabled()) break; \
45 : log4cplus::Logger _Xlogger = log4cplus::Logger::getRoot(); \
46 : if (_Xlogger.isEnabledFor(log4cplus::_Level##_LOG_LEVEL)) { \
47 : log4cplus::tostringstream _Xbuf; \
48 : _Xbuf << name_ << ": " << __func__ << ": " << _Msg; \
49 : _Xlogger.forcedLog(log4cplus::_Level##_LOG_LEVEL, \
50 : _Xbuf.str()); \
51 : } \
52 : } while (false)
53 :
54 : using std::pair;
55 : using std::string;
56 : using boost::system::error_code;
57 : using namespace pugi;
58 : using namespace contrail::sandesh::protocol;
59 : using process::ConnectionState;
60 : using process::ConnectionType;
61 : using process::ConnectionStatus;
62 : using namespace boost::system;
63 :
64 : uint32_t DbHandler::field_cache_index_ = 0;
65 : std::set<std::string> DbHandler::field_cache_set_;
66 : std::mutex DbHandler::fmutex_;
67 :
68 1 : DbHandler::DbHandler(EventManager *evm,
69 : GenDb::GenDbIf::DbErrorHandler err_handler,
70 : std::string name,
71 : const Options::Cassandra &cassandra_options,
72 : bool use_db_write_options,
73 : const DbWriteOptions &db_write_options,
74 1 : ConfigClientCollector *config_client) :
75 1 : dbif_(new cass::cql::CqlIf(evm, cassandra_options.cassandra_ips_,
76 1 : cassandra_options.cassandra_ports_[0],
77 1 : cassandra_options.user_, cassandra_options.password_,
78 1 : cassandra_options.use_ssl_, cassandra_options.ca_certs_,
79 1 : true)),
80 1 : name_(name),
81 1 : drop_level_(SandeshLevel::INVALID),
82 1 : ttl_map_(cassandra_options.ttlmap_),
83 1 : compaction_strategy_(cassandra_options.compaction_strategy_),
84 1 : flow_tables_compaction_strategy_(
85 1 : cassandra_options.flow_tables_compaction_strategy_),
86 1 : gen_partition_no_((uint8_t)g_viz_constants.PARTITION_MIN,
87 1 : (uint8_t)g_viz_constants.PARTITION_MAX),
88 1 : disable_all_writes_(cassandra_options.disable_all_db_writes_),
89 1 : disable_statistics_writes_(cassandra_options.disable_db_stats_writes_),
90 1 : disable_messages_writes_(cassandra_options.disable_db_messages_writes_),
91 1 : config_client_(config_client),
92 6 : use_db_write_options_(use_db_write_options) {
93 1 : udc_.reset(new UserDefinedCounters());
94 1 : if (config_client) {
95 0 : config_client->RegisterConfigReceive("udc",
96 : boost::bind(&DbHandler::ReceiveConfig, this, _1, _2));
97 : }
98 1 : error_code error;
99 1 : col_name_ = ResolveCanonicalName();
100 :
101 1 : if (cassandra_options.cluster_id_.empty()) {
102 1 : tablespace_ = g_viz_constants.COLLECTOR_KEYSPACE_CQL;
103 : } else {
104 0 : tablespace_ = g_viz_constants.COLLECTOR_KEYSPACE_CQL + '_' + cassandra_options.cluster_id_;
105 : }
106 :
107 1 : if (cassandra_options.replication_factor_.empty()) {
108 1 : replication_factor_ = "1";
109 2 : DB_LOG(WARN, "CASSANDRA.replication_factor not set; defaulting to 1");
110 : } else {
111 0 : replication_factor_ = cassandra_options.replication_factor_;
112 : }
113 :
114 1 : if (use_db_write_options_) {
115 : // Set disk-usage watermark defaults
116 0 : SetDiskUsagePercentageHighWaterMark(
117 : db_write_options.get_disk_usage_percentage_high_watermark0(),
118 : db_write_options.get_high_watermark0_message_severity_level());
119 0 : SetDiskUsagePercentageLowWaterMark(
120 : db_write_options.get_disk_usage_percentage_low_watermark0(),
121 : db_write_options.get_low_watermark0_message_severity_level());
122 0 : SetDiskUsagePercentageHighWaterMark(
123 : db_write_options.get_disk_usage_percentage_high_watermark1(),
124 : db_write_options.get_high_watermark1_message_severity_level());
125 0 : SetDiskUsagePercentageLowWaterMark(
126 : db_write_options.get_disk_usage_percentage_low_watermark1(),
127 : db_write_options.get_low_watermark1_message_severity_level());
128 0 : SetDiskUsagePercentageHighWaterMark(
129 : db_write_options.get_disk_usage_percentage_high_watermark2(),
130 : db_write_options.get_high_watermark2_message_severity_level());
131 0 : SetDiskUsagePercentageLowWaterMark(
132 : db_write_options.get_disk_usage_percentage_low_watermark2(),
133 : db_write_options.get_low_watermark2_message_severity_level());
134 :
135 : // Set cassandra pending tasks watermark defaults
136 0 : SetPendingCompactionTasksHighWaterMark(
137 : db_write_options.get_pending_compaction_tasks_high_watermark0(),
138 : db_write_options.get_high_watermark0_message_severity_level());
139 0 : SetPendingCompactionTasksLowWaterMark(
140 : db_write_options.get_pending_compaction_tasks_low_watermark0(),
141 : db_write_options.get_low_watermark0_message_severity_level());
142 0 : SetPendingCompactionTasksHighWaterMark(
143 : db_write_options.get_pending_compaction_tasks_high_watermark1(),
144 : db_write_options.get_high_watermark1_message_severity_level());
145 0 : SetPendingCompactionTasksLowWaterMark(
146 : db_write_options.get_pending_compaction_tasks_low_watermark1(),
147 : db_write_options.get_low_watermark1_message_severity_level());
148 0 : SetPendingCompactionTasksHighWaterMark(
149 : db_write_options.get_pending_compaction_tasks_high_watermark2(),
150 : db_write_options.get_high_watermark2_message_severity_level());
151 0 : SetPendingCompactionTasksLowWaterMark(
152 : db_write_options.get_pending_compaction_tasks_low_watermark2(),
153 : db_write_options.get_low_watermark2_message_severity_level());
154 :
155 : // Initialize drop-levels to lowest severity level.
156 0 : SetDiskUsagePercentageDropLevel(0,
157 : db_write_options.get_low_watermark2_message_severity_level());
158 0 : SetPendingCompactionTasksDropLevel(0,
159 : db_write_options.get_low_watermark2_message_severity_level());
160 : }
161 1 : session_table_db_stats_ = SessionTableDbStats();
162 1 : }
163 :
164 :
165 6 : DbHandler::DbHandler(GenDb::GenDbIf *dbif, const TtlMap& ttl_map) :
166 6 : dbif_(dbif),
167 6 : ttl_map_(ttl_map),
168 6 : gen_partition_no_((uint8_t)g_viz_constants.PARTITION_MIN,
169 6 : (uint8_t)g_viz_constants.PARTITION_MAX),
170 6 : disable_all_writes_(false),
171 6 : disable_statistics_writes_(false),
172 6 : disable_messages_writes_(false),
173 18 : use_db_write_options_(false) {
174 6 : udc_.reset(new UserDefinedCounters());
175 6 : }
176 :
177 13 : DbHandler::~DbHandler() {
178 13 : }
179 :
180 0 : uint64_t DbHandler::GetTtlInHourFromMap(const TtlMap& ttl_map,
181 : TtlType::type type) {
182 0 : TtlMap::const_iterator it = ttl_map.find(type);
183 0 : if (it != ttl_map.end()) {
184 0 : return it->second;
185 : } else {
186 0 : return 0;
187 : }
188 : }
189 :
190 8 : uint64_t DbHandler::GetTtlFromMap(const TtlMap& ttl_map,
191 : TtlType::type type) {
192 8 : TtlMap::const_iterator it = ttl_map.find(type);
193 8 : if (it != ttl_map.end()) {
194 8 : return it->second*3600;
195 : } else {
196 0 : return 0;
197 : }
198 : }
199 :
200 0 : std::string DbHandler::GetName() const {
201 0 : return name_;
202 : }
203 :
204 0 : std::vector<boost::asio::ip::tcp::endpoint> DbHandler::GetEndpoints() const {
205 0 : return dbif_->Db_GetEndpoints();
206 : }
207 :
208 0 : void DbHandler::SetDiskUsagePercentageDropLevel(size_t count,
209 : SandeshLevel::type drop_level) {
210 0 : disk_usage_percentage_drop_level_ = drop_level;
211 0 : }
212 :
213 0 : void DbHandler::SetDiskUsagePercentage(size_t disk_usage_percentage) {
214 0 : disk_usage_percentage_ = disk_usage_percentage;
215 0 : }
216 :
217 0 : void DbHandler::SetDiskUsagePercentageHighWaterMark(
218 : uint32_t disk_usage_percentage,
219 : SandeshLevel::type level) {
220 : WaterMarkInfo wm = WaterMarkInfo(disk_usage_percentage,
221 : boost::bind(&DbHandler::SetDiskUsagePercentageDropLevel,
222 0 : this, _1, level));
223 0 : disk_usage_percentage_watermark_tuple_.SetHighWaterMark(wm);
224 0 : }
225 :
226 0 : void DbHandler::SetDiskUsagePercentageLowWaterMark(
227 : uint32_t disk_usage_percentage,
228 : SandeshLevel::type level) {
229 : WaterMarkInfo wm = WaterMarkInfo(disk_usage_percentage,
230 : boost::bind(&DbHandler::SetDiskUsagePercentageDropLevel,
231 0 : this, _1, level));
232 0 : disk_usage_percentage_watermark_tuple_.SetLowWaterMark(wm);
233 0 : }
234 :
235 0 : void DbHandler::ProcessDiskUsagePercentage(uint32_t disk_usage_percentage) {
236 0 : std::scoped_lock lock(disk_usage_percentage_water_mutex_);
237 0 : disk_usage_percentage_watermark_tuple_.ProcessWaterMarks(
238 : disk_usage_percentage,
239 0 : DbHandler::disk_usage_percentage_);
240 0 : }
241 :
242 0 : void DbHandler::SetPendingCompactionTasksDropLevel(size_t count,
243 : SandeshLevel::type drop_level) {
244 0 : pending_compaction_tasks_drop_level_ = drop_level;
245 0 : }
246 :
247 0 : void DbHandler::SetPendingCompactionTasks(size_t pending_compaction_tasks) {
248 0 : pending_compaction_tasks_ = pending_compaction_tasks;
249 0 : }
250 :
251 0 : void DbHandler::SetPendingCompactionTasksHighWaterMark(
252 : uint32_t pending_compaction_tasks,
253 : SandeshLevel::type level) {
254 : WaterMarkInfo wm = WaterMarkInfo(pending_compaction_tasks,
255 : boost::bind(&DbHandler::SetPendingCompactionTasksDropLevel, this,
256 0 : _1, level));
257 0 : pending_compaction_tasks_watermark_tuple_.SetHighWaterMark(wm);
258 0 : }
259 :
260 0 : void DbHandler::SetPendingCompactionTasksLowWaterMark(
261 : uint32_t pending_compaction_tasks,
262 : SandeshLevel::type level) {
263 : WaterMarkInfo wm = WaterMarkInfo(pending_compaction_tasks,
264 : boost::bind(&DbHandler::SetPendingCompactionTasksDropLevel, this,
265 0 : _1, level));
266 0 : pending_compaction_tasks_watermark_tuple_.SetLowWaterMark(wm);
267 0 : }
268 :
269 0 : void DbHandler::ProcessPendingCompactionTasks(
270 : uint32_t pending_compaction_tasks) {
271 0 : std::scoped_lock lock(pending_compaction_tasks_water_mutex_);
272 0 : pending_compaction_tasks_watermark_tuple_.ProcessWaterMarks(
273 : pending_compaction_tasks,
274 0 : DbHandler::pending_compaction_tasks_);
275 0 : }
276 :
277 0 : bool DbHandler::DropMessage(const SandeshHeader &header,
278 : const VizMsg *vmsg) {
279 0 : SandeshType::type stype(header.get_Type());
280 : // If Flow message, drop it
281 0 : if (stype == SandeshType::FLOW) {
282 0 : std::scoped_lock lock(smutex_);
283 0 : dropped_msg_stats_.Update(vmsg);
284 0 : return true;
285 0 : }
286 0 : if (!(stype == SandeshType::SYSTEM || stype == SandeshType::OBJECT ||
287 : stype == SandeshType::UVE ||
288 : stype == SandeshType::SESSION)) {
289 0 : return false;
290 : }
291 : // First check again the queue watermark drop level
292 : SandeshLevel::type slevel(static_cast<SandeshLevel::type>(
293 0 : header.get_Level()));
294 0 : if (slevel >= drop_level_) {
295 0 : std::scoped_lock lock(smutex_);
296 0 : dropped_msg_stats_.Update(vmsg);
297 0 : return true;
298 0 : }
299 : // Next check against the disk usage and pending compaction tasks
300 : // drop levels
301 0 : bool disk_usage_percentage_drop = false;
302 0 : bool pending_compaction_tasks_drop = false;
303 0 : if (use_db_write_options_) {
304 : SandeshLevel::type disk_usage_percentage_drop_level =
305 0 : GetDiskUsagePercentageDropLevel();
306 : SandeshLevel::type pending_compaction_tasks_drop_level =
307 0 : GetPendingCompactionTasksDropLevel();
308 0 : if (slevel >= disk_usage_percentage_drop_level) {
309 0 : disk_usage_percentage_drop = true;
310 : }
311 0 : if (slevel >= pending_compaction_tasks_drop_level) {
312 0 : pending_compaction_tasks_drop = true;
313 : }
314 : }
315 :
316 0 : bool drop(disk_usage_percentage_drop || pending_compaction_tasks_drop);
317 0 : if (drop) {
318 0 : std::scoped_lock lock(smutex_);
319 0 : dropped_msg_stats_.Update(vmsg);
320 0 : }
321 0 : return drop;
322 : }
323 :
324 0 : void DbHandler::SetDropLevel(size_t queue_count, SandeshLevel::type level,
325 : boost::function<void (void)> cb) {
326 0 : if (drop_level_ != level) {
327 0 : DB_LOG(INFO, "DB DROP LEVEL: [" <<
328 : Sandesh::LevelToString(drop_level_) << "] -> [" <<
329 : Sandesh::LevelToString(level) << "], DB QUEUE COUNT: " <<
330 : queue_count);
331 0 : drop_level_ = level;
332 : }
333 : // Always invoke the callback
334 0 : if (!cb.empty()) {
335 0 : cb();
336 : }
337 0 : }
338 :
339 0 : bool DbHandler::CreateTables() {
340 0 : for (std::vector<GenDb::NewCf>::const_iterator it = vizd_tables.begin();
341 0 : it != vizd_tables.end(); it++) {
342 0 : if (!dbif_->Db_AddColumnfamily(*it, compaction_strategy_)) {
343 0 : DB_LOG(ERROR, it->cfname_ << " FAILED");
344 0 : return false;
345 : }
346 :
347 : // find schema for it->cfname_
348 : // find all columns with index_type field set
349 0 : table_schema cfschema;
350 0 : cfschema = g_viz_constants._VIZD_TABLE_SCHEMA.find(it->cfname_)->second;
351 0 : BOOST_FOREACH (schema_column column, cfschema.columns) {
352 0 : if (column.index_mode != GenDb::ColIndexMode::NONE) {
353 0 : if (!dbif_->Db_CreateIndex(it->cfname_, column.name, "",
354 : column.index_mode)) {
355 0 : DB_LOG(ERROR, it->cfname_ << ": CreateIndex FAILED for "
356 : << column.name);
357 0 : return false;
358 : }
359 : }
360 0 : }
361 0 : }
362 :
363 0 : for (std::vector<GenDb::NewCf>::const_iterator it = vizd_stat_tables.begin();
364 0 : it != vizd_stat_tables.end(); it++) {
365 0 : if (!dbif_->Db_AddColumnfamily(*it, compaction_strategy_)) {
366 0 : DB_LOG(ERROR, it->cfname_ << " FAILED");
367 0 : return false;
368 : }
369 0 : table_schema cfschema;
370 0 : cfschema = g_viz_constants._VIZD_STAT_TABLE_SCHEMA.find(it->cfname_)->second;
371 0 : BOOST_FOREACH (schema_column column, cfschema.columns) {
372 0 : if (column.index_mode != GenDb::ColIndexMode::NONE) {
373 0 : if (!dbif_->Db_CreateIndex(it->cfname_, column.name, "",
374 : column.index_mode)) {
375 0 : DB_LOG(ERROR, it->cfname_ << ": CreateIndex FAILED for "
376 : << column.name);
377 0 : return false;
378 : }
379 : }
380 0 : }
381 0 : }
382 :
383 0 : for (std::vector<GenDb::NewCf>::const_iterator it = vizd_session_tables.begin();
384 0 : it != vizd_session_tables.end(); it++) {
385 0 : if (!dbif_->Db_AddColumnfamily(*it, flow_tables_compaction_strategy_)) {
386 0 : DB_LOG(ERROR, it->cfname_ << " FAILED");
387 0 : return false;
388 : }
389 :
390 : // will be un-commented once we start using cassandra-2.10 for systemless tests
391 : table_schema cfschema = g_viz_constants._VIZD_SESSION_TABLE_SCHEMA
392 0 : .find(it->cfname_)->second;
393 0 : BOOST_FOREACH(schema_column column, cfschema.columns) {
394 0 : if (column.index_mode != GenDb::ColIndexMode::NONE) {
395 0 : if (!dbif_->Db_CreateIndex(it->cfname_, column.name, "",
396 : column.index_mode)) {
397 0 : DB_LOG(ERROR, it->cfname_ << ": CreateIndex FAILED for "
398 : << column.name);
399 0 : return false;
400 : }
401 : }
402 0 : }
403 0 : }
404 :
405 0 : if (!dbif_->Db_SetTablespace(tablespace_)) {
406 0 : DB_LOG(ERROR, "Set KEYSPACE: " << tablespace_ << " FAILED");
407 0 : return false;
408 : }
409 0 : GenDb::ColList col_list;
410 0 : std::string cfname = g_viz_constants.SYSTEM_OBJECT_TABLE;
411 0 : GenDb::DbDataValueVec key;
412 0 : key.push_back(g_viz_constants.SYSTEM_OBJECT_ANALYTICS);
413 :
414 0 : bool init_done = false;
415 0 : if (dbif_->Db_GetRow(&col_list, cfname, key,
416 : GenDb::DbConsistency::LOCAL_ONE)) {
417 0 : for (GenDb::NewColVec::iterator it = col_list.columns_.begin();
418 0 : it != col_list.columns_.end(); it++) {
419 0 : std::string col_name;
420 : try {
421 0 : col_name = boost::get<std::string>(it->name->at(0));
422 0 : } catch (boost::bad_get& ex) {
423 0 : DB_LOG(ERROR, cfname << ": Column Name Get FAILED");
424 0 : }
425 :
426 0 : if (col_name == g_viz_constants.SYSTEM_OBJECT_START_TIME) {
427 0 : init_done = true;
428 : }
429 0 : }
430 : }
431 :
432 0 : if (!init_done) {
433 0 : std::auto_ptr<GenDb::ColList> col_list(new GenDb::ColList);
434 0 : col_list->cfname_ = g_viz_constants.SYSTEM_OBJECT_TABLE;
435 : // Rowkey
436 0 : GenDb::DbDataValueVec& rowkey = col_list->rowkey_;
437 0 : rowkey.reserve(1);
438 0 : rowkey.push_back(g_viz_constants.SYSTEM_OBJECT_ANALYTICS);
439 : // Columns
440 0 : GenDb::NewColVec& columns = col_list->columns_;
441 0 : columns.reserve(4);
442 :
443 0 : uint64_t current_tm = UTCTimestampUsec();
444 :
445 : GenDb::NewCol *col(new GenDb::NewCol(
446 0 : g_viz_constants.SYSTEM_OBJECT_START_TIME, current_tm, 0));
447 0 : columns.push_back(col);
448 :
449 : GenDb::NewCol *flow_col(new GenDb::NewCol(
450 0 : g_viz_constants.SYSTEM_OBJECT_FLOW_START_TIME, current_tm, 0));
451 0 : columns.push_back(flow_col);
452 :
453 : GenDb::NewCol *msg_col(new GenDb::NewCol(
454 0 : g_viz_constants.SYSTEM_OBJECT_MSG_START_TIME, current_tm, 0));
455 0 : columns.push_back(msg_col);
456 :
457 : GenDb::NewCol *stat_col(new GenDb::NewCol(
458 0 : g_viz_constants.SYSTEM_OBJECT_STAT_START_TIME, current_tm, 0));
459 0 : columns.push_back(stat_col);
460 :
461 0 : if (!dbif_->Db_AddColumnSync(col_list,
462 : GenDb::DbConsistency::LOCAL_ONE)) {
463 0 : DB_LOG(ERROR, g_viz_constants.SYSTEM_OBJECT_TABLE <<
464 : ": Start Time Column Add FAILED");
465 0 : return false;
466 : }
467 0 : }
468 :
469 : /*
470 : * add ttls to cassandra to be retrieved by other daemons
471 : */
472 : {
473 0 : std::auto_ptr<GenDb::ColList> col_list(new GenDb::ColList);
474 0 : col_list->cfname_ = g_viz_constants.SYSTEM_OBJECT_TABLE;
475 : // Rowkey
476 0 : GenDb::DbDataValueVec& rowkey = col_list->rowkey_;
477 0 : rowkey.reserve(1);
478 0 : rowkey.push_back(g_viz_constants.SYSTEM_OBJECT_ANALYTICS);
479 : // Columns
480 0 : GenDb::NewColVec& columns = col_list->columns_;
481 0 : columns.reserve(4);
482 :
483 : GenDb::NewCol *col(new GenDb::NewCol(
484 0 : g_viz_constants.SYSTEM_OBJECT_FLOW_DATA_TTL, (uint64_t)DbHandler::GetTtlInHourFromMap(ttl_map_, TtlType::FLOWDATA_TTL), 0));
485 0 : columns.push_back(col);
486 :
487 : GenDb::NewCol *flow_col(new GenDb::NewCol(
488 0 : g_viz_constants.SYSTEM_OBJECT_STATS_DATA_TTL, (uint64_t)DbHandler::GetTtlInHourFromMap(ttl_map_, TtlType::STATSDATA_TTL), 0));
489 0 : columns.push_back(flow_col);
490 :
491 : GenDb::NewCol *msg_col(new GenDb::NewCol(
492 0 : g_viz_constants.SYSTEM_OBJECT_CONFIG_AUDIT_TTL, (uint64_t)DbHandler::GetTtlInHourFromMap(ttl_map_, TtlType::CONFIGAUDIT_TTL), 0));
493 0 : columns.push_back(msg_col);
494 :
495 : GenDb::NewCol *stat_col(new GenDb::NewCol(
496 0 : g_viz_constants.SYSTEM_OBJECT_GLOBAL_DATA_TTL, (uint64_t)DbHandler::GetTtlInHourFromMap(ttl_map_, TtlType::GLOBAL_TTL), 0));
497 0 : columns.push_back(stat_col);
498 :
499 0 : if (!dbif_->Db_AddColumnSync(col_list,
500 : GenDb::DbConsistency::LOCAL_ONE)) {
501 0 : DB_LOG(ERROR, g_viz_constants.SYSTEM_OBJECT_TABLE <<
502 : ": TTL Column Add FAILED");
503 0 : return false;
504 : }
505 0 : }
506 :
507 0 : return true;
508 0 : }
509 :
510 0 : void DbHandler::UnInit() {
511 0 : dbif_->Db_Uninit();
512 0 : dbif_->Db_SetInitDone(false);
513 0 : }
514 :
515 0 : bool DbHandler::Init(bool initial) {
516 0 : SetDropLevel(0, SandeshLevel::INVALID, NULL);
517 0 : if (initial) {
518 0 : return Initialize();
519 : } else {
520 0 : return Setup();
521 : }
522 : }
523 :
524 0 : bool DbHandler::Initialize() {
525 0 : DB_LOG(DEBUG, "Initializing..");
526 :
527 : /* init of vizd table structures */
528 0 : init_vizd_tables();
529 :
530 0 : if (!dbif_->Db_Init()) {
531 0 : DB_LOG(ERROR, "Connection to DB FAILED");
532 0 : return false;
533 : }
534 :
535 0 : if (!dbif_->Db_AddSetTablespace(tablespace_, replication_factor_)) {
536 0 : DB_LOG(ERROR, "Create/Set KEYSPACE: " << tablespace_ << " FAILED");
537 0 : return false;
538 : }
539 :
540 0 : if (!CreateTables()) {
541 0 : DB_LOG(ERROR, "CreateTables FAILED");
542 0 : return false;
543 : }
544 :
545 0 : dbif_->Db_SetInitDone(true);
546 0 : DB_LOG(DEBUG, "Initializing Done");
547 :
548 0 : return true;
549 : }
550 :
551 0 : bool DbHandler::Setup() {
552 0 : DB_LOG(DEBUG, "Setup..");
553 0 : if (!dbif_->Db_Init()) {
554 0 : DB_LOG(ERROR, "Connection to DB FAILED");
555 0 : return false;
556 : }
557 0 : if (!dbif_->Db_SetTablespace(tablespace_)) {
558 0 : DB_LOG(ERROR, "Set KEYSPACE: " << tablespace_ << " FAILED");
559 0 : return false;
560 : }
561 0 : for (std::vector<GenDb::NewCf>::const_iterator it = vizd_tables.begin();
562 0 : it != vizd_tables.end(); it++) {
563 0 : if (!dbif_->Db_UseColumnfamily(*it)) {
564 0 : DB_LOG(ERROR, it->cfname_ <<
565 : ": Db_UseColumnfamily FAILED");
566 0 : return false;
567 : }
568 : }
569 0 : for (std::vector<GenDb::NewCf>::const_iterator it = vizd_stat_tables.begin();
570 0 : it != vizd_stat_tables.end(); it++) {
571 0 : if (!dbif_->Db_UseColumnfamily(*it)) {
572 0 : DB_LOG(ERROR, it->cfname_ << ": Db_UseColumnfamily FAILED");
573 0 : return false;
574 : }
575 : }
576 0 : dbif_->Db_SetInitDone(true);
577 0 : DB_LOG(DEBUG, "Setup Done");
578 0 : return true;
579 : }
580 :
581 19 : bool DbHandler::IsAllWritesDisabled() const {
582 19 : return disable_all_writes_;
583 : }
584 :
585 0 : bool DbHandler::IsStatisticsWritesDisabled() const {
586 0 : return disable_statistics_writes_;
587 : }
588 :
589 2 : bool DbHandler::IsMessagesWritesDisabled() const {
590 2 : return disable_messages_writes_;
591 : }
592 :
593 0 : void DbHandler::DisableAllWrites(bool disable) {
594 0 : disable_all_writes_ = disable;
595 0 : }
596 :
597 0 : void DbHandler::DisableStatisticsWrites(bool disable) {
598 0 : disable_statistics_writes_ = disable;
599 0 : }
600 :
601 0 : void DbHandler::DisableMessagesWrites(bool disable) {
602 0 : disable_messages_writes_ = disable;
603 0 : }
604 :
605 0 : void DbHandler::SetDbQueueWaterMarkInfo(Sandesh::QueueWaterMarkInfo &wm,
606 : boost::function<void (void)> defer_undefer_cb) {
607 0 : dbif_->Db_SetQueueWaterMark(boost::get<2>(wm),
608 0 : boost::get<0>(wm),
609 0 : boost::bind(&DbHandler::SetDropLevel, this, _1, boost::get<1>(wm),
610 : defer_undefer_cb));
611 0 : }
612 :
613 0 : void DbHandler::ResetDbQueueWaterMarkInfo() {
614 0 : dbif_->Db_ResetQueueWaterMarks();
615 0 : }
616 :
617 0 : void DbHandler::GetSandeshStats(std::string *drop_level,
618 : std::vector<SandeshStats> *vdropmstats) const {
619 0 : *drop_level = Sandesh::LevelToString(drop_level_);
620 0 : if (vdropmstats) {
621 0 : std::scoped_lock lock(smutex_);
622 0 : dropped_msg_stats_.Get(vdropmstats);
623 0 : }
624 0 : }
625 :
626 0 : bool DbHandler::GetStats(uint64_t *queue_count, uint64_t *enqueues) const {
627 0 : return dbif_->Db_GetQueueStats(queue_count, enqueues);
628 : }
629 :
630 0 : bool DbHandler::GetStats(std::vector<GenDb::DbTableInfo> *vdbti,
631 : GenDb::DbErrors *dbe, std::vector<GenDb::DbTableInfo> *vstats_dbti) {
632 : {
633 0 : std::scoped_lock lock(smutex_);
634 0 : stable_stats_.GetDiffs(vstats_dbti);
635 0 : }
636 0 : return dbif_->Db_GetStats(vdbti, dbe);
637 : }
638 :
639 0 : bool DbHandler::GetCumulativeStats(std::vector<GenDb::DbTableInfo> *vdbti,
640 : GenDb::DbErrors *dbe, std::vector<GenDb::DbTableInfo> *vstats_dbti) const {
641 : {
642 0 : std::scoped_lock lock(smutex_);
643 0 : stable_stats_.GetCumulative(vstats_dbti);
644 0 : }
645 0 : return dbif_->Db_GetCumulativeStats(vdbti, dbe);
646 : }
647 :
648 0 : bool DbHandler::GetCqlMetrics(cass::cql::Metrics *metrics) const {
649 0 : cass::cql::CqlIf *cql_if(dynamic_cast<cass::cql::CqlIf *>(dbif_.get()));
650 0 : if (cql_if == NULL) {
651 0 : return false;
652 : }
653 0 : return cql_if->Db_GetCqlMetrics(metrics);
654 : }
655 :
656 0 : bool DbHandler::GetCqlStats(cass::cql::DbStats *stats) const {
657 0 : cass::cql::CqlIf *cql_if(dynamic_cast<cass::cql::CqlIf *>(dbif_.get()));
658 0 : if (cql_if == NULL) {
659 0 : return false;
660 : }
661 0 : return cql_if->Db_GetCqlStats(stats);
662 : }
663 :
664 17 : bool DbHandler::InsertIntoDb(std::auto_ptr<GenDb::ColList> col_list,
665 : GenDb::DbConsistency::type dconsistency,
666 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
667 17 : if (IsAllWritesDisabled()) {
668 0 : return true;
669 : }
670 17 : return dbif_->Db_AddColumn(col_list, dconsistency, db_cb);
671 : }
672 :
673 1 : bool DbHandler::AllowMessageTableInsert(const SandeshHeader &header) {
674 3 : return !IsMessagesWritesDisabled() && !IsAllWritesDisabled() &&
675 3 : (header.get_Type() != SandeshType::FLOW) &&
676 2 : (header.get_Type() != SandeshType::SESSION);
677 : }
678 :
679 3 : void DbHandler::MessageTableOnlyInsert(const VizMsg *vmsgp,
680 : const DbHandler::ObjectNamesVec &object_names,
681 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
682 3 : const SandeshHeader &header(vmsgp->msg->GetHeader());
683 3 : const std::string &message_type(vmsgp->msg->GetMessageType());
684 : uint64_t timestamp;
685 : int ttl;
686 3 : if (message_type == "VncApiConfigLog") {
687 1 : ttl = GetTtl(TtlType::CONFIGAUDIT_TTL);
688 : } else {
689 2 : ttl = GetTtl(TtlType::GLOBAL_TTL);
690 : }
691 3 : std::auto_ptr<GenDb::ColList> col_list(new GenDb::ColList);
692 3 : col_list->cfname_ = g_viz_constants.COLLECTOR_GLOBAL_TABLE;
693 3 : timestamp = header.get_Timestamp();
694 3 : uint32_t T2(timestamp >> g_viz_constants.RowTimeInBits);
695 3 : uint32_t T1(timestamp & g_viz_constants.RowTimeInMask);
696 :
697 : // Rowkey
698 3 : GenDb::DbDataValueVec& rowkey = col_list->rowkey_;
699 3 : rowkey.reserve(2);
700 3 : rowkey.push_back(T2);
701 3 : rowkey.push_back(gen_partition_no_());
702 :
703 : // Columns
704 3 : GenDb::DbDataValueVec *col_name(new GenDb::DbDataValueVec());
705 3 : col_name->reserve(20);
706 3 : col_name->push_back(T1);
707 3 : col_name->push_back(vmsgp->unm);
708 :
709 : // Prepend T2: to secondary index columns
710 3 : col_name->push_back(PrependT2(T2, header.get_Source()));
711 3 : col_name->push_back(PrependT2(T2, message_type));
712 3 : col_name->push_back(PrependT2(T2, header.get_Module()));
713 :
714 : // if number of entries in object_names > MSG_TABLE_MAX_OBJECTS_PER_MSG
715 : // - print error
716 : // - increment counter + export on introspect - TODO
717 : // - let first 6 entries go through
718 3 : unsigned int count = 0;
719 15 : BOOST_FOREACH(const std::string &object_name, object_names) {
720 6 : count++;
721 6 : if (count > g_viz_constants.MSG_TABLE_MAX_OBJECTS_PER_MSG) {
722 0 : DB_LOG(ERROR, "Number of object_names in message > " <<
723 : g_viz_constants.MSG_TABLE_MAX_OBJECTS_PER_MSG <<
724 : ". Ignoring extra object_names");
725 0 : break;
726 : }
727 6 : col_name->push_back(PrependT2(T2, object_name));
728 : }
729 : // Set the value as BLANK for remaining entries if
730 : // object_names.size() < MSG_TABLE_MAX_OBJECTS_PER_MSG
731 3 : for (int i = object_names.size();
732 15 : i < g_viz_constants.MSG_TABLE_MAX_OBJECTS_PER_MSG; i++) {
733 12 : col_name->push_back(GenDb::DbDataValue());
734 : }
735 3 : if (header.__isset.IPAddress) {
736 0 : boost::system::error_code ec;
737 0 : IpAddress ipaddr(IpAddress::from_string(header.get_IPAddress(), ec));
738 0 : if (ec ) {
739 0 : LOG(ERROR, "MessageTable: INVALID IP address:"
740 : << header.get_IPAddress());
741 0 : col_name->push_back(GenDb::DbDataValue());
742 : } else {
743 0 : col_name->push_back(ipaddr);
744 : }
745 : } else {
746 3 : col_name->push_back(GenDb::DbDataValue());
747 : }
748 3 : if (header.__isset.Pid) {
749 0 : col_name->push_back((uint32_t)header.get_Pid());
750 : } else {
751 3 : col_name->push_back(GenDb::DbDataValue());
752 : }
753 3 : col_name->push_back(header.get_Category());
754 3 : col_name->push_back((uint32_t)header.get_Level());
755 3 : col_name->push_back(header.get_NodeType());
756 3 : col_name->push_back(header.get_InstanceId());
757 3 : col_name->push_back((uint32_t)header.get_SequenceNum());
758 3 : col_name->push_back((uint8_t)header.get_Type());
759 : GenDb::DbDataValueVec *col_value(new GenDb::DbDataValueVec(1,
760 3 : vmsgp->msg->ExtractMessage()));
761 3 : GenDb::NewCol *col(new GenDb::NewCol(col_name, col_value, ttl));
762 3 : GenDb::NewColVec& columns = col_list->columns_;
763 3 : columns.reserve(1);
764 3 : columns.push_back(col);
765 3 : if (!InsertIntoDb(col_list, GenDb::DbConsistency::LOCAL_ONE, db_cb)) {
766 0 : DB_LOG(ERROR, "Addition of message: " << message_type <<
767 : ", message UUID: " << vmsgp->unm << " COLUMN FAILED");
768 0 : return;
769 : }
770 3 : }
771 :
772 1 : void DbHandler::MessageTableInsert(const VizMsg *vmsgp,
773 : const DbHandler::ObjectNamesVec &object_names,
774 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
775 1 : const SandeshHeader &header(vmsgp->msg->GetHeader());
776 1 : const std::string &message_type(vmsgp->msg->GetMessageType());
777 :
778 1 : if (!AllowMessageTableInsert(header))
779 0 : return;
780 :
781 1 : MessageTableOnlyInsert(vmsgp, object_names, db_cb);
782 :
783 :
784 1 : const SandeshType::type &stype(header.get_Type());
785 :
786 : /*
787 : * Insert the message types,module_id in the stat table
788 : * Construct the atttributes,attrib_tags beofore inserting
789 : * to the StatTableInsert
790 : */
791 1 : if ((stype == SandeshType::SYSLOG) || (stype == SandeshType::SYSTEM)) {
792 : //Insert only if sandesh type is a SYSTEM LOG or SYSLOG
793 : //Insert into the FieldNames stats table entries for Messagetype and Module ID
794 1 : int ttl = GetTtl(TtlType::GLOBAL_TTL);
795 1 : FieldNamesTableInsert(header.get_Timestamp(),
796 : g_viz_constants.MESSAGE_TABLE,
797 : ":Messagetype", message_type, ttl, db_cb);
798 1 : FieldNamesTableInsert(header.get_Timestamp(),
799 : g_viz_constants.MESSAGE_TABLE,
800 : ":ModuleId", header.get_Module(), ttl, db_cb);
801 1 : FieldNamesTableInsert(header.get_Timestamp(),
802 : g_viz_constants.MESSAGE_TABLE,
803 : ":Source", header.get_Source(), ttl, db_cb);
804 1 : if (!header.get_Category().empty()) {
805 0 : FieldNamesTableInsert(header.get_Timestamp(),
806 : g_viz_constants.MESSAGE_TABLE,
807 : ":Category", header.get_Category(), ttl, db_cb);
808 : }
809 : }
810 : }
811 :
812 : /*
813 : * This function takes field name and field value as arguments and inserts
814 : * into the FieldNames stats table
815 : */
816 11 : void DbHandler::FieldNamesTableInsert(uint64_t timestamp,
817 : const std::string& table_prefix,
818 : const std::string& field_name, const std::string& field_val, int ttl,
819 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
820 : /*
821 : * Insert the message types in the stat table
822 : * Construct the atttributes,attrib_tags before inserting
823 : * to the StatTableInsert
824 : */
825 11 : uint32_t temp_u32 = timestamp >> g_viz_constants.RowTimeInBits;
826 11 : std::string table_name(table_prefix);
827 11 : table_name.append(field_name);
828 :
829 : /* Check if fieldname and value were already seen in this T2;
830 : 2 caches are mainted one for last T2 and T2-1.
831 : We only need to record them if they have NOT been seen yet */
832 11 : bool record = false;
833 11 : std::string fc_entry(table_name);
834 11 : fc_entry.append(":");
835 11 : fc_entry.append(field_val);
836 : {
837 11 : std::scoped_lock lock(fmutex_);
838 11 : record = CanRecordDataForT2(temp_u32, fc_entry);
839 11 : }
840 :
841 11 : if (!record) return;
842 :
843 11 : DbHandler::TagMap tmap;
844 11 : DbHandler::AttribMap amap;
845 11 : DbHandler::Var pv;
846 11 : DbHandler::AttribMap attribs;
847 11 : pv = table_name;
848 11 : tmap.insert(make_pair("name", make_pair(pv, amap)));
849 11 : attribs.insert(make_pair(string("name"), pv));
850 11 : string sattrname("fields.value");
851 11 : pv = string(field_val);
852 11 : attribs.insert(make_pair(sattrname,pv));
853 :
854 : //pv = string(header.get_Source());
855 : // Put the name of the collector, not the message source.
856 : // Using the message source will make queries slower
857 11 : pv = string(col_name_);
858 11 : tmap.insert(make_pair("Source",make_pair(pv,amap)));
859 11 : attribs.insert(make_pair(string("Source"),pv));
860 :
861 11 : StatTableInsertTtl(timestamp, "FieldNames","fields", tmap, attribs, ttl,
862 : db_cb);
863 11 : }
864 :
865 : /*
866 : * This function checks if the data can be recorded or not
867 : * for the given t2. If t2 corresponding to the data is
868 : * older than field_cache_old_t2_ and field_cache_t2_
869 : * it is ignored
870 : */
871 17 : bool DbHandler::CanRecordDataForT2(uint32_t temp_u32, std::string fc_entry) {
872 17 : bool record = false;
873 :
874 17 : uint32_t cacheindex = temp_u32 >> g_viz_constants.CacheTimeInAdditionalBits;
875 17 : if (cacheindex > field_cache_index_) {
876 2 : field_cache_index_ = cacheindex;
877 2 : field_cache_set_.clear();
878 2 : field_cache_set_.insert(fc_entry);
879 2 : record = true;
880 15 : } else if (cacheindex == field_cache_index_) {
881 15 : if (field_cache_set_.find(fc_entry) ==
882 30 : field_cache_set_.end()) {
883 13 : field_cache_set_.insert(fc_entry);
884 13 : record = true;
885 : }
886 : }
887 17 : return record;
888 : }
889 :
890 0 : void DbHandler::GetRuleMap(RuleMap& rulemap) {
891 0 : }
892 :
893 : /*
894 : * insert an entry into an ObjectTrace table
895 : * key is T2
896 : * column is
897 : * name: <key>:T1 (value in timestamp)
898 : * value: uuid (of the corresponding global message)
899 : */
900 1 : void DbHandler::ObjectTableInsert(const std::string &table, const std::string &objectkey_str,
901 : uint64_t ×tamp, const boost::uuids::uuid& unm, const VizMsg *vmsgp,
902 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
903 1 : if (IsMessagesWritesDisabled() || IsAllWritesDisabled()) {
904 0 : return;
905 : }
906 1 : uint32_t T2(timestamp >> g_viz_constants.RowTimeInBits);
907 1 : uint32_t T1(timestamp & g_viz_constants.RowTimeInMask);
908 1 : const std::string &message_type(vmsgp->msg->GetMessageType());
909 : int ttl;
910 1 : if (message_type == "VncApiConfigLog") {
911 0 : ttl = GetTtl(TtlType::CONFIGAUDIT_TTL);
912 : } else {
913 1 : ttl = GetTtl(TtlType::GLOBAL_TTL);
914 : }
915 :
916 : {
917 1 : std::auto_ptr<GenDb::ColList> col_list(new GenDb::ColList);
918 1 : col_list->cfname_ = g_viz_constants.OBJECT_VALUE_TABLE;
919 1 : GenDb::DbDataValueVec& rowkey = col_list->rowkey_;
920 1 : rowkey.reserve(2);
921 1 : rowkey.push_back(T2);
922 1 : rowkey.push_back(table);
923 1 : GenDb::DbDataValueVec *col_name(new GenDb::DbDataValueVec(1, T1));
924 1 : GenDb::DbDataValueVec *col_value(new GenDb::DbDataValueVec(1, objectkey_str));
925 1 : GenDb::NewCol *col(new GenDb::NewCol(col_name, col_value, ttl));
926 1 : GenDb::NewColVec& columns = col_list->columns_;
927 1 : columns.reserve(1);
928 1 : columns.push_back(col);
929 1 : if (!InsertIntoDb(col_list, GenDb::DbConsistency::LOCAL_ONE, db_cb)) {
930 0 : DB_LOG(ERROR, "Addition of " << objectkey_str <<
931 : ", message UUID " << unm << " " << table << " into table "
932 : << g_viz_constants.OBJECT_VALUE_TABLE << " FAILED");
933 0 : return;
934 : }
935 :
936 : /*
937 : * Inserting into the stat table
938 : */
939 1 : const SandeshHeader &header(vmsgp->msg->GetHeader());
940 1 : const std::string &message_type(vmsgp->msg->GetMessageType());
941 : //Insert into the FieldNames stats table entries for Messagetype and Module ID
942 1 : FieldNamesTableInsert(timestamp,
943 : table, ":ObjectId", objectkey_str, ttl, db_cb);
944 1 : FieldNamesTableInsert(timestamp,
945 : table, ":Messagetype", message_type, ttl, db_cb);
946 1 : FieldNamesTableInsert(timestamp,
947 : table, ":ModuleId", header.get_Module(), ttl, db_cb);
948 1 : FieldNamesTableInsert(timestamp,
949 : table, ":Source", header.get_Source(), ttl, db_cb);
950 :
951 1 : FieldNamesTableInsert(timestamp,
952 : "OBJECT:", table, table, ttl, db_cb);
953 1 : }
954 : }
955 :
956 11 : bool DbHandler::StatTableWrite(uint32_t t2, const std::string& statName,
957 : const std::string& statAttr, const std::string& source, const std::string& name,
958 : const std::string& key, const std::string& proxy,
959 : const std::vector<std::vector<std::string> >& tags,
960 : uint32_t t1, const boost::uuids::uuid& unm,
961 : const std::string& jsonline, int ttl,
962 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
963 :
964 11 : uint8_t part = 0;
965 11 : std::auto_ptr<GenDb::ColList> col_list(new GenDb::ColList);
966 11 : col_list->cfname_ = g_viz_constants.STATS_TABLE;
967 :
968 11 : GenDb::DbDataValueVec& rowkey = col_list->rowkey_;
969 11 : rowkey.reserve(4);
970 11 : rowkey.push_back(t2);
971 11 : rowkey.push_back(part);
972 11 : rowkey.push_back(statName);
973 11 : rowkey.push_back(statAttr);
974 :
975 11 : GenDb::DbDataValueVec *col_name(new GenDb::DbDataValueVec);
976 11 : col_name->reserve(6);
977 11 : col_name->push_back(name);
978 11 : col_name->push_back(t1);
979 11 : col_name->push_back(unm);
980 11 : col_name->push_back(PrependT2(t2, source));
981 11 : col_name->push_back(PrependT2(t2, key));
982 11 : col_name->push_back(PrependT2(t2, proxy));
983 11 : col_name->push_back(PrependT2(t2, boost::algorithm::join(tags[0], ";")));
984 11 : col_name->push_back(PrependT2(t2, boost::algorithm::join(tags[1], ";")));
985 11 : col_name->push_back(PrependT2(t2, boost::algorithm::join(tags[2], ";")));
986 11 : col_name->push_back(PrependT2(t2, boost::algorithm::join(tags[3], ";")));
987 :
988 11 : GenDb::DbDataValueVec *col_value(new GenDb::DbDataValueVec(1, jsonline));
989 11 : GenDb::NewCol *col(new GenDb::NewCol(col_name, col_value, ttl));
990 11 : GenDb::NewColVec& columns = col_list->columns_;
991 11 : columns.push_back(col);
992 :
993 11 : if (!InsertIntoDb(col_list, GenDb::DbConsistency::LOCAL_ONE, db_cb)) {
994 0 : DB_LOG(ERROR, "Addition of " << statName <<
995 : ", " << statAttr << " into table " <<
996 : g_viz_constants.STATS_TABLE <<" FAILED");
997 0 : std::scoped_lock lock(smutex_);
998 0 : stable_stats_.Update(statName + ":" + statAttr, true, true, false, 1);
999 0 : return false;
1000 0 : } else {
1001 11 : std::scoped_lock lock(smutex_);
1002 11 : stable_stats_.Update(statName + ":" + statAttr, true, false, false, 1);
1003 11 : return true;
1004 11 : }
1005 11 : }
1006 :
1007 : void
1008 0 : DbHandler::StatTableInsert(uint64_t ts,
1009 : const std::string& statName,
1010 : const std::string& statAttr,
1011 : const TagMap & attribs_tag,
1012 : const AttribMap & attribs,
1013 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
1014 0 : if (IsAllWritesDisabled() || IsStatisticsWritesDisabled()) {
1015 0 : return;
1016 : }
1017 0 : int ttl = GetTtl(TtlType::STATSDATA_TTL);
1018 0 : StatTableInsertTtl(ts, statName, statAttr, attribs_tag, attribs, ttl,
1019 : db_cb);
1020 : }
1021 :
1022 0 : static inline unsigned int djb_hash (const char *str, size_t len) {
1023 0 : unsigned int hash = 5381;
1024 0 : for (size_t i = 0 ; i < len ; i++)
1025 0 : hash = ((hash << 5) + hash) + str[i];
1026 0 : return hash;
1027 : }
1028 :
1029 : typedef std::pair<std::string, std::string> MapElem;
1030 :
1031 : // This function writes Stats samples to the DB.
1032 : void
1033 11 : DbHandler::StatTableInsertTtl(uint64_t ts,
1034 : const std::string& statName,
1035 : const std::string& statAttr,
1036 : const TagMap & attribs_tag,
1037 : const AttribMap & attribs, int ttl,
1038 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
1039 :
1040 11 : uint64_t temp_u64 = ts;
1041 11 : uint32_t temp_u32 = temp_u64 >> g_viz_constants.RowTimeInBits;
1042 : boost::uuids::uuid unm;
1043 11 : if (statName.compare("FieldNames") != 0) {
1044 0 : unm = umn_gen_();
1045 : }
1046 :
1047 : // This is very primitive JSON encoding.
1048 : // Should replace with rapidJson at some point.
1049 :
1050 : // Encoding of all attribs
1051 :
1052 11 : contrail_rapidjson::Document dd;
1053 11 : dd.SetObject();
1054 :
1055 11 : AttribMap attribs_buf;
1056 11 : for (AttribMap::const_iterator it = attribs.begin();
1057 44 : it != attribs.end(); it++) {
1058 33 : switch (it->second.type) {
1059 33 : case STRING: {
1060 33 : contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
1061 66 : std::string nm = it->first + std::string("|s");
1062 : pair<AttribMap::iterator,bool> rt =
1063 33 : attribs_buf.insert(make_pair(nm, it->second));
1064 33 : val.SetString(it->second.str.c_str(), dd.GetAllocator());
1065 33 : contrail_rapidjson::Value vk;
1066 33 : dd.AddMember(vk.SetString(rt.first->first.c_str(),
1067 : dd.GetAllocator()), val, dd.GetAllocator());
1068 33 : string field_name = it->first;
1069 33 : if (field_name.compare("fields.value") == 0) {
1070 11 : if (statName.compare("FieldNames") == 0) {
1071 : //Make uuid a fn of the field.values
1072 11 : boost::uuids::name_generator gen(DbHandler::seed_uuid);
1073 11 : unm = gen(it->second.str.c_str());
1074 : }
1075 : }
1076 33 : }
1077 33 : break;
1078 0 : case UINT64: {
1079 0 : contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
1080 0 : std::string nm = it->first + std::string("|n");
1081 : pair<AttribMap::iterator,bool> rt =
1082 0 : attribs_buf.insert(make_pair(nm, it->second));
1083 0 : val.SetUint64(it->second.num);
1084 0 : contrail_rapidjson::Value vk;
1085 0 : dd.AddMember(vk.SetString(rt.first->first.c_str(),
1086 : dd.GetAllocator()), val, dd.GetAllocator());
1087 0 : }
1088 0 : break;
1089 0 : case DOUBLE: {
1090 0 : contrail_rapidjson::Value val(contrail_rapidjson::kNumberType);
1091 0 : std::string nm = it->first + std::string("|d");
1092 : pair<AttribMap::iterator,bool> rt =
1093 0 : attribs_buf.insert(make_pair(nm, it->second));
1094 0 : val.SetDouble(it->second.dbl);
1095 0 : contrail_rapidjson::Value vk;
1096 0 : dd.AddMember(vk.SetString(rt.first->first.c_str(),
1097 : dd.GetAllocator()), val, dd.GetAllocator());
1098 0 : }
1099 0 : break;
1100 0 : case LIST: {
1101 0 : contrail_rapidjson::Value val_array(contrail_rapidjson::kArrayType);
1102 0 : std::string nm = it->first + std::string("|a");
1103 0 : BOOST_FOREACH(const std::string& elem, it->second.vec) {
1104 0 : contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
1105 0 : val.SetString(elem.c_str(), dd.GetAllocator());
1106 0 : val_array.PushBack(val, dd.GetAllocator());
1107 0 : }
1108 : pair<AttribMap::iterator,bool> rt =
1109 0 : attribs_buf.insert(make_pair(nm, it->second));
1110 0 : contrail_rapidjson::Value vk;
1111 0 : dd.AddMember(vk.SetString(rt.first->first.c_str(),
1112 : dd.GetAllocator()), val_array, dd.GetAllocator());
1113 :
1114 0 : }
1115 0 : break;
1116 0 : case MAP: {
1117 0 : contrail_rapidjson::Value val_obj(contrail_rapidjson::kObjectType);
1118 0 : std::string nm = it->first + std::string("|m");
1119 0 : BOOST_FOREACH(const MapElem& pair, it->second.map) {
1120 0 : contrail_rapidjson::Value val(contrail_rapidjson::kStringType);
1121 0 : val.SetString(pair.second.c_str(), dd.GetAllocator());
1122 0 : contrail_rapidjson::Value val_key;
1123 0 : val_obj.AddMember(val_key.SetString(pair.first.c_str(),
1124 : dd.GetAllocator()), val, dd.GetAllocator());
1125 0 : }
1126 : pair<AttribMap::iterator,bool> rt =
1127 0 : attribs_buf.insert(make_pair(nm, it->second));
1128 0 : contrail_rapidjson::Value vk;
1129 0 : dd.AddMember(vk.SetString(rt.first->first.c_str(),
1130 : dd.GetAllocator()), val_obj, dd.GetAllocator());
1131 :
1132 0 : }
1133 0 : break;
1134 0 : default:
1135 0 : continue;
1136 0 : }
1137 : }
1138 :
1139 22 : contrail_rapidjson::StringBuffer sb;
1140 22 : contrail_rapidjson::Writer<contrail_rapidjson::StringBuffer> writer(sb);
1141 11 : dd.Accept(writer);
1142 22 : string jsonline(sb.GetString());
1143 :
1144 : uint32_t t1;
1145 11 : t1 = (uint32_t)(temp_u64& g_viz_constants.RowTimeInMask);
1146 :
1147 11 : if ( statName.compare("FieldNames") != 0) {
1148 0 : std::string tablename(std::string("StatTable.") + statName + "." + statAttr);
1149 0 : FieldNamesTableInsert(ts,
1150 : "STAT:", tablename, tablename, ttl, db_cb);
1151 0 : }
1152 :
1153 22 : std::vector<std::vector<std::string> > tags(4);
1154 22 : std::string name, source, key, proxy;
1155 11 : for (TagMap::const_iterator it = attribs_tag.begin();
1156 33 : it != attribs_tag.end(); it++) {
1157 :
1158 22 : pair<string,DbHandler::Var> ptag;
1159 22 : ptag.first = it->first;
1160 22 : ptag.second = it->second.first;
1161 :
1162 : /* Record in the fieldNames table if we have a string tag,
1163 : and if we are not recording a fieldNames stats entry itself */
1164 44 : if ((ptag.second.type == DbHandler::STRING) &&
1165 22 : (statName.compare("FieldNames") != 0)) {
1166 0 : FieldNamesTableInsert(ts, std::string("StatTable.") +
1167 0 : statName + "." + statAttr,
1168 0 : std::string(":") + ptag.first, ptag.second.str, ttl,
1169 : db_cb);
1170 : }
1171 :
1172 22 : if (ptag.first == g_viz_constants.STATS_NAME_FIELD) {
1173 11 : name = ptag.second.str;
1174 11 : } else if (ptag.first == g_viz_constants.STATS_SOURCE_FIELD) {
1175 11 : source = ptag.second.str;
1176 0 : } else if (boost::algorithm::ends_with(ptag.first, g_viz_constants.STATS_KEY_FIELD)) {
1177 0 : key = ptag.second.str;
1178 0 : } else if (boost::algorithm::ends_with(ptag.first, g_viz_constants.STATS_PROXY_FIELD)) {
1179 0 : proxy = ptag.second.str;
1180 : } else {
1181 0 : switch (ptag.second.type) {
1182 0 : case STRING:
1183 : case UINT64:
1184 : case DOUBLE: {
1185 0 : std::ostringstream tag_oss;
1186 0 : tag_oss << ptag.first << "=" << ptag.second;
1187 0 : size_t idx = djb_hash(ptag.first.c_str(), ptag.first.length())
1188 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1189 0 : tags[idx].push_back(tag_oss.str());
1190 0 : }
1191 0 : break;
1192 0 : case LIST: {
1193 0 : BOOST_FOREACH(const std::string& elem, ptag.second.vec) {
1194 0 : std::ostringstream tag_oss;
1195 0 : tag_oss << ptag.first << "=" << elem;
1196 0 : size_t idx = djb_hash(ptag.first.c_str(), ptag.first.length())
1197 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1198 0 : tags[idx].push_back(tag_oss.str());
1199 0 : }
1200 : }
1201 0 : break;
1202 0 : case MAP: {
1203 0 : BOOST_FOREACH(const MapElem& pair, ptag.second.map) {
1204 0 : std::ostringstream tag_oss;
1205 0 : std::string nm = ptag.first + "." + pair.first;
1206 0 : tag_oss << nm << "=" << pair.second;
1207 0 : size_t idx = djb_hash(nm.c_str(), nm.length())
1208 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1209 0 : tags[idx].push_back(tag_oss.str());
1210 0 : }
1211 : }
1212 0 : break;
1213 0 : default: {
1214 0 : continue;
1215 : }
1216 0 : }
1217 : }
1218 :
1219 22 : if (!it->second.second.empty()) {
1220 0 : for (AttribMap::const_iterator jt = it->second.second.begin();
1221 0 : jt != it->second.second.end(); jt++) {
1222 0 : if (jt->first == g_viz_constants.STATS_NAME_FIELD) {
1223 0 : name = jt->second.str;
1224 0 : } else if (jt->first == g_viz_constants.STATS_SOURCE_FIELD) {
1225 0 : source = jt->second.str;
1226 0 : } else if (boost::algorithm::ends_with(jt->first, g_viz_constants.STATS_KEY_FIELD)) {
1227 0 : key = jt->second.str;
1228 0 : } else if (boost::algorithm::ends_with(jt->first, g_viz_constants.STATS_PROXY_FIELD)) {
1229 0 : proxy = jt->second.str;
1230 : } else {
1231 0 : std::ostringstream tag_oss;
1232 0 : tag_oss << jt->first << "=" << jt->second;
1233 0 : size_t idx = djb_hash(jt->first.c_str(), jt->first.length())
1234 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1235 0 : tags[idx].push_back(tag_oss.str());
1236 0 : switch (jt->second.type) {
1237 0 : case STRING:
1238 : case UINT64:
1239 : case DOUBLE: {
1240 0 : std::ostringstream tag_oss;
1241 0 : tag_oss << jt->first << "=" << jt->second;
1242 0 : size_t idx = djb_hash(jt->first.c_str(), jt->first.length())
1243 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1244 0 : tags[idx].push_back(tag_oss.str());
1245 0 : }
1246 0 : break;
1247 0 : case LIST: {
1248 0 : BOOST_FOREACH(const std::string& elem, jt->second.vec) {
1249 0 : std::ostringstream tag_oss;
1250 0 : tag_oss << jt->first << "=" << elem;
1251 0 : size_t idx = djb_hash(jt->first.c_str(), jt->first.length())
1252 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1253 0 : tags[idx].push_back(tag_oss.str());
1254 0 : }
1255 : }
1256 0 : break;
1257 0 : case MAP: {
1258 0 : BOOST_FOREACH(const MapElem& pair, jt->second.map) {
1259 0 : std::ostringstream tag_oss;
1260 0 : std::string nm = jt->first + "." + pair.first;
1261 0 : tag_oss << nm << "=" << pair.second;
1262 0 : size_t idx = djb_hash(nm.c_str(), nm.length())
1263 0 : % g_viz_constants.NUM_STATS_TAGS_FIELD;
1264 0 : tags[idx].push_back(tag_oss.str());
1265 0 : }
1266 : }
1267 0 : break;
1268 0 : default: {
1269 0 : continue;
1270 : }
1271 0 : }
1272 0 : }
1273 : }
1274 : }
1275 22 : }
1276 11 : StatTableWrite(temp_u32, statName, statAttr, source, name, key, proxy, tags, t1,
1277 : unm, jsonline, ttl, db_cb);
1278 11 : }
1279 :
1280 : boost::uuids::uuid DbHandler::seed_uuid = StringToUuid(std::string("ffffffff-ffff-ffff-ffff-ffffffffffff"));
1281 :
1282 : SessionValueArray default_col_values = boost::assign::list_of
1283 : (GenDb::DbDataValue((uint32_t)0))
1284 : (GenDb::DbDataValue((uint8_t)0))
1285 : (GenDb::DbDataValue((uint8_t)0))
1286 : (GenDb::DbDataValue((uint8_t)0))
1287 : (GenDb::DbDataValue((uint16_t)0))
1288 : (GenDb::DbDataValue((uint16_t)0))
1289 : (GenDb::DbDataValue((uint32_t)0))
1290 : (GenDb::DbDataValue(boost::uuids::nil_uuid()))
1291 : (GenDb::DbDataValue("__UNKNOWN__"))
1292 : (GenDb::DbDataValue("__UNKNOWN__"))
1293 : (GenDb::DbDataValue("__UNKNOWN__"))
1294 : (GenDb::DbDataValue("__UNKNOWN__"))
1295 : (GenDb::DbDataValue("__UNKNOWN__"))
1296 : (GenDb::DbDataValue("__UNKNOWN__"))
1297 : (GenDb::DbDataValue("__UNKNOWN__"))
1298 : (GenDb::DbDataValue("__UNKNOWN__"))
1299 : (GenDb::DbDataValue("__UNKNOWN__"))
1300 : (GenDb::DbDataValue("__UNKNOWN__"))
1301 : (GenDb::DbDataValue("__UNKNOWN__"))
1302 : (GenDb::DbDataValue("__UNKNOWN__"))
1303 : (GenDb::DbDataValue("__UNKNOWN__"))
1304 : (GenDb::DbDataValue("__UNKNOWN__"))
1305 : (GenDb::DbDataValue("__UNKNOWN__"))
1306 : (GenDb::DbDataValue("__UNKNOWN__"))
1307 : (GenDb::DbDataValue("__UNKNOWN__"))
1308 : (GenDb::DbDataValue("__UNKNOWN__"))
1309 : (GenDb::DbDataValue(""))
1310 : (GenDb::DbDataValue(IpAddress()))
1311 : (GenDb::DbDataValue((uint64_t)0))
1312 : (GenDb::DbDataValue((uint64_t)0))
1313 : (GenDb::DbDataValue((uint64_t)0))
1314 : (GenDb::DbDataValue((uint64_t)0))
1315 : (GenDb::DbDataValue((uint64_t)0))
1316 : (GenDb::DbDataValue((uint64_t)0))
1317 : (GenDb::DbDataValue((uint64_t)0))
1318 : (GenDb::DbDataValue((uint64_t)0))
1319 : (GenDb::DbDataValue(""));
1320 :
1321 2 : static bool PopulateSessionTable(uint32_t t2, SessionValueArray& svalues,
1322 : DbInsertCb db_insert_cb, TtlMap& ttl_map) {
1323 :
1324 2 : std::auto_ptr<GenDb::ColList> colList(new GenDb::ColList);
1325 : // RowKey
1326 2 : colList->rowkey_.reserve(3);
1327 2 : colList->rowkey_.push_back(svalues[SessionRecordFields::SESSION_T2]);
1328 2 : colList->rowkey_.push_back(svalues[SessionRecordFields::SESSION_PARTITION_NO]);
1329 2 : colList->rowkey_.push_back(svalues[SessionRecordFields::SESSION_IS_SI]);
1330 4 : colList->rowkey_.push_back(svalues[
1331 2 : SessionRecordFields::SESSION_IS_CLIENT_SESSION]);
1332 :
1333 : // Column Names
1334 2 : GenDb::DbDataValueVec* cnames(new GenDb::DbDataValueVec);
1335 66 : for (int sfield = g_viz_constants.SESSION_MIN;
1336 66 : sfield != g_viz_constants.SESSION_MAX - 1; sfield++) {
1337 64 : if (svalues[sfield].which() == GenDb::DB_VALUE_BLANK) {
1338 18 : if (sfield >= g_viz_constants.SESSION_INDEX_MIN &&
1339 18 : sfield <= g_viz_constants.SESSION_INDEX_MAX) {
1340 10 : cnames->push_back(integerToString(t2) + ":" + g_viz_constants.UNKNOWN);
1341 : } else {
1342 8 : cnames->push_back(default_col_values[sfield]);
1343 : }
1344 : }
1345 : else {
1346 46 : cnames->push_back(svalues[sfield]);
1347 : }
1348 : }
1349 :
1350 : // Column Values
1351 2 : GenDb::DbDataValueVec* cvalue(new GenDb::DbDataValueVec);
1352 2 : cvalue->reserve(1);
1353 2 : cvalue->push_back(svalues[SessionRecordFields::SESSION_MAP]);
1354 :
1355 2 : int ttl = DbHandler::GetTtlFromMap(ttl_map, TtlType::FLOWDATA_TTL);
1356 :
1357 2 : colList->cfname_ = g_viz_constants.SESSION_TABLE;
1358 2 : colList->columns_.push_back(new GenDb::NewCol(cnames, cvalue, ttl));
1359 2 : if (!db_insert_cb(colList)) {
1360 0 : LOG(ERROR, "Populating SessionTable FAILED");
1361 : }
1362 :
1363 2 : return true;
1364 2 : }
1365 :
1366 2 : void JsonifySessionMap(const pugi::xml_node& root, std::string *json_string) {
1367 :
1368 2 : contrail_rapidjson::Document session_map;
1369 2 : session_map.SetObject();
1370 : contrail_rapidjson::Document::AllocatorType& allocator =
1371 2 : session_map.GetAllocator();
1372 :
1373 5 : for (pugi::xml_node ip_port = root.first_child(); ip_port; ip_port =
1374 3 : ip_port.next_sibling().next_sibling()) {
1375 3 : std::ostringstream ip_port_ss;
1376 3 : ip_port_ss << ip_port.child(g_flow_constants.PORT.c_str()).child_value() << ":"
1377 3 : << ip_port.child(g_flow_constants.IP.c_str()).child_value();
1378 3 : contrail_rapidjson::Value session_val(contrail_rapidjson::kObjectType);
1379 3 : pugi::xml_node session(ip_port.next_sibling());
1380 9 : for (pugi::xml_node field = session.first_child(); field;
1381 6 : field = field.next_sibling()) {
1382 6 : contrail_rapidjson::Value fk(contrail_rapidjson::kStringType);
1383 6 : std::string fname(field.name());
1384 : uint64_t val;
1385 6 : if (fname == "forward_flow_info" || fname == "reverse_flow_info") {
1386 6 : contrail_rapidjson::Value flow_info(contrail_rapidjson::kObjectType);
1387 6 : for (pugi::xml_node finfo = field.child("SessionFlowInfo").first_child();
1388 18 : finfo; finfo = finfo.next_sibling()) {
1389 12 : std::string name(finfo.name());
1390 12 : std::string value(finfo.child_value());
1391 : std::map<std::string, bool>::const_iterator it =
1392 12 : g_flow_constants.SessionFlowInfoField2Type.find(name);
1393 12 : assert(it != g_flow_constants.SessionFlowInfoField2Type.end());
1394 12 : if (it->second) {
1395 12 : stringToInteger(value, val);
1396 12 : contrail_rapidjson::Value fv(contrail_rapidjson::kNumberType);
1397 12 : flow_info.AddMember(fk.SetString(name.c_str(), allocator),
1398 : fv.SetUint64(val), allocator);
1399 12 : } else {
1400 0 : contrail_rapidjson::Value fv(contrail_rapidjson::kStringType);
1401 0 : flow_info.AddMember(fk.SetString(name.c_str(), allocator),
1402 : fv.SetString(value.c_str(), allocator), allocator);
1403 0 : }
1404 12 : }
1405 6 : session_val.AddMember(fk.SetString(fname.c_str(), allocator),
1406 : flow_info, allocator);
1407 6 : } else {
1408 0 : std::string fvalue(field.child_value());
1409 0 : if (stringToInteger(fvalue, val)) {
1410 0 : contrail_rapidjson::Value fv(contrail_rapidjson::kNumberType);
1411 0 : session_val.AddMember(fk.SetString(fname.c_str(), allocator),
1412 : fv.SetUint64(val), allocator);
1413 0 : } else {
1414 0 : contrail_rapidjson::Value fv(contrail_rapidjson::kStringType);
1415 0 : session_val.AddMember(fk.SetString(fname.c_str(), allocator),
1416 : fv.SetString(fvalue.c_str(), allocator), allocator);
1417 0 : }
1418 0 : }
1419 6 : }
1420 3 : contrail_rapidjson::Value vk(contrail_rapidjson::kStringType);
1421 3 : session_map.AddMember(vk.SetString(ip_port_ss.str().c_str(),
1422 : allocator), session_val, allocator);
1423 3 : }
1424 :
1425 2 : contrail_rapidjson::StringBuffer sb;
1426 2 : contrail_rapidjson::Writer<contrail_rapidjson::StringBuffer> writer(sb);
1427 2 : session_map.Accept(writer);
1428 2 : *json_string = sb.GetString();
1429 2 : }
1430 :
1431 : /*
1432 : * process the session sample and insert into the appropriate table
1433 : */
1434 1 : bool DbHandler::SessionSampleAdd(const pugi::xml_node& session_sample,
1435 : const SandeshHeader& header,
1436 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
1437 1 : SessionValueArray session_entry_values;
1438 1 : pugi::xml_node &mnode = const_cast<pugi::xml_node &>(session_sample);
1439 :
1440 : // Set T1 and T2 from timestamp
1441 1 : uint64_t timestamp(header.get_Timestamp());
1442 1 : uint32_t T2(timestamp >> g_viz_constants.RowTimeInBits);
1443 1 : uint32_t T1(timestamp & g_viz_constants.RowTimeInMask);
1444 1 : session_entry_values[SessionRecordFields::SESSION_T2] = T2;
1445 1 : session_entry_values[SessionRecordFields::SESSION_T1] = T1;
1446 : // vrouter
1447 1 : session_entry_values[SessionRecordFields::SESSION_VROUTER] = header.get_Source();
1448 :
1449 1 : pugi::xml_node session_agg_info_node;
1450 : // Populate session_entry_values from message
1451 17 : for (pugi::xml_node sfield = mnode.first_child(); sfield;
1452 16 : sfield = sfield.next_sibling()) {
1453 :
1454 16 : std::string col_type(sfield.attribute("type").value());
1455 16 : std::string col_name(sfield.name());
1456 16 : SessionTypeMap::const_iterator it = session_msg2type_map.find(col_name);
1457 16 : if (it != session_msg2type_map.end()) {
1458 15 : const SessionTypeInfo &stinfo(it->second);
1459 :
1460 15 : if (col_type == "set") {
1461 1 : pugi::xml_node set = sfield.child("set");
1462 1 : std::ostringstream set_value;
1463 1 : set_value << T2 << ":";
1464 1 : int i = 0;
1465 4 : for (pugi::xml_node set_elem = set.first_child(); set_elem;
1466 3 : set_elem = set_elem.next_sibling()) {
1467 3 : if (i) {
1468 2 : set_value << ";";
1469 : }
1470 3 : std::string val = set_elem.child_value();
1471 3 : TXMLProtocol::unescapeXMLControlChars(val);
1472 3 : set_value << val;
1473 3 : i++;
1474 3 : }
1475 1 : session_entry_values[stinfo.get<0>()] = set_value.str();
1476 1 : continue;
1477 1 : }
1478 :
1479 14 : switch(stinfo.get<1>()) {
1480 2 : case GenDb::DbDataType::Unsigned8Type:
1481 : {
1482 : uint8_t val;
1483 2 : stringToInteger(sfield.child_value(), val);
1484 2 : session_entry_values[stinfo.get<0>()] =
1485 4 : static_cast<uint8_t>(val);
1486 2 : break;
1487 : }
1488 0 : case GenDb::DbDataType::Unsigned16Type:
1489 : {
1490 : uint16_t val;
1491 0 : stringToInteger(sfield.child_value(), val);
1492 0 : session_entry_values[stinfo.get<0>()] =
1493 0 : static_cast<uint16_t>(val);
1494 0 : break;
1495 : }
1496 0 : case GenDb::DbDataType::Unsigned32Type:
1497 : {
1498 : uint32_t val;
1499 0 : stringToInteger(sfield.child_value(), val);
1500 0 : session_entry_values[stinfo.get<0>()] =
1501 0 : static_cast<uint32_t>(val);
1502 0 : break;
1503 : }
1504 0 : case GenDb::DbDataType::Unsigned64Type:
1505 : {
1506 : uint64_t val;
1507 0 : stringToInteger(sfield.child_value(), val);
1508 0 : session_entry_values[stinfo.get<0>()] =
1509 0 : static_cast<uint64_t>(val);
1510 0 : break;
1511 : }
1512 0 : case GenDb::DbDataType::LexicalUUIDType:
1513 : case GenDb::DbDataType::TimeUUIDType:
1514 : {
1515 0 : std::stringstream ss;
1516 0 : ss << sfield.child_value();
1517 : boost::uuids::uuid u;
1518 0 : if (!ss.str().empty()) {
1519 0 : ss >> u;
1520 0 : if (ss.fail()) {
1521 0 : LOG(ERROR, "SessionTable: " << col_name << ": (" <<
1522 : sfield.child_value() << ") INVALID");
1523 : }
1524 : }
1525 0 : session_entry_values[stinfo.get<0>()] = u;
1526 0 : break;
1527 0 : }
1528 11 : case GenDb::DbDataType::AsciiType:
1529 : case GenDb::DbDataType::UTF8Type:
1530 : {
1531 11 : std::string val = sfield.child_value();
1532 11 : TXMLProtocol::unescapeXMLControlChars(val);
1533 11 : switch(stinfo.get<0>()) {
1534 11 : case SessionRecordFields::SESSION_DEPLOYMENT:
1535 : case SessionRecordFields::SESSION_TIER:
1536 : case SessionRecordFields::SESSION_APPLICATION:
1537 : case SessionRecordFields::SESSION_SITE:
1538 : case SessionRecordFields::SESSION_REMOTE_DEPLOYMENT:
1539 : case SessionRecordFields::SESSION_REMOTE_TIER:
1540 : case SessionRecordFields::SESSION_REMOTE_APPLICATION:
1541 : case SessionRecordFields::SESSION_REMOTE_SITE:
1542 : case SessionRecordFields::SESSION_REMOTE_PREFIX:
1543 : case SessionRecordFields::SESSION_SECURITY_POLICY_RULE:
1544 : case SessionRecordFields::SESSION_VMI:
1545 : case SessionRecordFields::SESSION_VN:
1546 : case SessionRecordFields::SESSION_REMOTE_VN:
1547 : {
1548 11 : std::ostringstream v;
1549 11 : v << T2 << ":" << val;
1550 11 : session_entry_values[stinfo.get<0>()] = v.str();
1551 11 : break;
1552 11 : }
1553 0 : default:
1554 : {
1555 0 : session_entry_values[stinfo.get<0>()] = val;
1556 0 : break;
1557 : }
1558 : }
1559 11 : break;
1560 11 : }
1561 1 : case GenDb::DbDataType::InetType:
1562 : {
1563 1 : boost::system::error_code ec;
1564 : IpAddress ipaddr(IpAddress::from_string(
1565 1 : sfield.child_value(), ec));
1566 1 : if (ec) {
1567 0 : LOG(ERROR, "SessionRecordTable: " << col_name << ": ("
1568 : << sfield.child_value() << ") INVALID");
1569 : }
1570 1 : session_entry_values[stinfo.get<0>()] = ipaddr;
1571 1 : break;
1572 : }
1573 0 : default:
1574 : {
1575 0 : VIZD_ASSERT(0);
1576 : break;
1577 : }
1578 : }
1579 1 : } else if (col_type == "map" && col_name == "sess_agg_info") {
1580 1 : session_agg_info_node = sfield.child("map");
1581 1 : continue;
1582 : }
1583 18 : }
1584 :
1585 1 : for (pugi::xml_node ip_port_proto = session_agg_info_node.first_child();
1586 3 : ip_port_proto; ip_port_proto = ip_port_proto.next_sibling().next_sibling()) {
1587 : uint16_t val;
1588 2 : stringToInteger(ip_port_proto.child(g_flow_constants.SERVICE_PORT.c_str()).child_value(), val);
1589 2 : session_entry_values[SessionRecordFields::SESSION_SPORT] = val;
1590 2 : stringToInteger(ip_port_proto.child(g_flow_constants.PROTOCOL.c_str()).child_value(), val);
1591 2 : session_entry_values[SessionRecordFields::SESSION_PROTOCOL] = val;
1592 2 : session_entry_values[SessionRecordFields::SESSION_UUID] = umn_gen_();
1593 : // Partition No
1594 2 : uint8_t partition_no = gen_partition_no_();
1595 2 : session_entry_values[SessionRecordFields::SESSION_PARTITION_NO] = partition_no;
1596 2 : std::ostringstream oss;
1597 2 : oss << T2 << ":" << ip_port_proto.child(g_flow_constants.LOCAL_IP.c_str()).child_value();
1598 2 : session_entry_values[SessionRecordFields::SESSION_IP] = oss.str();
1599 2 : pugi::xml_node sess_agg_info = ip_port_proto.next_sibling();
1600 2 : for (pugi::xml_node agg_info = sess_agg_info.first_child();
1601 12 : agg_info; agg_info = agg_info.next_sibling()) {
1602 10 : if (strcmp(agg_info.attribute("type").value(), "map") == 0) {
1603 : int16_t samples;
1604 2 : stringToInteger(agg_info.child("map").attribute("size").value(), samples);
1605 2 : session_table_db_stats_.num_samples += samples;
1606 2 : std::string session_map;
1607 2 : JsonifySessionMap(agg_info.child("map"), &session_map);
1608 2 : session_table_db_stats_.curr_json_size += session_map.size();
1609 2 : session_entry_values[SessionRecordFields::SESSION_MAP]
1610 2 : = session_map;
1611 2 : continue;
1612 2 : }
1613 8 : std::string field_name(agg_info.name());
1614 : SessionTypeMap::const_iterator it =
1615 8 : session_msg2type_map.find(field_name);
1616 8 : if (it != session_msg2type_map.end()) {
1617 8 : const SessionTypeInfo &stinfo(it->second);
1618 : uint64_t val;
1619 8 : stringToInteger(agg_info.child_value(), val);
1620 8 : session_entry_values[stinfo.get<0>()]
1621 16 : = static_cast<uint64_t>(val);
1622 : }
1623 8 : }
1624 : DbInsertCb db_insert_cb =
1625 4 : boost::bind(&DbHandler::InsertIntoDb, this, _1,
1626 2 : GenDb::DbConsistency::LOCAL_ONE, db_cb);
1627 2 : if (!PopulateSessionTable(T2, session_entry_values,
1628 2 : db_insert_cb, ttl_map_)) {
1629 0 : DB_LOG(ERROR, "Populating SessionRecordTable FAILED");
1630 : }
1631 2 : session_table_db_stats_.num_writes++;
1632 2 : }
1633 :
1634 1 : int ttl = DbHandler::GetTtlFromMap(ttl_map_, TtlType::FLOWDATA_TTL);
1635 : // insert into FieldNames table
1636 2 : FieldNamesTableInsert(timestamp, g_viz_constants.SESSION_TABLE, ":vrouter",
1637 1 : boost::get<std::string>(session_entry_values[
1638 1 : SessionRecordFields::SESSION_VROUTER]), ttl, db_cb);
1639 2 : FieldNamesTableInsert(timestamp, g_viz_constants.SESSION_TABLE, ":vn",
1640 1 : boost::get<std::string>(session_entry_values[
1641 1 : SessionRecordFields::SESSION_VN]), ttl, db_cb);
1642 2 : FieldNamesTableInsert(timestamp, g_viz_constants.SESSION_TABLE, ":remote_vn",
1643 1 : boost::get<std::string>(session_entry_values[
1644 1 : SessionRecordFields::SESSION_REMOTE_VN]), ttl, db_cb);
1645 :
1646 1 : session_table_db_stats_.num_messages++;
1647 1 : return true;
1648 1 : }
1649 :
1650 : /*
1651 : * process the session sandesh message
1652 : */
1653 :
1654 1 : bool DbHandler::SessionTableInsert(const pugi::xml_node &parent,
1655 : const SandeshHeader& header, GenDb::GenDbIf::DbAddColumnCb db_cb) {
1656 1 : pugi::xml_node session_data(parent.child("session_data"));
1657 1 : if (!session_data) {
1658 0 : return true;
1659 : }
1660 : // Session sandesh message may contain a list of session samples or
1661 : // a single session sample
1662 1 : if (strcmp(session_data.attribute("type").value(), "list") == 0) {
1663 1 : pugi::xml_node session_list = session_data.child("list");
1664 2 : for (pugi::xml_node ssample = session_list.first_child(); ssample;
1665 1 : ssample = ssample.next_sibling()) {
1666 1 : SessionSampleAdd(ssample, header, db_cb);
1667 : }
1668 : } else {
1669 0 : SessionSampleAdd(session_data.first_child(), header, db_cb);
1670 : }
1671 1 : return true;
1672 : }
1673 :
1674 0 : bool DbHandler::GetSessionTableDbInfo(SessionTableDbInfo *session_table_info) {
1675 : {
1676 0 : std::scoped_lock lock(smutex_);
1677 0 : if (session_table_db_stats_.num_messages == 0) {
1678 0 : return true;
1679 : }
1680 0 : double writes_per_message = (double)session_table_db_stats_.num_writes /
1681 0 : session_table_db_stats_.num_messages;
1682 0 : double session_per_db_write = (double)session_table_db_stats_.num_samples /
1683 0 : session_table_db_stats_.num_writes;
1684 0 : double json_size_per_write = (double)session_table_db_stats_.curr_json_size /
1685 0 : session_table_db_stats_.num_writes;
1686 0 : session_table_info->set_writes_per_message(writes_per_message);
1687 0 : session_table_info->set_sessions_per_db_record(session_per_db_write);
1688 0 : session_table_info->set_json_size_per_write(json_size_per_write);
1689 0 : session_table_info->set_num_messages(session_table_db_stats_.num_messages);
1690 0 : session_table_db_stats_.num_writes = 0;
1691 0 : session_table_db_stats_.num_samples = 0;
1692 0 : session_table_db_stats_.num_messages = 0;
1693 0 : session_table_db_stats_.curr_json_size = 0;
1694 0 : }
1695 0 : return true;
1696 : }
1697 :
1698 0 : bool DbHandler::UnderlayFlowSampleInsert(const UFlowData& flow_data,
1699 : uint64_t timestamp,
1700 : GenDb::GenDbIf::DbAddColumnCb db_cb) {
1701 0 : const std::vector<UFlowSample>& flow = flow_data.get_flow();
1702 0 : for (std::vector<UFlowSample>::const_iterator it = flow.begin();
1703 0 : it != flow.end(); ++it) {
1704 : // Add all attributes
1705 0 : DbHandler::AttribMap amap;
1706 0 : DbHandler::Var name(flow_data.get_name());
1707 0 : amap.insert(std::make_pair("name", name));
1708 0 : DbHandler::Var pifindex = it->get_pifindex();
1709 0 : amap.insert(std::make_pair("flow.pifindex", pifindex));
1710 0 : DbHandler::Var sip = it->get_sip();
1711 0 : amap.insert(std::make_pair("flow.sip", sip));
1712 0 : DbHandler::Var dip = it->get_dip();
1713 0 : amap.insert(std::make_pair("flow.dip", dip));
1714 0 : DbHandler::Var sport = static_cast<uint64_t>(it->get_sport());
1715 0 : amap.insert(std::make_pair("flow.sport", sport));
1716 0 : DbHandler::Var dport = static_cast<uint64_t>(it->get_dport());
1717 0 : amap.insert(std::make_pair("flow.dport", dport));
1718 0 : DbHandler::Var protocol = static_cast<uint64_t>(it->get_protocol());
1719 0 : amap.insert(std::make_pair("flow.protocol", protocol));
1720 0 : DbHandler::Var ft = it->get_flowtype();
1721 0 : amap.insert(std::make_pair("flow.flowtype", ft));
1722 :
1723 0 : DbHandler::TagMap tmap;
1724 : // Add tag -> name:.pifindex
1725 0 : DbHandler::AttribMap amap_name_pifindex;
1726 0 : amap_name_pifindex.insert(std::make_pair("flow.pifindex", pifindex));
1727 0 : tmap.insert(std::make_pair("name", std::make_pair(name,
1728 : amap_name_pifindex)));
1729 : // Add tag -> .sip
1730 0 : DbHandler::AttribMap amap_sip;
1731 0 : tmap.insert(std::make_pair("flow.sip", std::make_pair(sip, amap_sip)));
1732 : // Add tag -> .dip
1733 0 : DbHandler::AttribMap amap_dip;
1734 0 : tmap.insert(std::make_pair("flow.dip", std::make_pair(dip, amap_dip)));
1735 : // Add tag -> .protocol:.sport
1736 0 : DbHandler::AttribMap amap_protocol_sport;
1737 0 : amap_protocol_sport.insert(std::make_pair("flow.sport", sport));
1738 0 : tmap.insert(std::make_pair("flow.protocol",
1739 0 : std::make_pair(protocol, amap_protocol_sport)));
1740 : // Add tag -> .protocol:.dport
1741 0 : DbHandler::AttribMap amap_protocol_dport;
1742 0 : amap_protocol_dport.insert(std::make_pair("flow.dport", dport));
1743 0 : tmap.insert(std::make_pair("flow.protocol",
1744 0 : std::make_pair(protocol, amap_protocol_dport)));
1745 0 : StatTableInsert(timestamp, "UFlowData", "flow", tmap, amap, db_cb);
1746 0 : }
1747 0 : return true;
1748 : }
1749 :
1750 : using namespace zookeeper::client;
1751 :
1752 0 : DbHandlerInitializer::DbHandlerInitializer(EventManager *evm,
1753 : const std::string &db_name, const std::string &timer_task_name,
1754 : DbHandlerInitializer::InitializeDoneCb callback,
1755 : const Options::Cassandra &cassandra_options,
1756 : const std::string &zookeeper_server_list,
1757 : bool use_zookeeper,
1758 : const DbWriteOptions &db_write_options,
1759 0 : ConfigClientCollector *config_client) :
1760 0 : db_name_(db_name),
1761 0 : db_handler_(new DbHandler(evm,
1762 : boost::bind(&DbHandlerInitializer::ScheduleInit, this),
1763 : db_name, cassandra_options,
1764 0 : true, db_write_options, config_client)),
1765 0 : callback_(callback),
1766 0 : db_init_timer_(TimerManager::CreateTimer(*evm->io_service(),
1767 0 : db_name + " Db Init Timer",
1768 : TaskScheduler::GetInstance()->GetTaskId(timer_task_name))),
1769 0 : zookeeper_server_list_(zookeeper_server_list),
1770 0 : use_zookeeper_(use_zookeeper),
1771 0 : zoo_locked_(false) {
1772 0 : if (use_zookeeper_) {
1773 0 : zoo_client_.reset(new ZookeeperClient(db_name_.c_str(),
1774 0 : zookeeper_server_list_.c_str()));
1775 0 : zoo_mutex_.reset(new ZookeeperLock(zoo_client_.get(), "/collector"));
1776 : }
1777 0 : }
1778 :
1779 0 : DbHandlerInitializer::DbHandlerInitializer(EventManager *evm,
1780 : const std::string &db_name, const std::string &timer_task_name,
1781 : DbHandlerInitializer::InitializeDoneCb callback,
1782 0 : DbHandlerPtr db_handler) :
1783 0 : db_name_(db_name),
1784 0 : db_handler_(db_handler),
1785 0 : callback_(callback),
1786 0 : db_init_timer_(TimerManager::CreateTimer(*evm->io_service(),
1787 0 : db_name + " Db Init Timer",
1788 0 : TaskScheduler::GetInstance()->GetTaskId(timer_task_name))) {
1789 0 : }
1790 :
1791 0 : DbHandlerInitializer::~DbHandlerInitializer() {
1792 0 : }
1793 :
1794 0 : bool DbHandlerInitializer::Initialize() {
1795 : // Synchronize creation across nodes using zookeeper
1796 0 : if (use_zookeeper_ && !zoo_locked_) {
1797 0 : assert(zoo_mutex_->Lock());
1798 0 : zoo_locked_ = true;
1799 : }
1800 0 : if (!db_handler_->Init(true)) {
1801 0 : if (use_zookeeper_ && zoo_locked_) {
1802 0 : assert(zoo_mutex_->Release());
1803 0 : zoo_locked_ = false;
1804 : }
1805 : // Update connection info
1806 0 : ConnectionState::GetInstance()->Update(ConnectionType::DATABASE,
1807 0 : db_name_, ConnectionStatus::DOWN, db_handler_->GetEndpoints(),
1808 0 : std::string());
1809 0 : LOG(DEBUG, db_name_ << ": Db Initialization FAILED");
1810 0 : ScheduleInit();
1811 0 : return false;
1812 : }
1813 0 : if (use_zookeeper_ && zoo_locked_) {
1814 0 : assert(zoo_mutex_->Release());
1815 0 : zoo_locked_ = false;
1816 : }
1817 : // Update connection info
1818 0 : ConnectionState::GetInstance()->Update(ConnectionType::DATABASE,
1819 0 : db_name_, ConnectionStatus::UP, db_handler_->GetEndpoints(),
1820 0 : std::string());
1821 :
1822 0 : if (callback_) {
1823 0 : callback_();
1824 : }
1825 :
1826 0 : LOG(DEBUG, db_name_ << ": Db Initialization DONE");
1827 0 : return true;
1828 : }
1829 :
1830 0 : DbHandlerPtr DbHandlerInitializer::GetDbHandler() const {
1831 0 : return db_handler_;
1832 : }
1833 :
1834 0 : void DbHandlerInitializer::Shutdown() {
1835 0 : TimerManager::DeleteTimer(db_init_timer_);
1836 0 : db_init_timer_ = NULL;
1837 0 : db_handler_->UnInit();
1838 0 : }
1839 :
1840 0 : bool DbHandlerInitializer::InitTimerExpired() {
1841 : // Start the timer again if initialization is not done
1842 0 : bool done = Initialize();
1843 0 : return !done;
1844 : }
1845 :
1846 0 : void DbHandlerInitializer::InitTimerErrorHandler(string error_name,
1847 : string error_message) {
1848 0 : LOG(ERROR, db_name_ << ": " << error_name << " " << error_message);
1849 0 : }
1850 :
1851 0 : void DbHandlerInitializer::StartInitTimer() {
1852 0 : db_init_timer_->Start(kInitRetryInterval,
1853 : boost::bind(&DbHandlerInitializer::InitTimerExpired, this),
1854 : boost::bind(&DbHandlerInitializer::InitTimerErrorHandler, this,
1855 : _1, _2));
1856 0 : }
1857 :
1858 0 : void DbHandlerInitializer::ScheduleInit() {
1859 0 : db_handler_->UnInit();
1860 0 : StartInitTimer();
1861 0 : }
1862 :
1863 : // Prepend T2 in decimal since T2 timestamp column is in decimal
1864 107 : std::string PrependT2(uint32_t T2, const std::string &str) {
1865 107 : std::string tempstr = integerToString(T2);
1866 107 : tempstr.append(":");
1867 107 : tempstr.append(str);
1868 107 : return tempstr;
1869 0 : }
|