Skip to main content

gear_common/
scheduler.rs

1// Copyright (C) Gear Technologies Inc.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4//! Module for scheduler implementation.
5//!
6//! Scheduler provides API for all available regular or time-dependent actions.
7
8use crate::storage::{
9    CountedByKey, DoubleMapStorage, EmptyCallback, KeyIterableByKeyMap, ValueStorage,
10};
11use core::{fmt::Debug, marker::PhantomData};
12
13/// Represents scheduler's logic of centralized delayed tasks management logic.
14pub trait Scheduler {
15    /// Block number type of the messenger.
16    type BlockNumber;
17    /// Task type.
18    type Task;
19    /// Cost type.
20    type Cost;
21    /// Inner error type generated by gear's storage types.
22    type Error: TaskPoolError;
23    /// Output error of each storage algorithm.
24    ///
25    /// Implements `From<Self::Error>` to be able to return
26    /// any required error type.
27    type OutputError: From<Self::Error> + Debug;
28
29    /// Storing costs per block.
30    type CostsPerBlock: SchedulingCostsPerBlock<BlockNumber = Self::BlockNumber, Cost = Self::Cost>;
31
32    /// The first block of incomplete tasks, which have already passed,
33    /// but still contain tasks to deal with.
34    ///
35    /// Used for checking if scheduler is able to process
36    /// current block aimed tasks, or there are some
37    /// incomplete job from previous blocks.
38    type FirstIncompleteTasksBlock: ValueStorage<Value = Self::BlockNumber>;
39
40    /// Gear task pool.
41    ///
42    /// Task pool contains tasks with block number when they should be done.
43    type TaskPool: TaskPool<
44            BlockNumber = Self::BlockNumber,
45            Task = Self::Task,
46            Error = Self::Error,
47            OutputError = Self::OutputError,
48        > + CountedByKey<Key = Self::BlockNumber, Length = usize>
49        + KeyIterableByKeyMap<Key1 = Self::BlockNumber, Key2 = Self::Task>;
50
51    /// Resets all related to messenger storages.
52    ///
53    /// It's a temporary production solution to avoid DB migrations
54    /// and would be available for test purposes only in the future.
55    fn reset() {
56        Self::FirstIncompleteTasksBlock::kill();
57        Self::TaskPool::clear();
58    }
59}
60
61/// Storing costs getter trait.
62pub trait SchedulingCostsPerBlock {
63    /// Block number type.
64    type BlockNumber;
65    /// Cost type.
66    type Cost;
67
68    /// Extra reserve for being able to pay for blocks with incomplete tasks.
69    fn reserve_for() -> Self::BlockNumber;
70
71    /// Cost for storing code per block.
72    fn code() -> Self::Cost;
73    /// Cost for storing message in mailbox per block.
74    fn mailbox() -> Self::Cost;
75    /// Cost for storing program per block.
76    fn program() -> Self::Cost;
77    /// Cost for storing message in waitlist per block.
78    fn waitlist() -> Self::Cost;
79    /// Cost for reservation holding.
80    fn reservation() -> Self::Cost;
81    /// Cost for storing message in dispatch stash.
82    /// Everything sent delayed goes into dispatch stash.
83    fn dispatch_stash() -> Self::Cost;
84
85    /// Derives the cost per block based on the lock identifier
86    fn by_storage_type(storage: StorageType) -> Self::Cost;
87}
88
89/// The type whose variants correspond to various storages used in Gear,
90/// including waitlist, mailbox, delayed messages stash etc.
91/// Used as a parameter in functions performing some common actions on storages
92/// like, for instance, holding cost calculation, to signal a concrete storage kind.
93#[derive(Debug, Clone, Copy)]
94pub enum StorageType {
95    Code,
96    Mailbox,
97    Program,
98    Waitlist,
99    Reservation,
100    DispatchStash,
101}
102
103/// Represents tasks managing logic.
104pub trait TaskPool {
105    /// Block number type.
106    type BlockNumber;
107    /// Task type.
108    type Task;
109    /// Inner error type of queue storing algorithm.
110    type Error: TaskPoolError;
111    /// Output error type of the queue.
112    type OutputError: From<Self::Error>;
113
114    /// Inserts given task in task pool.
115    fn add(bn: Self::BlockNumber, task: Self::Task) -> Result<(), Self::OutputError>;
116
117    /// Removes all tasks from task pool.
118    fn clear();
119
120    /// Returns bool, defining does task exist in task pool.
121    fn contains(bn: &Self::BlockNumber, task: &Self::Task) -> bool;
122
123    /// Removes task from task pool by given keys,
124    /// if present, else returns error.
125    fn delete(bn: Self::BlockNumber, task: Self::Task) -> Result<(), Self::OutputError>;
126}
127
128/// Represents store of task pool's action callbacks.
129pub trait TaskPoolCallbacks {
130    /// Callback on success `add`.
131    type OnAdd: EmptyCallback;
132    /// Callback on success `delete`.
133    type OnDelete: EmptyCallback;
134}
135
136/// Represents task pool error type.
137///
138/// Contains constructors for all existing errors.
139pub trait TaskPoolError {
140    /// Occurs when given task already exists in task pool.
141    fn duplicate_task() -> Self;
142
143    /// Occurs when task wasn't found in storage.
144    fn task_not_found() -> Self;
145}
146
147/// `TaskPool` implementation based on `DoubleMapStorage`.
148///
149/// Generic parameter `Error` requires `TaskPoolError` implementation.
150/// Generic parameter `Callbacks` presents actions for success operations
151/// over task pool.
152pub struct TaskPoolImpl<T, Task, Error, OutputError, Callbacks>(
153    PhantomData<(T, Task, Error, OutputError, Callbacks)>,
154)
155where
156    T: DoubleMapStorage<Key2 = Task, Value = ()>,
157    Error: TaskPoolError,
158    OutputError: From<Error>,
159    Callbacks: TaskPoolCallbacks;
160
161// Implementation of `TaskPool` for `TaskPoolImpl`.
162impl<T, Task, Error, OutputError, Callbacks> TaskPool
163    for TaskPoolImpl<T, Task, Error, OutputError, Callbacks>
164where
165    T: DoubleMapStorage<Key2 = Task, Value = ()>,
166    Error: TaskPoolError,
167    OutputError: From<Error>,
168    Callbacks: TaskPoolCallbacks,
169{
170    type BlockNumber = T::Key1;
171    type Task = T::Key2;
172    type Error = Error;
173    type OutputError = OutputError;
174
175    fn add(bn: Self::BlockNumber, task: Self::Task) -> Result<(), Self::OutputError> {
176        if !Self::contains(&bn, &task) {
177            T::insert(bn, task, ());
178            Callbacks::OnAdd::call();
179            Ok(())
180        } else {
181            Err(Self::Error::duplicate_task().into())
182        }
183    }
184
185    fn clear() {
186        T::clear()
187    }
188
189    fn contains(bn: &Self::BlockNumber, task: &Self::Task) -> bool {
190        T::contains_keys(bn, task)
191    }
192
193    fn delete(bn: Self::BlockNumber, task: Self::Task) -> Result<(), Self::OutputError> {
194        if T::contains_keys(&bn, &task) {
195            T::remove(bn, task);
196            Callbacks::OnDelete::call();
197            Ok(())
198        } else {
199            Err(Self::Error::task_not_found().into())
200        }
201    }
202}
203
204// Implementation of `CountedByKey` trait for `TaskPoolImpl` in case,
205// when inner `DoubleMapStorage` implements `CountedByKey`.
206impl<T, Task, Error, OutputError, Callbacks> CountedByKey
207    for TaskPoolImpl<T, Task, Error, OutputError, Callbacks>
208where
209    T: DoubleMapStorage<Key2 = Task, Value = ()> + CountedByKey<Key = T::Key1>,
210    Error: TaskPoolError,
211    OutputError: From<Error>,
212    Callbacks: TaskPoolCallbacks,
213{
214    type Key = T::Key1;
215    type Length = T::Length;
216
217    fn len(key: &Self::Key) -> Self::Length {
218        T::len(key)
219    }
220}
221
222// Implementation of `KeyIterableByKeyMap` trait for `TaskPoolImpl` in case,
223// when inner `DoubleMapStorage` implements `KeyIterableByKeyMap`.
224impl<T, Task, Error, OutputError, Callbacks> KeyIterableByKeyMap
225    for TaskPoolImpl<T, Task, Error, OutputError, Callbacks>
226where
227    T: DoubleMapStorage<Key2 = Task, Value = ()> + KeyIterableByKeyMap,
228    Error: TaskPoolError,
229    OutputError: From<Error>,
230    Callbacks: TaskPoolCallbacks,
231{
232    type Key1 = <T as KeyIterableByKeyMap>::Key1;
233    type Key2 = <T as KeyIterableByKeyMap>::Key2;
234    type DrainIter = T::DrainIter;
235    type Iter = T::Iter;
236
237    fn drain_prefix_keys(bn: Self::Key1) -> Self::DrainIter {
238        T::drain_prefix_keys(bn)
239    }
240
241    fn iter_prefix_keys(bn: Self::Key1) -> Self::Iter {
242        T::iter_prefix_keys(bn)
243    }
244}