Skip to content

Replace PartialEnvelope with CommandWithKeys trait#4724

Merged
muhamadazmy merged 2 commits into
mainfrom
pr4724
May 12, 2026
Merged

Replace PartialEnvelope with CommandWithKeys trait#4724
muhamadazmy merged 2 commits into
mainfrom
pr4724

Conversation

@muhamadazmy
Copy link
Copy Markdown
Contributor

@muhamadazmy muhamadazmy commented May 12, 2026

Replace PartialEnvelope with CommandWithKeys trait

Summary:
Replaces the type-erased PartialEnvelope with a CommandWithKeys trait
that unifies how WAL writers obtain record keys for a command:

  • Auto-implemented for any Command: HasRecordKeys (keys come from the
    command itself).
  • Implemented for BodyWithKeys<C> so commands that don't carry their
    own keys can still be enriched at the call site.

This lets generic write paths accept either form without an intermediate allocation,
and removes the now-redundant StorageDecode bound from the Command trait.

As a result:
Roll back the changes in the UpdatePartitionDurabilityCommand

  • UpdatePartitionDurabilityCommand no longer needs to carry
    partition_key_range (was added in a previous commit)
    the key range is supplied via BodyWithKeys at publish time.
    (follw up PR to handle the Write path)
  • DurabilityTracker takes a PartitionId instead of
    Arc<Partition>, since it no longer needs the key range.
    (also a rollback)

Stack created with Sapling. Best reviewed with ReviewStack.

/// partition key range
#[bilrost(tag(4))]
#[serde(default)]
pub partition_key_range: Keys,
Copy link
Copy Markdown
Contributor Author

@muhamadazmy muhamadazmy May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to roll back this change that was introduced in a previous commit. It's not necessary now for all commands to implement HasRecordKeys. This was needed for the write path but it's no longer necessary.

@muhamadazmy muhamadazmy requested a review from AhmedSoliman May 12, 2026 12:41
@muhamadazmy muhamadazmy marked this pull request as ready for review May 12, 2026 12:42
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

Test Results

  8 files  ±0    8 suites  ±0   2m 25s ⏱️ - 2m 27s
 50 tests ±0   50 ✅ ±0  0 💤 ±0  0 ❌ ±0 
218 runs  ±0  218 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 069ddb4. ± Comparison against base commit cf62e91.

♻️ This comment has been updated with latest results.

@muhamadazmy
Copy link
Copy Markdown
Contributor Author

@AhmedSoliman it might be a good idea to look at #4700 to inspect exactly how the new trait is used in the SelfProposer and friends.

Comment thread crates/wal-protocol/src/v1.rs Outdated
// log per partition `Keys::Single` is enough for routing
// (`Keys::None` would also work); v2 decodes the typed command and
// uses the full range.
Command::UpsertRuleBook(_) => Keys::Single(self.partition_key()),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is entirely correct. This means that bifrost server-side filtering will not deliver this command to the right-hand-side of a partition after the partition is split.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see what you mean. The comment might be wrong but the code is still valid since we don't support partition splitting atm. By the time we do we will be already on v2 fully (writing v2) and in that case we will fully honour the full key range.

I think updating the comment should be enough for now, what do you think?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assumption you are making here is that splitting will require that all historical commands be on V2. It's a fair assumption but we'll need to make the state machine aware of this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reworked this so v1 Command body still has the partition key-range but is dropped in v2 but still backward compatible.

Could you take another and let's follow this conversation on #4722 since it's the one that actually introduced the change.

Comment on lines +470 to +473
arena.reserve(cmd.encoded_len());
// safe to unwrap because we reserved enough space
cmd.bilrost_encode(&mut arena).unwrap();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice ❤️

## Summary
- Convert `UpsertRuleBookCommand` to a `bilrost::Message` carrying
  `Arc<RuleBook>` directly, instead of a serde struct wrapping an
  already-bilrost-encoded `Bytes`. Eliminates the previous double encoding
  (serde-around-bilrost) on the proposal path.
- In v1, `Command::UpsertRuleBook` now wraps an opaque `Bytes` payload (the
  bilrost-encoded `UpsertRuleBookCommand`) rather than the typed struct.
  Because `UpsertRuleBook` is `*Since v1.7.0` and still unreleased, this
  payload change is backward compatible.
- v1→v2 compatibility no longer decodes/re-encodes the rule book; it
  forwards the bilrost payload via `Envelope::from_bytes_unchecked`,
  matching the existing pattern used for `VQueues*` / `VQSchedulerDecisions`.
- `record_keys()` for the v1 variant falls back to `Keys::Single(self.partition_key())`
  since the `partition_key_range` is no longer reachable without decoding.
- Leader proposer encodes the command into the shared arena buffer before
  proposing, avoiding an extra allocation.
- State machine now ignores `UpsertRuleBook` messages whose
  `partition_key_range` does not overlap the local partition's range,
  mirroring how other range-targeted commands are filtered.
Summary:
Replaces the type-erased `PartialEnvelope` with a `CommandWithKeys` trait
that unifies how WAL writers obtain record keys for a command:

- Auto-implemented for any `Command: HasRecordKeys` (keys come from the
  command itself).
- Implemented for `BodyWithKeys<C>` so commands that don't carry their
  own keys can still be enriched at the call site.

This lets generic write paths accept either form without an intermediate allocation,
and removes the now-redundant `StorageDecode` bound from the `Command` trait.

As a result:
Roll back the changes in the `UpdatePartitionDurabilityCommand`
- `UpdatePartitionDurabilityCommand` no longer needs to carry
  `partition_key_range` (was added in a previous commit)
  the key range is supplied via `BodyWithKeys` at publish time.
  (follw up PR to handle the Write path)
- `DurabilityTracker` takes a `PartitionId` instead of
  `Arc<Partition>`, since it no longer needs the key range.
  (also a rollback)
@muhamadazmy muhamadazmy merged commit d0aa1be into main May 12, 2026
58 of 59 checks passed
@muhamadazmy muhamadazmy deleted the pr4724 branch May 12, 2026 16:17
@github-actions github-actions Bot locked and limited conversation to collaborators May 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants