solana_runtime::installed_scheduler_pool

Trait InstalledScheduler

Source
pub trait InstalledScheduler:
    Send
    + Sync
    + Debug
    + 'static {
    // Required methods
    fn id(&self) -> SchedulerId;
    fn context(&self) -> &SchedulingContext;
    fn schedule_execution(
        &self,
        transaction: SanitizedTransaction,
        index: usize,
    ) -> ScheduleResult;
    fn recover_error_after_abort(&mut self) -> TransactionError;
    fn wait_for_termination(
        self: Box<Self>,
        is_dropped: bool,
    ) -> (ResultWithTimings, UninstalledSchedulerBox);
    fn pause_for_recent_blockhash(&mut self);
}
Expand description

Schedules, executes, and commits transactions under encapsulated implementation

The following chart illustrates the ownership/reference interaction between inter-dependent objects across crates:

graph TD Bank["Arc#lt;Bank#gt;"] subgraph solana-runtime BankForks; BankWithScheduler; Bank; LoadExecuteAndCommitTransactions(["load_execute_and_commit_transactions()"]); SchedulingContext; InstalledSchedulerPool{{InstalledSchedulerPool}}; InstalledScheduler{{InstalledScheduler}}; end subgraph solana-unified-scheduler-pool SchedulerPool; PooledScheduler; ScheduleExecution(["schedule_execution()"]); end subgraph solana-ledger ExecuteBatch(["execute_batch()"]); end ScheduleExecution -. calls .-> ExecuteBatch; BankWithScheduler -. dyn-calls .-> ScheduleExecution; ExecuteBatch -. calls .-> LoadExecuteAndCommitTransactions; linkStyle 0,1,2 stroke:gray,color:gray; BankForks -- owns --> BankWithScheduler; BankForks -- owns --> InstalledSchedulerPool; BankWithScheduler -- refs --> Bank; BankWithScheduler -- owns --> InstalledScheduler; SchedulingContext -- refs --> Bank; InstalledScheduler -- owns --> SchedulingContext; SchedulerPool -- owns --> PooledScheduler; SchedulerPool -. impls .-> InstalledSchedulerPool; PooledScheduler -. impls .-> InstalledScheduler; PooledScheduler -- refs --> SchedulerPool;

Required Methods§

Source

fn id(&self) -> SchedulerId

Source

fn context(&self) -> &SchedulingContext

Source

fn schedule_execution( &self, transaction: SanitizedTransaction, index: usize, ) -> ScheduleResult

Schedule transaction for execution.

This non-blocking function will return immediately without waiting for actual execution.

Calling this is illegal as soon as wait_for_termination() is called. It would result in fatal logic error.

Note that the returned result indicates whether the scheduler has been aborted due to a previously-scheduled bad transaction, which terminates further block verification. So, almost always, the returned error isn’t due to the merely scheduling of the current transaction itself. At this point, calling this does nothing anymore while it’s still safe to do. As soon as notified, callers are expected to stop processing upcoming transactions of the same SchedulingContext (i.e. same block). Internally, the aborted scheduler will be disposed cleanly, not repooled, after wait_for_termination() is called like not-aborted schedulers.

Caller can acquire the error by calling a separate function called recover_error_after_abort(), which requires &mut self, instead of &self. This separation and the convoluted returned value semantics explained above are intentional to optimize the fast code-path of normal transaction scheduling to be multi-threaded at the cost of far slower error code-path while giving implementors increased flexibility by having &mut.

Source

fn recover_error_after_abort(&mut self) -> TransactionError

Return the error which caused the scheduler to abort.

Note that this must not be called until it’s observed that schedule_execution() has returned Err(SchedulerAborted). Violating this should panic!().

That said, calling this multiple times is completely acceptable after the error observation from schedule_execution(). While it’s not guaranteed, the same .clone()-ed errors of the first bad transaction are usually returned across invocations.

Source

fn wait_for_termination( self: Box<Self>, is_dropped: bool, ) -> (ResultWithTimings, UninstalledSchedulerBox)

Wait for a scheduler to terminate after processing.

This function blocks the current thread while waiting for the scheduler to complete all of the executions for the scheduled transactions and to return the finalized ResultWithTimings. This function still blocks for short period of time even in the case of aborted schedulers to gracefully shutdown the scheduler (like thread joining).

Along with the result being returned, this function also makes the scheduler itself uninstalled from the bank by transforming the consumed self.

If no transaction is scheduled, the result and timing will be Ok(()) and ExecuteTimings::default() respectively.

Source

fn pause_for_recent_blockhash(&mut self)

Pause a scheduler after processing to update bank’s recent blockhash.

This function blocks the current thread like wait_for_termination(). However, the scheduler won’t be consumed. This means the scheduler is responsible to retain the finalized ResultWithTimings internally until it’s wait_for_termination()-ed to collect the result later.

Implementors§