difftreelog
feat track free places inside the agenda
in: master
1 file changed
pallets/scheduler-v2/src/lib.rsdiffbeforeafterboth246 <T as frame_system::Config>::AccountId,246 <T as frame_system::Config>::AccountId,247>;247>;248248249#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]250#[scale_info(skip_type_params(T))]251pub struct BlockAgenda<T: Config> {252 agenda: BoundedVec<Option<ScheduledOf<T>>, T::MaxScheduledPerBlock>,253 free_places: u32,254}255256impl<T: Config> BlockAgenda<T> {257 fn try_push(&mut self, scheduled: ScheduledOf<T>) -> Option<u32> {258 if self.free_places == 0 {259 return None;260 }261262 self.free_places = self.free_places.saturating_sub(1);263264 if (self.agenda.len() as u32) < T::MaxScheduledPerBlock::get() {265 // will always succeed due to the above check.266 let _ = self.agenda.try_push(Some(scheduled));267 Some((self.agenda.len() - 1) as u32)268 } else {269 match self.agenda.iter().position(|i| i.is_none()) {270 Some(hole_index) => {271 self.agenda[hole_index] = Some(scheduled);272 Some(hole_index as u32)273 }274 None => unreachable!("free_places > 0; qed"),275 }276 }277 }278279 fn set_slot(&mut self, index: u32, slot: Option<ScheduledOf<T>>) {280 self.agenda[index as usize] = slot;281 }282283 fn iter(&self) -> impl Iterator<Item = &'_ Option<ScheduledOf<T>>> + '_ {284 self.agenda.iter()285 }286287 fn get(&self, index: u32) -> Option<&ScheduledOf<T>> {288 match self.agenda.get(index as usize) {289 Some(Some(scheduled)) => Some(scheduled),290 _ => None,291 }292 }293294 fn get_mut(&mut self, index: u32) -> Option<&mut ScheduledOf<T>> {295 match self.agenda.get_mut(index as usize) {296 Some(Some(scheduled)) => Some(scheduled),297 _ => None,298 }299 }300301 fn take(&mut self, index: u32) -> Option<ScheduledOf<T>> {302 let removed = self.agenda.get_mut(index as usize)?.take();303304 if removed.is_some() {305 self.free_places = self.free_places.saturating_add(1);306 }307308 removed309 }310}311312impl<T: Config> Default for BlockAgenda<T> {313 fn default() -> Self {314 let agenda = Default::default();315 let free_places = T::MaxScheduledPerBlock::get();316317 Self {318 agenda,319 free_places,320 }321 }322}323249struct WeightCounter {324struct WeightCounter {250 used: Weight,325 used: Weight,251 limit: Weight,326 limit: Weight,368443369 /// Items to be executed, indexed by the block number that they should be executed on.444 /// Items to be executed, indexed by the block number that they should be executed on.370 #[pallet::storage]445 #[pallet::storage]371 pub type Agenda<T: Config> = StorageMap<446 pub type Agenda<T: Config> =372 _,447 StorageMap<_, Twox64Concat, T::BlockNumber, BlockAgenda<T>, ValueQuery>;373 Twox64Concat,374 T::BlockNumber,375 BoundedVec<Option<ScheduledOf<T>>, T::MaxScheduledPerBlock>,376 ValueQuery,377 >;378448379 /// Lookup from a name to the block number and index of the task.449 /// Lookup from a name to the block number and index of the task.380 #[pallet::storage]450 #[pallet::storage]640 what: ScheduledOf<T>,710 what: ScheduledOf<T>,641 ) -> Result<u32, (DispatchError, ScheduledOf<T>)> {711 ) -> Result<u32, (DispatchError, ScheduledOf<T>)> {642 let mut agenda = Agenda::<T>::get(when);712 let mut agenda = Agenda::<T>::get(when);643 let index = if (agenda.len() as u32) < T::MaxScheduledPerBlock::get() {713 let index = agenda644 // will always succeed due to the above check.714 .try_push(what.clone())645 let _ = agenda.try_push(Some(what));646 agenda.len() as u32 - 1647 } else {715 .ok_or((<Error<T>>::AgendaIsExhausted.into(), what))?;648 if let Some(hole_index) = agenda.iter().position(|i| i.is_none()) {716649 agenda[hole_index] = Some(what);650 hole_index as u32651 } else {652 return Err((<Error<T>>::AgendaIsExhausted.into(), what));653 }654 };655 Agenda::<T>::insert(when, agenda);717 Agenda::<T>::insert(when, agenda);656 Ok(index)718 Ok(index)657 }719 }685 origin: Option<T::PalletsOrigin>,747 origin: Option<T::PalletsOrigin>,686 (when, index): TaskAddress<T::BlockNumber>,748 (when, index): TaskAddress<T::BlockNumber>,687 ) -> Result<(), DispatchError> {749 ) -> Result<(), DispatchError> {688 let scheduled = Agenda::<T>::try_mutate(when, |agenda| {750 let scheduled = Agenda::<T>::try_mutate(689 agenda.get_mut(index as usize).map_or(751 when,690 Ok(None),691 |s| -> Result<Option<Scheduled<_, _, _, _, _>>, DispatchError> {752 |agenda| -> Result<Option<Scheduled<_, _, _, _, _>>, DispatchError> {692 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {753 let scheduled = match agenda.get(index) {754 Some(scheduled) => scheduled,755 None => return Ok(None),756 };757758 if let Some(ref o) = origin {693 if matches!(759 if matches!(694 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),760 T::OriginPrivilegeCmp::cmp_privilege(o, &scheduled.origin),695 Some(Ordering::Less) | None761 Some(Ordering::Less) | None696 ) {762 ) {697 return Err(BadOrigin.into());763 return Err(BadOrigin.into());698 }764 }699 };765 }766700 Ok(s.take())767 Ok(agenda.take(index))701 },768 },702 )769 )?;703 })?;704 if let Some(s) = scheduled {770 if let Some(s) = scheduled {705 T::Preimages::drop(&s.call);771 T::Preimages::drop(&s.call);706772749 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: TaskName) -> DispatchResult {815 fn do_cancel_named(origin: Option<T::PalletsOrigin>, id: TaskName) -> DispatchResult {750 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {816 Lookup::<T>::try_mutate_exists(id, |lookup| -> DispatchResult {751 if let Some((when, index)) = lookup.take() {817 if let Some((when, index)) = lookup.take() {752 let i = index as usize;753 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {818 Agenda::<T>::try_mutate(when, |agenda| -> DispatchResult {754 if let Some(s) = agenda.get_mut(i) {819 let scheduled = match agenda.get(index) {755 if let (Some(ref o), Some(ref s)) = (origin, s.borrow()) {820 Some(scheduled) => scheduled,821 None => return Ok(()),822 };823824 if let Some(ref o) = origin {756 if matches!(825 if matches!(757 T::OriginPrivilegeCmp::cmp_privilege(o, &s.origin),826 T::OriginPrivilegeCmp::cmp_privilege(o, &scheduled.origin),758 Some(Ordering::Less) | None827 Some(Ordering::Less) | None759 ) {828 ) {760 return Err(BadOrigin.into());829 return Err(BadOrigin.into());761 }762 T::Preimages::drop(&s.call);763 }830 }764 *s = None;831 T::Preimages::drop(&scheduled.call);765 }832 }833834 agenda.take(index);835766 Ok(())836 Ok(())767 })?;837 })?;768 Self::deposit_event(Event::Canceled { when, index });838 Self::deposit_event(Event::Canceled { when, index });779 priority: schedule::Priority,849 priority: schedule::Priority,780 ) -> DispatchResult {850 ) -> DispatchResult {781 match Lookup::<T>::get(id) {851 match Lookup::<T>::get(id) {782 Some((when, index)) => {852 Some((when, index)) => Agenda::<T>::try_mutate(when, |agenda| {783 let i = index as usize;784 Agenda::<T>::try_mutate(when, |agenda| {785 if let Some(Some(s)) = agenda.get_mut(i) {853 let scheduled = match agenda.get_mut(index) {786 if matches!(854 Some(scheduled) => scheduled,787 T::OriginPrivilegeCmp::cmp_privilege(&origin, &s.origin),788 Some(Ordering::Less) | None789 ) {855 None => return Ok(()),790 return Err(BadOrigin.into());791 }856 };792857793 s.priority = priority;858 if matches!(859 T::OriginPrivilegeCmp::cmp_privilege(&origin, &scheduled.origin),860 Some(Ordering::Less) | None861 ) {862 return Err(BadOrigin.into());863 }864865 scheduled.priority = priority;794 Self::deposit_event(Event::PriorityChanged {866 Self::deposit_event(Event::PriorityChanged {795 when,867 when,796 index,868 index,797 priority,869 priority,798 });870 });799 }871800 Ok(())872 Ok(())801 })873 }),802 }803 None => Err(Error::<T>::NotFound.into()),874 None => Err(Error::<T>::NotFound.into()),804 }875 }805 }876 }885 let mut dropped = 0;956 let mut dropped = 0;886957887 for (agenda_index, _) in ordered.into_iter().take(max as usize) {958 for (agenda_index, _) in ordered.into_iter().take(max as usize) {888 let task = match agenda[agenda_index as usize].take() {959 let task = match agenda.take(agenda_index).take() {889 None => continue,960 None => continue,890 Some(t) => t,961 Some(t) => t,891 };962 };899 break;970 break;900 }971 }901 let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task);972 let result = Self::service_task(weight, now, when, agenda_index, *executed == 0, task);902 agenda[agenda_index as usize] = match result {973 match result {903 Err((Unavailable, slot)) => {974 Err((Unavailable, slot)) => {904 dropped += 1;975 dropped += 1;905 slot976 agenda.set_slot(agenda_index, slot);906 }977 }907 Err((Overweight, slot)) => {978 Err((Overweight, slot)) => {908 postponed += 1;979 postponed += 1;909 slot980 agenda.set_slot(agenda_index, slot);910 }981 }911 Ok(()) => {982 Ok(()) => {912 *executed += 1;983 *executed += 1;913 None914 }984 }915 };985 };916 }986 }1062 return Err(Overweight);1132 return Err(Overweight);1063 }1133 }106411341065 // let scheduled_origin =1066 // <<T as Config>::Origin as From<T::PalletsOrigin>>::from(origin.clone());1067 let ensured_origin = T::ScheduleOrigin::ensure_origin(dispatch_origin.into());1135 let ensured_origin = T::ScheduleOrigin::ensure_origin(dispatch_origin.into());106811361069 let r = match ensured_origin {1137 let r = match ensured_origin {