Skip to content

Commit 2484640

Browse files
Add IDL format to topic entities (#245)
* Refs #21458: Add type IDL to Topic info json [WORK IN PROGRESS] Signed-off-by: Carlosespicur <[email protected]> * Refs #21458: Add IDL getter for Monitor controller communication Signed-off-by: Carlosespicur <[email protected]> * Refs #21458: Delete Topic IDLs in topic info JSON Signed-off-by: Carlosespicur <[email protected]> * Refs #21458: Uncrustify Signed-off-by: Carlosespicur <[email protected]> * Refs #21458: Fix tests and idl serialization in callbacks Signed-off-by: Carlosespicur <[email protected]> * Refs #21458: Add review changes Signed-off-by: Carlosespicur <[email protected]> --------- Signed-off-by: Carlosespicur <[email protected]>
1 parent cdc0284 commit 2484640

File tree

11 files changed

+271
-6
lines changed

11 files changed

+271
-6
lines changed

include/fastdds_statistics_backend/StatisticsBackend.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ class StatisticsBackend
263263
static Info get_info(
264264
EntityId entity_id);
265265

266+
/**
267+
* @brief Get the IDL representation of a data type in string format for a given topic entity
268+
*
269+
* @param entity_id The entity for which the data type IDL is retrieved.
270+
* @return String object describing the entity's data type IDL.
271+
*/
272+
FASTDDS_STATISTICS_BACKEND_DllAPI
273+
static std::string get_type_idl(
274+
EntityId entity_id);
275+
266276
/**
267277
* @brief Provides access to the data measured during the monitoring.
268278
*

src/cpp/StatisticsBackend.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,18 @@ Info StatisticsBackend::get_info(
537537
return StatisticsBackendData::get_instance()->database_->get_info(entity_id);
538538
}
539539

540+
std::string StatisticsBackend::get_type_idl(
541+
EntityId entity_id)
542+
{
543+
// Check if the entity is a topic
544+
if (EntityKind::TOPIC != get_type(entity_id))
545+
{
546+
throw BadParameter("EntityId received does not match with a valid topic entity");
547+
}
548+
Info topic_info = StatisticsBackend::get_info(entity_id);
549+
return StatisticsBackendData::get_instance()->database_->get_type_idl(topic_info[DATA_TYPE_TAG]);
550+
}
551+
540552
std::vector<StatisticsData> StatisticsBackend::get_data(
541553
DataKind data_type,
542554
const std::vector<EntityId>& entity_ids_source,

src/cpp/database/database.cpp

+38-2
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ EntityId Database::insert_new_topic(
264264
std::shared_ptr<Domain> domain = std::const_pointer_cast<Domain>(
265265
std::static_pointer_cast<const Domain>(get_entity_nts(domain_id)));
266266

267+
// Create the topic to insert in the database
267268
auto topic = std::make_shared<Topic>(
268269
name,
269270
type_name,
@@ -279,6 +280,24 @@ EntityId Database::insert_new_topic(
279280
return entity_id;
280281
}
281282

283+
bool Database::is_type_in_database(
284+
const std::string& type_name)
285+
{
286+
return (type_idls_.find(type_name) != type_idls_.end());
287+
}
288+
289+
void Database::insert_new_type_idl(
290+
const std::string& type_name,
291+
const std::string& type_idl)
292+
{
293+
std::lock_guard<std::shared_timed_mutex> guard(mutex_);
294+
if (type_name.empty())
295+
{
296+
throw BadParameter("Type name cannot be empty");
297+
}
298+
type_idls_[type_name] = type_idl;
299+
}
300+
282301
EntityId Database::insert_new_endpoint(
283302
const std::string& endpoint_guid,
284303
const std::string& name,
@@ -656,7 +675,7 @@ void Database::insert_nts(
656675
throw BadParameter("Topic data type cannot be empty");
657676
}
658677

659-
/* Check that domain exits */
678+
/* Check that domain exists */
660679
bool domain_exists = false;
661680
for (const auto& domain_it : domains_)
662681
{
@@ -2103,6 +2122,24 @@ std::vector<std::pair<EntityId, EntityId>> Database::get_entities_by_name_nts(
21032122
return entities;
21042123
}
21052124

2125+
std::string Database::get_type_idl(
2126+
const std::string& type_name) const
2127+
{
2128+
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
2129+
return get_type_idl_nts(type_name);
2130+
}
2131+
2132+
std::string Database::get_type_idl_nts(
2133+
const std::string& type_name) const
2134+
{
2135+
auto it = type_idls_.find(type_name);
2136+
if (it != type_idls_.end())
2137+
{
2138+
return it->second;
2139+
}
2140+
throw BadParameter("Type " + type_name + " not found in the database");
2141+
}
2142+
21062143
void Database::erase(
21072144
EntityId& domain_id)
21082145
{
@@ -4624,7 +4661,6 @@ DatabaseDump Database::dump_entity_(
46244661
entity_info[ALIAS_TAG] = entity->alias;
46254662
entity_info[DATA_TYPE_TAG] = entity->data_type;
46264663
entity_info[STATUS_TAG] = entity->status;
4627-
46284664
entity_info[DOMAIN_ENTITY_TAG] = id_to_string(entity->domain->id);
46294665

46304666
// metatraffic and active attributes are stored but ignored when loading

src/cpp/database/database.hpp

+46
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,24 @@ class Database
156156
const std::string& alias,
157157
const EntityId& domain_id);
158158

159+
/**
160+
* @brief Check if a Topic data type is already in the database
161+
* @param type_name The type name of the Topic.
162+
*
163+
* @return True if the Topic data type is in the database.
164+
*/
165+
bool is_type_in_database(
166+
const std::string& type_name);
167+
168+
/**
169+
* @brief Insert a new type IDL into the database.
170+
* @param topic_type The type of the topic.
171+
* @param topic_idl The IDL representation of the type
172+
*/
173+
void insert_new_type_idl(
174+
const std::string& topic_type,
175+
const std::string& topic_idl);
176+
159177
/**
160178
* @brief Create new Endpoint and corresponding Locator, and insert them in database.
161179
* @param endpoint_guid The GUID of the Endpoint.
@@ -444,6 +462,16 @@ class Database
444462
EntityKind entity_kind,
445463
const std::string& name) const;
446464

465+
/**
466+
* @brief Get the type IDL of a given type name, if it exists.
467+
*
468+
* @param type_name The name of the data type for which to search.
469+
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
470+
* @return The IDL representation of the type in std::string format.
471+
*/
472+
std::string get_type_idl(
473+
const std::string& type_name) const;
474+
447475
/**
448476
* @brief Get the entity of a given EntityKind that matches with the requested GUID.
449477
*
@@ -1167,6 +1195,16 @@ class Database
11671195
EntityKind entity_kind,
11681196
const std::string& name) const;
11691197

1198+
/**
1199+
* @brief Get the type IDL of a given type name, if it exists. This method is not thread safe.
1200+
*
1201+
* @param type_name The name of the data type for which to search.
1202+
* @throws eprosima::statistics_backend::BadParameter if \c type_name does not exist in the database.
1203+
* @return The IDL representation of the type in std::string format.
1204+
*/
1205+
std::string get_type_idl_nts(
1206+
const std::string& type_name) const;
1207+
11701208
/**
11711209
* @brief Get the entity of a given EntityKind that matches with the requested GUID. This method is not thread safe.
11721210
*
@@ -1446,6 +1484,14 @@ class Database
14461484
*/
14471485
std::map<EntityId, std::map<EntityId, std::shared_ptr<Topic>>> topics_;
14481486

1487+
/**
1488+
* Collection of topic IDLs sorted by topic data types, with which they are biunivocally identified.
1489+
* This is used to store the IDLs of the discovered topics
1490+
*
1491+
* Each value in the collection is in turn a map of the actual Topic IDLs sorted by data type
1492+
*/
1493+
std::map<std::string, std::string> type_idls_;
1494+
14491495
//! Graph map describing per domain complete topology of the entities.
14501496
std::map<EntityId, Graph> domain_view_graph;
14511497

src/cpp/database/database_queue.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ EntityId DatabaseEntityQueue::process_endpoint_discovery(
356356
details::StatisticsBackendData::DiscoveryStatus::DISCOVERY);
357357
}
358358

359+
// Store type IDL in the database if available and in case it is not already stored. Ignore metatraffic topics
360+
if (!database_->is_type_in_database(info.type_name) && !info.is_virtual_metatraffic)
361+
{
362+
database_->insert_new_type_idl(info.type_name, info.type_idl);
363+
}
364+
359365
// Create the endpoint
360366
EntityId endpoint_id;
361367
std::stringstream name;

src/cpp/database/database_queue.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#include <fastdds/rtps/common/SequenceNumber.hpp>
3333
#include <fastdds/rtps/common/RemoteLocators.hpp>
3434
#include <fastdds/dds/log/Log.hpp>
35-
3635
#include <fastdds_statistics_backend/types/JSONTags.h>
3736

3837
#include <database/database.hpp>
@@ -372,9 +371,10 @@ struct EntityDiscoveryInfo
372371
std::string user;
373372
std::string process;
374373

375-
// Enpoint data
374+
// Endpoint data
376375
std::string topic_name;
377376
std::string type_name;
377+
std::string type_idl;
378378
fastdds::rtps::RemoteLocatorList locators;
379379

380380
// Alias

src/cpp/subscriber/StatisticsParticipantListener.cpp

+55-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@
2222

2323
#include <fastdds/dds/core/status/StatusMask.hpp>
2424
#include <fastdds/dds/domain/DomainParticipant.hpp>
25+
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
2526
#include <fastdds/dds/domain/DomainParticipantListener.hpp>
2627
#include <fastdds/dds/log/Log.hpp>
27-
#include <fastdds/rtps/writer/WriterDiscoveryStatus.hpp>
28+
#include <fastdds/dds/xtypes/dynamic_types/DynamicTypeBuilder.hpp>
29+
#include <fastdds/dds/xtypes/dynamic_types/DynamicTypeBuilderFactory.hpp>
30+
#include <fastdds/dds/xtypes/utils.hpp>
2831
#include <fastdds/rtps/common/EntityId_t.hpp>
32+
#include <fastdds/rtps/writer/WriterDiscoveryStatus.hpp>
2933

3034
#include "database/database_queue.hpp"
3135
#include "subscriber/QosSerializer.hpp"
@@ -318,6 +322,31 @@ void StatisticsParticipantListener::on_data_reader_discovery(
318322
}
319323
}
320324

325+
// In case of a new data reader discovered, add type info if available
326+
if (ReaderDiscoveryStatus::DISCOVERED_READER == reason && info.type_information.assigned() == true)
327+
{
328+
// Create IDL representation of the discovered type
329+
// Get remote type information
330+
xtypes::TypeObject remote_type_object;
331+
if (RETCODE_OK != DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
332+
info.type_information.type_information.complete().typeid_with_size().type_id(),
333+
remote_type_object))
334+
{
335+
EPROSIMA_LOG_ERROR(STATISTICS_PARTICIPANT_LISTENER,
336+
"Error getting type object for type " << info.type_name);
337+
return;
338+
}
339+
340+
// Build remotely discovered type
341+
DynamicType::_ref_type remote_type = DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(
342+
remote_type_object)->build();
343+
344+
// Serialize DynamicType into its IDL representation
345+
std::stringstream idl;
346+
idl_serialize(remote_type, idl);
347+
discovery_info.type_idl = idl.str();
348+
}
349+
321350
entity_queue_->push(timestamp, discovery_info);
322351

323352
// Wait until the entity queue is processed and restart the data queues
@@ -376,6 +405,31 @@ void StatisticsParticipantListener::on_data_writer_discovery(
376405
}
377406
}
378407

408+
// In case of a new data writer discovered, add type info if available
409+
if (WriterDiscoveryStatus::DISCOVERED_WRITER == reason && info.type_information.assigned() == true)
410+
{
411+
// Create IDL representation of the discovered type
412+
// Get remote type information
413+
xtypes::TypeObject remote_type_object;
414+
if (RETCODE_OK != DomainParticipantFactory::get_instance()->type_object_registry().get_type_object(
415+
info.type_information.type_information.complete().typeid_with_size().type_id(),
416+
remote_type_object))
417+
{
418+
EPROSIMA_LOG_ERROR(STATISTICS_PARTICIPANT_LISTENER,
419+
"Error getting type object for type " << info.type_name);
420+
return;
421+
}
422+
423+
// Build remotely discovered type
424+
DynamicType::_ref_type remote_type = DynamicTypeBuilderFactory::get_instance()->create_type_w_type_object(
425+
remote_type_object)->build();
426+
427+
// Serialize DynamicType into its IDL representation
428+
std::stringstream idl;
429+
idl_serialize(remote_type, idl);
430+
discovery_info.type_idl = idl.str();
431+
}
432+
379433
entity_queue_->push(timestamp, discovery_info);
380434

381435
// Wait until the entity queue is processed and restart the data queues

test/mock/database/database/database/database.hpp

+7
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ class Database
7979
const std::string& topic_type,
8080
const EntityId& topic_id));
8181

82+
MOCK_METHOD1(is_type_in_database, bool(
83+
const std::string& type_name));
84+
85+
MOCK_METHOD2(insert_new_type_idl, void(
86+
const std::string& type_name,
87+
const std::string& type_idl));
88+
8289
MOCK_METHOD4(insert_new_topic, EntityId(
8390
const std::string& name,
8491
const std::string& type_name,

test/unittest/DatabaseQueue/DatabaseQueueTests.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,8 @@ TEST_F(database_queue_tests, push_datawriter)
13911391
std::make_pair(EntityId(0), EntityId(2)))));
13921392
EXPECT_CALL(database, is_topic_in_database(_, EntityId(2))).Times(AnyNumber())
13931393
.WillRepeatedly(Return(true));
1394+
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
1395+
.WillRepeatedly(Return(true));
13941396

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

1630+
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
1631+
.WillRepeatedly(Return(false));
1632+
16281633
// Datawriter discovery: SUCCESS
16291634
{
16301635
// Precondition: The writer does not exist
@@ -1681,6 +1686,10 @@ TEST_F(database_queue_tests, push_datawriter_topic_does_not_exist)
16811686
EXPECT_CALL(database, insert_new_endpoint(_, _, _, _, _, _, _, _, _, _)).Times(1)
16821687
.WillOnce(Invoke(&insert_datawriter_args, &InsertEndpointArgs::insert));
16831688

1689+
// Expectation: Add the type to the database
1690+
EXPECT_CALL(database, is_type_in_database(type_name)).Times(1).WillOnce(Return(false));
1691+
EXPECT_CALL(database, insert_new_type_idl(type_name, "")).Times(1);
1692+
16841693
// Expectation: Modify graph and notify user
16851694
EXPECT_CALL(database, update_endpoint_in_graph(_, _, _, _)).Times(1).WillOnce(Return(true));
16861695
EXPECT_CALL(*details::StatisticsBackendData::get_instance(), on_domain_view_graph_update(_)).Times(1);
@@ -1746,6 +1755,8 @@ TEST_F(database_queue_tests, push_datareader)
17461755
std::make_pair(EntityId(0), EntityId(2)))));
17471756
EXPECT_CALL(database, is_topic_in_database(_, EntityId(2))).Times(AnyNumber())
17481757
.WillRepeatedly(Return(true));
1758+
EXPECT_CALL(database, is_type_in_database(type_name)).Times(AnyNumber())
1759+
.WillRepeatedly(Return(true));
17491760

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

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

2052+
// Expectation: Add the type to the database
2053+
EXPECT_CALL(database, is_type_in_database(type_name)).Times(1).WillOnce(Return(false));
2054+
EXPECT_CALL(database, insert_new_type_idl(type_name, "")).Times(1);
2055+
20392056
// Expectation: Modify graph and notify user
20402057
EXPECT_CALL(database, update_endpoint_in_graph(_, _, _, _)).Times(1).WillOnce(Return(true));
20412058
EXPECT_CALL(*details::StatisticsBackendData::get_instance(), on_domain_view_graph_update(_)).Times(1);

test/unittest/StatisticsBackend/IsActiveTests.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,6 @@ TEST_F(is_active_tests, discover_datawriter_on_inactive_domain)
544544
// The discovered reader is in the topic
545545
data.topic_name = topic->name;
546546
data.type_name = topic->data_type;
547-
548547
// The discovered reader contains the locator
549548
eprosima::fastdds::rtps::Locator_t dds_existing_unicast_locator(LOCATOR_KIND_UDPv4, 1024);
550549
dds_existing_unicast_locator.address[12] = 127;

0 commit comments

Comments
 (0)