diff --git a/src/ifmap/client/config_cassandra_client.cc b/src/ifmap/client/config_cassandra_client.cc index 3eb563626ad..126c62c37bd 100644 --- a/src/ifmap/client/config_cassandra_client.cc +++ b/src/ifmap/client/config_cassandra_client.cc @@ -107,6 +107,18 @@ ConfigCassandraPartition *ConfigCassandraClient::GetPartition(const string &uuid return partitions_[worker_id]; } +const ConfigCassandraPartition *ConfigCassandraClient::GetPartition( + const string &uuid) const { + int worker_id = HashUUID(uuid); + return partitions_[worker_id]; +} + +const ConfigCassandraPartition *ConfigCassandraClient::GetPartition( + int worker_id) const { + assert(worker_id < num_workers_); + return partitions_[worker_id]; +} + int ConfigCassandraClient::HashUUID(const string &uuid_str) const { boost::hash string_hash; return string_hash(uuid_str) % num_workers_; @@ -427,7 +439,7 @@ void ConfigCassandraClient::AddFQNameCache(const string &uuid, void ConfigCassandraClient::InvalidateFQNameCache(const string &uuid) { tbb::spin_rw_mutex::scoped_lock write_lock(rw_mutex_, true); - map::iterator it = fq_name_cache_.find(uuid); + FQNameCacheMap::iterator it = fq_name_cache_.find(uuid); if (it != fq_name_cache_.end()) { it->second.deleted = true; } @@ -442,7 +454,7 @@ void ConfigCassandraClient::PurgeFQNameCache(const string &uuid) { ConfigCassandraClient::ObjTypeFQNPair ConfigCassandraClient::UUIDToFQName( const string &uuid, bool deleted_ok) const { tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false); - map::const_iterator it = fq_name_cache_.find(uuid); + FQNameCacheMap::const_iterator it = fq_name_cache_.find(uuid); if (it != fq_name_cache_.end()) { if (!it->second.deleted || (it->second.deleted && deleted_ok)) { return make_pair(it->second.obj_type, it->second.obj_name); @@ -451,6 +463,51 @@ ConfigCassandraClient::ObjTypeFQNPair ConfigCassandraClient::UUIDToFQName( return make_pair("ERROR", "ERROR"); } +void ConfigCassandraClient::FillFQNameCacheInfo(const string &uuid, + FQNameCacheMap::const_iterator it, ConfigDBFQNameCacheEntry &entry) const { + entry.set_uuid(it->first); + entry.set_obj_type(it->second.obj_type); + entry.set_fq_name(it->second.obj_name); + entry.set_deleted(it->second.deleted); +} + +bool ConfigCassandraClient::UUIDToFQNameShow(const string &uuid, + ConfigDBFQNameCacheEntry &entry) const { + tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false); + FQNameCacheMap::const_iterator it = fq_name_cache_.find(uuid); + if (it == fq_name_cache_.end()) { + return false; + } + FillFQNameCacheInfo(uuid, it, entry); + return true; +} + +bool ConfigCassandraClient::UUIDToFQNameShow(const string &start_uuid, + uint32_t num_entries, vector &entries) const { + uint32_t count = 0; + tbb::spin_rw_mutex::scoped_lock read_lock(rw_mutex_, false); + for(FQNameCacheMap::const_iterator it = + fq_name_cache_.upper_bound(start_uuid); + count < num_entries && it != fq_name_cache_.end(); it++, count++) { + ConfigDBFQNameCacheEntry entry; + FillFQNameCacheInfo(it->first, it, entry); + entries.push_back(entry); + } + return true; +} + +bool ConfigCassandraClient::UUIDToObjCacheShow(int inst_num, const string &uuid, + ConfigDBUUIDCacheEntry &entry) const { + return GetPartition(inst_num)->UUIDToObjCacheShow(uuid, entry); +} + +bool ConfigCassandraClient::UUIDToObjCacheShow(int inst_num, + const string &start_uuid, uint32_t num_entries, + vector &entries) const { + return GetPartition(inst_num)->UUIDToObjCacheShow(start_uuid, + num_entries, entries); +} + void ConfigCassandraClient::EnqueueUUIDRequest(string oper, string obj_type, string uuid_str) { ObjectProcessReq *req = new ObjectProcessReq(oper, obj_type, uuid_str); @@ -823,3 +880,42 @@ void ConfigCassandraPartition::MarkCacheDirty(const string &uuid) { it->second.second = false; } } + +void ConfigCassandraPartition::FillUUIDToObjCacheInfo(const string &uuid, + ObjectCacheMap::const_iterator uuid_iter, + ConfigDBUUIDCacheEntry &entry) const { + entry.set_uuid(uuid); + vector fields; + for (FieldDetailMap::const_iterator it = uuid_iter->second.begin(); + it != uuid_iter->second.end(); it++) { + ConfigDBUUIDCacheData each_field; + each_field.set_refresh(it->second.second); + each_field.set_field_name(it->first); + each_field.set_timestamp(UTCUsecToString(it->second.first)); + fields.push_back(each_field); + } + entry.set_field_list(fields); +} + +bool ConfigCassandraPartition::UUIDToObjCacheShow(const string &uuid, + ConfigDBUUIDCacheEntry &entry) const { + ObjectCacheMap::const_iterator uuid_iter = object_cache_map_.find(uuid); + if (uuid_iter == object_cache_map_.end()) { + return false; + } + FillUUIDToObjCacheInfo(uuid, uuid_iter, entry); + return true; +} + +bool ConfigCassandraPartition::UUIDToObjCacheShow(const string &start_uuid, + uint32_t num_entries, vector &entries) const { + uint32_t count = 0; + for(ObjectCacheMap::const_iterator it = + object_cache_map_.upper_bound(start_uuid); + count < num_entries && it != object_cache_map_.end(); it++, count++) { + ConfigDBUUIDCacheEntry entry; + FillUUIDToObjCacheInfo(it->first, it, entry); + entries.push_back(entry); + } + return true; +} diff --git a/src/ifmap/client/config_cassandra_client.h b/src/ifmap/client/config_cassandra_client.h index 19f63015d05..81938d71af9 100644 --- a/src/ifmap/client/config_cassandra_client.h +++ b/src/ifmap/client/config_cassandra_client.h @@ -21,6 +21,8 @@ struct ConfigDBConnInfo; class TaskTrigger; class ConfigCassandraClient; struct ConfigCassandraParseContext; +class ConfigDBFQNameCacheEntry; +class ConfigDBUUIDCacheEntry; class ObjectProcessReq { public: @@ -60,6 +62,13 @@ class ConfigCassandraPartition { void Enqueue(ObjectProcessReq *req); + bool UUIDToObjCacheShow(const std::string &uuid, + ConfigDBUUIDCacheEntry &entry) const; + + bool UUIDToObjCacheShow(const std::string &start_uuid, + uint32_t num_entries, + std::vector &entries) const; + private: friend class ConfigCassandraClient; @@ -97,6 +106,10 @@ class ConfigCassandraPartition { return config_client_; } + void FillUUIDToObjCacheInfo(const std::string &uuid, + ObjectCacheMap::const_iterator uuid_iter, + ConfigDBUUIDCacheEntry &entry) const; + ObjProcessWorkQType obj_process_queue_; UUIDProcessSet uuid_read_set_; ObjectCacheMap object_cache_map_; @@ -148,6 +161,8 @@ class ConfigCassandraClient : public ConfigDbClient { ConfigClientManager *mgr() { return mgr_; } const ConfigClientManager *mgr() const { return mgr_; } ConfigCassandraPartition *GetPartition(const std::string &uuid); + const ConfigCassandraPartition *GetPartition(const std::string &uuid) const; + const ConfigCassandraPartition *GetPartition(int worker_id) const; void EnqueueUUIDRequest(std::string oper, std::string obj_type, std::string uuid_str); @@ -164,6 +179,20 @@ class ConfigCassandraClient : public ConfigDbClient { virtual void InvalidateFQNameCache(const std::string &uuid); void PurgeFQNameCache(const std::string &uuid); + virtual bool UUIDToFQNameShow(const std::string &uuid, + ConfigDBFQNameCacheEntry &entry) const; + + virtual bool UUIDToFQNameShow(const std::string &start_uuid, + uint32_t num_entries, + std::vector &entries) const; + + virtual bool UUIDToObjCacheShow(int inst_num, const std::string &uuid, + ConfigDBUUIDCacheEntry &entry) const; + + virtual bool UUIDToObjCacheShow(int inst_num, const std::string &start_uuid, + uint32_t num_entries, + std::vector &entries) const; + protected: typedef std::pair ObjTypeUUIDType; typedef std::list ObjTypeUUIDList; @@ -233,6 +262,8 @@ class ConfigCassandraClient : public ConfigDbClient { std::string *last_column); void HandleCassandraConnectionStatus(bool success); + void FillFQNameCacheInfo(const std::string &uuid, + FQNameCacheMap::const_iterator it, ConfigDBFQNameCacheEntry &entry) const; ConfigClientManager *mgr_; EventManager *evm_; diff --git a/src/ifmap/client/config_db_client.h b/src/ifmap/client/config_db_client.h index 32e8b2eb592..c182a8a4608 100644 --- a/src/ifmap/client/config_db_client.h +++ b/src/ifmap/client/config_db_client.h @@ -13,6 +13,8 @@ struct IFMapConfigOptions; struct ConfigDBConnInfo; +struct ConfigDBFQNameCacheEntry; +struct ConfigDBUUIDCacheEntry; /* * This is the base class for interactions with a database that stores the user * configuration. @@ -35,9 +37,20 @@ class ConfigDbClient { virtual void AddFQNameCache(const std::string &uuid, const std::string &obj_type, const std::string &fq_name) = 0; virtual void InvalidateFQNameCache(const std::string &uuid) = 0; + virtual bool UUIDToFQNameShow(const std::string &uuid, + ConfigDBFQNameCacheEntry &entry) const = 0; + virtual bool UUIDToFQNameShow(const std::string &start_uuid, + uint32_t num_entries, + std::vector &entries) const = 0; virtual void GetConnectionInfo(ConfigDBConnInfo &status) const = 0; + virtual bool UUIDToObjCacheShow(int inst_num, const std::string &uuid, + ConfigDBUUIDCacheEntry &entry) const = 0; + virtual bool UUIDToObjCacheShow(int inst_num, const std::string &start_uuid, + uint32_t num_entries, + std::vector &entries) const = 0; + private: std::string config_db_user_; std::string config_db_password_; diff --git a/src/ifmap/client/test/config_json_parser_test.cc b/src/ifmap/client/test/config_json_parser_test.cc index b42902f4258..8dbb300a2b7 100644 --- a/src/ifmap/client/test/config_json_parser_test.cc +++ b/src/ifmap/client/test/config_json_parser_test.cc @@ -6,6 +6,7 @@ #include "ifmap/ifmap_sandesh_context.h" #include +#include #include #include "base/logging.h" @@ -20,6 +21,8 @@ #include "ifmap/ifmap_node.h" #include "ifmap/ifmap_origin.h" #include "ifmap/ifmap_server.h" +#include "ifmap/ifmap_server_show_types.h" +#include "ifmap/ifmap_server_show_internal_types.h" #include "ifmap/test/config_cassandra_client_test.h" #include "ifmap/test/ifmap_test_util.h" #include "io/test/event_manager_test.h" @@ -29,8 +32,42 @@ #include "testing/gunit.h" using namespace std; +using boost::assign::list_of; class ConfigJsonParserTest : public ::testing::Test { +public: + void ValidateFQNameCacheResponse(Sandesh *sandesh, + vector &result, const string &next_batch) { + const ConfigDBUUIDToFQNameResp *resp = + dynamic_cast(sandesh); + TASK_UTIL_EXPECT_TRUE(resp != NULL); + TASK_UTIL_EXPECT_EQ(result.size(), resp->get_fqname_cache().size()); + TASK_UTIL_EXPECT_EQ(next_batch, resp->get_next_batch()); + for (size_t i = 0; i < resp->get_fqname_cache().size(); ++i) { + string result_match = resp->get_fqname_cache()[i].get_obj_type() + + ':' + resp->get_fqname_cache()[i].get_fq_name(); + TASK_UTIL_EXPECT_EQ(result[i], result_match); + cout << resp->get_fqname_cache()[i].log() << endl; + } + validate_done_ = true; + } + + void ValidateObjCacheResponse(Sandesh *sandesh, + vector &result, const string &next_batch) { + const ConfigDBUUIDCacheResp *resp = + dynamic_cast(sandesh); + TASK_UTIL_EXPECT_TRUE(resp != NULL); + TASK_UTIL_EXPECT_EQ(result.size(), resp->get_uuid_cache().size()); + TASK_UTIL_EXPECT_EQ(next_batch, resp->get_next_batch()); + for (size_t i = 0; i < resp->get_uuid_cache().size(); ++i) { + TASK_UTIL_EXPECT_EQ(result[i], + resp->get_uuid_cache()[i].get_uuid()); + cout << resp->get_uuid_cache()[i].log() << endl; + } + validate_done_ = true; + } + + protected: ConfigJsonParserTest() : thread_(&evm_), @@ -38,10 +75,13 @@ class ConfigJsonParserTest : public ::testing::Test { ifmap_server_(new IFMapServer(&db_, &graph_, evm_.io_service())), config_client_manager_(new ConfigClientManager(&evm_, ifmap_server_.get(), "localhost", "config-test", config_options_)), - ifmap_sandesh_context_(new IFMapSandeshContext(ifmap_server_.get())) { + ifmap_sandesh_context_(new IFMapSandeshContext(ifmap_server_.get())), + validate_done_(false) { + ifmap_server_->set_config_manager(config_client_manager_.get()); } void SandeshSetup() { + Sandesh::set_module_context("IFMap", ifmap_sandesh_context_.get()); if (!getenv("CONFIG_JSON_PARSER_TEST_INTROSPECT")) return; int port = @@ -50,7 +90,6 @@ class ConfigJsonParserTest : public ::testing::Test { port = 5910; boost::system::error_code error; string hostname(boost::asio::ip::host_name(error)); - Sandesh::set_module_context("IFMap", ifmap_sandesh_context_.get()); Sandesh::InitGenerator("ConfigJsonParserTest", hostname, "IFMapTest", "Test", &evm_, port, ifmap_sandesh_context_.get()); std::cout << "Introspect at http://localhost:" << Sandesh::http_port() @@ -72,6 +111,7 @@ class ConfigJsonParserTest : public ::testing::Test { bgp_schema_JsonParserInit(config_client_manager_->config_json_parser()); bgp_schema_Server_ModuleInit(&db_, &graph_); SandeshSetup(); + thread_.Start(); task_util::WaitForIdle(); } @@ -117,6 +157,7 @@ class ConfigJsonParserTest : public ::testing::Test { boost::scoped_ptr ifmap_server_; boost::scoped_ptr config_client_manager_; boost::scoped_ptr ifmap_sandesh_context_; + bool validate_done_; }; TEST_F(ConfigJsonParserTest, BulkSync) { @@ -147,6 +188,272 @@ TEST_F(ConfigJsonParserTest, ServerParserAddInOneShot) { TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); } +// Verify introspect for FQName cache +TEST_F(ConfigJsonParserTest, IntrospectVerify_FQNameCache) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector fq_name_expected_entries = list_of("virtual_network:vn1") + ("virtual_network:vn2") + ("virtual_network:vn3"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateFQNameCacheResponse, this, + _1, fq_name_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDToFQNameReq *req = new ConfigDBUUIDToFQNameReq; + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for FQName cache - Given valid uuid +TEST_F(ConfigJsonParserTest, IntrospectVerify_FQNameCache_SpecificUUID) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector fq_name_expected_entries = list_of("virtual_network:vn1"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateFQNameCacheResponse, this, + _1, fq_name_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDToFQNameReq *req = new ConfigDBUUIDToFQNameReq; + req->set_uuid("634ae160-d3ef-4e81-b58d-d196211eb4d9"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for FQName cache - Given invalid uuid +TEST_F(ConfigJsonParserTest, IntrospectVerify_FQNameCache_InvalidUUID) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector fq_name_expected_entries; + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateFQNameCacheResponse, this, + _1, fq_name_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDToFQNameReq *req = new ConfigDBUUIDToFQNameReq; + req->set_uuid("deadbeef-dead-beef-dead-beefdeaddead"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for FQName cache - Request iterate +TEST_F(ConfigJsonParserTest, IntrospectVerify_FQNameCache_ReqIterate) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector fq_name_expected_entries = list_of("virtual_network:vn2") + ("virtual_network:vn3"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateFQNameCacheResponse, this, + _1, fq_name_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDToFQNameReqIterate *req = new ConfigDBUUIDToFQNameReqIterate; + req->set_uuid_info("634ae160-d3ef-4e81-b58d-d196211eb4d9"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for FQName cache - Request iterate with deleted object +// The upper bound on the deleted uuid should return remaining valid entries +TEST_F(ConfigJsonParserTest, IntrospectVerify_FQNameCache_ReqIterate_Deleted) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector fq_name_expected_entries = list_of("virtual_network:vn1") + ("virtual_network:vn2") + ("virtual_network:vn3"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateFQNameCacheResponse, this, + _1, fq_name_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDToFQNameReqIterate *req = new ConfigDBUUIDToFQNameReqIterate; + req->set_uuid_info("00000000-0000-0000-0000-000000000001"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for Object cache +TEST_F(ConfigJsonParserTest, IntrospectVerify_ObjectCache) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector obj_cache_expected_entries = + list_of("634ae160-d3ef-4e81-b58d-d196211eb4d9") + ("634ae160-d3ef-4e82-b58d-d196211eb4da") + ("634ae160-d3ef-4e83-b58d-d196211eb4db"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateObjCacheResponse, this, + _1, obj_cache_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDCacheReq *req = new ConfigDBUUIDCacheReq; + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for Object cache - Specific valid UUID +TEST_F(ConfigJsonParserTest, IntrospectVerify_ObjectCache_SpecificUUID) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector obj_cache_expected_entries = + list_of("634ae160-d3ef-4e81-b58d-d196211eb4d9"); + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateObjCacheResponse, this, + _1, obj_cache_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDCacheReq *req = new ConfigDBUUIDCacheReq; + req->set_uuid("634ae160-d3ef-4e81-b58d-d196211eb4d9"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for Object cache - Specific UUID (invalid) +TEST_F(ConfigJsonParserTest, IntrospectVerify_ObjectCache_InvalidUUID) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector obj_cache_expected_entries; + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateObjCacheResponse, this, + _1, obj_cache_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDCacheReq *req = new ConfigDBUUIDCacheReq; + req->set_uuid("deadbeef-dead-beef-dead-beefdeaddead"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for Object cache - Request iterate +TEST_F(ConfigJsonParserTest, IntrospectVerify_ObjectCache_ReqIterate) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector obj_cache_expected_entries = + list_of("634ae160-d3ef-4e82-b58d-d196211eb4da") + ("634ae160-d3ef-4e83-b58d-d196211eb4db"); + + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateObjCacheResponse, this, + _1, obj_cache_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDCacheReqIterate *req = new ConfigDBUUIDCacheReqIterate; + req->set_uuid_info("634ae160-d3ef-4e81-b58d-d196211eb4d9"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + +// Verify introspect for Object cache - Request iterate with deleted object +// upper_bound should return rest of the UUID in the list +TEST_F(ConfigJsonParserTest, IntrospectVerify_ObjectCache_ReqIterate_Deleted) { + ParseEventsJson("controller/src/ifmap/testdata/server_parser_test01.json"); + FeedEventsJson(); + + IFMapTable *table = IFMapTable::FindTable(&db_, "virtual-network"); + TASK_UTIL_EXPECT_EQ(3, table->Size()); + + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn1") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn2") != NULL); + TASK_UTIL_EXPECT_TRUE(NodeLookup("virtual-network", "vn3") != NULL); + + string next_batch; + vector obj_cache_expected_entries = + list_of("634ae160-d3ef-4e81-b58d-d196211eb4d9") + ("634ae160-d3ef-4e82-b58d-d196211eb4da") + ("634ae160-d3ef-4e83-b58d-d196211eb4db"); + + Sandesh::set_response_callback(boost::bind( + &ConfigJsonParserTest::ValidateObjCacheResponse, this, + _1, obj_cache_expected_entries, next_batch)); + validate_done_ = false; + ConfigDBUUIDCacheReqIterate *req = new ConfigDBUUIDCacheReqIterate; + req->set_uuid_info("000000-0000-0000-0000-000000000001"); + req->HandleRequest(); + req->Release(); + TASK_UTIL_EXPECT_TRUE(validate_done_); +} + // In a multiple messages, adds (vn1, vn2), and vn3. TEST_F(ConfigJsonParserTest, ServerParserAddInMultipleShots) { ParseEventsJson( diff --git a/src/ifmap/ifmap_server_show.cc b/src/ifmap/ifmap_server_show.cc index b8133a3914f..9b7d86517f0 100644 --- a/src/ifmap/ifmap_server_show.cc +++ b/src/ifmap/ifmap_server_show.cc @@ -16,6 +16,9 @@ #include "db/db_table_partition.h" #include "base/bitset.h" +#include "ifmap/client/config_client_manager.h" +#include "ifmap/client/config_db_client.h" + #include "ifmap/ifmap_client.h" #include "ifmap/ifmap_exporter.h" #include "ifmap/ifmap_link.h" @@ -1948,3 +1951,411 @@ void IFMapNodeTableListShowReq::HandleRequest() const { RequestPipeline rp(ps); } +class ShowConfigDBUUIDCache { +public: + static const uint32_t kMaxElementsPerRound = 50; + + struct ShowData : public RequestPipeline::InstData { + vector send_buffer; + }; + + static RequestPipeline::InstData *AllocBuffer(int stage) { + return static_cast(new ShowData); + } + + static bool BufferStageCommon(const ConfigDBUUIDCacheReq *request, + int instNum, RequestPipeline::InstData *data, + const string &last_uuid); + static bool BufferStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static void SendStageCommon(const ConfigDBUUIDCacheReq *request, + const RequestPipeline::PipeSpec ps, + ConfigDBUUIDCacheResp *response); + static bool SendStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data); + static bool SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool SortList(const ConfigDBUUIDCacheEntry& lhs, + const ConfigDBUUIDCacheEntry& rhs); +}; + +bool ShowConfigDBUUIDCache::SortList( + const ConfigDBUUIDCacheEntry& lhs, + const ConfigDBUUIDCacheEntry& rhs) { + BOOL_KEY_COMPARE(lhs.uuid, rhs.uuid); + return false; +} + +bool ShowConfigDBUUIDCache::BufferStageCommon(const ConfigDBUUIDCacheReq *req, + int instNum, RequestPipeline::InstData *data, const string &last_uuid) { + IFMapSandeshContext *sctx = + static_cast(req->module_context("IFMap")); + ConfigClientManager *ccmgr = sctx->ifmap_server()->get_config_manager(); + ShowData *show_data = static_cast(data); + show_data->send_buffer.reserve(kMaxElementsPerRound); + if (req->get_uuid().length()) { + ConfigDBUUIDCacheEntry entry; + if (!ccmgr->config_db_client()->UUIDToObjCacheShow(instNum, + req->get_uuid(), entry)) { + return true; + } + show_data->send_buffer.push_back(entry); + return true; + } else { + ccmgr->config_db_client()->UUIDToObjCacheShow(instNum, last_uuid, + kMaxElementsPerRound, show_data->send_buffer); + return true; + } +} + +bool ShowConfigDBUUIDCache::BufferStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDCacheReq *request = + static_cast(ps.snhRequest_.get()); + string last_uuid; + return BufferStageCommon(request, instNum, data, last_uuid); +} + +bool ShowConfigDBUUIDCache::BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDCacheReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + ConfigDBUUIDCacheReq *request = new ConfigDBUUIDCacheReq; + request->set_context(request_iterate->context()); + string last_uuid = request_iterate->get_uuid_info(); + BufferStageCommon(request, instNum, data, last_uuid); + request->Release(); + return true; +} + +void ShowConfigDBUUIDCache::SendStageCommon(const ConfigDBUUIDCacheReq *request, + const RequestPipeline::PipeSpec ps, + ConfigDBUUIDCacheResp *response) { + const RequestPipeline::StageData *prev_stage_data = ps.GetStageData(0); + + vector uuid_cache_list; + for (size_t i = 0; i < prev_stage_data->size(); ++i) { + const ShowConfigDBUUIDCache::ShowData &show_data = static_cast + (prev_stage_data->at(i)); + if (show_data.send_buffer.size()) { + size_t list_size = uuid_cache_list.size(); + uuid_cache_list.reserve(list_size + show_data.send_buffer.size()); + copy(show_data.send_buffer.begin(), + show_data.send_buffer.end(), + std::back_inserter(uuid_cache_list)); + if (list_size) { + std::inplace_merge(uuid_cache_list.begin(), + uuid_cache_list.begin() + list_size, + uuid_cache_list.end(), + boost::bind(&ShowConfigDBUUIDCache::SortList, _1, _2)); + } + } + } + + // If we have filled the buffer, set next_batch with all the values we will + // need in the next round. + string next_batch; + if (uuid_cache_list.size() > kMaxElementsPerRound) { + vector ouput_list(uuid_cache_list.begin(), + uuid_cache_list.begin() + kMaxElementsPerRound); + response->set_uuid_cache(ouput_list); + next_batch = ouput_list.back().uuid; + } else { + response->set_uuid_cache(uuid_cache_list); + } + + response->set_next_batch(next_batch); +} + +bool ShowConfigDBUUIDCache::SendStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDCacheReq *request = + static_cast(ps.snhRequest_.get()); + ConfigDBUUIDCacheResp *response = new ConfigDBUUIDCacheResp; + SendStageCommon(request, ps, response); + response->set_context(request->context()); + response->set_more(false); + response->Response(); + return true; +} + +bool ShowConfigDBUUIDCache::SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDCacheReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + ConfigDBUUIDCacheResp *response = new ConfigDBUUIDCacheResp; + ConfigDBUUIDCacheReq *request = new ConfigDBUUIDCacheReq; + request->set_context(request_iterate->context()); + request->set_uuid(request_iterate->get_uuid_info()); + SendStageCommon(request, ps, response); + response->set_context(request->context()); + response->set_more(false); + response->Response(); + + request->Release(); + return true; +} + +void ConfigDBUUIDCacheReq::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("cassandra::Reader"); + s0.allocFn_ = ShowConfigDBUUIDCache::AllocBuffer; + s0.cbFn_ = ShowConfigDBUUIDCache::BufferStage; + for (int i = 0; i < ConfigClientManager::GetNumConfigReader(); ++i) { + s0.instances_.push_back(i); + } + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowConfigDBUUIDCache::SendStage; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} + +void ConfigDBUUIDCacheReqIterate::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("cassandra::Reader"); + s0.allocFn_ = ShowConfigDBUUIDCache::AllocBuffer; + s0.cbFn_ = ShowConfigDBUUIDCache::BufferStageIterate; + for (int i = 0; i < ConfigClientManager::GetNumConfigReader(); ++i) { + s0.instances_.push_back(i); + } + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowConfigDBUUIDCache::SendStageIterate; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} + +class ShowConfigDBUUIDToFQName { +public: + static const uint32_t kMaxElementsPerRound = 50; + + struct ShowData : public RequestPipeline::InstData { + vector send_buffer; + }; + + static RequestPipeline::InstData *AllocBuffer(int stage) { + return static_cast(new ShowData); + } + + static bool BufferStageCommon(const ConfigDBUUIDToFQNameReq *request, + RequestPipeline::InstData *data, + const string &last_uuid); + static bool BufferStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static void SendStageCommon(const ConfigDBUUIDToFQNameReq *request, + const RequestPipeline::PipeSpec ps, + ConfigDBUUIDToFQNameResp *response); + static bool SendStage(const Sandesh *sr, const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data); + static bool SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, int stage, + int instNum, RequestPipeline::InstData *data); + static bool SortList(const ConfigDBFQNameCacheEntry& lhs, + const ConfigDBFQNameCacheEntry& rhs); +}; + +bool ShowConfigDBUUIDToFQName::BufferStageCommon( + const ConfigDBUUIDToFQNameReq *request, + RequestPipeline::InstData *data, const string &last_uuid) { + IFMapSandeshContext *sctx = + static_cast(request->module_context("IFMap")); + ConfigClientManager *ccmgr = sctx->ifmap_server()->get_config_manager(); + ShowData *show_data = static_cast(data); + show_data->send_buffer.reserve(kMaxElementsPerRound); + if (request->get_uuid().length()) { + ConfigDBFQNameCacheEntry entry; + if (!ccmgr->config_db_client()->UUIDToFQNameShow(request->get_uuid(), + entry)) { + return true; + } + show_data->send_buffer.push_back(entry); + return true; + } else { + ccmgr->config_db_client()->UUIDToFQNameShow(last_uuid, + kMaxElementsPerRound, show_data->send_buffer); + return true; + } +} + +bool ShowConfigDBUUIDToFQName::BufferStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDToFQNameReq *request = + static_cast(ps.snhRequest_.get()); + string last_uuid; + return BufferStageCommon(request, data, last_uuid); +} + +bool ShowConfigDBUUIDToFQName::BufferStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDToFQNameReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + ConfigDBUUIDToFQNameReq *request = new ConfigDBUUIDToFQNameReq; + request->set_context(request_iterate->context()); + string last_uuid = request_iterate->get_uuid_info(); + BufferStageCommon(request, data, last_uuid); + request->Release(); + return true; +} + +bool ShowConfigDBUUIDToFQName::SortList( + const ConfigDBFQNameCacheEntry& lhs, + const ConfigDBFQNameCacheEntry& rhs) { + BOOL_KEY_COMPARE(lhs.uuid, rhs.uuid); + return false; +} + +void ShowConfigDBUUIDToFQName::SendStageCommon( + const ConfigDBUUIDToFQNameReq *request, + const RequestPipeline::PipeSpec ps, + ConfigDBUUIDToFQNameResp *response) { + const RequestPipeline::StageData *prev_stage_data = ps.GetStageData(0); + + vector fq_name_cache_list; + const ShowConfigDBUUIDToFQName::ShowData &show_data = static_cast + (prev_stage_data->at(0)); + if (show_data.send_buffer.size()) { + size_t list_size = fq_name_cache_list.size(); + fq_name_cache_list.reserve(list_size + show_data.send_buffer.size()); + copy(show_data.send_buffer.begin(), show_data.send_buffer.end(), + std::back_inserter(fq_name_cache_list)); + if (list_size) { + std::inplace_merge(fq_name_cache_list.begin(), + fq_name_cache_list.begin() + list_size, + fq_name_cache_list.end(), + boost::bind(&ShowConfigDBUUIDToFQName::SortList, _1, _2)); + } + } + + // If we have filled the buffer, set next_batch with all the values we will + // need in the next round. + string next_batch; + if (fq_name_cache_list.size() == kMaxElementsPerRound) { + next_batch = fq_name_cache_list.back().uuid; + } + + response->set_fqname_cache(fq_name_cache_list); + response->set_next_batch(next_batch); +} + +bool ShowConfigDBUUIDToFQName::SendStage(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDToFQNameReq *request = + static_cast(ps.snhRequest_.get()); + ConfigDBUUIDToFQNameResp *response = new ConfigDBUUIDToFQNameResp; + SendStageCommon(request, ps, response); + response->set_context(request->context()); + response->set_more(false); + response->Response(); + return true; +} + +bool ShowConfigDBUUIDToFQName::SendStageIterate(const Sandesh *sr, + const RequestPipeline::PipeSpec ps, + int stage, int instNum, + RequestPipeline::InstData *data) { + const ConfigDBUUIDToFQNameReqIterate *request_iterate = + static_cast(ps.snhRequest_.get()); + + ConfigDBUUIDToFQNameResp *response = new ConfigDBUUIDToFQNameResp; + ConfigDBUUIDToFQNameReq *request = new ConfigDBUUIDToFQNameReq; + request->set_context(request_iterate->context()); + request->set_uuid(request_iterate->get_uuid_info()); + SendStageCommon(request, ps, response); + response->set_context(request->context()); + response->set_more(false); + response->Response(); + + request->Release(); + return true; +} + +void ConfigDBUUIDToFQNameReq::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("cassandra::Reader"); + s0.allocFn_ = ShowConfigDBUUIDToFQName::AllocBuffer; + s0.cbFn_ = ShowConfigDBUUIDToFQName::BufferStage; + s0.instances_.push_back(0); + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowConfigDBUUIDToFQName::SendStage; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} + +void ConfigDBUUIDToFQNameReqIterate::HandleRequest() const { + + RequestPipeline::StageSpec s0, s1; + TaskScheduler *scheduler = TaskScheduler::GetInstance(); + + // 2 stages - first: gather/read, second: send + + s0.taskId_ = scheduler->GetTaskId("cassandra::Reader"); + s0.allocFn_ = ShowConfigDBUUIDToFQName::AllocBuffer; + s0.cbFn_ = ShowConfigDBUUIDToFQName::BufferStageIterate; + s0.instances_.push_back(0); + + // control-node ifmap show command task + s1.taskId_ = scheduler->GetTaskId("cn_ifmap::ShowCommand"); + s1.cbFn_ = ShowConfigDBUUIDToFQName::SendStageIterate; + s1.instances_.push_back(0); + + RequestPipeline::PipeSpec ps(this); + ps.stages_= list_of(s0)(s1); + RequestPipeline rp(ps); +} diff --git a/src/ifmap/ifmap_server_show.sandesh b/src/ifmap/ifmap_server_show.sandesh index 0e1a9a700af..0d28c4e329f 100644 --- a/src/ifmap/ifmap_server_show.sandesh +++ b/src/ifmap/ifmap_server_show.sandesh @@ -394,3 +394,42 @@ response sandesh IFMapPendingVmRegResp { 1: i32 map_count; 2: list vm_reg_map; } + +request sandesh ConfigDBUUIDToFQNameReq { + 1: string uuid; +} + +struct ConfigDBFQNameCacheEntry { + 1: string uuid; + 2: string obj_type; + 3: string fq_name; + 4: bool deleted; +} + + +response sandesh ConfigDBUUIDToFQNameResp { + 1: list fqname_cache; + 2: optional string next_batch (link="ConfigDBUUIDToFQNameReqIterate", + link_title="next_batch"); +} + +request sandesh ConfigDBUUIDCacheReq { + 1: string uuid; +} + +struct ConfigDBUUIDCacheData { + 1: string field_name; + 2: string timestamp; + 3: bool refresh; +} + +struct ConfigDBUUIDCacheEntry { + 1: string uuid; + 2: list field_list +} + +response sandesh ConfigDBUUIDCacheResp { + 1: list uuid_cache + 2: optional string next_batch (link="ConfigDBUUIDCacheReqIterate", + link_title="next_batch"); +} diff --git a/src/ifmap/ifmap_server_show_internal.sandesh b/src/ifmap/ifmap_server_show_internal.sandesh index a809ba16018..1f0fda57d90 100644 --- a/src/ifmap/ifmap_server_show_internal.sandesh +++ b/src/ifmap/ifmap_server_show_internal.sandesh @@ -18,3 +18,10 @@ request sandesh IFMapPerClientLinksShowReqIterate { 1: string link_info; } +request sandesh ConfigDBUUIDToFQNameReqIterate { + 1: string uuid_info; +} + +request sandesh ConfigDBUUIDCacheReqIterate { + 1: string uuid_info; +}