fix(replicated_state): truncate canister log records when log capacity shrinks - #11396
Open
mraszyk wants to merge 1 commit into
Open
fix(replicated_state): truncate canister log records when log capacity shrinks#11396mraszyk wants to merge 1 commit into
mraszyk wants to merge 1 commit into
Conversation
…y shrinks
The "a single record fits the ring buffer" invariant was established only
when a record was created: `CanisterLog::add_record` truncates the content
against the log memory store's byte capacity at that moment. Nothing
re-established it when the capacity was later lowered, so
`RingBuffer::append_log` hit
debug_assert!(false, "Log record size exceeds ring buffer capacity");
continue;
which aborts every debug-assertions build (`cargo test`, `bazel test`, a
debug replica) and silently drops the record otherwise.
Both outcomes are reachable from ordinary, unprivileged `update_settings`
traffic that lowers `log_memory_limit`: `LogMemoryStore::resize_impl`
migrates the already stored records into a newly allocated, smaller ring
buffer, where a record created against the old capacity no longer fits.
`LogRecord::truncate_to_capacity` now re-establishes the invariant at
append time, applying the same policy `add_record` applies at creation
time — truncating the record rather than dropping it. This makes the
capacity check unconditionally satisfied for both callers of `append_log`
(`resize_impl` and `append_delta_log`), so the assertion and its
silent-drop fallback are removed.
A zero `log_memory_limit` deallocates the buffer instead of creating a
zero-capacity one, and every live buffer has `data_capacity` of at least
`DATA_CAPACITY_MIN`, so a truncated record always fits.
The delta log of an in-flight execution cannot carry a stale, larger
capacity into `append_delta_log`: `update_settings` never runs on a
canister with a paused execution, and an aborted execution re-executes
from scratch against the new capacity.
The regression test in `canister_logging.rs` stores a record against a 64 KiB
log memory limit and then lowers the limit below the size of that single
record; it fails on the assertion above without this fix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes canister log migration when reducing ring-buffer capacity by truncating oversized records instead of asserting or dropping them.
Changes:
- Adds capacity-aware log-record truncation.
- Applies truncation during ring-buffer appends.
- Adds an end-to-end resize regression test.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
ring_buffer.rs |
Truncates records before appending. |
log_record.rs |
Implements serialized-record truncation. |
canister_logging.rs |
Tests shrinking below one record’s size. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
✅ No security or compliance issues detected. Reviewed everything up to e2630d0. Security Overview
Detected Code Changes
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The "a single record fits the ring buffer" invariant was established only when a record was created:
CanisterLog::add_recordtruncates the content against the log memory store's byte capacity at that moment. Nothing re-established it when the capacity was later lowered, soRingBuffer::append_loghitwhich aborts every debug-assertions build (
cargo test,bazel test, a debug replica) and silently drops the record otherwise.Both outcomes are reachable from ordinary, unprivileged
update_settingstraffic that lowerslog_memory_limit:LogMemoryStore::resize_implmigrates the already stored records into a newly allocated, smaller ring buffer, where a record created against the old capacity no longer fits.LogRecord::truncate_to_capacitynow re-establishes the invariant at append time, applying the same policyadd_recordapplies at creation time — truncating the record rather than dropping it. This makes the capacity check unconditionally satisfied for both callers ofappend_log(resize_implandappend_delta_log), so the assertion and its silent-drop fallback are removed.A zero
log_memory_limitdeallocates the buffer instead of creating a zero-capacity one, and every live buffer hasdata_capacityof at leastDATA_CAPACITY_MIN, so a truncated record always fits.The delta log of an in-flight execution cannot carry a stale, larger capacity into
append_delta_log:update_settingsnever runs on a canister with a paused execution (can_execute_subnet_msgreturnsfalseforExecutionTask::PausedExecution), and an aborted execution re-executes from scratch against the new capacity.The regression test in
canister_logging.rsstores a record against a 64 KiB log memory limit and then lowers the limit below the size of that single record; it fails on the assertion above without this fix.🤖 Generated with Claude Code