-
Notifications
You must be signed in to change notification settings - Fork 30
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
Support specifying patterns for matching topics at run-time #34
base: main
Are you sure you want to change the base?
Changes from all commits
e374fdf
2ea8877
31ef0dd
a7217b0
3b7221e
a7ed8fa
7a596d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -37,6 +37,7 @@ | |||
#include <boost/atomic.hpp> | ||||
#include <boost/thread/mutex.hpp> | ||||
#include <boost/thread/shared_mutex.hpp> | ||||
#include <boost/regex.hpp> | ||||
#include <ros/ros.h> | ||||
#include <ros/time.h> | ||||
#include <rosbag_snapshot_msgs/TriggerSnapshot.h> | ||||
|
@@ -51,6 +52,8 @@ | |||
#include <string> | ||||
#include <utility> | ||||
#include <vector> | ||||
#include <memory> | ||||
#include <unordered_map> | ||||
|
||||
namespace rosbag_snapshot | ||||
{ | ||||
|
@@ -86,6 +89,27 @@ struct ROSBAG_DECL SnapshotterTopicOptions | |||
int32_t memory_limit = INHERIT_MEMORY_LIMIT, int32_t count_limit = INHERIT_COUNT_LIMIT); | ||||
}; | ||||
|
||||
/* Regular expression matching fully qualified topic names that should be tracked. | ||||
*/ | ||||
class ROSBAG_DECL SnapshotterTopicPattern | ||||
{ | ||||
public: | ||||
SnapshotterTopicPattern(const std::string &pattern, const SnapshotterTopicOptions &topic_options); | ||||
|
||||
const boost::regex& get_pattern() const; | ||||
const SnapshotterTopicOptions& get_topic_options() const; | ||||
|
||||
// Return true if pattern matches the given topic name exactly. | ||||
bool matches(const std::string &topic) const; | ||||
|
||||
private: | ||||
// Maximum difference in time from newest and oldest message in buffer before older messages are removed | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
boost::regex pattern_; | ||||
SnapshotterTopicOptions topic_options_; | ||||
}; | ||||
typedef std::shared_ptr<SnapshotterTopicPattern> SnapshotterTopicPatternPtr; | ||||
typedef std::shared_ptr<const SnapshotterTopicPattern> SnapshotterTopicPatternConstPtr; | ||||
|
||||
/* Configuration for the Snapshotter node. Contains default limits for memory and duration | ||||
* and a map of topics to their limits which may override the defaults. | ||||
*/ | ||||
|
@@ -110,6 +134,12 @@ struct ROSBAG_DECL SnapshotterOptions | |||
// Provides list of topics to snapshot and their limit configurations | ||||
topics_t topics_; | ||||
|
||||
typedef std::vector<SnapshotterTopicPatternConstPtr> patterns_t; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we eliminate this typedef since it is only used the once? |
||||
// List of regexs that match topics which should be tracked by the recorder. | ||||
patterns_t patterns_; | ||||
// Cache of the first pattern that has matched a given topic (or nullptr if no pattern matched). | ||||
std::unordered_map<std::string, SnapshotterTopicPatternConstPtr> matching_patterns_cache_; | ||||
|
||||
SnapshotterOptions(ros::Duration default_duration_limit = ros::Duration(30), int32_t default_memory_limit = -1, | ||||
int32_t default_count_limit = -1, ros::Duration status_period = ros::Duration(1), | ||||
bool clear_buffer = true); | ||||
|
@@ -119,6 +149,20 @@ struct ROSBAG_DECL SnapshotterOptions | |||
ros::Duration duration_limit = SnapshotterTopicOptions::INHERIT_DURATION_LIMIT, | ||||
int32_t memory_limit = SnapshotterTopicOptions::INHERIT_MEMORY_LIMIT, | ||||
int32_t count_limit = SnapshotterTopicOptions::INHERIT_COUNT_LIMIT); | ||||
// Add a new topic pattern to the configuration, returns false if the pattern is invalid | ||||
bool addPattern(std::string const& pattern, | ||||
ros::Duration duration_limit = SnapshotterTopicOptions::INHERIT_DURATION_LIMIT, | ||||
int32_t memory_limit = SnapshotterTopicOptions::INHERIT_MEMORY_LIMIT, | ||||
int32_t count_limit = SnapshotterTopicOptions::INHERIT_COUNT_LIMIT); | ||||
|
||||
// Add a new topic or topic pattern to the configuration, returns false if the topic was already present | ||||
bool addTopicOrPattern(std::string const& topic_or_pattern, | ||||
ros::Duration duration_limit = SnapshotterTopicOptions::INHERIT_DURATION_LIMIT, | ||||
int32_t memory_limit = SnapshotterTopicOptions::INHERIT_MEMORY_LIMIT, | ||||
int32_t count_limit = SnapshotterTopicOptions::INHERIT_COUNT_LIMIT); | ||||
|
||||
// Return the first matching topic pattern that matches the given topic, otherwise null. | ||||
SnapshotterTopicPatternConstPtr findFirstMatchingPattern(const std::string &topic); | ||||
}; | ||||
|
||||
/* Stores a buffered message of an ambiguous type and it's associated metadata (time of arrival, connection data), | ||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,11 @@ const ros::Duration SnapshotterTopicOptions::INHERIT_DURATION_LIMIT = ros::Durat | |
const int32_t SnapshotterTopicOptions::INHERIT_MEMORY_LIMIT = 0; | ||
const int32_t SnapshotterTopicOptions::INHERIT_COUNT_LIMIT = 0; | ||
|
||
static bool is_topic_name_pattern(const std::string& s) | ||
{ | ||
return s.find_first_of(".*+?()[]{}\\") != std::string::npos; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add to the README with information about the pattern matching syntax. This is most important so that it doesn't get mixed up with glob syntax |
||
} | ||
|
||
SnapshotterTopicOptions::SnapshotterTopicOptions(ros::Duration duration_limit, int32_t memory_limit, | ||
int32_t count_limit) | ||
: duration_limit_(duration_limit), memory_limit_(memory_limit), count_limit_(count_limit) | ||
|
@@ -76,6 +81,8 @@ SnapshotterOptions::SnapshotterOptions(ros::Duration default_duration_limit, int | |
, status_period_(status_period) | ||
, clear_buffer_(clear_buffer) | ||
, topics_() | ||
, patterns_() | ||
, matching_patterns_cache_() | ||
{ | ||
} | ||
|
||
|
@@ -87,6 +94,71 @@ bool SnapshotterOptions::addTopic(std::string const& topic, ros::Duration durati | |
return ret.second; | ||
} | ||
|
||
bool SnapshotterOptions::addPattern(std::string const& pattern, ros::Duration duration, int32_t memory, int32_t count) | ||
{ | ||
SnapshotterTopicOptions ops(duration, memory, count); | ||
try | ||
{ | ||
patterns_.emplace_back(std::make_shared<SnapshotterTopicPattern>(pattern, ops)); | ||
ROS_INFO("Added topic pattern: %s", pattern.c_str()); | ||
return true; | ||
} | ||
catch (boost::regex_error& e) | ||
{ | ||
ROS_ERROR("Invalid topic pattern '%s': %s", pattern.c_str(), e.what()); | ||
return false; | ||
} | ||
} | ||
|
||
bool SnapshotterOptions::addTopicOrPattern(std::string const& topic_or_pattern, | ||
ros::Duration duration, int32_t memory, int32_t count) | ||
{ | ||
if (is_topic_name_pattern(topic_or_pattern)) | ||
return addPattern(topic_or_pattern, duration, memory, count); | ||
else | ||
return addTopic(topic_or_pattern, duration, memory, count); | ||
} | ||
|
||
SnapshotterTopicPatternConstPtr SnapshotterOptions::findFirstMatchingPattern(const std::string &topic) | ||
{ | ||
if (patterns_.empty()) | ||
return nullptr; | ||
auto it = matching_patterns_cache_.find(topic); | ||
if (it != matching_patterns_cache_.end()) | ||
return it->second; | ||
SnapshotterTopicPatternConstPtr matching_pattern = nullptr; | ||
for (auto& pattern : patterns_) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please put in curly braces for the for loop? Its not a strict requirement, I just dislike the look when its multiple lines (even though its one statement) |
||
if (pattern->matches(topic)) | ||
{ | ||
matching_pattern = pattern; | ||
break; | ||
} | ||
matching_patterns_cache_[topic] = matching_pattern; | ||
return matching_pattern; | ||
} | ||
|
||
SnapshotterTopicPattern::SnapshotterTopicPattern(const std::string &pattern, | ||
const SnapshotterTopicOptions &topic_options) | ||
: pattern_(pattern) | ||
, topic_options_(topic_options) | ||
{ | ||
} | ||
|
||
const boost::regex& SnapshotterTopicPattern::get_pattern() const | ||
{ | ||
return pattern_; | ||
} | ||
|
||
const SnapshotterTopicOptions& SnapshotterTopicPattern::get_topic_options() const | ||
{ | ||
return topic_options_; | ||
} | ||
|
||
bool SnapshotterTopicPattern::matches(const std::string &topic) const | ||
{ | ||
return boost::regex_match(topic, pattern_); | ||
} | ||
|
||
SnapshotterClientOptions::SnapshotterClientOptions() : action_(SnapshotterClientOptions::TRIGGER_WRITE) | ||
{ | ||
} | ||
|
@@ -562,6 +634,14 @@ void Snapshotter::pollTopics(ros::TimerEvent const& e, rosbag_snapshot::Snapshot | |
for (ros::master::TopicInfo const& t : topics) | ||
{ | ||
std::string topic = t.name; | ||
SnapshotterTopicOptions topic_options; | ||
if (!options->all_topics_) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment here to the effect of |
||
{ | ||
SnapshotterTopicPatternConstPtr matching_topic_pattern = options->findFirstMatchingPattern(topic); | ||
if (matching_topic_pattern == nullptr) | ||
continue; | ||
topic_options = matching_topic_pattern->get_topic_options(); | ||
} | ||
if (options->addTopic(topic)) | ||
{ | ||
SnapshotterTopicOptions topic_options; | ||
|
@@ -606,10 +686,9 @@ int Snapshotter::run() | |
status_timer_ = nh_.createTimer(options_.status_period_, &Snapshotter::publishStatus, this); | ||
|
||
// Start timer to poll ROS master for topics | ||
if (options_.all_topics_) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How would you feel about changing this to |
||
poll_topic_timer_ = nh_.createTimer(ros::Duration(1.0), | ||
boost::bind(&Snapshotter::pollTopics, this, | ||
boost::placeholders::_1, &options_)); | ||
poll_topic_timer_ = nh_.createTimer(ros::Duration(1.0), | ||
boost::bind(&Snapshotter::pollTopics, this, | ||
boost::placeholders::_1, &options_)); | ||
|
||
// Use multiple callback threads | ||
ros::MultiThreadedSpinner spinner(4); // Use 4 threads | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Other than adding the
regex
component to Boost, are any of these CMakeLists changes needed?