-
Notifications
You must be signed in to change notification settings - Fork 248
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
Recording triggerable snapshot design proposal #755
Conversation
|
||
### Outside rosbag2 | ||
|
||
First approach implements `ros2 bag snapshot` as a different package. Mostly it requires rewriting `Recorder` node completly. Completly means in this case diving into implementation of `Writer`, `SequentialWriter` and `BaseWriterInterface` to copy and adjust writing to disk algorithms. |
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.
I don't think that this makes sense, and I would honestly remove it from the proposal - you might add a section at the end called "alternate approaches considered" - but top-level I like to see a design being a single proposal of what should be implemented, not a selection of choices.
I think everyone would agree that this is a useful feature for rosbag2 to do - somebody could implement something in a separate repository/package without doing any design here - I think our goal is to determine a design that does fit into rosbag2
directly.
Second approach would base on making changes to `Recorder`, writers and their interfaces. This approach bases on adding service to `Recorder` which handles triggering buffer save. Although current design of writers bases on `BaseWriterInterface` which would need to be changed to enable some kind of `save()/flush()` functionality. I believe this is not an elegant approach but I haven't find other way to trigger buffer save from `Recorder`, through `Writer` to `SequentialWriter`. For sure it requires implementing new `SnapshotWriter` since it needs to take care of buffering the messages from subscribers instead of passing them straight to `MessageCache` and `CacheConsumer`. | ||
|
||
Pros: | ||
* Maintaining snapshot inside `ros2 bag snapshot ...` (or even `ros2 bag record snapshot ...`) and `Recorder` functionality |
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.
I'm not sure that this makes sense as a separate verb. I would think that the circular-buffer + snapshot approach should be considered a behavioral modification of recording, just like rosbag2 play --loop
I'd like to see a specific section for "User Interface" - how do I interact with this feature (without knowing how it is built)?
I think maybe something like the following:
# Recording is invoked with this feature via an extra option to "record"
ros2 bag record --buffer-snapshot
# Snapshot is exposed as a Service on the Recorder node (so it can be triggered remotely)
ros2 service call /rosbag2_recorder rosbag2_interfaces/Snapshot
# C++ API
* RecordingOptions has a new value "buffer_snapshot"
* Recorder has a new API `Recorder::snapshot`
|
||
### Custom `Recorder` implementation | ||
|
||
Last but not least it is possible to write new alternative to `Recorder` node inside `rosbag2_transport` package. `Snapshoter` would implement functionalities of subscribing the messages, buffering them at high level node and most probably passing data straight to `MessageCache` and `CacheConsumer`. |
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.
I think that the Recorder
actually won't know much about this behavior. The SequentialWriter
has the message_cache_
and is the entity that will probably implement this behavior. That's the sort of proposal I'm looking for here, like "what owns what functionality, logically". The Recorder itself I think should just pass through configuration, its responsibility is the transport layer, e.g. Subscriptions, and the Writer should handle behavior around writing.
Thanks for taking this on! Hopefully the above comments help clarify the goal - overall I'd structure it like:
Hashing out the above things via this document makes it feel to me like there won't be any big surprises or rabbit-holes in the implementation/review stage. |
After long time I found some time to design the feature in more details. Still haven't figured out some of the concerns, but I believe code-like documentation will help dispel them. I am waiting for more suggestions and opinions. |
It feels like at this point of development a validation of my idea would be helpful. |
Managed to get some community review, but would love maintainers feedback (@emersonknapp @Karsten1987) |
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.
Thanks for going through the iterations, I appreciate the effort. I think these design reviews are valuable because they help clarify what features are useful and what interfaces make sense. However, I can see that you're inclined to get into code, which I understand. I would be willing to review a PR that starts with just the API changes, so that we can review the interfaces first, like we are doing here.
My main comment across this review is:
We should try to keep the interface as simple as possible. We already have --max-cache-size
argument, which could be used to implement the first version of this feature. I would rather review a simplified feature that does one thing well than everything you might want it to do. It seems likely that we could maintain bag splitting and everything, just changing the MessageCache
to have a different implementation, so that it doesn't provide a queue to the Consumer/Writer until triggered, rather than the current implementation where it provides the buffer once it is full.
|
||
## In-depth structure changes | ||
|
||
```diff |
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.
I don't know if I accidentally implied that you should do this diff thing - but please remove the entire diff section. The design review is not the place to put actual code - this will be out of date as soon as we actually implement it. The design should be the place for high level concepts that don't get out of date.
If you would like to open a separate PR with all these changes actually implementing this feature, that would be great! We can link them together in the descriptions as companions of each other.
* Save data to rosbag on trigger | ||
* Enable triggering buffer save to disk with service call | ||
|
||
* Pause and resume buffering process |
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.
I don't understand this feature very well - my understanding for the intention of this feature is:
- rosbag2 is always keeping a circular buffer of the latest information - but not writing anything to disk
- when we trigger a snapshot - dump the entire buffer to disk
Why does a user want to pause buffering? This sounds to me like it makes rosbag2 just drop data, such that you wouldn't be able to take a snapshot of it.
|
||
| parameter name | description | behavior | | ||
| -------------- | ------------- | --------- | | ||
| buffer size | maximum memory per topic | <ul><li> defined by new `--max-buffer-size` argument, default value is 0 [bytes] </li><li>if not set/set to non-positive value only duration parameter will be relevant (*note: either buffer size or duration must be specified*) </li></ul> | |
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.
Why would "buffer size" be different than the "cache size" that is currently used for double-buffered writing? It seems to me that we already have a configuration for an in-memory buffer of data. When snapshot is enabled, we would use this buffer circularly rather than triggering a write-to-disk when it reaches the configured size.
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.
Additionally, why would this be per-topic. It seems better to use this as a total value so that the user has a guarantee of maximum memory usage. Regardless, we don't currently have per-topic caches, so that would require a rewrite of the caching system.
| parameter name | description | behavior | | ||
| -------------- | ------------- | --------- | | ||
| buffer size | maximum memory per topic | <ul><li> defined by new `--max-buffer-size` argument, default value is 0 [bytes] </li><li>if not set/set to non-positive value only duration parameter will be relevant (*note: either buffer size or duration must be specified*) </li></ul> | | ||
| duration | maximum time difference between newest and oldest message | <ul><li> defined by new `--max-buffer-duration` argument, default value is 10.0 [s] </li><li> if not set/set to non-positive value only buffer size parameter will be relevant (*note: either buffer size or duration must be specified*) </li></ul> | |
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.
Same as above comment - I think we have a feature request for a maximum duration of the write cache, this should probably be the same parameter, to minimize the number of parameters.
ros2 service call /rosbag2_recorder/snapshot/duration rosbag2_interfaces/srv/SetDuration "{duration: 50.0}" | ||
|
||
# Clear snapshot buffer | ||
ros2 service call /rosbag2_recorder/snapshot/clear_buffer rosbag2_interfaces/srv/ClearBuffer "{ }" |
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.
I'm a little confused by this feature (and it doesn't seem to be mentioned in the introduction) - a snapshot write should clear the buffers, but why would we want to do it without a write?
|
||
#### TODO | ||
|
||
* Deleting empty rosbag after node closure |
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.
This is a separate feature that already has an issue open, you don't need to worry about it for this design.
|
||
* Deleting empty rosbag after node closure | ||
* Resolve how to implement pause/resume functionality | ||
* Think about configuration change during runtime |
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.
I think that this feature can be intentionally excluded from this design. Maybe add an "Out of scope" section near the top, something like
## Out of scope
* Reconfiguration of recording settings during runtime
I'll throw in my two cents here, I think my comments are high level enough that I'm not going to insert them into the review process.
|
The main point I am trying to make is that this shouldn't be annoyingly complicated. All of the functionality to do splitting, bag sizes, etc is already handled by the I think that strong separation of concerns makes for much more simple implementations - I think we can manage that here. |
Closing in favor of #837 |
Description
As suggested in #663, this PR contains a design proposal for rosbag2 triggerable snapshot feature implementation.
For now I found multiple inconveniences with design decision making and I'm looking for a feedback and tips on what are the expectations for this feature design.