use crate::types::{DeadlineNs, QoSClass, Ticks};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SlidingWindow {
stride: usize,
}
impl SlidingWindow {
#[must_use]
pub fn new(stride: usize) -> Self {
Self { stride }
}
#[must_use]
pub fn stride(&self) -> &usize {
&self.stride
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WindowKind {
Disjoint,
Sliding(SlidingWindow),
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BatchingPolicy {
fixed_n: Option<usize>,
max_delta_t: Option<Ticks>,
window_kind: WindowKind,
}
impl BatchingPolicy {
pub const fn none() -> Self {
Self {
fixed_n: Some(1),
max_delta_t: None,
window_kind: WindowKind::Disjoint,
}
}
pub const fn fixed(n: usize) -> Self {
Self {
fixed_n: Some(n),
max_delta_t: None,
window_kind: WindowKind::Disjoint,
}
}
pub const fn delta_t(cap: Ticks) -> Self {
Self {
fixed_n: None,
max_delta_t: Some(cap),
window_kind: WindowKind::Disjoint,
}
}
pub const fn fixed_and_delta_t(n: usize, cap: Ticks) -> Self {
Self {
fixed_n: Some(n),
max_delta_t: Some(cap),
window_kind: WindowKind::Disjoint,
}
}
#[inline]
pub const fn with_window(
n: Option<usize>,
cap: Option<Ticks>,
window_kind: WindowKind,
) -> Self {
Self {
fixed_n: n,
max_delta_t: cap,
window_kind,
}
}
#[inline]
pub const fn fixed_with_window(n: usize, window_kind: WindowKind) -> Self {
Self {
fixed_n: Some(n),
max_delta_t: None,
window_kind,
}
}
#[inline]
pub const fn delta_t_with_window(cap: Ticks, window_kind: WindowKind) -> Self {
Self {
fixed_n: None,
max_delta_t: Some(cap),
window_kind,
}
}
#[inline]
pub const fn fixed_n(&self) -> &Option<usize> {
&self.fixed_n
}
#[inline]
pub const fn max_delta_t(&self) -> &Option<Ticks> {
&self.max_delta_t
}
#[inline]
pub const fn window_kind(&self) -> WindowKind {
self.window_kind
}
}
impl Default for BatchingPolicy {
fn default() -> Self {
BatchingPolicy::none()
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct BudgetPolicy {
tick_budget: Option<Ticks>,
watchdog_ticks: Option<Ticks>,
}
impl BudgetPolicy {
pub const fn new(tick_budget: Option<Ticks>, watchdog_ticks: Option<Ticks>) -> Self {
Self {
tick_budget,
watchdog_ticks,
}
}
#[inline]
pub const fn tick_budget(&self) -> &Option<Ticks> {
&self.tick_budget
}
#[inline]
pub const fn watchdog_ticks(&self) -> &Option<Ticks> {
&self.watchdog_ticks
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct DeadlinePolicy {
require_absolute_deadline: bool,
slack_tolerance_ns: Option<DeadlineNs>,
default_deadline_ns: Option<DeadlineNs>,
}
impl DeadlinePolicy {
pub const fn new(
require_absolute_deadline: bool,
slack_tolerance_ns: Option<DeadlineNs>,
default_deadline_ns: Option<DeadlineNs>,
) -> Self {
Self {
require_absolute_deadline,
slack_tolerance_ns,
default_deadline_ns,
}
}
#[inline]
pub const fn require_absolute_deadline(&self) -> bool {
self.require_absolute_deadline
}
#[inline]
pub const fn slack_tolerance_ns(&self) -> &Option<DeadlineNs> {
&self.slack_tolerance_ns
}
#[inline]
pub const fn default_deadline_ns(&self) -> &Option<DeadlineNs> {
&self.default_deadline_ns
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OverBudgetAction {
Drop,
SkipStage,
Degrade,
DefaultOnTimeout,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct QueueCaps {
pub max_items: usize,
pub soft_items: usize,
pub max_bytes: Option<usize>,
pub soft_bytes: Option<usize>,
}
impl QueueCaps {
pub const fn new(
max_items: usize,
soft_items: usize,
max_bytes: Option<usize>,
soft_bytes: Option<usize>,
) -> Self {
Self {
max_items,
soft_items,
max_bytes,
soft_bytes,
}
}
#[inline]
pub const fn max_items(&self) -> &usize {
&self.max_items
}
#[inline]
pub const fn soft_items(&self) -> &usize {
&self.soft_items
}
#[inline]
pub const fn max_bytes(&self) -> &Option<usize> {
&self.max_bytes
}
#[inline]
pub const fn soft_bytes(&self) -> &Option<usize> {
&self.soft_bytes
}
pub fn below_soft(&self, items: usize, bytes: usize) -> bool {
let items_ok = items < self.soft_items;
let bytes_ok = match (self.max_bytes, self.soft_bytes) {
(Some(_), Some(soft)) => bytes < soft,
_ => true,
};
items_ok && bytes_ok
}
pub fn at_or_above_hard(&self, items: usize, bytes: usize) -> bool {
if items >= self.max_items {
return true;
}
if let Some(maxb) = self.max_bytes {
if bytes >= maxb {
return true;
}
}
false
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum WatermarkState {
BelowSoft,
BetweenSoftAndHard,
AtOrAboveHard,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AdmissionPolicy {
DeadlineAndQoSAware,
DropNewest,
DropOldest,
Block,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AdmissionDecision {
Admit,
Reject,
DropNewest,
Evict(usize),
EvictUntilBelowHard,
Block,
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EdgePolicy {
pub caps: QueueCaps,
pub admission: AdmissionPolicy,
pub over_budget: OverBudgetAction,
}
impl EdgePolicy {
pub const fn new(
caps: QueueCaps,
admission: AdmissionPolicy,
over_budget: OverBudgetAction,
) -> Self {
Self {
caps,
admission,
over_budget,
}
}
#[inline]
pub const fn caps(&self) -> &QueueCaps {
&self.caps
}
#[inline]
pub const fn admission(&self) -> &AdmissionPolicy {
&self.admission
}
#[inline]
pub const fn over_budget(&self) -> &OverBudgetAction {
&self.over_budget
}
pub fn watermark(&self, items: usize, bytes: usize) -> WatermarkState {
if self.caps.at_or_above_hard(items, bytes) {
WatermarkState::AtOrAboveHard
} else if self.caps.below_soft(items, bytes) {
WatermarkState::BelowSoft
} else {
WatermarkState::BetweenSoftAndHard
}
}
pub fn decide(
&self,
items: usize,
bytes: usize,
item_bytes: usize,
_deadline: Option<DeadlineNs>,
_qos: QoSClass,
) -> AdmissionDecision {
match self.watermark(items, bytes) {
WatermarkState::BelowSoft => AdmissionDecision::Admit,
WatermarkState::BetweenSoftAndHard => match self.admission {
AdmissionPolicy::DeadlineAndQoSAware => {
AdmissionDecision::Admit
}
AdmissionPolicy::DropNewest => AdmissionDecision::DropNewest,
AdmissionPolicy::DropOldest => AdmissionDecision::Evict(1),
AdmissionPolicy::Block => AdmissionDecision::Block,
},
WatermarkState::AtOrAboveHard => {
if self.caps.at_or_above_hard(0, item_bytes) {
return AdmissionDecision::Reject;
}
match self.admission {
AdmissionPolicy::DeadlineAndQoSAware => {
AdmissionDecision::Reject
}
AdmissionPolicy::DropNewest => AdmissionDecision::DropNewest,
AdmissionPolicy::DropOldest => AdmissionDecision::EvictUntilBelowHard,
AdmissionPolicy::Block => AdmissionDecision::Block,
}
}
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct NodePolicy {
batching: BatchingPolicy,
budget: BudgetPolicy,
deadline: DeadlinePolicy,
}
impl NodePolicy {
pub const fn new(
batching: BatchingPolicy,
budget: BudgetPolicy,
deadline: DeadlinePolicy,
) -> Self {
Self {
batching,
budget,
deadline,
}
}
#[inline]
pub const fn batching(&self) -> &BatchingPolicy {
&self.batching
}
#[inline]
pub const fn budget(&self) -> &BudgetPolicy {
&self.budget
}
#[inline]
pub const fn deadline(&self) -> &DeadlinePolicy {
&self.deadline
}
}