Skip to content

Commit 3e14098

Browse files
committed
wip
1 parent 2388b6a commit 3e14098

5 files changed

Lines changed: 274 additions & 105 deletions

File tree

apps/jet/src/tpu_sink.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ use {
77
task::{Context, Poll, ready},
88
},
99
yellowstone_jet_tpu_client::yellowstone_grpc::sender::{
10-
PollTpuSender, SendErrorKind, ShieldBlockList, YellowstoneTpuSender,
10+
PollYellowstoneTpuSender, SendErrorKind, ShieldBlockList, YellowstoneTpuSender,
1111
},
1212
yellowstone_shield_store::PolicyStore,
1313
};
1414

1515
pub struct TpuSink<St> {
16-
tpu_sender: PollTpuSender,
16+
tpu_sender: PollYellowstoneTpuSender,
1717
source: St,
1818
shield_store: Option<PolicyStore>,
1919
}
@@ -25,7 +25,7 @@ impl<St> TpuSink<St> {
2525
shield_store: Option<PolicyStore>,
2626
) -> Self {
2727
Self {
28-
tpu_sender: PollTpuSender::new(tpu_sender),
28+
tpu_sender: PollYellowstoneTpuSender::new(tpu_sender),
2929
source,
3030
shield_store,
3131
}

crates/tpu-client/src/core.rs

Lines changed: 126 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::prom;
4343
use {
4444
crate::config::{TpuOverrideInfo, TpuPortKind, TpuSenderConfig},
4545
bytes::Bytes,
46+
core::fmt,
4647
derive_more::Display,
4748
futures::task::AtomicWaker,
4849
quinn::{
@@ -58,11 +59,12 @@ use {
5859
solana_tls_utils::{QuicClientCertificate, SkipServerVerification, new_dummy_x509_certificate},
5960
std::{
6061
collections::{BTreeMap, HashMap, HashSet, VecDeque},
62+
future,
6163
net::{IpAddr, Ipv4Addr, SocketAddr},
6264
num::NonZeroUsize,
6365
pin::Pin,
6466
sync::{Arc, Mutex as StdMutex, atomic::AtomicBool},
65-
task::Poll,
67+
task::{Poll, ready},
6668
time::{Duration, Instant},
6769
},
6870
tokio::{
@@ -74,6 +76,7 @@ use {
7476
task::{self, Id, JoinError, JoinHandle, JoinSet},
7577
time::{Sleep, interval},
7678
},
79+
tokio_util::sync::PollSender,
7780
};
7881

7982
/// This has been copy-pasted from `solana_streamer::nonblocking::quic::ALPN_TPU_PROTOCOL_ID`
@@ -149,10 +152,25 @@ struct MultiStepIdentitySynchronizationCommand {
149152
/// Command to control driver behavior.
150153
///
151154
enum DriverCommand {
152-
UpdateIdenttiy(UpdateIdentityCommand),
155+
UpdateIdentity(UpdateIdentityCommand),
153156
MultiStepIdentitySynchronization(MultiStepIdentitySynchronizationCommand),
154157
}
155158

159+
impl fmt::Debug for DriverCommand {
160+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161+
match self {
162+
DriverCommand::UpdateIdentity(cmd) => f
163+
.debug_struct("UpdateIdentity")
164+
.field("new_identity", &cmd.new_identity.pubkey())
165+
.finish(),
166+
DriverCommand::MultiStepIdentitySynchronization(cmd) => f
167+
.debug_struct("MultiStepIdentitySynchronization")
168+
.field("new_identity", &cmd.new_identity.pubkey())
169+
.finish(),
170+
}
171+
}
172+
}
173+
156174
enum DriverTaskMeta {
157175
DropAllWorkers,
158176
}
@@ -2696,7 +2714,7 @@ where
26962714

26972715
async fn handle_cnc(&mut self, command: DriverCommand) {
26982716
match command {
2699-
DriverCommand::UpdateIdenttiy(cmd) => {
2717+
DriverCommand::UpdateIdentity(cmd) => {
27002718
let UpdateIdentityCommand {
27012719
new_identity,
27022720
callback,
@@ -3382,7 +3400,7 @@ impl TpuSenderDriverSpawner {
33823400
TpuSenderSessionContext {
33833401
driver_tx_sink: tx_inlet,
33843402
identity_updater: TpuSenderIdentityUpdater {
3385-
cnc_tx: driver_cnc_tx,
3403+
cnc_tx: PollSender::new(driver_cnc_tx),
33863404
},
33873405
driver_join_handle: jh,
33883406
}
@@ -3392,11 +3410,12 @@ impl TpuSenderDriverSpawner {
33923410
///
33933411
/// Handle to update the identity used by the TPU sender driver.
33943412
///
3413+
#[derive(Clone)]
33953414
pub struct TpuSenderIdentityUpdater {
33963415
///
33973416
/// Command-and-control channel to send command to the QUIC driver
33983417
///
3399-
cnc_tx: mpsc::Sender<DriverCommand>,
3418+
cnc_tx: PollSender<DriverCommand>,
34003419
}
34013420

34023421
///
@@ -3406,7 +3425,7 @@ impl TpuSenderIdentityUpdater {
34063425
///
34073426
/// Changes the configured identity in the QUIC driver
34083427
///
3409-
pub async fn update_identity(&mut self, identity: Keypair) {
3428+
pub fn update_identity(&mut self, identity: Keypair) -> UpdateIdentity {
34103429
let shared = UpdateIdentityInner {
34113430
set: AtomicBool::new(false),
34123431
waker: AtomicWaker::new(),
@@ -3416,15 +3435,12 @@ impl TpuSenderIdentityUpdater {
34163435
new_identity: identity,
34173436
callback: Arc::clone(&shared),
34183437
};
3419-
self.cnc_tx
3420-
.send(DriverCommand::UpdateIdenttiy(cmd))
3421-
.await
3422-
.expect("disconnected");
3423-
let update_identity = UpdateIdentity {
3438+
let cnc_tx = self.cnc_tx.clone();
3439+
3440+
UpdateIdentity {
34243441
inner: shared,
3425-
_this: self,
3426-
};
3427-
update_identity.await
3442+
state: UpdateIdentityState::Init { cnc_tx, cmd },
3443+
}
34283444
}
34293445

34303446
///
@@ -3446,10 +3462,13 @@ impl TpuSenderIdentityUpdater {
34463462
new_identity: identity,
34473463
barrier,
34483464
};
3449-
self.cnc_tx
3450-
.send(DriverCommand::MultiStepIdentitySynchronization(cmd))
3465+
let mut cnc_tx = self.cnc_tx.clone();
3466+
future::poll_fn(|cx| cnc_tx.poll_reserve(cx))
34513467
.await
34523468
.expect("disconnected");
3469+
cnc_tx
3470+
.send_item(DriverCommand::MultiStepIdentitySynchronization(cmd))
3471+
.expect("disconnected");
34533472
}
34543473
}
34553474

@@ -3461,39 +3480,106 @@ struct UpdateIdentityInner {
34613480
waker: AtomicWaker,
34623481
}
34633482

3483+
enum UpdateIdentityState {
3484+
Init {
3485+
cnc_tx: PollSender<DriverCommand>,
3486+
cmd: UpdateIdentityCommand,
3487+
},
3488+
Closed,
3489+
WaitingForCompletion,
3490+
}
3491+
34643492
///
34653493
/// Future that waits for the identity update to complete.
34663494
/// This future is used to ensure that the identity update is completed before proceeding.
34673495
///
3468-
pub struct UpdateIdentity<'a> {
3496+
pub struct UpdateIdentity {
34693497
inner: Arc<UpdateIdentityInner>,
3470-
_this: &'a TpuSenderIdentityUpdater, /* phantom data to prevent two threads from updating the identity at the same time */
3498+
state: UpdateIdentityState,
3499+
}
3500+
3501+
impl UpdateIdentity {
3502+
fn take_state(&mut self) -> UpdateIdentityState {
3503+
std::mem::replace(&mut self.state, UpdateIdentityState::Closed)
3504+
}
34713505
}
34723506

3473-
impl Future for UpdateIdentity<'_> {
3474-
type Output = ();
3507+
#[derive(Debug, thiserror::Error)]
3508+
#[error("tpu sender runtime closed")]
3509+
pub struct UpdateIdentityError;
3510+
3511+
impl Future for UpdateIdentity {
3512+
type Output = Result<(), UpdateIdentityError>;
34753513

34763514
fn poll(
34773515
self: std::pin::Pin<&mut Self>,
34783516
cx: &mut std::task::Context<'_>,
34793517
) -> std::task::Poll<Self::Output> {
3480-
// quick check to avoid registration if already done.
3481-
if self.inner.set.load(std::sync::atomic::Ordering::Relaxed) {
3482-
return Poll::Ready(());
3483-
}
3484-
3485-
self.inner.waker.register(cx.waker());
3518+
let this = self.get_mut();
3519+
3520+
let (result, next_state) = match this.take_state() {
3521+
UpdateIdentityState::Init { mut cnc_tx, cmd } => {
3522+
match ready!(cnc_tx.poll_reserve(cx)) {
3523+
Ok(()) => {
3524+
match cnc_tx.send_item(DriverCommand::UpdateIdentity(cmd)) {
3525+
Ok(()) => {
3526+
this.inner.waker.register(cx.waker());
3527+
// Between the time we send and the registration, the driver may have already completed the update and set the atomic bool.
3528+
// So we need to immediately wake the waker, so that the next poll will check the atomic bool and return ready if the update is already complete.
3529+
cx.waker().wake_by_ref();
3530+
(None, UpdateIdentityState::WaitingForCompletion)
3531+
}
3532+
Err(_) => (Some(Err(UpdateIdentityError)), UpdateIdentityState::Closed),
3533+
}
3534+
}
3535+
Err(_) => (Some(Err(UpdateIdentityError)), UpdateIdentityState::Closed),
3536+
}
3537+
}
3538+
UpdateIdentityState::WaitingForCompletion => {
3539+
if this.inner.set.load(std::sync::atomic::Ordering::Relaxed) {
3540+
(Some(Ok(())), UpdateIdentityState::Closed)
3541+
} else {
3542+
(None, UpdateIdentityState::WaitingForCompletion)
3543+
}
3544+
}
3545+
UpdateIdentityState::Closed => {
3546+
panic!("UpdateIdentity polled after completion");
3547+
}
3548+
};
34863549

3487-
// Need to check condition **after** `register` to avoid a race
3488-
// condition that would result in lost notifications.
3489-
if self.inner.set.load(std::sync::atomic::Ordering::Relaxed) {
3490-
Poll::Ready(())
3550+
this.state = next_state;
3551+
if let Some(result) = result {
3552+
return Poll::Ready(result);
34913553
} else {
3492-
Poll::Pending
3554+
return Poll::Pending;
34933555
}
34943556
}
34953557
}
34963558

3559+
// impl Future for UpdateIdentity<'_> {
3560+
// type Output = ();
3561+
3562+
// fn poll(
3563+
// self: std::pin::Pin<&mut Self>,
3564+
// cx: &mut std::task::Context<'_>,
3565+
// ) -> std::task::Poll<Self::Output> {
3566+
// // quick check to avoid registration if already done.
3567+
// if self.inner.set.load(std::sync::atomic::Ordering::Relaxed) {
3568+
// return Poll::Ready(());
3569+
// }
3570+
3571+
// self.inner.waker.register(cx.waker());
3572+
3573+
// // Need to check condition **after** `register` to avoid a race
3574+
// // condition that would result in lost notifications.
3575+
// if self.inner.set.load(std::sync::atomic::Ordering::Relaxed) {
3576+
// Poll::Ready(())
3577+
// } else {
3578+
// Poll::Pending
3579+
// }
3580+
// }
3581+
// }
3582+
34973583
pub const fn module_path_for_test() -> &'static str {
34983584
module_path!()
34993585
}
@@ -3508,15 +3594,18 @@ mod test {
35083594
solana_pubkey::Pubkey,
35093595
std::time::Duration,
35103596
tokio::sync::mpsc,
3597+
tokio_util::sync::PollSender,
35113598
};
35123599

35133600
#[tokio::test]
35143601
async fn test_update_identity_fut() {
35153602
let (cnc_tx, mut cnc_rx) = mpsc::channel(10);
3516-
let mut updater = TpuSenderIdentityUpdater { cnc_tx };
3603+
let mut updater = TpuSenderIdentityUpdater {
3604+
cnc_tx: PollSender::new(cnc_tx),
3605+
};
35173606

35183607
let jh = tokio::spawn(async move {
3519-
let DriverCommand::UpdateIdenttiy(UpdateIdentityCommand {
3608+
let DriverCommand::UpdateIdentity(UpdateIdentityCommand {
35203609
new_identity,
35213610
callback,
35223611
}) = cnc_rx.recv().await.unwrap()
@@ -3533,7 +3622,10 @@ mod test {
35333622
});
35343623

35353624
let identity = Keypair::new();
3536-
updater.update_identity(identity.insecure_clone()).await;
3625+
updater
3626+
.update_identity(identity.insecure_clone())
3627+
.await
3628+
.unwrap();
35373629

35383630
let actual = jh.await.unwrap();
35393631
assert_eq!(actual, identity)

0 commit comments

Comments
 (0)