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