-
Notifications
You must be signed in to change notification settings - Fork 288
Feature/rosbag2 circular logging size duration 2217 #2218
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
base: rolling
Are you sure you want to change the base?
Feature/rosbag2 circular logging size duration 2217 #2218
Conversation
Signed-off-by: Luke Sy <[email protected]>
- Add StorageOptions.max_splits (+ YAML/params, Python bindings) - CLI: --max-splits (before size/duration) - Writer: delete oldest files when exceeding size, duration, or split count Signed-off-by: Luke Sy <[email protected]>
Signed-off-by: Luke Sy <[email protected]>
309537d to
7b4c6bb
Compare
Signed-off-by: Luke Sy <[email protected]>
Signed-off-by: Luke Sy <[email protected]>
Signed-off-by: Luke Sy <[email protected]>
30f9f5c to
cf16699
Compare
Signed-off-by: Luke Sy <[email protected]>
|
I've committed changes that should address the unit test error. I'm also happy to include @fujitatomoya ’s suggestion to remove |
Simplify storage options by removing max_record_size and max_record_duration fields and CLI arguments. Circular logging now only supports limiting by split count (max_splits). Signed-off-by: Luke Sy <[email protected]>
Signed-off-by: Luke Sy <[email protected]>
MichaelOrlov
left a comment
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.
@luke-alloy Thank you for your contribution. This is a long-time-wanted feature that will be very useful.
I've made a thorough review, and overall implementation looks good to me. However, I have a few suggestions:
- The naming is hard. I would propose to rename
--max-splitsparameter to--max_bag_filesto avoid confusion and multiple user questions, like:
- Will splits stop after reaching
max_splits?- Why is there one file when
max_splits = 1? I would expect to have at least two files after the split.
- I would like to see at least one integration test with real files writing and deletion.
To facilitate this, we do have a specialTemporaryDirectoryFixture. Please consider modifying your tests or adding another one. I recently added a similar test in one of my PR. Please, refer to the 81ef9fd#diff-c14a7d44179cf64868ce86b5e60c7f741f957ef368c04a0477ccfe7ccd89f1f2R138-R164 as an example from the #2224.
| '--max-splits', type=int, default=0, | ||
| help='Maximum number of splits to retain before deleting the oldest bagfile ' | ||
| '(circular logging). Default: %(default)d, unlimited. ' | ||
| 'Requires --max-bag-size or --max-bag-duration to be set.') |
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.
| 'Requires --max-bag-size or --max-bag-duration to be set.') | |
| 'Requires --max-bag-size or --max-bag-duration to be set or usage of the bag split ' | |
| 'via direct recorder API or service calls.') |
| storage_options_.uri = format_storage_uri( | ||
| base_folder_, | ||
| metadata_.relative_file_paths.size()); | ||
| next_file_index_); |
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 assignment would be better readable in one line
| storage_options_.uri = format_storage_uri( | |
| base_folder_, | |
| metadata_.relative_file_paths.size()); | |
| next_file_index_); | |
| storage_options_.uri = format_storage_uri(base_folder_, next_file_index_); |
| // Delete oldest files if circular buffer limit exceeded (after split creates new file) | ||
| delete_oldest_files_if_needed(); |
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.
| // Delete oldest files if circular buffer limit exceeded (after split creates new file) | |
| delete_oldest_files_if_needed(); |
I think it would be better to move this delete_oldest_files call into the void SequentialWriter::switch_to_next_storage() right before storage_->update_metadata(metadata_);. This way we can avoid extra storage_->update_metadata(metadata_); call inside delete_oldest_files_if_needed();
Please be aware that our update_metadata(metadata_) in mcap is a bit suboptimal, and each time update is called, we are writing a new section with metadata instead of really updating the one.
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.
| // Delete the oldest files if circular buffer limit exceeded (after split creates new file) | |
| delete_oldest_files_if_needed(); | |
| storage_->update_metadata(metadata_); |
"Moved from after the split"
| // Delete oldest files until we're under the split-count limit | ||
| // Note: We just split, so we have at least 2 files and the oldest is definitely not current | ||
| while (metadata_.files.size() > 1) { | ||
| // If we're under the limit, stop deleting | ||
| if (metadata_.files.size() <= storage_options_.max_splits) { | ||
| break; | ||
| } |
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.
| // Delete oldest files until we're under the split-count limit | |
| // Note: We just split, so we have at least 2 files and the oldest is definitely not current | |
| while (metadata_.files.size() > 1) { | |
| // If we're under the limit, stop deleting | |
| if (metadata_.files.size() <= storage_options_.max_splits) { | |
| break; | |
| } | |
| // Delete the oldest files until we're under the split-count limit | |
| while (metadata_.files.size() <= storage_options_.max_splits) { |
Simplify logic.
Note: if storage_options_.max_splits were storage_options_.max_bag_files, the logic would be easy to understand.
| // Update metadata after deletions | ||
| if (!metadata_.files.empty()) { | ||
| storage_->update_metadata(metadata_); | ||
| } |
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.
| // Update metadata after deletions | |
| if (!metadata_.files.empty()) { | |
| storage_->update_metadata(metadata_); | |
| } |
Metadata update should happen once in the SequentialWriter::switch_to_next_storage()
|
|
||
| // The maximum number of bagfile splits to retain before the oldest bagfile is deleted. | ||
| // A value of 0 indicates that no deletion based on split count will occur. | ||
| // This feature is only available if either max_bagfile_size or max_bagfile_duration is set. |
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 feature is only available if either max_bagfile_size or max_bagfile_duration is set. | |
| // This feature is only available when the bag split is active. | |
| // Requires --max-bag-size or --max-bag-duration to be set or usage of the bag split via | |
| // direct recorder API or service calls.set. |
| // The maximum number of bagfile splits to retain before the oldest bagfile is deleted. | ||
| // A value of 0 indicates that no deletion based on split count will occur. | ||
| // This feature is only available if either max_bagfile_size or max_bagfile_duration is set. | ||
| uint64_t max_splits = 0; |
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.
| uint64_t max_splits = 0; | |
| uint64_t max_bag_files = 0; |
The naming is hard. I would propose to rename this parameter to max_bag_files to avoid confusion and multiple user questions, like:
- Will splits stop after reaching
max_splits? - Why is there one file when
max_splits = 1? I would expect to have at least two files after the split.
| } | ||
| } | ||
|
|
||
|
|
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.
The stray empty line should be removed.
@MichaelOrlov Thanks for the detailed review! I will update the PR soon. I completely agree regarding the naming confusion—good catch. To maintain consistency with the other CLI flags, would |
|
@luke-alloy Yes. Need to use |
Description
Adds circular logging by split count, record size and duration to rosbag2 recording.
--max-splitsFixes #2217
Is this user-facing behavior change?
Yes.
--max-splits N: limit number of retained bagfile splits.ros2 bag record -a --max-bag-size 100MB --max-splits 5Did you use Generative AI?
Yes.
Additional Information
--log-levelif needed.metadata.yamlcurrently retains aggregatemessage_countandtopics_with_message_countacross the entire capture, even when older bagfiles are pruned by circular logging. File lists and durations reflect pruning, but those two fields still represent the full session totals.