LocatorSelector.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. // Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @file LocatorSelector.hpp
  16. */
  17. #ifndef _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_HPP_
  18. #define _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_HPP_
  19. #include <fastdds/rtps/common/LocatorSelectorEntry.hpp>
  20. #include <fastdds/rtps/common/Guid.h>
  21. #include <fastdds/rtps/common/Locator.h>
  22. #include <fastrtps/utils/collections/ResourceLimitedVector.hpp>
  23. #include <fastrtps/utils/IPLocator.h>
  24. #include <algorithm>
  25. namespace eprosima {
  26. namespace fastrtps {
  27. namespace rtps {
  28. /**
  29. * A class used for the efficient selection of locators when sending data to multiple entities.
  30. *
  31. * Algorithm:
  32. * - Entries are added/removed with add_entry/remove_entry when matched/unmatched.
  33. * - When data is to be sent:
  34. * - A reference to this object is passed to the message group
  35. * - For each submessage:
  36. * - A call to reset is performed
  37. * - A call to enable is performed per desired destination
  38. * - If state_has_changed() returns true:
  39. * - the message group is flushed
  40. * - selection_start is called
  41. * - for each transport:
  42. * - transport_starts is called
  43. * - transport handles the selection state of each entry
  44. * - select may be called
  45. * - Submessage is added to the message group
  46. */
  47. class LocatorSelector
  48. {
  49. public:
  50. /**
  51. * Construct a LocatorSelector.
  52. *
  53. * @param entries_allocation Allocation configuration regarding the number of remote entities.
  54. */
  55. LocatorSelector(const ResourceLimitedContainerConfig& entries_allocation)
  56. : entries_(entries_allocation)
  57. , selections_(entries_allocation)
  58. , last_state_(entries_allocation)
  59. {
  60. }
  61. /**
  62. * Clears all internal data.
  63. */
  64. void clear()
  65. {
  66. entries_.clear();
  67. selections_.clear();
  68. last_state_.clear();
  69. }
  70. /**
  71. * Add an entry to this selector.
  72. *
  73. * @param entry Pointer to the LocatorSelectorEntry to add.
  74. */
  75. bool add_entry(LocatorSelectorEntry* entry)
  76. {
  77. return entries_.push_back(entry) != nullptr;
  78. }
  79. /**
  80. * Remove an entry from this selector.
  81. * @param guid Identifier of the entry to be removed.
  82. */
  83. bool remove_entry(const GUID_t& guid)
  84. {
  85. return entries_.remove_if(
  86. [& guid](LocatorSelectorEntry* entry)
  87. {
  88. return entry->remote_guid == guid;
  89. });
  90. }
  91. /**
  92. * Reset the enabling state of the selector.
  93. *
  94. * @param enable_all Indicates whether entries should be initially enabled.
  95. */
  96. void reset(bool enable_all)
  97. {
  98. last_state_.clear();
  99. for(LocatorSelectorEntry* entry : entries_)
  100. {
  101. last_state_.push_back(entry->enabled ? 1 : 0);
  102. entry->enable(enable_all);
  103. }
  104. }
  105. /**
  106. * Enable an entry given its GUID.
  107. *
  108. * @param guid GUID of the entry to enable.
  109. */
  110. void enable(const GUID_t& guid)
  111. {
  112. for (LocatorSelectorEntry* entry : entries_)
  113. {
  114. if (entry->remote_guid == guid)
  115. {
  116. entry->enabled = true;
  117. break;
  118. }
  119. }
  120. }
  121. /**
  122. * Check if enabling state has changed.
  123. *
  124. * @return true if the enabling state has changed, false otherwise.
  125. */
  126. bool state_has_changed() const
  127. {
  128. if (entries_.size() != last_state_.size())
  129. {
  130. return true;
  131. }
  132. for (size_t i = 0; i < entries_.size(); ++i)
  133. {
  134. if (last_state_.at(i) != (entries_.at(i)->enabled ? 1 : 0) )
  135. {
  136. return true;
  137. }
  138. }
  139. return false;
  140. }
  141. /**
  142. * Reset the selection state of the selector.
  143. */
  144. void selection_start()
  145. {
  146. selections_.clear();
  147. for (LocatorSelectorEntry* entry : entries_)
  148. {
  149. entry->reset();
  150. }
  151. }
  152. /**
  153. * Called when the selection algorithm starts for a specific transport.
  154. *
  155. * Will set the temporary transport_should_process flag for all enabled entries.
  156. *
  157. * @return a reference to the entries collection.
  158. */
  159. ResourceLimitedVector<LocatorSelectorEntry*>& transport_starts()
  160. {
  161. for (LocatorSelectorEntry* entry : entries_)
  162. {
  163. entry->transport_should_process = entry->enabled;
  164. }
  165. return entries_;
  166. }
  167. /**
  168. * Marks an entry as selected.
  169. *
  170. * @param index The index of the entry to mark as selected.
  171. */
  172. void select(size_t index)
  173. {
  174. if (index < entries_.size() &&
  175. std::find(selections_.begin(), selections_.end(), index) == selections_.end())
  176. {
  177. selections_.push_back(index);
  178. }
  179. }
  180. /**
  181. * Count the number of selected locators.
  182. *
  183. * @return the number of selected locators.
  184. */
  185. size_t selected_size() const
  186. {
  187. size_t result = 0;
  188. for (size_t index : selections_)
  189. {
  190. LocatorSelectorEntry* entry = entries_.at(index);
  191. result += entry->state.multicast.size();
  192. result += entry->state.unicast.size();
  193. }
  194. return result;
  195. }
  196. /**
  197. * Check if a locator is present in the selections of this object.
  198. *
  199. * @param locator The locator to be checked.
  200. *
  201. * @return True if the locator has been selected, false otherwise.
  202. */
  203. bool is_selected(const Locator_t locator) const
  204. {
  205. if(IPLocator::isMulticast(locator))
  206. {
  207. for (size_t index : selections_)
  208. {
  209. LocatorSelectorEntry* entry = entries_.at(index);
  210. for (size_t loc_index : entry->state.multicast)
  211. {
  212. if (entry->multicast.at(loc_index) == locator)
  213. {
  214. return true;
  215. }
  216. }
  217. }
  218. }
  219. else
  220. {
  221. for (size_t index : selections_)
  222. {
  223. LocatorSelectorEntry* entry = entries_.at(index);
  224. for (size_t loc_index : entry->state.unicast)
  225. {
  226. if (entry->unicast.at(loc_index) == locator)
  227. {
  228. return true;
  229. }
  230. }
  231. }
  232. }
  233. return false;
  234. }
  235. /**
  236. * Performs an action on each selected locator.
  237. *
  238. * @param action Unary function that accepts a locator as argument.
  239. * The function shall not modify its argument.
  240. * This can either be a function pointer or a function object.
  241. */
  242. template<class UnaryPredicate>
  243. void for_each(UnaryPredicate action) const
  244. {
  245. for (size_t index : selections_)
  246. {
  247. LocatorSelectorEntry* entry = entries_.at(index);
  248. for (size_t loc_index : entry->state.multicast)
  249. {
  250. action(entry->multicast.at(loc_index));
  251. }
  252. for (size_t loc_index : entry->state.unicast)
  253. {
  254. action(entry->unicast.at(loc_index));
  255. }
  256. }
  257. }
  258. struct IteratorIndex
  259. {
  260. size_t selections_index;
  261. size_t state_index;
  262. bool state_multicast_done;
  263. Locator_t* locator;
  264. };
  265. class iterator : public std::iterator<
  266. std::input_iterator_tag, // iterator_category
  267. Locator_t, // value_type
  268. IteratorIndex, // difference_type
  269. Locator_t*, // pointer
  270. Locator_t&>, // reference
  271. public LocatorsIterator
  272. {
  273. const LocatorSelector& locator_selector_;
  274. IteratorIndex current_;
  275. void go_to_next_entry()
  276. {
  277. // While entries selected
  278. while (++current_.selections_index < locator_selector_.selections_.size())
  279. {
  280. LocatorSelectorEntry* entry =
  281. locator_selector_.entries_.at(locator_selector_.selections_[current_.selections_index]);
  282. // No multicast locators in this entry
  283. if (entry->state.multicast.size() == 0)
  284. {
  285. // But there's unicast
  286. if (entry->state.unicast.size() > 0)
  287. {
  288. current_.locator = &entry->unicast[entry->state.unicast.at(0)];
  289. return;
  290. }
  291. }
  292. else // process multicast
  293. {
  294. current_.state_multicast_done = false;
  295. current_.locator = &entry->multicast[entry->state.multicast.at(0)];
  296. return;
  297. }
  298. }
  299. current_.locator = nullptr;
  300. }
  301. public:
  302. enum class Position
  303. {
  304. Begin,
  305. End
  306. };
  307. explicit iterator(
  308. const LocatorSelector& locator_selector,
  309. Position index_pos)
  310. : locator_selector_(locator_selector)
  311. {
  312. current_ = {std::numeric_limits<size_t>::max(),0,true, nullptr};
  313. if (index_pos == Position::Begin)
  314. {
  315. go_to_next_entry();
  316. }
  317. }
  318. iterator(const iterator& other)
  319. : locator_selector_(other.locator_selector_)
  320. , current_(other.current_)
  321. {
  322. }
  323. iterator& operator++()
  324. {
  325. // Shouldn't call ++ when index already at the end
  326. assert(current_.selections_index < locator_selector_.selections_.size());
  327. LocatorSelectorEntry* entry =
  328. locator_selector_.entries_.at(locator_selector_.selections_[current_.selections_index]);
  329. // Index at unicast locators
  330. if (current_.state_multicast_done)
  331. {
  332. // No more unicast locators selected
  333. if (++current_.state_index >= entry->state.unicast.size())
  334. {
  335. current_.state_index = 0;
  336. go_to_next_entry();
  337. }
  338. else // current unicast locator
  339. {
  340. current_.locator = &entry->unicast[entry->state.unicast.at(current_.state_index)];
  341. }
  342. }
  343. else // Index at multicast locators
  344. {
  345. // No more multicast locators selected
  346. if (++current_.state_index >= entry->state.multicast.size())
  347. {
  348. // Reset index to process unicast
  349. current_.state_multicast_done = true;
  350. current_.state_index = 0;
  351. // No unicast locators
  352. if (current_.state_index >= entry->state.unicast.size())
  353. {
  354. go_to_next_entry();
  355. }
  356. else // current unicast locator
  357. {
  358. current_.locator = &entry->unicast[entry->state.unicast.at(current_.state_index)];
  359. }
  360. }
  361. else // current multicast locator
  362. {
  363. current_.locator = &entry->multicast[entry->state.multicast.at(current_.state_index)];
  364. }
  365. }
  366. return *this;
  367. }
  368. bool operator==(
  369. const LocatorsIterator& other) const
  370. {
  371. return *this == static_cast<const iterator&>(other);
  372. }
  373. bool operator!=(
  374. const LocatorsIterator& other) const
  375. {
  376. return !(*this == other);
  377. }
  378. bool operator==(
  379. const iterator& other) const
  380. {
  381. return (current_.locator == other.current_.locator);
  382. }
  383. bool operator!=(
  384. const iterator& other) const
  385. {
  386. return !(*this == other);
  387. }
  388. pointer operator->() const
  389. {
  390. return current_.locator;
  391. }
  392. reference operator*() const
  393. {
  394. return *current_.locator;
  395. }
  396. };
  397. iterator begin() const
  398. {
  399. return iterator(*this, iterator::Position::Begin);
  400. }
  401. iterator end() const
  402. {
  403. return iterator(*this, iterator::Position::End);
  404. }
  405. private:
  406. //! Entries collection.
  407. ResourceLimitedVector<LocatorSelectorEntry*> entries_;
  408. //! List of selected indexes.
  409. ResourceLimitedVector<size_t> selections_;
  410. //! Enabling state when reset was called.
  411. ResourceLimitedVector<int> last_state_;
  412. };
  413. } /* namespace rtps */
  414. } /* namespace fastrtps */
  415. } /* namespace eprosima */
  416. #endif /* _FASTDDS_RTPS_COMMON_LOCATORSELECTOR_H_ */