LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/config-client-mgr - config_client_manager.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 107 152 70.4 %
Date: 2026-08-03 02:19:58 Functions: 13 18 72.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : #include "config_client_manager.h"
       5             : 
       6             : #include <boost/assign/list_of.hpp>
       7             : #include <sandesh/request_pipeline.h>
       8             : #include <sstream>
       9             : #include <string>
      10             : 
      11             : #include "base/connection_info.h"
      12             : #include "base/task.h"
      13             : #include "base/task_trigger.h"
      14             : #include "config_amqp_client.h"
      15             : #include "config_db_client.h"
      16             : #include "config_cassandra_client.h"
      17             : #include "config_client_log.h"
      18             : #include "config_client_log_types.h"
      19             : #include "config_client_show_types.h"
      20             : #include "config_factory.h"
      21             : #include "io/event_manager.h"
      22             : #include "schema/bgp_schema_types.h"
      23             : #include "schema/vnc_cfg_types.h"
      24             : 
      25             : using namespace boost::assign;
      26             : using namespace std;
      27             : 
      28             : const set<string> ConfigClientManager::skip_properties =
      29             :     list_of("perms2")("draft_mode_state");
      30             : bool ConfigClientManager::end_of_rib_computed_;
      31             : 
      32        4213 : int ConfigClientManager::GetNumConfigReader() {
      33             :     static bool init_ = false;
      34             :     static int num_config_readers = 0;
      35             : 
      36        4213 :     if (!init_) {
      37             :         // XXX To be used for testing purposes only.
      38          17 :         char *count_str = getenv("CONFIG_NUM_WORKERS");
      39          17 :         if (count_str) {
      40           0 :             num_config_readers = strtol(count_str, NULL, 0);
      41             :         } else {
      42          17 :             num_config_readers = kNumConfigReaderTasks;
      43             :         }
      44          17 :         init_ = true;
      45             :     }
      46        4213 :     return num_config_readers;
      47             : }
      48             : 
      49        3673 : void ConfigClientManager::SetDefaultSchedulingPolicy() {
      50             :     static bool config_policy_set;
      51        3673 :     if (config_policy_set)
      52        3656 :         return;
      53          17 :     config_policy_set = true;
      54             :  
      55          17 :     TaskScheduler *scheduler = TaskScheduler::GetInstance();
      56             :     // Policy for config_client::Reader Task.
      57             :     TaskPolicy cassadra_reader_policy = boost::assign::list_of
      58          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::Init")))
      59          17 :         (TaskExclusion(scheduler->GetTaskId("config_client::DBReader")));
      60         153 :     for (int idx = 0; idx < ConfigClientManager::GetNumConfigReader(); ++idx) {
      61         136 :         cassadra_reader_policy.push_back(
      62         272 :         TaskExclusion(scheduler->GetTaskId("config_client::ObjectProcessor"), idx));
      63             :     }
      64          17 :     scheduler->SetPolicy(scheduler->GetTaskId("config_client::Reader"),
      65             :         cassadra_reader_policy);
      66             : 
      67             :     // Policy for config_client::ObjectProcessor Task.
      68             :     TaskPolicy cassadra_obj_process_policy = boost::assign::list_of
      69          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::Init")));
      70         153 :     for (int idx = 0; idx < ConfigClientManager::GetNumConfigReader(); ++idx) {
      71         136 :         cassadra_obj_process_policy.push_back(
      72         272 :                  TaskExclusion(scheduler->GetTaskId("config_client::Reader"), idx));
      73             :     }
      74          17 :     scheduler->SetPolicy(scheduler->GetTaskId("config_client::ObjectProcessor"),
      75             :         cassadra_obj_process_policy);
      76             : 
      77             :     // Policy for config_client::DBReader Task.
      78             :     TaskPolicy fq_name_reader_policy = boost::assign::list_of
      79          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::Init")))
      80          17 :         (TaskExclusion(scheduler->GetTaskId("config_client::Reader")));
      81          17 :     scheduler->SetPolicy(scheduler->GetTaskId("config_client::DBReader"),
      82             :         fq_name_reader_policy);
      83             : 
      84             :     // Policy for config_client::Init process
      85             :     TaskPolicy cassandra_init_policy = boost::assign::list_of
      86          34 :         (TaskExclusion(scheduler->GetTaskId("amqp::RabbitMQReader")))
      87          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::ObjectProcessor")))
      88          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::DBReader")))
      89          17 :         (TaskExclusion(scheduler->GetTaskId("config_client::Reader")));
      90          17 :     scheduler->SetPolicy(scheduler->GetTaskId("config_client::Init"),
      91             :         cassandra_init_policy);
      92             : 
      93             :     // Policy for amqp::RabbitMQReader process
      94             :     TaskPolicy rabbitmq_reader_policy = boost::assign::list_of
      95          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::Init")));
      96          17 :     scheduler->SetPolicy(scheduler->GetTaskId("amqp::RabbitMQReader"),
      97             :         rabbitmq_reader_policy);
      98             : 
      99             :     // Policy for etcd::EtcdWatcher process
     100             :     TaskPolicy etcd_watcher_policy = boost::assign::list_of
     101          34 :         (TaskExclusion(scheduler->GetTaskId("config_client::Init")));
     102          17 :     scheduler->SetPolicy(scheduler->GetTaskId("etcd::EtcdWatcher"),
     103             :         etcd_watcher_policy);
     104             : 
     105          17 : }
     106             : 
     107        3673 : void ConfigClientManager::SetUp(ConfigJsonParserBase *cfg_json_base) {
     108        3673 :     config_json_parser_.reset(cfg_json_base);
     109        3673 :     config_json_parser_->Init(this);
     110        3673 :     thread_count_ = GetNumConfigReader();
     111        3673 :     end_of_rib_computed_at_ = UTCTimestampUsec();
     112        3673 :     if (!config_options_.config_db_use_etcd) {
     113        7346 :         config_db_client_.reset(
     114        3673 :                 ConfigStaticObjectFactory::CreateRef<ConfigCassandraClient>(
     115             :                     this,
     116             :                     evm_,
     117        3673 :                     config_options_,
     118             :                     thread_count_));
     119        7346 :         config_amqp_client_.reset(new ConfigAmqpClient(this, hostname_,
     120        3673 :                                                module_name_, config_options_));
     121             :     }
     122        3673 :     SetDefaultSchedulingPolicy();
     123             : 
     124             :     int task_id;
     125        3673 :     task_id = TaskScheduler::GetInstance()->GetTaskId("config_client::Init");
     126             : 
     127        7346 :     init_trigger_.reset(new
     128             :         TaskTrigger(boost::bind(&ConfigClientManager::InitConfigClient, this),
     129        3673 :          task_id, 0));
     130             : 
     131        3673 :     reinit_triggered_ = false;
     132        3673 : }
     133             : 
     134        3673 : ConfigClientManager::ConfigClientManager(EventManager *evm,
     135             :         ConfigJsonParserBase *cfg_json_base,
     136             :         std::string hostname,
     137             :         std::string module_name,
     138        3673 :         const ConfigClientOptions& config_options)
     139        3673 :         : evm_(evm),
     140        3673 :         generation_number_(0),
     141        3673 :         hostname_(hostname), module_name_(module_name),
     142        7346 :         config_options_(config_options) {
     143        3673 :     end_of_rib_computed_ = false;
     144        3673 :     SetUp(cfg_json_base);
     145        3673 : }
     146             : 
     147        3673 : ConfigClientManager::~ConfigClientManager() {
     148        3673 : }
     149             : 
     150        7738 : void ConfigClientManager::Initialize() {
     151        7738 :     if (init_trigger_.get() != nullptr) {
     152        7738 :         init_trigger_->Set();
     153             :     }
     154        7738 : }
     155             : 
     156         222 : ConfigDbClient *ConfigClientManager::config_db_client() const {
     157         222 :     return config_db_client_.get();
     158             : }
     159             : 
     160         444 : ConfigAmqpClient *ConfigClientManager::config_amqp_client() const {
     161         444 :     return config_amqp_client_.get();
     162             : }
     163             : 
     164           7 : bool ConfigClientManager::GetEndOfRibComputed() const {
     165           7 :     std::scoped_lock lock(end_of_rib_sync_mutex_);
     166           7 :     return end_of_rib_computed_;
     167           7 : }
     168             : 
     169           0 : uint64_t ConfigClientManager::GetEndOfRibComputedAt() const {
     170           0 :     std::scoped_lock lock(end_of_rib_sync_mutex_);
     171           0 :     return end_of_rib_computed_at_;
     172           0 : }
     173             : 
     174       44496 : void ConfigClientManager::EnqueueUUIDRequest(string oper, string obj_type,
     175             :                                              string uuid_str) {
     176       44496 :     config_db_client_->EnqueueUUIDRequest(oper, obj_type, uuid_str);
     177       44496 : }
     178             : 
     179        7789 : void ConfigClientManager::EndOfConfig() {
     180             :     {
     181             :         // Notify waiting caller with the result
     182        7789 :         std::scoped_lock lock(end_of_rib_sync_mutex_);
     183        7789 :         assert(!end_of_rib_computed_);
     184        7789 :         end_of_rib_computed_ = true;
     185        7789 :         cond_var_.notify_all();
     186        7789 :         end_of_rib_computed_at_ = UTCTimestampUsec();
     187        7789 :         CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
     188             :             "Config Client Mgr SM: End of RIB computed and notification sent");
     189        7789 :     }
     190             : 
     191             :     // Once we have finished reading the complete cassandra DB, we should verify
     192             :     // whether all DBEntries(node/link) are as per the new generation number.
     193             :     // The stale entry cleanup task ensure this.
     194             :     // There is no need to run stale clean up during first time startup
     195        7789 :     if (GetGenerationNumber())
     196           0 :         config_json_parser()->EndOfConfig();
     197             : 
     198        7789 :     process::ConnectionState::GetInstance()->Update();
     199        7789 : }
     200             : 
     201             : // This function waits forever for bulk sync of cassandra config to finish
     202             : // The condition variable is triggered even in case of "reinit". In such a case
     203             : // wait is terminated and function returns.
     204             : // AMQP reader task starts consuming messages only after bulk sync.
     205             : // During reinit, the tight loop is broken by triggering the condition variable
     206           2 : void ConfigClientManager::WaitForEndOfConfig() {
     207           2 :     std::unique_lock<std::mutex> lock(end_of_rib_sync_mutex_);
     208             :     // Wait for End of config
     209           2 :     while (!end_of_rib_computed_) {
     210           0 :         cond_var_.wait(lock);
     211           0 :         if (is_reinit_triggered()) break;
     212             :     }
     213           2 :     string message;
     214             :     message = "Config Client Mgr SM: End of RIB notification received, "
     215           2 :               "re init triggered" + is_reinit_triggered()?"TRUE":"FALSE";
     216           2 :     CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug, message);
     217           4 :     return;
     218           2 : }
     219             : 
     220           0 : void ConfigClientManager::GetClientManagerInfo(
     221             :                                    ConfigClientManagerInfo &info) const {
     222           0 :     std::scoped_lock lock(end_of_rib_sync_mutex_);
     223           0 :     info.end_of_rib_computed = end_of_rib_computed_;
     224           0 :     info.end_of_rib_computed_at = end_of_rib_computed_at_;
     225           0 :     info.end_of_rib_computed_at = UTCUsecToString(end_of_rib_computed_at_);
     226           0 : }
     227             : 
     228           0 : void ConfigClientManager::PostShutdown() {
     229           0 :     config_db_client_->PostShutdown();
     230           0 :     reinit_triggered_ = false;
     231           0 :     end_of_rib_computed_ = false;
     232             : 
     233             :     // All set to read next version of the config. Increment the generation
     234           0 :     IncrementGenerationNumber();
     235             : 
     236             :     // scoped ptr reset deletes the previous config db object
     237             :     // Create new config db client and amqp client
     238             :     // Delete of config db client object guarantees the flusing of
     239             :     // object uuid cache and uuid read request list.
     240           0 :     if (!config_options_.config_db_use_etcd) {
     241           0 :         config_db_client_.reset(ConfigStaticObjectFactory::
     242           0 :             CreateRef<ConfigCassandraClient>(
     243             :                 this,
     244             :                 evm_,
     245           0 :                 config_options_,
     246             :                 thread_count_));
     247           0 :         config_amqp_client_.reset(new ConfigAmqpClient(this, hostname_,
     248           0 :                                                module_name_, config_options_));
     249             :     }
     250           0 :     stringstream ss;
     251           0 :     ss << GetGenerationNumber();
     252           0 :     CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
     253             :             "Config Client Mgr SM: Post shutdown, next version of config: "
     254             :             + ss.str());
     255           0 : }
     256             : 
     257        7738 : bool ConfigClientManager::InitConfigClient() {
     258        7738 :     if (is_reinit_triggered()) {
     259             :         // "config_client::Init" task is mutually exclusive to
     260             :         // 1. FQName reader task
     261             :         // 2. Object UUID Table reader task
     262             :         // 3. AMQP reader task
     263             :         // 4. Object processing Work queue task
     264             :         // Due to this task policy, if the reinit task is running, it ensured
     265             :         // that above mutually exclusive tasks have finished/aborted
     266             :         // Perform PostShutdown to prepare for new connection
     267             :         // However, it is possible that these tasks have been scheduled
     268             :         // but yet to begin execution. For Task and WorkQueue events, their
     269             :         // destructor takes core of this but for TaskTrigger events, the
     270             :         // destructor will crash (See Bug #1786154) as it expects the task
     271             :         // to not be scheduled. Taking care of that case here by checking
     272             :         // if TaskTrigger events are scheduled (but not executing) and
     273             :         // return if they are so that this will be retried.
     274           0 :         if (config_db_client_->IsTaskTriggered()) {
     275           0 :             return false;
     276             :         }
     277           0 :         PostShutdown();
     278             :     }
     279             :     // Common code path for both init/reinit
     280        7738 :     if (!config_options_.config_db_use_etcd) {
     281        7738 :         CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
     282             :             "Config Client Mgr SM: Start RabbitMqReader and init Database");
     283        7738 :         config_amqp_client_->StartRabbitMQReader();
     284             :     }
     285        7738 :     CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
     286             :             "Config Client Mgr SM: Init Database");
     287        7738 :     config_db_client_->InitDatabase();
     288        7738 :     if (is_reinit_triggered()) return false;
     289        7738 :     return true;
     290             : }
     291             : 
     292           0 : void ConfigClientManager::ReinitConfigClient(
     293             :                         const ConfigClientOptions &config) {
     294           0 :     config_options_ = config;
     295           0 :     ReinitConfigClient();
     296           0 : }
     297             : 
     298           0 : void ConfigClientManager::ReinitConfigClient() {
     299             :     {
     300             :         // Wake up the amqp task waiting for EOR for config reading
     301           0 :         std::scoped_lock lock(end_of_rib_sync_mutex_);
     302           0 :         cond_var_.notify_all();
     303           0 :     }
     304           0 :     reinit_triggered_ = true;
     305           0 :     if (init_trigger_.get() != nullptr) {
     306           0 :         init_trigger_->Set();
     307             :     }
     308           0 :     CONFIG_CLIENT_DEBUG(ConfigClientMgrDebug,
     309             :             "Config Client Mgr SM: Re init triggered!");
     310           0 : }

Generated by: LCOV version 1.14