Skip to content

Commit 26c2b87

Browse files
committed
problem: OOM on compaction, b/c it reads faster than writes
1 parent 399dfe6 commit 26c2b87

2 files changed

Lines changed: 12 additions & 6 deletions

File tree

src/storage/avro_reader.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ use std::io::Read;
22
use anyhow::anyhow;
33
use apache_avro::Schema;
44
use apache_avro::types::Record;
5-
use tokio::sync::mpsc::{unbounded_channel, UnboundedReceiver};
5+
use tokio::sync::mpsc;
66
use crate::{avros, global, metrics};
77
use crate::archiver::datakind::DataKind;
88

9+
/// How many deserialized records the reader may buffer before it blocks waiting
10+
/// for the consumer to catch up. Keeps memory bounded while still allowing the
11+
/// reader thread to stay ahead of the consumer.
12+
const READ_CHANNEL_CAPACITY: usize = 16;
13+
914
/// Wraps a `Read` and reports bytes read to metrics as they flow through.
1015
struct CountingReader<R> {
1116
inner: R,
@@ -20,8 +25,8 @@ impl<R: Read> Read for CountingReader<R> {
2025
}
2126
}
2227

23-
pub(super) fn consume_sync<R: Read + Send + 'static>(kind: DataKind, schema: &'static Schema, reader: R) -> UnboundedReceiver<Record<'static>> {
24-
let (tx, rx) = unbounded_channel();
28+
pub(super) fn consume_sync<R: Read + Send + 'static>(kind: DataKind, schema: &'static Schema, reader: R) -> mpsc::Receiver<Record<'static>> {
29+
let (tx, rx) = mpsc::channel(READ_CHANNEL_CAPACITY);
2530

2631
tokio::task::spawn_blocking(move || {
2732
tracing::trace!("Reading avro file...");
@@ -50,7 +55,9 @@ pub(super) fn consume_sync<R: Read + Send + 'static>(kind: DataKind, schema: &'s
5055
continue
5156
}
5257
let record = record.unwrap();
53-
if let Err(e) = tx.send(record) {
58+
// blocking_send applies backpressure — the reader thread pauses when
59+
// the channel is full, preventing unbounded memory growth
60+
if let Err(e) = tx.blocking_send(record) {
5461
tracing::error!("Error sending record to channel: {:?}", e);
5562
break
5663
}

src/storage/copy.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use tokio::sync::mpsc::UnboundedReceiver;
21
use crate::global;
32

4-
pub(super) fn copy_from_sync<T: Send + 'static>(mut source: UnboundedReceiver<T>) -> tokio::sync::mpsc::Receiver<T> {
3+
pub(super) fn copy_from_sync<T: Send + 'static>(mut source: tokio::sync::mpsc::Receiver<T>) -> tokio::sync::mpsc::Receiver<T> {
54
let (tx, rx) = tokio::sync::mpsc::channel(2);
65
tokio::spawn(async move {
76
let shutdown = global::get_shutdown();

0 commit comments

Comments
 (0)