mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 05:15:00 +00:00
Cap MessageStream
buffer size to 1MB
We temporarily let it grow when the message size exceed the limit, but restore the buffer's capacity shortly after. This ensures that, for each connection in its entire lifetime, we only ever use 1MB.
This commit is contained in:
parent
da46d78ea5
commit
339069b1d3
17 changed files with 62 additions and 19 deletions
|
@ -17,7 +17,7 @@ anyhow = "1.0.38"
|
||||||
isahc = "1.7"
|
isahc = "1.7"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
smol = "1.2.5"
|
smol = "1.2.5"
|
||||||
tempdir = "0.3.7"
|
tempdir = "0.3.7"
|
||||||
|
|
|
@ -16,7 +16,7 @@ anyhow = "1.0"
|
||||||
clap = { version = "3.1", features = ["derive"] }
|
clap = { version = "3.1", features = ["derive"] }
|
||||||
dirs = "3.0"
|
dirs = "3.0"
|
||||||
ipc-channel = "0.16"
|
ipc-channel = "0.16"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
core-foundation = "0.9"
|
core-foundation = "0.9"
|
||||||
|
|
|
@ -34,7 +34,7 @@ parking_lot = "0.11.1"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
reqwest = { version = "0.11", features = ["json"], optional = true }
|
reqwest = { version = "0.11", features = ["json"], optional = true }
|
||||||
scrypt = "0.7"
|
scrypt = "0.7"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
sha-1 = "0.9"
|
sha-1 = "0.9"
|
||||||
time = "0.2"
|
time = "0.2"
|
||||||
|
|
|
@ -23,7 +23,7 @@ anyhow = "1.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
language = { path = "../language", features = ["test-support"] }
|
language = { path = "../language", features = ["test-support"] }
|
||||||
|
|
|
@ -45,7 +45,7 @@ ordered-float = "2.1.1"
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
postage = { version = "0.4", features = ["futures-traits"] }
|
postage = { version = "0.4", features = ["futures-traits"] }
|
||||||
rand = { version = "0.8.3", optional = true }
|
rand = { version = "0.8.3", optional = true }
|
||||||
serde = { version = "1", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
rand = "0.8.3"
|
rand = "0.8.3"
|
||||||
resvg = "0.14"
|
resvg = "0.14"
|
||||||
seahash = "4.1"
|
seahash = "4.1"
|
||||||
serde = { version = "1.0.125", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
|
|
|
@ -40,7 +40,7 @@ log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
parking_lot = "0.11.1"
|
parking_lot = "0.11.1"
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
rand = { version = "0.8.3", optional = true }
|
rand = { version = "0.8.3", optional = true }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1", features = ["preserve_order"] }
|
serde_json = { version = "1", features = ["preserve_order"] }
|
||||||
similar = "1.3"
|
similar = "1.3"
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
|
|
|
@ -21,7 +21,7 @@ log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
lsp-types = "0.91"
|
lsp-types = "0.91"
|
||||||
parking_lot = "0.11"
|
parking_lot = "0.11"
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["raw_value"] }
|
serde_json = { version = "1.0", features = ["raw_value"] }
|
||||||
smol = "1.2"
|
smol = "1.2"
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ parking_lot = "0.11.1"
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
rand = "0.8.3"
|
rand = "0.8.3"
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
sha2 = "0.10"
|
sha2 = "0.10"
|
||||||
similar = "1.3"
|
similar = "1.3"
|
||||||
|
|
|
@ -25,7 +25,7 @@ parking_lot = "0.11.1"
|
||||||
prost = "0.8"
|
prost = "0.8"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rsa = "0.4"
|
rsa = "0.4"
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
smol-timeout = "0.6"
|
smol-timeout = "0.6"
|
||||||
tracing = { version = "0.1.34", features = ["log"] }
|
tracing = { version = "0.1.34", features = ["log"] }
|
||||||
zstd = "0.9"
|
zstd = "0.9"
|
||||||
|
|
|
@ -254,6 +254,8 @@ entity_messages!(
|
||||||
|
|
||||||
entity_messages!(channel_id, ChannelMessageSent);
|
entity_messages!(channel_id, ChannelMessageSent);
|
||||||
|
|
||||||
|
const MAX_BUFFER_LEN: usize = 1 * 1024 * 1024;
|
||||||
|
|
||||||
/// A stream of protobuf messages.
|
/// A stream of protobuf messages.
|
||||||
pub struct MessageStream<S> {
|
pub struct MessageStream<S> {
|
||||||
stream: S,
|
stream: S,
|
||||||
|
@ -293,14 +295,16 @@ where
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
Message::Envelope(message) => {
|
Message::Envelope(message) => {
|
||||||
self.encoding_buffer.resize(message.encoded_len(), 0);
|
self.encoding_buffer.reserve(message.encoded_len());
|
||||||
self.encoding_buffer.clear();
|
|
||||||
message
|
message
|
||||||
.encode(&mut self.encoding_buffer)
|
.encode(&mut self.encoding_buffer)
|
||||||
.map_err(|err| io::Error::from(err))?;
|
.map_err(|err| io::Error::from(err))?;
|
||||||
let buffer =
|
let buffer =
|
||||||
zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL)
|
zstd::stream::encode_all(self.encoding_buffer.as_slice(), COMPRESSION_LEVEL)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
self.encoding_buffer.clear();
|
||||||
|
self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
|
||||||
self.stream.send(WebSocketMessage::Binary(buffer)).await?;
|
self.stream.send(WebSocketMessage::Binary(buffer)).await?;
|
||||||
}
|
}
|
||||||
Message::Ping => {
|
Message::Ping => {
|
||||||
|
@ -327,10 +331,12 @@ where
|
||||||
while let Some(bytes) = self.stream.next().await {
|
while let Some(bytes) = self.stream.next().await {
|
||||||
match bytes? {
|
match bytes? {
|
||||||
WebSocketMessage::Binary(bytes) => {
|
WebSocketMessage::Binary(bytes) => {
|
||||||
self.encoding_buffer.clear();
|
|
||||||
zstd::stream::copy_decode(bytes.as_slice(), &mut self.encoding_buffer).unwrap();
|
zstd::stream::copy_decode(bytes.as_slice(), &mut self.encoding_buffer).unwrap();
|
||||||
let envelope = Envelope::decode(self.encoding_buffer.as_slice())
|
let envelope = Envelope::decode(self.encoding_buffer.as_slice())
|
||||||
.map_err(io::Error::from)?;
|
.map_err(io::Error::from)?;
|
||||||
|
|
||||||
|
self.encoding_buffer.clear();
|
||||||
|
self.encoding_buffer.shrink_to(MAX_BUFFER_LEN);
|
||||||
return Ok(Message::Envelope(envelope));
|
return Ok(Message::Envelope(envelope));
|
||||||
}
|
}
|
||||||
WebSocketMessage::Ping(_) => return Ok(Message::Ping),
|
WebSocketMessage::Ping(_) => return Ok(Message::Ping),
|
||||||
|
@ -379,3 +385,40 @@ impl From<Nonce> for u128 {
|
||||||
upper_half | lower_half
|
upper_half | lower_half
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_buffer_size() {
|
||||||
|
let (tx, rx) = futures::channel::mpsc::unbounded();
|
||||||
|
let mut sink = MessageStream::new(tx.sink_map_err(|_| anyhow!("")));
|
||||||
|
sink.write(Message::Envelope(Envelope {
|
||||||
|
payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
|
||||||
|
root_name: "abcdefg".repeat(10),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
|
||||||
|
sink.write(Message::Envelope(Envelope {
|
||||||
|
payload: Some(envelope::Payload::UpdateWorktree(UpdateWorktree {
|
||||||
|
root_name: "abcdefg".repeat(1000000),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
assert!(sink.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
|
||||||
|
|
||||||
|
let mut stream = MessageStream::new(rx.map(|msg| anyhow::Ok(msg)));
|
||||||
|
stream.read().await.unwrap();
|
||||||
|
assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
|
||||||
|
stream.read().await.unwrap();
|
||||||
|
assert!(stream.encoding_buffer.capacity() <= MAX_BUFFER_LEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ workspace = { path = "../workspace" }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -19,7 +19,7 @@ util = { path = "../util" }
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
json_comments = "0.2"
|
json_comments = "0.2"
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
serde = { version = "1", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
serde_path_to_error = "0.1.4"
|
serde_path_to_error = "0.1.4"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
|
|
|
@ -12,7 +12,7 @@ gpui = { path = "../gpui" }
|
||||||
anyhow = "1.0.38"
|
anyhow = "1.0.38"
|
||||||
indexmap = "1.6.2"
|
indexmap = "1.6.2"
|
||||||
parking_lot = "0.11.1"
|
parking_lot = "0.11.1"
|
||||||
serde = { version = "1", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
serde_path_to_error = "0.1.4"
|
serde_path_to_error = "0.1.4"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
|
|
|
@ -13,7 +13,7 @@ collections = { path = "../collections" }
|
||||||
editor = { path = "../editor" }
|
editor = { path = "../editor" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
settings = { path = "../settings" }
|
settings = { path = "../settings" }
|
||||||
workspace = { path = "../workspace" }
|
workspace = { path = "../workspace" }
|
||||||
itertools = "0.10"
|
itertools = "0.10"
|
||||||
|
|
|
@ -25,7 +25,7 @@ futures = "0.3"
|
||||||
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
log = { version = "0.4.16", features = ["kv_unstable_serde"] }
|
||||||
parking_lot = "0.11.1"
|
parking_lot = "0.11.1"
|
||||||
postage = { version = "0.4.1", features = ["futures-traits"] }
|
postage = { version = "0.4.1", features = ["futures-traits"] }
|
||||||
serde = { version = "1", features = ["derive", "rc"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
smallvec = { version = "1.6", features = ["union"] }
|
smallvec = { version = "1.6", features = ["union"] }
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ rand = "0.8.3"
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
rsa = "0.4"
|
rsa = "0.4"
|
||||||
rust-embed = { version = "6.3", features = ["include-exclude"] }
|
rust-embed = { version = "6.3", features = ["include-exclude"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive", "rc"] }
|
||||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||||
serde_path_to_error = "0.1.4"
|
serde_path_to_error = "0.1.4"
|
||||||
simplelog = "0.9"
|
simplelog = "0.9"
|
||||||
|
|
Loading…
Reference in a new issue