Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include "config-client-mgr/config_cassandra_client.h"
7 :
8 : #include <sandesh/request_pipeline.h>
9 :
10 : #include <boost/algorithm/string/join.hpp>
11 : #include <boost/algorithm/string/predicate.hpp>
12 : #include <boost/foreach.hpp>
13 : #include <boost/functional/hash.hpp>
14 : #include <boost/ptr_container/ptr_map.hpp>
15 : #include <boost/uuid/uuid.hpp>
16 : #include <map>
17 : #include <set>
18 : #include <string>
19 : #include <utility>
20 : #include <vector>
21 :
22 : #include "base/connection_info.h"
23 : #include "base/logging.h"
24 : #include "base/regex.h"
25 : #include "base/task.h"
26 : #include "base/task_annotations.h"
27 : #include "base/task_trigger.h"
28 : #include "config_cass2json_adapter.h"
29 : #include "io/event_manager.h"
30 : #include "database/cassandra/cql/cql_if.h"
31 : #include "config_factory.h"
32 : #include "config_client_log.h"
33 : #include "config_client_log_types.h"
34 : #include "config_client_show_types.h"
35 : #include "sandesh/common/vns_constants.h"
36 :
37 : using contrail::regex;
38 : using contrail::regex_match;
39 : using contrail::regex_search;
40 : using std::unique_ptr;
41 : using std::multimap;
42 : using std::set;
43 : using std::string;
44 :
45 : const string ConfigCassandraClient::kUuidTableName = "obj_uuid_table";
46 : const string ConfigCassandraClient::kFqnTableName = "obj_fq_name_table";
47 : const string ConfigCassandraClient::kCassClientTaskId = "config_client::Reader";
48 : const string ConfigCassandraClient::kObjectProcessTaskId =
49 : "config_client::ObjectProcessor";
50 :
51 3677 : ConfigCassandraClient::ConfigCassandraClient(ConfigClientManager *mgr,
52 : EventManager *evm, const ConfigClientOptions &options,
53 3677 : int num_workers)
54 3677 : : ConfigDbClient(mgr, evm, options), num_workers_(num_workers) {
55 3677 : dbif_.reset(ConfigStaticObjectFactory::CreateRef<cass::cql::CqlIf>(
56 : evm, config_db_ips(),
57 3677 : GetFirstConfigDbPort(), config_db_user(),
58 3677 : config_db_password(),
59 3677 : static_cast<bool>(options.config_db_use_ssl), options.config_db_ca_certs));
60 :
61 : // Initialized the casssadra connection status;
62 3677 : InitConnectionInfo();
63 3677 : bulk_sync_status_ = 0;
64 :
65 33093 : for (int i = 0; i < num_workers_; i++) {
66 58832 : partitions_.push_back(
67 : ConfigStaticObjectFactory::Create<ConfigCassandraPartition>
68 29416 : (this, static_cast<size_t>(i)));
69 : }
70 :
71 7354 : fq_name_reader_.reset(new
72 : TaskTrigger(boost::bind(&ConfigCassandraClient::FQNameReader, this),
73 7354 : TaskScheduler::GetInstance()->GetTaskId("config_client::DBReader"),
74 3677 : 0));
75 3677 : }
76 :
77 3679 : ConfigCassandraClient::~ConfigCassandraClient() {
78 3677 : if (dbif_) {
79 : // dbif_->Db_Uninit(....);
80 : }
81 :
82 3677 : STLDeleteValues(&partitions_);
83 3679 : }
84 :
85 7738 : void ConfigCassandraClient::InitDatabase() {
86 7738 : HandleCassandraConnectionStatus(false, true);
87 : while (true) {
88 19002 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug, "Cassandra SM: Db Init");
89 19002 : if (!dbif_->Db_Init()) {
90 2816 : CONFIG_CLIENT_DEBUG(ConfigCassInitErrorMessage,
91 : "Database initialization failed");
92 2816 : if (!InitRetry()) return;
93 2816 : continue;
94 : }
95 16186 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
96 : "Cassandra SM: Db SetTableSpace");
97 16186 : if (!dbif_->Db_SetTablespace(
98 : g_vns_constants.API_SERVER_KEYSPACE_NAME)) {
99 2816 : CONFIG_CLIENT_DEBUG(ConfigCassInitErrorMessage,
100 : "Setting database keyspace failed");
101 2816 : if (!InitRetry()) return;
102 2816 : continue;
103 : }
104 13370 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
105 : "Cassandra SM: Db UseColumnFamily uuidTableName");
106 13370 : if (!dbif_->Db_UseColumnfamily(kUuidTableName)) {
107 2816 : if (!InitRetry()) return;
108 2816 : continue;
109 : }
110 10554 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
111 : "Cassandra SM: Db UseColumnFamily fqnTableName");
112 10554 : if (!dbif_->Db_UseColumnfamily(kFqnTableName)) {
113 2816 : if (!InitRetry()) return;
114 2816 : continue;
115 : }
116 7738 : break;
117 : }
118 7738 : HandleCassandraConnectionStatus(true);
119 7738 : BulkDataSync();
120 : }
121 :
122 11264 : bool ConfigCassandraClient::InitRetry() {
123 11264 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug, "Cassandra SM: DB uninit");
124 11264 : dbif_->Db_Uninit();
125 : // If reinit is triggered, return false to abort connection attempt
126 11264 : if (mgr()->is_reinit_triggered()) return false;
127 11264 : usleep(GetInitRetryTimeUSec());
128 11264 : return true;
129 : }
130 :
131 : ConfigCassandraPartition *
132 68061 : ConfigCassandraClient::GetPartition(const string &uuid) {
133 68061 : int worker_id = HashUUID(uuid);
134 68061 : return partitions_[worker_id];
135 : }
136 :
137 : const ConfigCassandraPartition *
138 0 : ConfigCassandraClient::GetPartition(const string &uuid) const {
139 0 : int worker_id = HashUUID(uuid);
140 0 : return partitions_[worker_id];
141 : }
142 :
143 : const ConfigCassandraPartition *
144 208 : ConfigCassandraClient::GetPartition(int worker_id) const {
145 208 : assert(worker_id < num_workers_);
146 208 : return partitions_[worker_id];
147 : }
148 :
149 73283 : int ConfigCassandraClient::HashUUID(const string &uuid_str) const {
150 : boost::hash<string> string_hash;
151 73283 : return string_hash(uuid_str) % num_workers_;
152 : }
153 :
154 20764 : bool ConfigCassandraPartition::ReadObjUUIDTable(const set<string> &req_list) {
155 20764 : GenDb::ColListVec col_list_vec;
156 :
157 20764 : set<string> uuid_list = req_list;
158 20764 : vector<GenDb::DbDataValueVec> keys;
159 20764 : for (set<string>::const_iterator it = uuid_list.begin();
160 52384 : it != uuid_list.end(); it++) {
161 31619 : GenDb::DbDataValueVec key;
162 63236 : key.push_back(GenDb::Blob(reinterpret_cast<const uint8_t *>
163 31618 : (it->c_str()), it->size()));
164 31619 : keys.push_back(key);
165 31620 : }
166 :
167 20764 : GenDb::Blob col_filter(reinterpret_cast<const uint8_t *>("d"), 1);
168 20764 : GenDb::ColumnNameRange crange;
169 : crange.start_ =
170 20764 : boost::assign::list_of(GenDb::DbDataValue(col_filter)).convert_to_container<GenDb::DbDataValueVec>();
171 :
172 20763 : GenDb::FieldNamesToReadVec field_vec;
173 20763 : field_vec.push_back(boost::make_tuple("key", true, false, false));
174 20764 : field_vec.push_back(boost::make_tuple("column1", false, true, false));
175 20764 : field_vec.push_back(boost::make_tuple("value", false, false, true));
176 :
177 20764 : if (client()->dbif_->Db_GetMultiRow(&col_list_vec,
178 : ConfigCassandraClient::kUuidTableName, keys,
179 : crange, field_vec,
180 : GenDb::DbConsistency::QUORUM)) {
181 20764 : client()->HandleCassandraConnectionStatus(true);
182 84004 : BOOST_FOREACH(const GenDb::ColList &col_list, col_list_vec) {
183 31620 : assert(col_list.rowkey_.size() == 1);
184 31620 : assert(col_list.rowkey_[0].which() == GenDb::DB_VALUE_BLOB);
185 31620 : if (col_list.columns_.size()) {
186 31620 : GenDb::Blob uuid(boost::get<GenDb::Blob>(col_list.rowkey_[0]));
187 31620 : string uuid_str(reinterpret_cast<const char *>(uuid.data()),
188 63240 : uuid.size());
189 31620 : ProcessObjUUIDTableEntry(uuid_str, col_list);
190 31620 : uuid_list.erase(uuid_str);
191 31620 : }
192 : }
193 : } else {
194 : // Failure is returned due to connectivity issue or consistency
195 : // issues in reading from cassandra
196 0 : client()->HandleCassandraConnectionStatus(false);
197 0 : CONFIG_CLIENT_WARN(ConfigClientGetRowError,
198 : "GetMultiRow failed for table",
199 : ConfigCassandraClient::kUuidTableName, "");
200 : //
201 : // Task is rescheduled to read the request queue
202 : // Due to a bug CQL driver from datastax, connection status is
203 : // not notified asynchronously. Because of this, polling is the only
204 : // choice to determine the cql connection status.
205 : // Since there are dedicated threads to read config,
206 : // and it is ok to retry by rescheduling the reader task
207 : // TODO: Sleep or No Sleep?
208 : //
209 0 : return false;
210 : }
211 :
212 : // Delete all stale entries from the data base.
213 20763 : BOOST_FOREACH(string uuid_key, uuid_list) {
214 0 : CONFIG_CLIENT_WARN(ConfigClientGetRowError, "Missing row in the table",
215 : ConfigCassandraClient::kUuidTableName, uuid_key);
216 0 : HandleObjectDelete(uuid_key, false);
217 0 : }
218 :
219 : // Clear the uuid list.
220 20764 : uuid_list.clear();
221 20764 : return true;
222 20764 : }
223 :
224 : // Notes on list map property processing:
225 : // Separate entries per list/map keys are stored in the ObjUuidCache partition
226 : // based on the uuid.
227 : // The cache map entries contain a refreshed bit and timestamp in addition to
228 : // the values etc.
229 : // A set containing list/map property names (updated_list_map_properties) that
230 : // have key/value pairs with a new timestamp, a second set
231 : // (candidate_list_map_properties) also containing list/map property names that
232 : // may require an update given some key/value pairs have been deleted, and a
233 : // multimap (list_map_properties) for all the list/map key value pairs in the
234 : // new configuration, are build and held in the context(temporary).
235 : // These lists are used to determine which list/map properties need to be pushed
236 : // to the backend, they are built as columns are parsed. Once all columns are
237 : // parsed,
238 : // in ListMapPropReviseUpdateList, for each property name in
239 : // candidate_list_map_properties we check it is already in the
240 : // updated_list_map_property list, if not we proceed to find at least one stale
241 : // list/map key value pair with the property name in the ObJUuidCache, if one is
242 : // found that requires an update, the property name is added to
243 : // updated_list_map_properties.
244 : // Once updated_list_map_properties is revised, we iterate through each property
245 : // name in it and push all matching key/value pairs in list_map_properties.
246 : // ConfigCass2JsonAdapter groups the key value pairs belonging to the same
247 : // property so that a single DB request is sent to the
248 : // backend.
249 : // Deletes are handled by FormDeleteRequestList. Note that deletes are sent
250 : // only when all key/value pairs for a given list/map property are removed.
251 : // Additionally, the resulting DB request only resets the property_set bit, it
252 : // does not clear the entries in the backend.
253 : //
254 : // parent_or_ref_fq_name_unknown indicates that at least one parent or
255 : // ref cannot be found in the FQNameCache, this can happen if the parent or
256 : // referred object is not yet read.
257 : struct ConfigCassandraParseContext {
258 34231 : ConfigCassandraParseContext() : obj_type(""), fq_name_present(false),
259 68462 : ignore_object(false), parent_or_ref_fq_name_unknown(false) {
260 34231 : }
261 : std::multimap<string, JsonAdapterDataType> list_map_properties;
262 : set<string> updated_list_map_properties;
263 : set<string> candidate_list_map_properties;
264 : string obj_type;
265 : string fq_name;
266 : bool fq_name_present;
267 : bool ignore_object;
268 : bool parent_or_ref_fq_name_unknown;
269 :
270 : private:
271 : DISALLOW_COPY_AND_ASSIGN(ConfigCassandraParseContext);
272 : };
273 :
274 34231 : bool ConfigCassandraPartition::ProcessObjUUIDTableEntry(const string &uuid_key,
275 : const GenDb::ColList &col_list) {
276 34231 : CassColumnKVVec cass_data_vec;
277 :
278 34231 : ConfigCassandraParseContext context;
279 :
280 34231 : ConfigCassandraPartition::ObjCacheEntry *obj = MarkCacheDirty(uuid_key);
281 :
282 34231 : ParseObjUUIDTableEntry(uuid_key, col_list, &cass_data_vec, context);
283 : // Ignore draft objects.
284 34231 : if (context.ignore_object) {
285 4 : client()->PurgeFQNameCache(uuid_key);
286 4 : DeleteCacheMap(uuid_key);
287 4 : return false;
288 : }
289 : // If type or fq-name is not present in the db object, ignore the object
290 : // and trigger delete of the object.
291 34227 : if (context.obj_type.empty() || !context.fq_name_present) {
292 : // Handle as delete
293 20 : CONFIG_CLIENT_WARN(ConfigClientGetRowError,
294 : "Parsing row response for type/fq_name failed for table",
295 : ConfigCassandraClient::kUuidTableName, uuid_key);
296 20 : obj->DisableCassandraReadRetry(uuid_key);
297 20 : HandleObjectDelete(uuid_key, false);
298 20 : return false;
299 : }
300 :
301 34207 : obj->SetFQName(context.fq_name);
302 34207 : obj->SetObjType(context.obj_type);
303 :
304 34206 : if (context.parent_or_ref_fq_name_unknown) {
305 10 : obj->EnableCassandraReadRetry(uuid_key);
306 : } else {
307 34196 : obj->DisableCassandraReadRetry(uuid_key);
308 : }
309 :
310 34207 : ListMapPropReviseUpdateList(uuid_key, context);
311 :
312 : // Read the context for map and list properties
313 34207 : if (context.updated_list_map_properties.size()) {
314 188 : for (set<string>::iterator it =
315 188 : context.updated_list_map_properties.begin();
316 400 : it != context.updated_list_map_properties.end(); it++) {
317 : pair<multimap<string, JsonAdapterDataType>::iterator,
318 : multimap<string, JsonAdapterDataType>::iterator> ret =
319 212 : context.list_map_properties.equal_range(*it);
320 212 : for (multimap<string, JsonAdapterDataType>::iterator mit =
321 640 : ret.first; mit != ret.second; mit++) {
322 428 : cass_data_vec.push_back(mit->second);
323 : }
324 : }
325 : }
326 34207 : GenerateAndPushJson(uuid_key, context.obj_type, cass_data_vec, true);
327 34207 : HandleObjectDelete(uuid_key, true);
328 34207 : return true;
329 34231 : }
330 :
331 31620 : void ConfigCassandraPartition::ParseObjUUIDTableEntry(const string &uuid,
332 : const GenDb::ColList &col_list, CassColumnKVVec *cass_data_vec,
333 : ConfigCassandraParseContext &context) {
334 284566 : BOOST_FOREACH(const GenDb::NewCol &ncol, col_list.columns_) {
335 126468 : assert(ncol.name->size() == 1);
336 126468 : assert(ncol.value->size() == 1);
337 126465 : assert(ncol.timestamp->size() == 1);
338 :
339 126465 : const GenDb::DbDataValue &dname(ncol.name->at(0));
340 126464 : assert(dname.which() == GenDb::DB_VALUE_BLOB);
341 126463 : GenDb::Blob dname_blob(boost::get<GenDb::Blob>(dname));
342 126464 : string key(reinterpret_cast<const char *>(dname_blob.data()),
343 252925 : dname_blob.size());
344 :
345 126467 : const GenDb::DbDataValue &dvalue(ncol.value->at(0));
346 126465 : assert(dvalue.which() == GenDb::DB_VALUE_STRING);
347 126464 : string value(boost::get<string>(dvalue));
348 :
349 126472 : const GenDb::DbDataValue &dtimestamp(ncol.timestamp->at(0));
350 126471 : assert(dtimestamp.which() == GenDb::DB_VALUE_UINT64);
351 126469 : uint64_t timestamp = boost::get<uint64_t>(dtimestamp);
352 126467 : ParseObjUUIDTableEachColumnBuildContext(uuid, key, value, timestamp,
353 : cass_data_vec, context);
354 126478 : }
355 31620 : }
356 :
357 142604 : void ConfigCassandraPartition::ParseObjUUIDTableEachColumnBuildContext(
358 : const string &uuid, const string &key, const string &value,
359 : uint64_t timestamp, CassColumnKVVec *cass_data_vec,
360 : ConfigCassandraParseContext &context) {
361 : // Check whether there was an update to property of ref
362 142604 : JsonAdapterDataType adapter(key, value);
363 142616 : if (StoreKeyIfUpdated(uuid, &adapter, timestamp, context)) {
364 : // Field is updated.. enqueue to parsing
365 141474 : cass_data_vec->push_back(adapter);
366 : }
367 142617 : }
368 :
369 2752 : void ConfigCassandraPartition::GenerateAndPushJson(
370 : const string &uuid_key, const string &obj_type,
371 : const CassColumnKVVec &cass_data_vec, bool add_change) {
372 :
373 : ConfigCass2JsonAdapter ccja(uuid_key, client(), obj_type,
374 2752 : cass_data_vec);
375 2752 : client()->mgr()->config_json_parser()->Receive(ccja, add_change);
376 2752 : }
377 :
378 : // Post shutdown during reinit, cleanup all previous states and connections
379 : // 1. Disconnect from cassandra cluster
380 : // 2. Clean FQ Name cache
381 : // 3. Delete partitions which inturn will clear up the object cache and
382 : // previously enqueued uuid read requests
383 0 : void ConfigCassandraClient::PostShutdown() {
384 0 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
385 : "Cassandra SM: Post shutdown during re init");
386 0 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug, "Cassandra SM: Db Uninit");
387 0 : dbif_->Db_Uninit();
388 0 : STLDeleteValues(&partitions_);
389 0 : ClearFQNameCache();
390 0 : }
391 :
392 7738 : bool ConfigCassandraClient::BulkDataSync() {
393 7738 : CONFIG_CLIENT_DEBUG(
394 : ConfigClientMgrDebug, "Cassandra SM: BulkDataSync Started");
395 7738 : bulk_sync_status_ = num_workers_;
396 7738 : fq_name_reader_->Set();
397 7738 : return true;
398 : }
399 :
400 0 : bool ConfigCassandraClient::IsTaskTriggered() const {
401 : // If FQNameReader task has been triggered return true.
402 0 : if (fq_name_reader_->IsSet()) {
403 0 : return true;
404 : }
405 :
406 : /**
407 : * Walk the partitions and check if ConfigReader task has
408 : * been triggered in any of them. If so, return true.
409 : */
410 0 : BOOST_FOREACH(ConfigCassandraPartition *partition, partitions_) {
411 0 : if (partition->IsTaskTriggered()) {
412 0 : return true;
413 : }
414 : }
415 0 : return false;
416 : }
417 :
418 7738 : bool ConfigCassandraClient::FQNameReader() {
419 7738 : for (ConfigClientManager::ObjectTypeList::const_iterator it =
420 7738 : mgr()->config_json_parser()->ObjectTypeListToRead().begin();
421 9844 : it != mgr()->config_json_parser()->ObjectTypeListToRead().end();
422 2106 : it++) {
423 2106 : string column_name;
424 : while (true) {
425 : // Ensure that FQName reader task aborts on reinit trigger.
426 6318 : if (mgr()->is_reinit_triggered()) {
427 0 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
428 : "Cassandra SM: Abort FQName reader on reinit trigger");
429 0 : return true;
430 : }
431 :
432 : // Rowkey is obj-type
433 6318 : GenDb::DbDataValueVec key;
434 12636 : key.push_back(GenDb::Blob(reinterpret_cast<const uint8_t *>
435 6318 : (it->c_str()), it->size()));
436 6318 : GenDb::ColumnNameRange crange;
437 6318 : if (!column_name.empty()) {
438 : GenDb::Blob col_filter(reinterpret_cast<const uint8_t *>
439 4212 : (column_name.c_str()), column_name.size());
440 : // Start reading the next set of entries from where we ended in
441 : // last read
442 : crange.start_ =
443 4212 : boost::assign::list_of(
444 8424 : GenDb::DbDataValue(col_filter)).convert_to_container
445 4212 : <GenDb::DbDataValueVec>();
446 4212 : crange.start_op_ = GenDb::Op::GT;
447 4212 : }
448 :
449 : // In large scale scenarios, each object type may have a large
450 : // number of uuid entries. Read a fixed number of entries at a time
451 : // to avoid cpu hogging by this thread.
452 6318 : crange.count_ = GetFQNameEntriesToRead();
453 :
454 6318 : GenDb::FieldNamesToReadVec field_vec;
455 6318 : field_vec.push_back(boost::make_tuple("key", true, false, false));
456 6318 : field_vec.push_back(boost::make_tuple("column1", false, true,
457 6318 : false));
458 :
459 6318 : GenDb::ColList col_list;
460 6318 : if (dbif_->Db_GetRow(&col_list, kFqnTableName, key,
461 : GenDb::DbConsistency::QUORUM, crange, field_vec)) {
462 6318 : HandleCassandraConnectionStatus(true);
463 :
464 : // No entries for this obj-type
465 6318 : if (!col_list.columns_.size())
466 2106 : break;
467 :
468 6318 : ObjTypeUUIDList uuid_list;
469 6318 : ParseFQNameRowGetUUIDList(*it, col_list, uuid_list,
470 : &column_name);
471 6318 : EnqueueDBSyncRequest(uuid_list);
472 :
473 : // If we read less than what we sought, it means there are
474 : // no more entries for current obj-type. We move to next
475 : // obj-type.
476 6318 : if (col_list.columns_.size() < GetFQNameEntriesToRead())
477 2106 : break;
478 6318 : } else {
479 0 : HandleCassandraConnectionStatus(false);
480 0 : CONFIG_CLIENT_WARN(ConfigClientGetRowError,
481 : "GetRow failed for table", kFqnTableName, *it);
482 0 : usleep(GetInitRetryTimeUSec());
483 : }
484 16848 : }
485 2106 : }
486 : // At the end of task trigger
487 131546 : BOOST_FOREACH(ConfigCassandraPartition *partition, partitions_) {
488 61904 : ObjectProcessReq *req = new ObjectProcessReq("EndOfConfig", "", "");
489 61904 : partition->Enqueue(req);
490 : }
491 :
492 7738 : return true;
493 : }
494 :
495 6318 : bool ConfigCassandraClient::ParseFQNameRowGetUUIDList(const string &obj_type,
496 : const GenDb::ColList &col_list, ObjTypeUUIDList &uuid_list,
497 : string *last_column) {
498 6318 : string column_name;
499 48438 : BOOST_FOREACH(const GenDb::NewCol &ncol, col_list.columns_) {
500 21060 : assert(ncol.name->size() == 1);
501 21060 : const GenDb::DbDataValue &dname(ncol.name->at(0));
502 21060 : assert(dname.which() == GenDb::DB_VALUE_BLOB);
503 21060 : GenDb::Blob dname_blob(boost::get<GenDb::Blob>(dname));
504 42120 : column_name = string(reinterpret_cast<const char *>(dname_blob.data()),
505 21060 : dname_blob.size());
506 21060 : UpdateFQNameCache(column_name, obj_type, uuid_list);
507 21060 : }
508 :
509 6318 : *last_column = column_name;
510 6318 : return true;
511 6318 : }
512 :
513 23244 : void ConfigCassandraClient::UpdateFQNameCache(const string &key,
514 : const string &obj_type, ObjTypeUUIDList &uuid_list) {
515 23244 : string uuid_str = FetchUUIDFromFQNameEntry(key);
516 23244 : if (uuid_str.empty())
517 0 : return;
518 23244 : uuid_list.push_back(make_pair(obj_type, uuid_str));
519 23244 : AddFQNameCache(uuid_str, obj_type, key.substr(0, key.rfind(':')));
520 23244 : }
521 :
522 21060 : string ConfigCassandraClient::FetchUUIDFromFQNameEntry(
523 : const string &key) const {
524 21060 : size_t temp = key.rfind(':');
525 21060 : return (temp == string::npos) ? "" : key.substr(temp+1);
526 : }
527 :
528 6358 : bool ConfigCassandraClient::EnqueueDBSyncRequest(
529 : const ObjTypeUUIDList &uuid_list) {
530 6358 : for (ObjTypeUUIDList::const_iterator it = uuid_list.begin();
531 29602 : it != uuid_list.end(); it++) {
532 23244 : EnqueueUUIDRequest("CREATE", it->first, it->second);
533 : }
534 6358 : return true;
535 : }
536 :
537 208 : bool ConfigCassandraClient::UUIDToObjCacheShow(
538 : const string &search_string, int inst_num, const string &last_uuid,
539 : uint32_t num_entries, vector<ConfigDBUUIDCacheEntry> *entries) const {
540 208 : return GetPartition(inst_num)->UUIDToObjCacheShow(search_string, last_uuid,
541 208 : num_entries, entries);
542 : }
543 :
544 67740 : void ConfigCassandraClient::EnqueueUUIDRequest(string oper, string obj_type,
545 : string uuid_str) {
546 67740 : ObjectProcessReq *req = new ObjectProcessReq(oper, uuid_str, obj_type);
547 67740 : GetPartition(uuid_str)->Enqueue(req);
548 67740 : }
549 :
550 61894 : void ConfigCassandraClient::BulkSyncDone() {
551 : long num_config_readers_still_processing =
552 61894 : bulk_sync_status_.fetch_sub(1);
553 61894 : if (num_config_readers_still_processing == 1) {
554 7738 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
555 : "Cassandra SM: BulkSyncDone by all readers");
556 7738 : mgr()->EndOfConfig();
557 : } else {
558 54156 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
559 : "Cassandra SM: One reader finished BulkSync");
560 : }
561 61904 : }
562 :
563 42558 : void ConfigCassandraClient::HandleCassandraConnectionStatus(bool success,
564 : bool force_update) {
565 42558 : UpdateConnectionInfo(success, force_update);
566 :
567 42558 : if (success) {
568 : // Update connection info
569 104460 : process::ConnectionState::GetInstance()->Update(
570 : process::ConnectionType::DATABASE, "Cassandra",
571 : process::ConnectionStatus::UP,
572 69640 : dbif_->Db_GetEndpoints(), "Established Cassandra connection");
573 34820 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
574 : "Cassandra SM: Established Cassandra connection");
575 : } else {
576 23214 : process::ConnectionState::GetInstance()->Update(
577 : process::ConnectionType::DATABASE, "Cassandra",
578 : process::ConnectionStatus::DOWN,
579 15476 : dbif_->Db_GetEndpoints(), "Lost Cassandra connection");
580 7738 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
581 : "Cassandra SM: Lost Cassandra connection");
582 : }
583 42558 : }
584 :
585 190 : bool ConfigCassandraClient::IsListOrMapPropEmpty(const string &uuid_key,
586 : const string &lookup_key) {
587 190 : return GetPartition(uuid_key)->IsListOrMapPropEmpty(uuid_key, lookup_key);
588 : }
589 :
590 29416 : ConfigCassandraPartition::ConfigCassandraPartition(
591 29416 : ConfigCassandraClient *client, size_t idx)
592 29416 : : config_client_(client), worker_id_(idx) {
593 29416 : int task_id = TaskScheduler::GetInstance()->GetTaskId("config_client::Reader");
594 58832 : config_reader_.reset(new
595 : TaskTrigger(boost::bind(&ConfigCassandraPartition::ConfigReader, this),
596 29416 : task_id, idx));
597 : task_id =
598 29416 : TaskScheduler::GetInstance()->GetTaskId("config_client::ObjectProcessor");
599 58832 : obj_process_queue_.reset(new WorkQueue<ObjectProcessReq *>(
600 : task_id, idx, bind(&ConfigCassandraPartition::RequestHandler, this, _1),
601 29416 : WorkQueue<ObjectProcessReq *>::kMaxSize, 512));
602 29416 : }
603 :
604 40808 : ConfigCassandraPartition::~ConfigCassandraPartition() {
605 29416 : obj_process_queue_->Shutdown();
606 40808 : }
607 :
608 129644 : void ConfigCassandraPartition::Enqueue(ObjectProcessReq *req) {
609 129644 : obj_process_queue_->Enqueue(req);
610 129644 : }
611 :
612 129558 : bool ConfigCassandraPartition::RequestHandler(ObjectProcessReq *req) {
613 129558 : AddUUIDToRequestList(req->oper_, req->value_, req->uuid_str_);
614 129636 : delete req;
615 129639 : return true;
616 : }
617 :
618 129582 : void ConfigCassandraPartition::AddUUIDToRequestList(const string &oper,
619 : const string &obj_type,
620 : const string &uuid_str) {
621 129582 : pair<UUIDProcessSet::iterator, bool> ret;
622 129590 : bool trigger = uuid_read_set_.empty();
623 : ObjectProcessRequestType *req =
624 129588 : new ObjectProcessRequestType(oper, obj_type, uuid_str);
625 129642 : ret = uuid_read_set_.insert(make_pair(client()->GetUUID(uuid_str), req));
626 129632 : if (ret.second) {
627 127823 : if (trigger) {
628 95580 : config_reader_->Set();
629 : }
630 : } else {
631 1809 : delete req;
632 1808 : ret.first->second->oper = oper;
633 1807 : ret.first->second->uuid = uuid_str;
634 : }
635 129637 : }
636 :
637 65925 : void ConfigCassandraPartition::HandleObjectDelete(
638 : const string &uuid, bool add_change) {
639 65925 : if (!add_change) {
640 : ConfigCassandraClient::ObjTypeFQNPair obj_type_fq_name_pair =
641 31718 : client()->UUIDToFQName(uuid, true);
642 31719 : if (obj_type_fq_name_pair.second == "ERROR") {
643 10529 : return;
644 : }
645 31719 : }
646 :
647 55397 : bool needNotify = false;
648 55397 : std::string obj_type("");
649 55396 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid);
650 55396 : if (uuid_iter == object_cache_map_.end()) {
651 2 : assert(!add_change);
652 2 : return;
653 : }
654 :
655 55394 : CassColumnKVVec cass_data_vec;
656 55391 : for (FieldDetailMap::iterator it =
657 55394 : uuid_iter->second->GetFieldDetailMap().begin(), itnext;
658 282105 : it != uuid_iter->second->GetFieldDetailMap().end();
659 226714 : it = itnext) {
660 226695 : itnext = it;
661 226695 : ++itnext;
662 226693 : if (it->first.key == "type") {
663 55379 : obj_type = it->first.value;
664 110758 : obj_type.erase(remove(obj_type.begin(),
665 110758 : obj_type.end(), '\"'), obj_type.end());
666 55377 : cass_data_vec.push_back(it->first);
667 : }
668 :
669 226689 : if (it->first.key == "fq_name") {
670 55376 : cass_data_vec.push_back(it->first);
671 : }
672 :
673 226709 : if (!add_change || !it->second.refreshed) {
674 84734 : if (it->first.key == "type" || it->first.key == "fq_name") {
675 42343 : continue;
676 : }
677 :
678 42392 : needNotify = true;
679 42392 : cass_data_vec.push_back(it->first);
680 42397 : if (add_change) {
681 77 : uuid_iter->second->GetFieldDetailMap().erase(it);
682 : }
683 : }
684 : }
685 :
686 55393 : if (add_change != true) {
687 21188 : object_cache_map_.erase(uuid_iter);
688 : }
689 55393 : if (needNotify) {
690 21225 : GenerateAndPushJson(uuid, obj_type, cass_data_vec, false);
691 : }
692 55393 : if (!add_change) {
693 21188 : client()->PurgeFQNameCache(uuid);
694 : }
695 55395 : }
696 :
697 190 : bool ConfigCassandraPartition::IsListOrMapPropEmpty(const string &uuid_key,
698 : const string &lookup_key) {
699 190 : string key;
700 190 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid_key);
701 190 : if (uuid_iter == object_cache_map_.end()) {
702 132 : return true;
703 : }
704 :
705 58 : key = "propm:" + lookup_key;
706 : FieldDetailMap::iterator lower_bound_it =
707 116 : uuid_iter->second->GetFieldDetailMap().lower_bound(
708 116 : JsonAdapterDataType(key, ""));
709 116 : if (lower_bound_it != uuid_iter->second->GetFieldDetailMap().end() &&
710 58 : boost::starts_with(lower_bound_it->first.key, key)) {
711 16 : return false;
712 : }
713 42 : key = "propl:" + lookup_key;
714 : lower_bound_it =
715 84 : uuid_iter->second->GetFieldDetailMap().lower_bound(
716 84 : JsonAdapterDataType(key, ""));
717 84 : if (lower_bound_it != uuid_iter->second->GetFieldDetailMap().end() &&
718 42 : boost::starts_with(lower_bound_it->first.key, key)) {
719 16 : return false;
720 : }
721 26 : return true;
722 190 : }
723 :
724 0 : bool ConfigCassandraPartition::IsTaskTriggered() const {
725 0 : return (config_reader_->IsSet());
726 : }
727 :
728 97684 : bool ConfigCassandraPartition::ConfigReader() {
729 97684 : CHECK_CONCURRENCY("config_client::Reader");
730 :
731 97690 : set<string> bunch_req_list;
732 97687 : int num_req_handled = 0;
733 : // Config reader task should stop on reinit trigger
734 97687 : for (UUIDProcessSet::iterator it = uuid_read_set_.begin(), itnext;
735 223412 : it != uuid_read_set_.end() && !client()->mgr()->is_reinit_triggered();
736 125728 : it = itnext) {
737 127818 : itnext = it;
738 127818 : ++itnext;
739 127819 : ObjectProcessRequestType *obj_req = it->second;
740 :
741 221410 : if (obj_req->oper == "CREATE" || obj_req->oper == "UPDATE" ||
742 93588 : obj_req->oper == "UPDATE-IMPLICIT") {
743 34229 : bunch_req_list.insert(obj_req->uuid);
744 34231 : bool is_last = (itnext == uuid_read_set_.end());
745 48494 : if (is_last ||
746 14263 : bunch_req_list.size() == client()->GetNumReadRequestToBunch()) {
747 19968 : if (!ReadObjUUIDTable(bunch_req_list)) {
748 2104 : return false;
749 : }
750 19968 : num_req_handled += bunch_req_list.size();
751 19968 : RemoveObjReqEntries(bunch_req_list);
752 19968 : if (num_req_handled >= client()->GetMaxRequestsToYield()) {
753 2104 : return false;
754 : }
755 : }
756 32127 : continue;
757 125718 : } else if (obj_req->oper == "DELETE") {
758 31699 : HandleObjectDelete(obj_req->uuid, false);
759 61892 : } else if (obj_req->oper == "EndOfConfig") {
760 61894 : client()->BulkSyncDone();
761 : }
762 93599 : RemoveObjReqEntry(obj_req->uuid);
763 93603 : if (++num_req_handled == client()->GetMaxRequestsToYield()) {
764 0 : return false;
765 : }
766 : }
767 :
768 : // No need to read the object uuid table if reinit is triggered
769 95587 : if (!bunch_req_list.empty() && !client()->mgr()->is_reinit_triggered()) {
770 1792 : if (!ReadObjUUIDTable(bunch_req_list))
771 0 : return false;
772 1792 : RemoveObjReqEntries(bunch_req_list);
773 : }
774 : // Clear the UUID read set if we are currently processing reinit request
775 95586 : if (client()->mgr()->is_reinit_triggered()) {
776 0 : CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
777 : "Cassandra SM: Clear UUID read set due to reinit");
778 0 : uuid_read_set_.clear();
779 : }
780 95586 : assert(uuid_read_set_.empty());
781 95586 : return true;
782 97690 : }
783 :
784 21760 : void ConfigCassandraPartition::RemoveObjReqEntries(set<string> &req_list) {
785 90222 : BOOST_FOREACH(string uuid, req_list) {
786 34231 : RemoveObjReqEntry(uuid);
787 34231 : }
788 21760 : req_list.clear();
789 21760 : }
790 :
791 127834 : void ConfigCassandraPartition::RemoveObjReqEntry(string &uuid) {
792 : UUIDProcessSet::iterator req_it =
793 127834 : uuid_read_set_.find(client()->GetUUID(uuid));
794 127834 : delete req_it->second;
795 127834 : uuid_read_set_.erase(req_it);
796 127834 : }
797 :
798 :
799 0 : boost::asio::io_context *ConfigCassandraPartition::ioservice() {
800 0 : return client()->event_manager()->io_service();
801 : }
802 :
803 : ConfigCassandraPartition::ObjCacheEntry *
804 2 : ConfigCassandraPartition::GetObjCacheEntry(const string &uuid) {
805 2 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid);
806 2 : if (uuid_iter == object_cache_map_.end())
807 0 : return NULL;
808 2 : return uuid_iter->second;
809 : }
810 :
811 : const ConfigCassandraPartition::ObjCacheEntry *
812 125 : ConfigCassandraPartition::GetObjCacheEntry(const string &uuid) const {
813 125 : ObjectCacheMap::const_iterator uuid_iter = object_cache_map_.find(uuid);
814 125 : if (uuid_iter == object_cache_map_.end())
815 0 : return NULL;
816 125 : return uuid_iter->second;
817 : }
818 :
819 0 : int ConfigCassandraPartition::UUIDRetryTimeInMSec(
820 : const ObjCacheEntry *obj) const {
821 : uint32_t retry_time_pow_of_two =
822 0 : obj->GetRetryCount() > kMaxUUIDRetryTimePowOfTwo ?
823 0 : kMaxUUIDRetryTimePowOfTwo : obj->GetRetryCount();
824 0 : return ((1 << retry_time_pow_of_two) * kMinUUIDRetryTimeMSec);
825 : }
826 :
827 47038 : ConfigCassandraPartition::ObjCacheEntry::~ObjCacheEntry() {
828 23519 : if (retry_timer_) {
829 1 : TimerManager::DeleteTimer(retry_timer_);
830 : }
831 47038 : }
832 :
833 10 : void ConfigCassandraPartition::ObjCacheEntry::EnableCassandraReadRetry(
834 : const string uuid) {
835 10 : if (!retry_timer_) {
836 18 : retry_timer_ = TimerManager::CreateTimer(
837 6 : *parent_->client()->event_manager()->io_service(),
838 12 : "UUID retry timer for " + uuid,
839 : TaskScheduler::GetInstance()->GetTaskId(
840 : "config_client::Reader"),
841 6 : parent_->worker_id_);
842 6 : CONFIG_CLIENT_DEBUG(ConfigClientReadRetry,
843 : "Created UUID read retry timer ", uuid);
844 : }
845 10 : retry_timer_->Cancel();
846 20 : retry_timer_->Start(parent_->UUIDRetryTimeInMSec(this),
847 20 : boost::bind(
848 : &ConfigCassandraPartition::ObjCacheEntry::CassReadRetryTimerExpired,
849 : this, uuid),
850 : boost::bind(
851 : &ConfigCassandraPartition::ObjCacheEntry::CassReadRetryTimerErrorHandler,
852 : this));
853 10 : CONFIG_CLIENT_DEBUG(ConfigClientReadRetry,
854 : "Start/restart UUID Read Retry timer due to configuration", uuid);
855 10 : }
856 :
857 34217 : void ConfigCassandraPartition::ObjCacheEntry::DisableCassandraReadRetry(
858 : const string uuid) {
859 34217 : if (retry_timer_) {
860 5 : retry_timer_->Cancel();
861 5 : TimerManager::DeleteTimer(retry_timer_);
862 5 : retry_timer_ = NULL;
863 5 : retry_count_ = 0;
864 5 : CONFIG_CLIENT_DEBUG(ConfigClientReadRetry,
865 : "UUID Read retry timer - deleted timer due to configuration",
866 : uuid);
867 : }
868 34217 : }
869 :
870 36 : bool ConfigCassandraPartition::ObjCacheEntry::IsRetryTimerRunning() const {
871 36 : if (retry_timer_)
872 0 : return (retry_timer_->running());
873 36 : return false;
874 : }
875 :
876 4 : bool ConfigCassandraPartition::ObjCacheEntry::CassReadRetryTimerExpired(
877 : const string uuid) {
878 8 : parent_->client()->mgr()->EnqueueUUIDRequest(
879 8 : "UPDATE", GetObjType(), parent_->client()->uuid_str(uuid));
880 4 : retry_count_++;
881 4 : CONFIG_CLIENT_DEBUG(ConfigClientReadRetry, "timer expired ", uuid);
882 4 : return false;
883 : }
884 :
885 : void
886 0 : ConfigCassandraPartition::ObjCacheEntry::CassReadRetryTimerErrorHandler() {
887 0 : std::string message = "Timer";
888 0 : CONFIG_CLIENT_WARN(ConfigClientGetRowError,
889 : "UUID Read Retry Timer error ", message, message);
890 0 : }
891 :
892 34207 : void ConfigCassandraPartition::ListMapPropReviseUpdateList(
893 : const string &uuid, ConfigCassandraParseContext &context) {
894 34207 : for (set<string>::iterator it =
895 34207 : context.candidate_list_map_properties.begin();
896 34231 : it != context.candidate_list_map_properties.end(); it++) {
897 24 : if (context.updated_list_map_properties.find(*it) !=
898 48 : context.updated_list_map_properties.end()) {
899 8 : continue;
900 : }
901 16 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid);
902 16 : assert(uuid_iter != object_cache_map_.end());
903 : FieldDetailMap::iterator field_iter =
904 32 : uuid_iter->second->GetFieldDetailMap().lower_bound(
905 32 : JsonAdapterDataType(*it, ""));
906 16 : assert(field_iter != uuid_iter->second->GetFieldDetailMap().end());
907 16 : assert(it->compare(0, it->size() - 1, field_iter->first.key,
908 : 0, it->size() - 1) == 0);
909 80 : while (it->compare(0, it->size() - 1, field_iter->first.key,
910 80 : 0, it->size() - 1) == 0) {
911 32 : if (field_iter->second.refreshed == false) {
912 8 : context.updated_list_map_properties.insert(*it);
913 8 : break;
914 : }
915 24 : field_iter++;
916 : }
917 : }
918 34207 : }
919 :
920 142617 : bool ConfigCassandraPartition::StoreKeyIfUpdated(const string &uuid,
921 : JsonAdapterDataType *adapter, uint64_t timestamp,
922 : ConfigCassandraParseContext &context) {
923 142617 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid);
924 142609 : assert(uuid_iter != object_cache_map_.end());
925 142606 : size_t from_front_pos = adapter->key.find(':');
926 142607 : size_t from_back_pos = adapter->key.rfind(':');
927 142607 : string type_field = adapter->key.substr(0, from_front_pos+1);
928 142608 : bool is_ref = (type_field == ConfigCass2JsonAdapter::ref_prefix);
929 142608 : bool is_parent = (type_field == ConfigCass2JsonAdapter::parent_prefix);
930 142606 : bool is_propl = (type_field == ConfigCass2JsonAdapter::list_prop_prefix);
931 142605 : bool is_propm = (type_field == ConfigCass2JsonAdapter::map_prop_prefix);
932 142606 : bool is_prop = (type_field == ConfigCass2JsonAdapter::prop_prefix);
933 142599 : if (is_prop) {
934 37144 : string prop_name = adapter->key.substr(from_front_pos+1);
935 : //
936 : // properties like perms2 has no importance to control-node/dns
937 : // This property is present on each config object. Hence skipping such
938 : // properties gives performance improvement
939 : //
940 37144 : if (ConfigClientManager::skip_properties.find(prop_name) !=
941 74286 : ConfigClientManager::skip_properties.end()) {
942 611 : if ((prop_name.compare("draft_mode_state") == 0) &&
943 6 : !adapter->value.empty()) {
944 4 : context.ignore_object = true;
945 : }
946 606 : return false;
947 : }
948 37143 : }
949 :
950 141992 : string prop_name = "";
951 141999 : if (is_ref || is_parent) {
952 2846 : string ref_uuid = adapter->key.substr(from_back_pos+1);
953 :
954 2846 : string ref_name = client()->UUIDToFQName(ref_uuid).second;
955 2846 : if (ref_name == "ERROR") {
956 14 : context.parent_or_ref_fq_name_unknown = true;
957 14 : CONFIG_CLIENT_DEBUG(ConfigClientReadRetry,
958 : "Out of order parent or ref", uuid + ":" + adapter->key);
959 14 : return false;
960 : }
961 2832 : if (is_ref) {
962 1201 : adapter->ref_fq_name = ref_name;
963 : }
964 144845 : } else if (is_propl || is_propm) {
965 444 : prop_name = adapter->key.substr(0, from_back_pos);
966 :
967 444 : context.list_map_properties.insert(make_pair(prop_name, *adapter));
968 : }
969 :
970 141985 : if (adapter->key.compare("type") == 0) {
971 34212 : if (context.obj_type.empty()) {
972 34212 : context.obj_type = adapter->value;
973 68426 : context.obj_type.erase(remove(context.obj_type.begin(),
974 102638 : context.obj_type.end(), '\"'), context.obj_type.end());
975 : }
976 107770 : } else if (adapter->key.compare("fq_name") == 0) {
977 34210 : context.fq_name_present = true;
978 34210 : if (context.fq_name.empty()) {
979 34210 : context.fq_name = adapter->value.substr(1, adapter->value.size()-2);
980 68422 : context.fq_name.erase(remove(context.fq_name.begin(),
981 68422 : context.fq_name.end(), '\"'), context.fq_name.end());
982 68422 : context.fq_name.erase(remove(context.fq_name.begin(),
983 68422 : context.fq_name.end(), ' '), context.fq_name.end());
984 34211 : replace(context.fq_name.begin(), context.fq_name.end(), ',', ':');
985 : }
986 : }
987 : FieldDetailMap::iterator field_iter =
988 141988 : uuid_iter->second->GetFieldDetailMap().find(*adapter);
989 141988 : if (field_iter == uuid_iter->second->GetFieldDetailMap().end()) {
990 : // seeing field for first time
991 : FieldTimeStampInfo field_ts_info;
992 99116 : field_ts_info.refreshed = true;
993 99116 : field_ts_info.time_stamp = timestamp;
994 198241 : uuid_iter->second->GetFieldDetailMap().insert(make_pair
995 198244 : (*adapter, field_ts_info));
996 : } else {
997 42868 : field_iter->second.refreshed = true;
998 43981 : if (client()->SkipTimeStampCheckForTypeAndFQName() &&
999 1115 : ((adapter->key.compare("type") == 0) ||
1000 483 : (adapter->key.compare("fq_name") == 0))) {
1001 296 : return true;
1002 : }
1003 42570 : if (timestamp && field_iter->second.time_stamp == timestamp) {
1004 116 : if (is_propl || is_propm) {
1005 44 : context.candidate_list_map_properties.insert(prop_name);
1006 : }
1007 116 : return false;
1008 : }
1009 42454 : field_iter->second.time_stamp = timestamp;
1010 : }
1011 141579 : if (is_propl || is_propm) {
1012 401 : context.updated_list_map_properties.insert(prop_name);
1013 400 : return false;
1014 : } else {
1015 141178 : return true;
1016 : }
1017 142609 : }
1018 :
1019 : ConfigCassandraPartition::ObjCacheEntry *
1020 34231 : ConfigCassandraPartition::MarkCacheDirty(const string &uuid) {
1021 34231 : ObjectCacheMap::iterator uuid_iter = object_cache_map_.find(uuid);
1022 34231 : if (uuid_iter == object_cache_map_.end()) {
1023 : ObjCacheEntry *obj;
1024 23520 : string tmp_uuid = uuid;
1025 23520 : obj = new ObjCacheEntry(this, UTCTimestampUsec());
1026 : pair<ObjectCacheMap::iterator, bool> ret_uuid =
1027 23520 : object_cache_map_.insert(tmp_uuid, obj);
1028 23520 : assert(ret_uuid.second);
1029 23520 : uuid_iter = ret_uuid.first;
1030 23520 : } else {
1031 10711 : uuid_iter->second->SetLastReadTimeStamp(UTCTimestampUsec());
1032 : }
1033 34231 : for (FieldDetailMap::iterator it =
1034 34231 : uuid_iter->second->GetFieldDetailMap().begin();
1035 77193 : it != uuid_iter->second->GetFieldDetailMap().end(); it++) {
1036 42963 : it->second.refreshed = false;
1037 : }
1038 34231 : return uuid_iter->second;
1039 : }
1040 :
1041 36 : void ConfigCassandraPartition::FillUUIDToObjCacheInfo(const string &uuid,
1042 : ObjectCacheMap::const_iterator uuid_iter,
1043 : ConfigDBUUIDCacheEntry *entry) const {
1044 36 : entry->set_uuid(uuid);
1045 36 : entry->set_timestamp(
1046 72 : UTCUsecToString(uuid_iter->second->GetLastReadTimeStamp()));
1047 36 : entry->set_retry_count(uuid_iter->second->GetRetryCount());
1048 36 : entry->set_fq_name(uuid_iter->second->GetFQName());
1049 36 : entry->set_obj_type(uuid_iter->second->GetObjType());
1050 36 : entry->set_timer_running(uuid_iter->second->IsRetryTimerRunning());
1051 36 : entry->set_timer_created(uuid_iter->second->IsRetryTimerCreated());
1052 36 : vector<ConfigDBUUIDCacheData> fields;
1053 36 : for (FieldDetailMap::const_iterator it =
1054 36 : uuid_iter->second->GetFieldDetailMap().begin();
1055 158 : it != uuid_iter->second->GetFieldDetailMap().end(); it++) {
1056 122 : ConfigDBUUIDCacheData each_field;
1057 122 : each_field.set_refresh(it->second.refreshed);
1058 122 : each_field.set_field_name(it->first.key);
1059 122 : each_field.set_timestamp(UTCUsecToString(it->second.time_stamp));
1060 122 : fields.push_back(each_field);
1061 122 : }
1062 36 : entry->set_field_list(fields);
1063 36 : }
1064 :
1065 208 : bool ConfigCassandraPartition::UUIDToObjCacheShow(
1066 : const string &search_string, const string &last_uuid, uint32_t num_entries,
1067 : vector<ConfigDBUUIDCacheEntry> *entries) const {
1068 208 : uint32_t count = 0;
1069 208 : regex search_expr(search_string);
1070 208 : for (ObjectCacheMap::const_iterator it =
1071 208 : object_cache_map_.upper_bound(last_uuid);
1072 272 : count < num_entries && it != object_cache_map_.end(); it++) {
1073 64 : if (regex_search(it->first, search_expr) ||
1074 96 : regex_search(it->second->GetObjType(), search_expr) ||
1075 96 : regex_search(it->second->GetFQName(), search_expr)) {
1076 36 : count++;
1077 36 : ConfigDBUUIDCacheEntry entry;
1078 36 : FillUUIDToObjCacheInfo(it->first, it, &entry);
1079 36 : entries->push_back(entry);
1080 36 : }
1081 : }
1082 208 : return true;
1083 208 : }
|