Skip to content

Optional serialization/deserialization for WorkerChannel - #566

Open
gabotechs wants to merge 1 commit into
mainfrom
gabrielmusat/optional-serde
Open

Optional serialization/deserialization for WorkerChannel#566
gabotechs wants to merge 1 commit into
mainfrom
gabrielmusat/optional-serde

Conversation

@gabotechs

@gabotechs gabotechs commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator

Adds some small changes to the WorkerChannel contract so that [de]serialization is optional. In-memory implementations might not want to pay the overhead of serializing plans.

Details about the changes explained in individual comments guiding reviews.

@gabotechs
gabotechs force-pushed the gabrielmusat/optional-serde branch from a7fe44c to 40cf654 Compare July 26, 2026 12:39
Comment on lines -201 to +203
.coordinator_channel(headers, coordinator_to_worker_stream)
.coordinator_channel(
headers,
set_plan_request,
coordinator_to_worker_stream,
&task_ctx,
metrics_set,
)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Now we need to pass two extra things here:

  1. the SetPlanRequest. Before, this was sent as the first message in the stream, this being an invariant of the coordinator->worker channel: the first message always needs to be the SetPlanRequest. This was an artificial invariant imposed by gRPC spec limitations: in gRPC you cannot send both a stream and a unary message at the same time. As this is specific to gRPC, handling this behavior was moved under the grpc scope, and the WorkerChannel protocol accepts now the two things separately the CoordinatorToWorkerStream and the SetPlanRequest.
  2. An ExecutionPlanMetricsSet. The coordinator_channel implementations now decide if the inner messages need to be deserialized or can be passed in-memory, so some metrics like plan_bytes_sent are now implementation specific (an in-memory implementation will never even serialize to bytes). For this, ExecutionPlanMetricsSet is passed to give the chance to implementations to contribute their own metrics.

}

impl ProducerHead {
pub(crate) fn to_spec(&self, cfg: &SessionConfig) -> Result<ProducerHeadSpec> {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Now, we can get read of the intermediary ProducerHeadSpec, as this existed just for bridging a gap that no longer exists: the original ProducerHead can just hold a reference to MaybeEncoded and handle both in-memory and serialized formats.

More information about what this was needed before in point 1 of the PR description in #512 (comment).

}
ProducerHead::RepartitionExec { partitioning } => Arc::new(RepartitionExec::try_new(
input,
partitioning.try_decoded()?,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I don't love this. This is a runtime failure that was irrepresentable before, but now we need this try_decoded()? runtime check because we cannot proceed here if the ProducerHead contains a serialized Partitioning struct.

It allows to remove so much code that I think it's worth it.

Comment on lines +204 to 208
pb::coordinator_to_worker_msg::Inner::SetPlanRequest(_) => {
return Err(Status::invalid_argument(
"SetPlanRequest must be the first coordinator message",
));
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

As the fact that SetPlanRequest is the first message in the stream is an invariant imposed by gRPC itself, it's now checked here, instead of the outside of the grpc scope

@gabotechs
gabotechs force-pushed the gabrielmusat/optional-serde branch from 40cf654 to fb1b599 Compare July 26, 2026 13:30
@gabotechs

Copy link
Copy Markdown
Collaborator Author

cc @stuhood and @mdashti, this should be complimentary to #548. With this, an in-memory implementation of the WorkerChannel no longer needs to pay the price of serialization, keeping everything in-memory.

@stuhood

stuhood commented Jul 27, 2026

Copy link
Copy Markdown

cc @stuhood and @mdashti, this should be complimentary to #548. With this, an in-memory implementation of the WorkerChannel no longer needs to pay the price of serialization, keeping everything in-memory.

Interesting, thanks. Is there some other motivation for this beyond the in-memory implementation?

While the in-memory implementation is important for test/smoke coverage, I think that all practical implementations will need to serialize: ours certainly does.

Knowing what the other use cases are would help justify the added complexity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants