11use std:: sync:: Arc ;
22
3- use ahash:: HashSet ;
3+ use ahash:: HashMap ;
44use parking_lot:: Mutex ;
5- use rbuilder_primitives:: { OrderId , SimulatedOrder } ;
5+ use rbuilder_primitives:: { Order , OrderId , SimulatedOrder } ;
6+ use rbuilder_utils:: replace_event_scheduler:: ReplaceEventSchedulerSubscription ;
67use reth_provider:: StateProvider ;
7- use tokio:: sync:: mpsc:: { self , error :: TryRecvError } ;
8+ use tokio:: sync:: mpsc;
89use tokio_util:: sync:: CancellationToken ;
910use tracing:: { error, trace} ;
11+ use uuid:: Uuid ;
1012
1113use crate :: {
1214 building:: { BlockBuildingContext , ThreadBlockBuildingContext } ,
13- live_builder:: {
14- order_input:: order_sink:: OrderPoolCommand ,
15- simulation:: { simulation_job_tracer:: SimulationJobTracer , SimulatedOrderCommand } ,
16- } ,
15+ live_builder:: simulation:: { simulation_job_tracer:: SimulationJobTracer , SimulatedOrderCommand } ,
1716 provider:: StateProviderFactory ,
1817} ;
1918
@@ -23,67 +22,9 @@ use super::{simulate::simulate_priority_update, PriorityUpdatePool};
2322/// [`PUSimulationContext::subscribe`]. Matches the builder pipeline channel.
2423const PU_SUBSCRIBER_CHANNEL_CAPACITY : usize = 10_000 ;
2524
26- /// Upper bound on PU messages a sim worker drains per call to
27- /// [`PUSimWorkerOrderpool::consume_updates`].
25+ /// Upper bound on PU updates a sim worker drains per loop iteration.
2826const PU_BATCH_DRAIN_LIMIT : usize = 256 ;
2927
30- #[ derive( Debug ) ]
31- struct ClassifierInner {
32- cmd_sender : mpsc:: UnboundedSender < OrderPoolCommand > ,
33- tracked_orders : Mutex < HashSet < OrderId > > ,
34- }
35-
36- /// Classifier shared with [`SimulationJob`]: PU-classified commands are
37- /// forwarded to the PUR sim thread and swallowed from the main pipeline.
38- #[ derive( Clone , Debug ) ]
39- pub struct PURCommandClassifier {
40- inner : Arc < ClassifierInner > ,
41- }
42-
43- /// Receiver side handed to the PUR sim thread.
44- pub struct PURSimulationInput {
45- cmd_receiver : mpsc:: UnboundedReceiver < OrderPoolCommand > ,
46- }
47-
48- pub fn new_pur_simulation_channel ( ) -> ( PURCommandClassifier , PURSimulationInput ) {
49- let ( cmd_sender, cmd_receiver) = mpsc:: unbounded_channel ( ) ;
50- let classifier = PURCommandClassifier {
51- inner : Arc :: new ( ClassifierInner {
52- cmd_sender,
53- tracked_orders : Mutex :: new ( HashSet :: default ( ) ) ,
54- } ) ,
55- } ;
56- let input = PURSimulationInput { cmd_receiver } ;
57- ( classifier, input)
58- }
59-
60- impl PURCommandClassifier {
61- pub fn try_consuming_new_order_command ( & self , cmd : & OrderPoolCommand ) -> bool {
62- match cmd {
63- OrderPoolCommand :: Insert ( order) => {
64- if order. metadata ( ) . priority_update_data . is_none ( ) {
65- return false ;
66- }
67- self . inner . tracked_orders . lock ( ) . insert ( order. id ( ) ) ;
68- let _ = self
69- . inner
70- . cmd_sender
71- . send ( OrderPoolCommand :: Insert ( Arc :: clone ( order) ) ) ;
72- true
73- }
74- OrderPoolCommand :: Remove ( id) => {
75- let known = self . inner . tracked_orders . lock ( ) . remove ( id) ;
76- if known {
77- let _ = self . inner . cmd_sender . send ( OrderPoolCommand :: Remove ( * id) ) ;
78- true
79- } else {
80- false
81- }
82- }
83- }
84- }
85- }
86-
8728/// Shared inner state of the priority-update pool plus the fan-out subscriber
8829/// list.
8930#[ derive( Debug ) ]
@@ -139,7 +80,8 @@ impl PUSimWorkerOrderpool {
13980 Ok ( SimulatedOrderCommand :: Cancellation ( id) ) => {
14081 pool. apply_remove ( & id) ;
14182 }
142- Err ( TryRecvError :: Empty ) | Err ( TryRecvError :: Disconnected ) => break ,
83+ Err ( mpsc:: error:: TryRecvError :: Empty )
84+ | Err ( mpsc:: error:: TryRecvError :: Disconnected ) => break ,
14385 }
14486 }
14587 }
@@ -196,10 +138,11 @@ pub fn new_pu_simulation_runtime(
196138 )
197139}
198140
141+ /// Drives the priority-update simulation thread for one block.
199142pub async fn run_pur_sim_worker < P > (
200143 provider : P ,
201144 block_ctx : BlockBuildingContext ,
202- input : PURSimulationInput ,
145+ subscription : ReplaceEventSchedulerSubscription < Uuid , Option < Arc < Order > > > ,
203146 state : PUSimulationWorkerState ,
204147 block_cancellation : CancellationToken ,
205148 sim_tracer : Arc < dyn SimulationJobTracer > ,
@@ -215,72 +158,86 @@ pub async fn run_pur_sim_worker<P>(
215158 }
216159 } ;
217160
218- let PURSimulationInput { mut cmd_receiver } = input;
219-
220161 let mut local_ctx = ThreadBlockBuildingContext :: default ( ) ;
162+ let mut active: HashMap < Uuid , OrderId > = HashMap :: default ( ) ;
163+ let mut buf: Vec < ( Uuid , Option < Arc < Order > > ) > = Vec :: new ( ) ;
221164
222165 loop {
166+ buf. clear ( ) ;
167+ subscription. pop_unprocessed_events ( PU_BATCH_DRAIN_LIMIT , & mut buf) ;
168+ for ( uuid, maybe_order) in buf. drain ( ..) {
169+ process_event (
170+ uuid,
171+ maybe_order,
172+ & block_ctx,
173+ & mut local_ctx,
174+ & parent_state,
175+ & state,
176+ & sim_tracer,
177+ & mut active,
178+ )
179+ . await ;
180+ }
181+
223182 tokio:: select! {
224183 _ = block_cancellation. cancelled( ) => return ,
225- maybe_cmd = cmd_receiver. recv( ) => {
226- let Some ( cmd) = maybe_cmd else { return ; } ;
227- process_command(
228- cmd,
229- & block_ctx,
230- & mut local_ctx,
231- & parent_state,
232- & state,
233- & sim_tracer,
234- )
235- . await ;
236- }
184+ _ = subscription. notified( ) => { }
237185 }
238186 }
239187}
240188
241- async fn process_command (
242- cmd : OrderPoolCommand ,
189+ #[ allow( clippy:: too_many_arguments) ]
190+ async fn process_event (
191+ uuid : Uuid ,
192+ maybe_order : Option < Arc < Order > > ,
243193 block_ctx : & BlockBuildingContext ,
244194 local_ctx : & mut ThreadBlockBuildingContext ,
245195 parent_state : & Arc < dyn StateProvider > ,
246196 state : & PUSimulationWorkerState ,
247197 sim_tracer : & Arc < dyn SimulationJobTracer > ,
198+ active : & mut HashMap < Uuid , OrderId > ,
248199) {
249- match cmd {
250- OrderPoolCommand :: Insert ( order) => {
200+ match maybe_order {
201+ Some ( order) => {
251202 let order_id = order. id ( ) ;
252-
253203 let sim_res = simulate_priority_update (
254204 Arc :: clone ( & order) ,
255205 block_ctx,
256206 local_ctx,
257207 Arc :: clone ( parent_state) ,
258208 ) ;
259-
260209 let simulated_order = match sim_res {
261210 Ok ( Some ( res) ) => {
262- trace ! ( ?order_id, success = true , "PU simulated" ) ;
211+ trace ! ( ?order_id, ?uuid , success = true , "PU simulated" ) ;
263212 res
264213 }
265214 Ok ( None ) => {
266- trace ! ( ?order_id, success = false , "PU simulated" ) ;
215+ trace ! ( ?order_id, ?uuid , success = false , "PU simulated" ) ;
267216 return ;
268217 }
269218 Err ( err) => {
270- trace ! ( ?order_id, success = false , ?err, "PU simulated" ) ;
219+ trace ! ( ?order_id, ?uuid , success = false , ?err, "PU simulated" ) ;
271220 return ;
272221 }
273222 } ;
274223
224+ // New version supersedes the old: drop the previous OrderId for this uuid first.
225+ if let Some ( prev_id) = active. remove ( & uuid) {
226+ state. apply_remove ( prev_id) . await ;
227+ sim_tracer. update_cancellation_sent ( & prev_id) ;
228+ }
275229 let evicted = state. apply_update ( Arc :: clone ( & simulated_order) ) . await ;
276230 for evicted_id in & evicted {
277231 trace ! ( order_id = ?evicted_id, reason = "conflicting" , "PU removed" ) ;
278232 }
233+ active. insert ( uuid, order_id) ;
279234 }
280- OrderPoolCommand :: Remove ( order_id) => {
281- trace ! ( ?order_id, reason = "cancelled" , "PU removed" ) ;
282- state. apply_remove ( order_id) . await ;
283- sim_tracer. update_cancellation_sent ( & order_id) ;
235+ None => {
236+ if let Some ( prev_id) = active. remove ( & uuid) {
237+ trace ! ( order_id = ?prev_id, ?uuid, reason = "cancelled" , "PU removed" ) ;
238+ state. apply_remove ( prev_id) . await ;
239+ sim_tracer. update_cancellation_sent ( & prev_id) ;
240+ }
284241 }
285242 }
286243}
0 commit comments