Share byte buffers across exec-server output chunks (#49972)

## Why

Retaining process output, publishing events, and serving reads cloned the underlying byte buffers. Sharing those buffers avoids copying output bytes when chunks are cloned.

## What changed

Store `ByteChunk` bytes in `Arc<Vec<u8>>` and retain `ProcessOutputChunk` values directly. Add borrowed byte access for the MCP process transport while preserving base64 serialization and owned byte extraction through `into_inner()`.

## Testing

Add a unit test covering base64 serialization, deserialization, and independent owned bytes extracted from shared chunks.

GitOrigin-RevId: 6bba114af48424aa844487aa75163cfc604e0575
This commit is contained in:
jif
2026-10-01 12:41:39 +00:00
committed by copyberry
parent d6c3b448a4
commit a933dd77db
7 changed files with 60 additions and 44 deletions
+31 -4
View File
@@ -60,19 +60,26 @@ pub const HTTP_REQUEST_BODY_DELTA_METHOD: &str = "http/request/bodyDelta";
/// Maximum decoded response-body bytes carried by one streamed HTTP notification.
pub const MAX_HTTP_BODY_DELTA_BYTES: usize = 1024 * 1024;
/// Shared immutable bytes, encoded as a base64 string on the wire.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct ByteChunk(#[serde(with = "base64_bytes")] pub Vec<u8>);
pub struct ByteChunk(#[serde(with = "base64_bytes")] pub Arc<Vec<u8>>);
impl ByteChunk {
pub fn into_inner(self) -> Vec<u8> {
self.0
Arc::unwrap_or_clone(self.0)
}
}
impl From<Vec<u8>> for ByteChunk {
fn from(value: Vec<u8>) -> Self {
Self(value)
Self(Arc::new(value))
}
}
impl AsRef<[u8]> for ByteChunk {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
@@ -1193,6 +1200,7 @@ mod base64_bytes {
use serde::Deserialize;
use serde::Deserializer;
use serde::Serializer;
use std::sync::Arc;
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
@@ -1201,13 +1209,14 @@ mod base64_bytes {
serializer.serialize_str(&BASE64_STANDARD.encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let encoded = String::deserialize(deserializer)?;
BASE64_STANDARD
.decode(encoded)
.map(Arc::new)
.map_err(serde::de::Error::custom)
}
}
@@ -1264,6 +1273,24 @@ mod tests {
use pretty_assertions::assert_eq;
use std::collections::HashMap;
#[test]
fn shared_byte_chunks_preserve_base64_and_owned_bytes() {
let chunk = super::ByteChunk::from(vec![0, 255, 10]);
let shared = chunk.clone();
assert_eq!(serde_json::to_string(&shared).unwrap(), r#""AP8K""#);
assert_eq!(
serde_json::from_str::<super::ByteChunk>(r#""AP8K""#).unwrap(),
chunk,
);
let mut owned = shared.into_inner();
owned[0] = 1;
assert_eq!(
(owned, chunk.into_inner()),
(vec![1, 255, 10], vec![0, 255, 10])
);
}
#[test]
fn exec_params_keeps_proxy_launch_separate_from_sandbox_facts() {
let cwd =