Skip to content

Commit 77b2639

Browse files
committed
[worker] Introduce a new byte aware self proposer scheduler
1 parent c86fd62 commit 77b2639

9 files changed

Lines changed: 814 additions & 220 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/bifrost/src/background_appender.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ use std::num::NonZeroUsize;
1313
use bytes::BytesMut;
1414
use futures::FutureExt;
1515
use pin_project::pin_project;
16-
use restate_memory::{MemoryLease, MemoryPool, NonZeroByteCount};
1716
use tokio::sync::mpsc::error::TryRecvError;
1817
use tokio::sync::{mpsc, oneshot};
1918
use tracing::{trace, warn};
2019

2120
use restate_core::{ShutdownError, TaskCenter, TaskHandle, cancellation_token};
21+
use restate_memory::{MemoryLease, MemoryPool, NonZeroByteCount, PollMemoryPool};
2222
use restate_types::logs::Record;
2323
use restate_types::storage::StorageEncode;
2424

@@ -310,15 +310,11 @@ pub struct LogSender<T> {
310310
}
311311

312312
impl<T: StorageEncode> LogSender<T> {
313-
/// Returns whether the next record or batch can be admitted.
314-
pub fn has_capacity(&self) -> bool {
315-
self.mem_pool.available() > 0
316-
}
317-
318-
/// Waits until the next record or batch can be admitted.
319-
pub fn wait_for_capacity(&self) -> impl std::future::Future<Output = ()> + 'static {
320-
let mem_pool = self.mem_pool.clone();
321-
async move { mem_pool.wait_until_available().await }
313+
/// Returns a poll-style watcher over the appender's memory-pool capacity,
314+
/// for use in manual [`std::future::Future::poll`] implementations. Waker
315+
/// registration survives across polls.
316+
pub fn capacity_poller(&self) -> PollMemoryPool {
317+
PollMemoryPool::new(self.mem_pool.clone())
322318
}
323319

324320
fn admit<E>(&self, payload: E) -> Result<E, EnqueueError<E>> {

crates/memory/src/pool.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,44 @@ impl PollMemoryPool {
531531
}
532532
}
533533
}
534+
535+
/// Waits until the pool has any available budget, registering `cx` for
536+
/// wakeup while it is exhausted.
537+
///
538+
/// Like [`MemoryPool::wait_until_available`], there is no guarantee that
539+
/// the budget is still available by the time the caller acts on it.
540+
pub fn poll_available(&mut self, cx: &mut std::task::Context<'_>) -> Poll<()> {
541+
// Fast path: unlimited pools always have budget.
542+
if self.pool.is_unlimited() {
543+
return Poll::Ready(());
544+
}
545+
546+
loop {
547+
// Ensure we have a notified future *before* checking availability,
548+
// so we don't miss a concurrent `return_memory()` notification.
549+
let notified = self.notified.get_or_insert_with(|| {
550+
Box::pin(
551+
self.pool
552+
.availability_notified_owned()
553+
.expect("bounded pool must provide notified"),
554+
)
555+
});
556+
557+
if self.pool.available() > 0 {
558+
self.notified = None;
559+
return Poll::Ready(());
560+
}
561+
562+
match notified.as_mut().poll(cx) {
563+
Poll::Pending => return Poll::Pending,
564+
Poll::Ready(()) => {
565+
// We were notified — discard the consumed future and loop
566+
// to re-check availability with a fresh notified.
567+
self.notified = None;
568+
}
569+
}
570+
}
571+
}
534572
}
535573

536574
const _: () = {

crates/worker/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ bytes = { workspace = true }
6060
bytestring = { workspace = true }
6161
codederror = { workspace = true }
6262
derive_more = { workspace = true, features = ["debug", "display", "from"] }
63+
enum-map = { workspace = true }
6364
futures = { workspace = true }
6465
itertools = { workspace = true }
6566
metrics = { workspace = true }

0 commit comments

Comments
 (0)