use super::SharedState;
use super::dirty::DirtyPool;
use super::distribution_service::DistributionService;
#[cfg(feature = "readiness")]
use super::readiness::ReadinessService;
use super::ring_service::{RingService, StandardIoService};
use super::service::{ServiceInstanceId, ServiceMode, ServiceModeLabel};
pub(super) const DIRTY_CPU: &str = "dirty-cpu";
pub(super) const DIRTY_IO: &str = "dirty-io";
pub(super) const FILE_IO_RING: &str = "file-io-ring";
pub(super) const STANDARD_IO_RING: &str = "standard-io-ring";
pub(super) const GENERIC_IO_RING: &str = "generic-io-ring";
pub(super) const DISTRIBUTION: &str = "distribution";
pub(super) const READINESS: &str = "readiness";
pub(super) const DIRTY_COMPLETE: &str = "dirty-complete";
pub(super) const HEARTBEAT: &str = "heartbeat";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ServiceInventoryEntry {
pub service: &'static str,
pub mode: ServiceModeLabel,
pub instance: ServiceInstanceId,
pub configured: usize,
pub actual: usize,
pub thread_names: Vec<String>,
pub fd_classes: Vec<&'static str>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ServicePolicyLine {
pub policy: &'static str,
pub mode: ServiceModeLabel,
pub spawned_total: u64,
}
pub(super) struct ServiceInstances {
pub(super) generic_bridge_requested: bool,
}
impl ServiceInstances {
pub(super) fn mint(generic_bridge_requested: bool) -> Self {
Self {
generic_bridge_requested,
}
}
}
fn dirty_pool_entry(service: &'static str, mode: &ServiceMode<DirtyPool>) -> ServiceInventoryEntry {
match mode.service() {
Some(pool) => {
let thread_names = pool.live_worker_names();
ServiceInventoryEntry {
service,
mode: mode.label(),
instance: mode.instance_id(),
configured: pool.requested_threads(),
actual: thread_names.len(),
thread_names,
fd_classes: Vec::new(),
}
}
None => disabled_entry(service),
}
}
fn ring_entry(service: &'static str, mode: &ServiceMode<RingService>) -> ServiceInventoryEntry {
match mode.service() {
Some(ring) => {
let thread_names = ring.worker_thread_names();
ServiceInventoryEntry {
service,
mode: mode.label(),
instance: mode.instance_id(),
configured: ring.requested_worker_count(),
actual: thread_names.len(),
thread_names,
fd_classes: Vec::new(),
}
}
None => disabled_entry(service),
}
}
fn standard_io_entry(
service: &'static str,
mode: &ServiceMode<StandardIoService>,
) -> ServiceInventoryEntry {
match mode.service() {
Some(standard) => {
let thread_names = standard.server().worker_thread_names();
ServiceInventoryEntry {
service,
mode: mode.label(),
instance: mode.instance_id(),
configured: standard.server().requested_worker_count(),
actual: thread_names.len(),
thread_names,
fd_classes: Vec::new(),
}
}
None => disabled_entry(service),
}
}
fn distribution_entry(mode: &ServiceMode<DistributionService>) -> ServiceInventoryEntry {
match mode.service() {
Some(dist) => {
let thread_names = dist.runtime_thread_names();
ServiceInventoryEntry {
service: DISTRIBUTION,
mode: mode.label(),
instance: mode.instance_id(),
configured: dist.configured_runtimes(),
actual: thread_names.len(),
thread_names,
fd_classes: Vec::new(),
}
}
None => disabled_entry(DISTRIBUTION),
}
}
#[cfg(feature = "readiness")]
fn readiness_entry(mode: &ServiceMode<ReadinessService>) -> ServiceInventoryEntry {
match mode.service() {
Some(readiness) => {
let thread_names = readiness.poll_thread_names();
ServiceInventoryEntry {
service: READINESS,
mode: mode.label(),
instance: mode.instance_id(),
configured: 1,
actual: thread_names.len(),
thread_names,
fd_classes: readiness.poll_fd_classes(),
}
}
None => disabled_entry(READINESS),
}
}
fn disabled_entry(service: &'static str) -> ServiceInventoryEntry {
ServiceInventoryEntry {
service,
mode: ServiceModeLabel::Disabled,
instance: ServiceInstanceId::DISABLED,
configured: 0,
actual: 0,
thread_names: Vec::new(),
fd_classes: Vec::new(),
}
}
pub(super) fn build_service_inventory(shared: &SharedState) -> Vec<ServiceInventoryEntry> {
let instances = &shared.service_instances;
let mut entries = Vec::with_capacity(6);
entries.push(dirty_pool_entry(DIRTY_CPU, &shared.dirty_cpu));
entries.push(dirty_pool_entry(DIRTY_IO, &shared.dirty_io));
entries.push(ring_entry(FILE_IO_RING, &shared.file_io_ring));
entries.push(standard_io_entry(STANDARD_IO_RING, &shared.standard_io));
match shared.io_ring.service() {
Some(ring) => {
let mut names = ring.worker_thread_names();
let configured =
ring.requested_worker_count() + usize::from(instances.generic_bridge_requested);
if super::lock_or_recover(&shared.io_bridge).is_some() {
names.push(crate::io::bridge::IO_COMPLETION_THREAD_NAME.to_owned());
}
entries.push(ServiceInventoryEntry {
service: GENERIC_IO_RING,
mode: shared.io_ring.label(),
instance: shared.io_ring.instance_id(),
configured,
actual: names.len(),
thread_names: names,
fd_classes: Vec::new(),
});
}
None => entries.push(disabled_entry(GENERIC_IO_RING)),
}
entries.push(distribution_entry(&shared.distribution));
#[cfg(feature = "readiness")]
entries.push(readiness_entry(&shared.readiness));
entries
}
#[must_use]
pub fn deduped_thread_aggregate(entries: &[ServiceInventoryEntry]) -> usize {
let mut counted = std::collections::BTreeSet::new();
let mut aggregate = 0;
for entry in entries {
match entry.mode {
ServiceModeLabel::Disabled => {}
ServiceModeLabel::Owned | ServiceModeLabel::Shared => {
if counted.insert(entry.instance) {
aggregate += entry.actual;
}
}
}
}
aggregate
}
pub(super) fn build_service_policies(shared: &SharedState) -> Vec<ServicePolicyLine> {
let dirty_complete_mode =
if shared.dirty_cpu.service().is_some() || shared.dirty_io.service().is_some() {
ServiceModeLabel::Owned
} else {
ServiceModeLabel::Disabled
};
let (heartbeat_mode, heartbeat_spawned) = match shared.distribution.service() {
Some(dist) if dist.heartbeat_enabled() => {
(shared.distribution.label(), dist.heartbeat_tasks_spawned())
}
_ => (ServiceModeLabel::Disabled, 0),
};
vec![
ServicePolicyLine {
policy: DIRTY_COMPLETE,
mode: dirty_complete_mode,
spawned_total: shared
.dirty_completion_spawns
.load(std::sync::atomic::Ordering::Relaxed),
},
ServicePolicyLine {
policy: HEARTBEAT,
mode: heartbeat_mode,
spawned_total: heartbeat_spawned,
},
]
}