Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[21458] Add IDL format to topic entities #245

Merged
merged 6 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/fastdds_statistics_backend/StatisticsBackend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,16 @@ class StatisticsBackend
static Info get_info(
EntityId entity_id);

/**
* @brief Get the IDL representation of a data type in string format for a given topic entity
*
* @param entity_id The entity for which the data type IDL is retrieved.
* @return String object describing the entity's data type IDL.
*/
FASTDDS_STATISTICS_BACKEND_DllAPI
static std::string get_type_idl(
EntityId entity_id);

/**
* @brief Provides access to the data measured during the monitoring.
*
Expand Down
12 changes: 12 additions & 0 deletions src/cpp/StatisticsBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,18 @@ Info StatisticsBackend::get_info(
return StatisticsBackendData::get_instance()->database_->get_info(entity_id);
}

std::string StatisticsBackend::get_type_idl(
EntityId entity_id)
{
// Check if the entity is a topic
if (EntityKind::TOPIC != get_type(entity_id))
{
throw BadParameter("EntityId received does not match with a valid topic entity");
}
Info topic_info = StatisticsBackend::get_info(entity_id);
return StatisticsBackendData::get_instance()->database_->get_type_idl(topic_info[DATA_TYPE_TAG]);
}

std::vector<StatisticsData> StatisticsBackend::get_data(
DataKind data_type,
const std::vector<EntityId>& entity_ids_source,
Expand Down
40 changes: 38 additions & 2 deletions src/cpp/database/database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ EntityId Database::insert_new_topic(
std::shared_ptr<Domain> domain = std::const_pointer_cast<Domain>(
std::static_pointer_cast<const Domain>(get_entity_nts(domain_id)));

// Create the topic to insert in the database
auto topic = std::make_shared<Topic>(
name,
type_name,
Expand All @@ -279,6 +280,24 @@ EntityId Database::insert_new_topic(
return entity_id;
}

bool Database::is_type_in_database(
const std::string& type_name)
{
return (type_idls_.find(type_name) != type_idls_.end());
}

void Database::insert_new_type_idl(
const std::string& type_name,
const std::string& type_idl)
{
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
if (type_name.empty())
{
throw BadParameter("Type name cannot be empty");
}
type_idls_[type_name] = type_idl;
}

EntityId Database::insert_new_endpoint(
const std::string& endpoint_guid,
const std::string& name,
Expand Down Expand Up @@ -656,7 +675,7 @@ void Database::insert_nts(
throw BadParameter("Topic data type cannot be empty");
}

/* Check that domain exits */
/* Check that domain exists */
bool domain_exists = false;
for (const auto& domain_it : domains_)
{
Expand Down Expand Up @@ -2103,6 +2122,24 @@ std::vector<std::pair<EntityId, EntityId>> Database::get_entities_by_name_nts(
return entities;
}

std::string Database::get_type_idl(
const std::string& type_name) const
{
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
return get_type_idl_nts(type_name);
}

std::string Database::get_type_idl_nts(
const std::string& type_name) const
{
auto it = type_idls_.find(type_name);
if (it != type_idls_.end())
{
return it->second;
}
throw BadParameter("Type " + type_name + " not found in the database");
JesusPoderoso marked this conversation as resolved.
Show resolved Hide resolved
}

void Database::erase(
EntityId& domain_id)
{
Expand Down Expand Up @@ -4624,7 +4661,6 @@ DatabaseDump Database::dump_entity_(
entity_info[ALIAS_TAG] = entity->alias;
entity_info[DATA_TYPE_TAG] = entity->data_type;
entity_info[STATUS_TAG] = entity->status;

entity_info[DOMAIN_ENTITY_TAG] = id_to_string(entity->domain->id);

// metatraffic and active attributes are stored but ignored when loading
Expand Down
46 changes: 46 additions & 0 deletions src/cpp/database/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,24 @@ class Database
const std::string& alias,
const EntityId& domain_id);

/**
* @brief Check if a Topic data type is already in the database
* @param type_name The type name of the Topic.
*
* @return True if the Topic data type is in the database.
*/
bool is_type_in_database(
const std::string& type_name);

/**
* @brief Insert a new type IDL into the database.
* @param topic_type The type of the topic.
* @param topic_idl The IDL representation of the type
*/
void insert_new_type_idl(
const std::string& topic_type,
const std::string& topic_idl);

/**
* @brief Create new Endpoint and corresponding Locator, and insert them in database.
* @param endpoint_guid The GUID of the Endpoint.
Expand Down Expand Up @@ -444,6 +462,16 @@ class Database
EntityKind entity_kind,
const std::string& name) const;

/**
* @brief Get the type IDL of a given type name, if it exists.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The IDL representation of the type in std::string format.
*/
std::string get_type_idl(
const std::string& type_name) const;

/**
* @brief Get the entity of a given EntityKind that matches with the requested GUID.
*
Expand Down Expand Up @@ -1167,6 +1195,16 @@ class Database
EntityKind entity_kind,
const std::string& name) const;

/**
* @brief Get the type IDL of a given type name, if it exists. This method is not thread safe.
*
* @param type_name The name of the data type for which to search.
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
* @return The IDL representation of the type in std::string format.
*/
std::string get_type_idl_nts(
const std::string& type_name) const;

/**
* @brief Get the entity of a given EntityKind that matches with the requested GUID. This method is not thread safe.
*
Expand Down Expand Up @@ -1446,6 +1484,14 @@ class Database
*/
std::map<EntityId, std::map<EntityId, std::shared_ptr<Topic>>> topics_;

/**
* Collection of topic IDLs sorted by topic data types, with which they are biunivocally identified.
* This is used to store the IDLs of the discovered topics
*
* Each value in the collection is in turn a map of the actual Topic IDLs sorted by data type
*/
std::map<std::string, std::string> type_idls_;

//! Graph map describing per domain complete topology of the entities.
std::map<EntityId, Graph> domain_view_graph;

Expand Down
6 changes: 6 additions & 0 deletions src/cpp/database/database_queue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,12 @@ EntityId DatabaseEntityQueue::process_endpoint_discovery(
details::StatisticsBackendData::DiscoveryStatus::DISCOVERY);
}

// Store type IDL in the database if available and in case it is not already stored. Ignore metatraffic topics
if (!database_->is_type_in_database(info.type_name) && !info.is_virtual_metatraffic)
{
database_->insert_new_type_idl(info.type_name, info.type_idl);
}

// Create the endpoint
EntityId endpoint_id;
std::stringstream name;
Expand Down
4 changes: 2 additions & 2 deletions src/cpp/database/database_queue.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
#include <fastdds/rtps/common/SequenceNumber.hpp>
#include <fastdds/rtps/common/RemoteLocators.hpp>
#include <fastdds/dds/log/Log.hpp>

#include <fastdds_statistics_backend/types/JSONTags.h>

#include <database/database.hpp>
Expand Down Expand Up @@ -372,9 +371,10 @@ struct EntityDiscoveryInfo
std::string user;
std::string process;

// Enpoint data
// Endpoint data
std::string topic_name;
std::string type_name;
std::string type_idl;
fastdds::rtps::RemoteLocatorList locators;

// Alias
Expand Down
56 changes: 55 additions & 1 deletion src/cpp/subscriber/StatisticsParticipantListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@

#include <fastdds/dds/core/status/StatusMask.hpp>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/domain/DomainParticipantListener.hpp>
#include <fastdds/dds/log/Log.hpp>
#include <fastdds/rtps/writer/WriterDiscoveryStatus.hpp>
#include <fastdds/dds/xtypes/dynamic_types/DynamicTypeBuilder.hpp>
#include <fastdds/dds/xtypes/dynamic_types/DynamicTypeBuilderFactory.hpp>
#include <fastdds/dds/xtypes/utils.hpp>
#include <fastdds/rtps/common/EntityId_t.hpp>
#include <fastdds/rtps/writer/WriterDiscoveryStatus.hpp>

#include "database/database_queue.hpp"
#include "subscriber/QosSerializer.hpp"
Expand Down Expand Up @@ -318,6 +322,31 @@ void StatisticsParticipantListener::on_data_reader_discovery(
}
}

// In case of a new data reader discovered, add type info if available
if (ReaderDiscoveryStatus::DISCOVERED_READER == reason && info.type_information.assigned() == true)
{
// Create IDL representation of the discovered type
// Get remote type information
xtypes::TypeObject remote_type_object;
if (RETCODE_OK != DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
info.type_information.type_information.complete().typeid_with_size().type_id(),
remote_type_object))
{
EPROSIMA_LOG_ERROR(STATISTICS_PARTICIPANT_LISTENER,
"Error getting type object for type " << info.type_name);
return;
}

// Build remotely discovered type
DynamicType::_ref_type remote_type = DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(
remote_type_object)->build();

// Serialize DynamicType into its IDL representation
std::stringstream idl;
idl_serialize(remote_type, idl);
discovery_info.type_idl = idl.str();
}

entity_queue_->push(timestamp, discovery_info);

// Wait until the entity queue is processed and restart the data queues
Expand Down Expand Up @@ -376,6 +405,31 @@ void StatisticsParticipantListener::on_data_writer_discovery(
}
}

// In case of a new data writer discovered, add type info if available
if (WriterDiscoveryStatus::DISCOVERED_WRITER == reason && info.type_information.assigned() == true)
{
// Create IDL representation of the discovered type
// Get remote type information
xtypes::TypeObject remote_type_object;
if (RETCODE_OK != DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
info.type_information.type_information.complete().typeid_with_size().type_id(),
remote_type_object))
{
EPROSIMA_LOG_ERROR(STATISTICS_PARTICIPANT_LISTENER,
"Error getting type object for type " << info.type_name);
return;
}

// Build remotely discovered type
DynamicType::_ref_type remote_type = DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(
remote_type_object)->build();

// Serialize DynamicType into its IDL representation
std::stringstream idl;
idl_serialize(remote_type, idl);
discovery_info.type_idl = idl.str();
}

entity_queue_->push(timestamp, discovery_info);

// Wait until the entity queue is processed and restart the data queues
Expand Down
7 changes: 7 additions & 0 deletions test/mock/database/database/database/database.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ class Database
const std::string& topic_type,
const EntityId& topic_id));

MOCK_METHOD1(is_type_in_database, bool(
const std::string& type_name));

MOCK_METHOD2(insert_new_type_idl, void(
const std::string& type_name,
const std::string& type_idl));

MOCK_METHOD4(insert_new_topic, EntityId(
const std::string& name,
const std::string& type_name,
Expand Down
17 changes: 17 additions & 0 deletions test/unittest/DatabaseQueue/DatabaseQueueTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1391,6 +1391,8 @@ TEST_F(database_queue_tests, push_datawriter)
std::make_pair(EntityId(0), EntityId(2)))));
EXPECT_CALL(database, is_topic_in_database(_, EntityId(2))).Times(AnyNumber())
.WillRepeatedly(Return(true));
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
.WillRepeatedly(Return(true));

// Datawriter undiscovery: FAILURE
{
Expand Down Expand Up @@ -1625,6 +1627,9 @@ TEST_F(database_queue_tests, push_datawriter_topic_does_not_exist)
EXPECT_CALL(database, get_entities_by_name(EntityKind::TOPIC, topic_name)).Times(AnyNumber())
.WillOnce(Return(std::vector<std::pair<EntityId, EntityId>>()));

EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
.WillRepeatedly(Return(false));

// Datawriter discovery: SUCCESS
{
// Precondition: The writer does not exist
Expand Down Expand Up @@ -1681,6 +1686,10 @@ TEST_F(database_queue_tests, push_datawriter_topic_does_not_exist)
EXPECT_CALL(database, insert_new_endpoint(_, _, _, _, _, _, _, _, _, _)).Times(1)
.WillOnce(Invoke(&insert_datawriter_args, &InsertEndpointArgs::insert));

// Expectation: Add the type to the database
EXPECT_CALL(database, is_type_in_database(type_name)).Times(1).WillOnce(Return(false));
EXPECT_CALL(database, insert_new_type_idl(type_name, "")).Times(1);

// Expectation: Modify graph and notify user
EXPECT_CALL(database, update_endpoint_in_graph(_, _, _, _)).Times(1).WillOnce(Return(true));
EXPECT_CALL(*details::StatisticsBackendData::get_instance(), on_domain_view_graph_update(_)).Times(1);
Expand Down Expand Up @@ -1746,6 +1755,8 @@ TEST_F(database_queue_tests, push_datareader)
std::make_pair(EntityId(0), EntityId(2)))));
EXPECT_CALL(database, is_topic_in_database(_, EntityId(2))).Times(AnyNumber())
.WillRepeatedly(Return(true));
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
.WillRepeatedly(Return(true));

// Datareader undiscovery: FAILURE
{
Expand Down Expand Up @@ -1979,6 +1990,8 @@ TEST_F(database_queue_tests, push_datareader_topic_does_not_exist)
// Precondition: The topic does not exist
EXPECT_CALL(database, get_entities_by_name(EntityKind::TOPIC, topic_name)).Times(AnyNumber())
.WillOnce(Return(std::vector<std::pair<EntityId, EntityId>>()));
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
.WillOnce(Return(false));

// Datareader discovery: SUCCESS
{
Expand Down Expand Up @@ -2036,6 +2049,10 @@ TEST_F(database_queue_tests, push_datareader_topic_does_not_exist)
EXPECT_CALL(database, insert_new_endpoint(_, _, _, _, _, _, _, _, _, _)).Times(1)
.WillOnce(Invoke(&insert_datareader_args, &InsertEndpointArgs::insert));

// Expectation: Add the type to the database
EXPECT_CALL(database, is_type_in_database(type_name)).Times(1).WillOnce(Return(false));
EXPECT_CALL(database, insert_new_type_idl(type_name, "")).Times(1);

// Expectation: Modify graph and notify user
EXPECT_CALL(database, update_endpoint_in_graph(_, _, _, _)).Times(1).WillOnce(Return(true));
EXPECT_CALL(*details::StatisticsBackendData::get_instance(), on_domain_view_graph_update(_)).Times(1);
Expand Down
1 change: 0 additions & 1 deletion test/unittest/StatisticsBackend/IsActiveTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,6 @@ TEST_F(is_active_tests, discover_datawriter_on_inactive_domain)
// The discovered reader is in the topic
data.topic_name = topic->name;
data.type_name = topic->data_type;

// The discovered reader contains the locator
eprosima::fastdds::rtps::Locator_t dds_existing_unicast_locator(LOCATOR_KIND_UDPv4, 1024);
dds_existing_unicast_locator.address[12] = 127;
Expand Down
Loading
Loading