summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeon Yang (Containers) <lnyng@meta.com>2024-04-11 13:18:46 -0700
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>2024-04-11 13:18:46 -0700
commitb4bb5b576633a0d24151f5ae2494ce52ef45c9a1 (patch)
tree34b6fae58c325744dead4745da5dcf20e5c6acaf
parentf3d3d29d863a2a6e1478dfb6405df0e4eb7feab7 (diff)
QueriableContainer
Summary: Some rust type gymnastics to unify the FieldId type for Vec, BTreeMap, and CgroupModel. Reduce some code. We can then add feature to this trait to get X field of an item from a container whose Y field equals Z, is min/max among other items, etc. Reviewed By: brianc118 Differential Revision: D55968833 fbshipit-source-id: bab97d65bb72234fd67b723f23043327bac87234
-rw-r--r--below/dump/src/cgroup.rs8
-rw-r--r--below/dump/src/system.rs5
-rw-r--r--below/dump/src/test.rs12
-rw-r--r--below/model/src/cgroup.rs76
-rw-r--r--below/model/src/lib.rs236
-rw-r--r--below/render/src/default_configs.rs27
-rw-r--r--below/view/src/cgroup_tabs.rs8
7 files changed, 139 insertions, 233 deletions
diff --git a/below/dump/src/cgroup.rs b/below/dump/src/cgroup.rs
index dd8604f5..04dafaeb 100644
--- a/below/dump/src/cgroup.rs
+++ b/below/dump/src/cgroup.rs
@@ -127,10 +127,10 @@ impl Dumper for Cgroup {
//sort
if let Some(field_id) = &handle.select {
// field_id that queries its own data
- let field_id = CgroupModelFieldId {
- path: Some(vec![]),
- subquery_id: field_id.to_owned(),
- };
+ let field_id = CgroupModelFieldId::new(
+ Some(model::CgroupPath { path: vec![] }),
+ field_id.to_owned(),
+ );
if handle.opts.sort {
model::sort_queriables(&mut children, &field_id, false);
}
diff --git a/below/dump/src/system.rs b/below/dump/src/system.rs
index 2c0b26d9..6141599d 100644
--- a/below/dump/src/system.rs
+++ b/below/dump/src/system.rs
@@ -48,10 +48,7 @@ impl Dumper for System {
{
let value = subquery_id.clone();
fields.push(DumpField::FieldId(model::SystemModelFieldId::Cpus(
- model::BTreeMapFieldId {
- key: Some(*key),
- subquery_id: value,
- },
+ model::BTreeMapFieldId::new(Some(*key), value),
)));
}
}
diff --git a/below/dump/src/test.rs b/below/dump/src/test.rs
index 21126d82..6fb44574 100644
--- a/below/dump/src/test.rs
+++ b/below/dump/src/test.rs
@@ -41,10 +41,7 @@ fn test_dump_sys_content() {
let mut fields = command::expand_fields(command::DEFAULT_SYSTEM_FIELDS, true);
for subquery_id in enum_iterator::all::<model::SingleCpuModelFieldId>() {
fields.push(DumpField::FieldId(model::SystemModelFieldId::Cpus(
- model::BTreeMapFieldId {
- key: Some(31),
- subquery_id,
- },
+ model::BTreeMapFieldId::new(Some(31), subquery_id),
)));
}
opts.output_format = Some(OutputFormat::Json);
@@ -97,10 +94,9 @@ fn test_dump_sys_titles() {
.into_iter()
.chain(
enum_iterator::all::<model::SingleCpuModelFieldId>().map(|subquery_id| {
- DumpField::FieldId(model::SystemModelFieldId::Cpus(model::BTreeMapFieldId {
- key: Some(31),
- subquery_id,
- }))
+ DumpField::FieldId(model::SystemModelFieldId::Cpus(
+ model::BTreeMapFieldId::new(Some(31), subquery_id),
+ ))
}),
)
.filter_map(|dump_field| match dump_field {
diff --git a/below/model/src/cgroup.rs b/below/model/src/cgroup.rs
index 1c42e537..b94f3626 100644
--- a/below/model/src/cgroup.rs
+++ b/below/model/src/cgroup.rs
@@ -70,75 +70,49 @@ pub struct CgroupModel {
/// The path is used to drill into the Cgroup Model tree. If Vec empty, the
/// current CgroupModel is selected and queried with the subquery_id.
/// The path is optional in parsing and converting to String.
-#[derive(Clone, Debug, PartialEq)]
-pub struct CgroupModelFieldId {
- /// To drill into children recursively. If Vec empty, queries self.
- /// None is only for listing variants and otherwise invalid.
- pub path: Option<Vec<String>>,
- pub subquery_id: SingleCgroupModelFieldId,
-}
+pub type CgroupModelFieldId = QueriableContainerFieldId<CgroupModel>;
-impl FieldId for CgroupModelFieldId {
- type Queriable = CgroupModel;
-}
-
-impl DelegatedSequence for CgroupModelFieldId {
- type Delegate = SingleCgroupModelFieldId;
- fn get_delegate(&self) -> &Self::Delegate {
- &self.subquery_id
- }
- fn from_delegate(delegate: Self::Delegate) -> Self {
- Self {
- path: None,
- subquery_id: delegate,
- }
- }
-}
-
-impl Sequence for CgroupModelFieldId {
- impl_sequence_for_delegated_sequence!();
+#[derive(Clone, Debug, PartialEq)]
+pub struct CgroupPath {
+ pub path: Vec<String>,
}
-impl std::string::ToString for CgroupModelFieldId {
+impl ToString for CgroupPath {
fn to_string(&self) -> String {
- match &self.path {
- Some(path) if path.is_empty() => self.subquery_id.to_string(),
- Some(path) => format!("path:/{}/.{}", path.join("/"), self.subquery_id.to_string()),
- None => format!("[path:/<cgroup_path>/.]{}", self.subquery_id.to_string()),
- }
+ format!("path:/{}/", self.path.join("/"))
}
}
-impl std::str::FromStr for CgroupModelFieldId {
+impl FromStr for CgroupPath {
type Err = anyhow::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- let (path_str, subquery_id_str) = if s.starts_with("path:") {
- s["path:".len()..]
- .rsplit_once("/.")
- .ok_or_else(|| anyhow!("Path is not terminated by `/.`: {}", s))?
- } else {
- ("", s)
- };
- let path = Some(
- path_str
+ if !s.starts_with("path:/") {
+ return Err(anyhow!("Path is not prefixed with `path:/`: {}", s));
+ }
+ Ok(Self {
+ path: s["path:/".len()..]
.split('/')
.filter(|part| !part.is_empty())
.map(|part| part.to_owned())
.collect(),
- );
- let subquery_id = SingleCgroupModelFieldId::from_str(subquery_id_str)?;
- Ok(Self { path, subquery_id })
+ })
}
}
-impl Queriable for CgroupModel {
- type FieldId = CgroupModelFieldId;
- fn query(&self, field_id: &Self::FieldId) -> Option<Field> {
+impl QueriableContainer for CgroupModel {
+ type Idx = CgroupPath;
+ type SubqueryId = SingleCgroupModelFieldId;
+ const IDX_PLACEHOLDER: &'static str = "[path:/<cgroup_path>/.]";
+ fn split(s: &str) -> Option<(&str, &str)> {
+ let idx_end = s.rfind("/.")?;
+ Some((&s[..idx_end + 1], &s[idx_end + 2..]))
+ }
+ fn get_item(&self, idx: &Self::Idx) -> Option<&SingleCgroupModel> {
let mut model = self;
- for part in field_id.path.as_ref()?.iter() {
+ for part in idx.path.iter() {
model = model.children.get(part.as_str())?;
}
- model.data.query(&field_id.subquery_id)
+ Some(&model.data)
}
}
@@ -926,8 +900,6 @@ mod tests {
let model: CgroupModel =
serde_json::from_str(model_json).expect("Failed to deserialize cgroup model JSON");
for (field_id, expected) in &[
- // "path:" omitted falls back to querying self (root)
- ("full_path", Some("")),
// Ignore consecutive slashes
("path:///////.name", Some("<root>")),
("path:/system.slice/.full_path", Some("/system.slice")),
diff --git a/below/model/src/lib.rs b/below/model/src/lib.rs
index 36174868..c69380f5 100644
--- a/below/model/src/lib.rs
+++ b/below/model/src/lib.rs
@@ -15,6 +15,7 @@
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt;
+use std::marker::PhantomData;
use std::str::FromStr;
use std::time::Duration;
use std::time::Instant;
@@ -341,160 +342,96 @@ pub trait Nameable {
fn name() -> &'static str;
}
-/// Sequence that wraps a delegate sequence and owns no variants.
-trait DelegatedSequence {
- type Delegate: Sequence;
- fn get_delegate(&self) -> &Self::Delegate;
- // Not using From trait as conversion should only be used for Sequence
- fn from_delegate(delegate: Self::Delegate) -> Self;
+/// Type that contains sub-queriables of the same type, individually retrieveable
+/// by some index. It is itself a Queriable.
+pub trait QueriableContainer {
+ type Idx;
+ type SubqueryId: FieldId;
+ const IDX_PLACEHOLDER: &'static str = "<idx>.";
+ fn split(s: &str) -> Option<(&str, &str)> {
+ s.split_once('.')
+ }
+ fn get_item(&self, idx: &Self::Idx) -> Option<&<Self::SubqueryId as FieldId>::Queriable>;
}
-/// Implements Sequence for DelegatedSequence. Must be a macro due to orphan
-/// rule. See https://github.com/rust-lang/rfcs/issues/1124
-macro_rules! impl_sequence_for_delegated_sequence {
- () => {
- const CARDINALITY: usize = <Self as DelegatedSequence>::Delegate::CARDINALITY;
- fn next(&self) -> Option<Self> {
- self.get_delegate().next().map(Self::from_delegate)
- }
- fn previous(&self) -> Option<Self> {
- self.get_delegate().previous().map(Self::from_delegate)
- }
- fn first() -> Option<Self> {
- <Self as DelegatedSequence>::Delegate::first().map(Self::from_delegate)
- }
- fn last() -> Option<Self> {
- <Self as DelegatedSequence>::Delegate::last().map(Self::from_delegate)
- }
- };
+impl<C: QueriableContainer> Queriable for C {
+ type FieldId = QueriableContainerFieldId<C>;
+ fn query(&self, field_id: &<C as Queriable>::FieldId) -> Option<Field> {
+ self.get_item(field_id.idx.as_ref()?)
+ .and_then(|sub| sub.query(&field_id.subquery_id.0))
+ }
}
-pub(crate) use impl_sequence_for_delegated_sequence;
-/// Type that makes Vec Queriable if Vec's inner type is Queriable. Uses `idx`
-/// to query into a Vec. Uses `subquery_id` to query into the selected item.
#[derive(Clone, Debug, PartialEq)]
-pub struct VecFieldId<F: FieldId> {
+pub struct QueriableContainerFieldId<C: QueriableContainer> {
/// None is only for listing variants and otherwise invalid.
- pub idx: Option<usize>,
- pub subquery_id: F,
+ /// If None, shows up as C::IDX_PLACEHOLDER
+ pub idx: Option<C::Idx>,
+ // Wraps inside a tuple so we can #[derive] traits without adding type constraints
+ pub subquery_id: (C::SubqueryId,),
+ phantom: PhantomData<C>,
}
-impl<F: FieldId> FieldId for VecFieldId<F>
-where
- <F as FieldId>::Queriable: Sized,
-{
- type Queriable = Vec<F::Queriable>;
+impl<C: QueriableContainer> FieldId for QueriableContainerFieldId<C> {
+ type Queriable = C;
}
-impl<F: FieldId + Sequence> DelegatedSequence for VecFieldId<F> {
- type Delegate = F;
- fn get_delegate(&self) -> &Self::Delegate {
- &self.subquery_id
- }
- fn from_delegate(delegate: Self::Delegate) -> Self {
+impl<C: QueriableContainer> QueriableContainerFieldId<C> {
+ pub fn new(idx: Option<C::Idx>, subquery_id: C::SubqueryId) -> Self {
Self {
- idx: None,
- subquery_id: delegate,
+ idx,
+ subquery_id: (subquery_id,),
+ phantom: PhantomData,
}
}
}
-impl<F: FieldId + Sequence> Sequence for VecFieldId<F> {
- impl_sequence_for_delegated_sequence!();
-}
-
-impl<F: FieldId + ToString> ToString for VecFieldId<F> {
- fn to_string(&self) -> String {
- match self.idx {
- Some(idx) => format!("{}.{}", idx, self.subquery_id.to_string()),
- None => format!("<idx>.{}", self.subquery_id.to_string()),
- }
- }
-}
-
-impl<F: FieldId + FromStr> FromStr for VecFieldId<F>
+impl<C: QueriableContainer> Sequence for QueriableContainerFieldId<C>
where
- <F as FromStr>::Err: Into<anyhow::Error>,
+ C::SubqueryId: Sequence,
{
- type Err = anyhow::Error;
- fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- if let Some(dot_idx) = s.find('.') {
- Ok(Self {
- idx: Some(s[..dot_idx].parse()?),
- subquery_id: F::from_str(&s[dot_idx + 1..]).map_err(Into::into)?,
- })
- } else {
- Err(anyhow!(
- "Unable to find a variant of the given enum matching string `{}`.",
- s,
- ))
- }
+ const CARDINALITY: usize = C::SubqueryId::CARDINALITY;
+ fn next(&self) -> Option<Self> {
+ self.subquery_id.0.next().map(|s| Self::new(None, s))
}
-}
-
-impl<Q: Queriable> Queriable for Vec<Q> {
- type FieldId = VecFieldId<Q::FieldId>;
- fn query(&self, field_id: &Self::FieldId) -> Option<Field> {
- self.get(field_id.idx?)
- .and_then(|f| f.query(&field_id.subquery_id))
+ fn previous(&self) -> Option<Self> {
+ self.subquery_id.0.previous().map(|s| Self::new(None, s))
}
-}
-
-/// Type that makes BTreeMap Queriable if its value is Queriable. Uses `key`
-/// to query into a map. Uses `subquery_id` to query into the selected value.
-#[derive(Clone, Debug, PartialEq)]
-pub struct BTreeMapFieldId<K, F: FieldId> {
- /// None is only for listing variants and otherwise invalid.
- pub key: Option<K>,
- pub subquery_id: F,
-}
-
-impl<K: Ord, F: FieldId> FieldId for BTreeMapFieldId<K, F>
-where
- <F as FieldId>::Queriable: Sized,
-{
- type Queriable = BTreeMap<K, F::Queriable>;
-}
-
-impl<K, F: FieldId + Sequence> DelegatedSequence for BTreeMapFieldId<K, F> {
- type Delegate = F;
- fn get_delegate(&self) -> &Self::Delegate {
- &self.subquery_id
+ fn first() -> Option<Self> {
+ C::SubqueryId::first().map(|s| Self::new(None, s))
}
- fn from_delegate(delegate: Self::Delegate) -> Self {
- Self {
- key: None,
- subquery_id: delegate,
- }
+ fn last() -> Option<Self> {
+ C::SubqueryId::last().map(|s| Self::new(None, s))
}
}
-impl<K, F: FieldId + Sequence> Sequence for BTreeMapFieldId<K, F> {
- impl_sequence_for_delegated_sequence!();
-}
-
-impl<K: ToString, F: FieldId + ToString> ToString for BTreeMapFieldId<K, F> {
+impl<C: QueriableContainer> ToString for QueriableContainerFieldId<C>
+where
+ C::Idx: ToString,
+ C::SubqueryId: ToString,
+{
fn to_string(&self) -> String {
- match &self.key {
- Some(key) => format!("{}.{}", key.to_string(), self.subquery_id.to_string()),
- None => format!("<key>.{}", self.subquery_id.to_string()),
+ match self.idx.as_ref() {
+ Some(idx) => format!("{}.{}", idx.to_string(), self.subquery_id.0.to_string()),
+ None => format!("{}{}", C::IDX_PLACEHOLDER, self.subquery_id.0.to_string()),
}
}
}
-impl<K: FromStr, F: FieldId + FromStr> FromStr for BTreeMapFieldId<K, F>
+impl<C: QueriableContainer> FromStr for QueriableContainerFieldId<C>
where
- <K as FromStr>::Err: Into<anyhow::Error>,
- <F as FromStr>::Err: Into<anyhow::Error>,
+ C::Idx: FromStr,
+ C::SubqueryId: FromStr,
+ <C::Idx as FromStr>::Err: Into<anyhow::Error>,
+ <C::SubqueryId as FromStr>::Err: Into<anyhow::Error>,
{
type Err = anyhow::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
- // Only works with keys that don't contain dot
- if let Some(dot_idx) = s.find('.') {
- Ok(Self {
- key: Some(K::from_str(&s[..dot_idx]).map_err(Into::into)?),
- subquery_id: F::from_str(&s[dot_idx + 1..]).map_err(Into::into)?,
- })
+ if let Some((idx_str, subquery_id_str)) = C::split(s) {
+ Ok(Self::new(
+ Some(C::Idx::from_str(idx_str).map_err(Into::into)?),
+ C::SubqueryId::from_str(subquery_id_str).map_err(Into::into)?,
+ ))
} else {
Err(anyhow!(
"Unable to find a variant of the given enum matching string `{}`.",
@@ -504,14 +441,27 @@ where
}
}
-impl<K: Ord, Q: Queriable> Queriable for BTreeMap<K, Q> {
- type FieldId = BTreeMapFieldId<K, Q::FieldId>;
- fn query(&self, field_id: &Self::FieldId) -> Option<Field> {
- self.get(field_id.key.as_ref()?)
- .and_then(|f| f.query(&field_id.subquery_id))
+impl<Q: Queriable> QueriableContainer for Vec<Q> {
+ type Idx = usize;
+ type SubqueryId = Q::FieldId;
+ fn get_item(&self, idx: &usize) -> Option<&Q> {
+ self.get(*idx)
}
}
+pub type VecFieldId<Q> = QueriableContainerFieldId<Vec<Q>>;
+
+impl<K: Ord, Q: Queriable> QueriableContainer for BTreeMap<K, Q> {
+ type Idx = K;
+ type SubqueryId = Q::FieldId;
+ const IDX_PLACEHOLDER: &'static str = "<key>.";
+ fn get_item(&self, idx: &K) -> Option<&Q> {
+ self.get(idx)
+ }
+}
+
+pub type BTreeMapFieldId<K, Q> = QueriableContainerFieldId<BTreeMap<K, Q>>;
+
pub struct NetworkStats<'a> {
net: &'a procfs::NetStat,
ethtool: &'a Option<ethtool::EthtoolStats>,
@@ -645,14 +595,8 @@ mod tests {
#[test]
fn test_vec_field_id() {
let query_str = "1.msg";
- let query = <VecFieldId<TestModelFieldId>>::from_str(query_str).expect("bad query str");
- assert_eq!(
- query,
- VecFieldId {
- idx: Some(1),
- subquery_id: TestModelFieldId::Msg,
- }
- );
+ let query = <VecFieldId<TestModel>>::from_str(query_str).expect("bad query str");
+ assert_eq!(query, VecFieldId::new(Some(1), TestModelFieldId::Msg),);
assert_eq!(query.to_string(), query_str);
}
@@ -667,10 +611,7 @@ mod tests {
},
];
assert_eq!(
- data.query(&VecFieldId {
- idx: Some(1),
- subquery_id: TestModelFieldId::Msg,
- }),
+ data.query(&VecFieldId::new(Some(1), TestModelFieldId::Msg,)),
Some(Field::Str("world".to_owned()))
);
}
@@ -678,14 +619,11 @@ mod tests {
#[test]
fn test_btreemap_field_id() {
let query_str = "hello.msg";
- let query = <BTreeMapFieldId<String, TestModelFieldId>>::from_str(query_str)
- .expect("bad query str");
+ let query =
+ <BTreeMapFieldId<String, TestModel>>::from_str(query_str).expect("bad query str");
assert_eq!(
query,
- BTreeMapFieldId {
- key: Some("hello".to_owned()),
- subquery_id: TestModelFieldId::Msg,
- }
+ BTreeMapFieldId::new(Some("hello".to_owned()), TestModelFieldId::Msg)
);
assert_eq!(query.to_string(), query_str);
}
@@ -706,10 +644,10 @@ mod tests {
},
);
assert_eq!(
- data.query(&BTreeMapFieldId {
- key: Some("hello".to_owned()),
- subquery_id: TestModelFieldId::Msg,
- }),
+ data.query(&BTreeMapFieldId::new(
+ Some("hello".to_owned()),
+ TestModelFieldId::Msg,
+ )),
Some(Field::Str("world".to_owned()))
);
}
diff --git a/below/render/src/default_configs.rs b/below/render/src/default_configs.rs
index 1942e0d1..2f955863 100644
--- a/below/render/src/default_configs.rs
+++ b/below/render/src/default_configs.rs
@@ -35,13 +35,13 @@ impl HasRenderConfig for model::SingleCgroupModel {
Cpu(field_id) => model::CgroupCpuModel::get_render_config_builder(field_id),
Io(field_id) => model::CgroupIoModel::get_render_config_builder(field_id),
IoDetails(field_id) => {
- model::CgroupIoModel::get_render_config_builder(&field_id.subquery_id)
+ model::CgroupIoModel::get_render_config_builder(&field_id.subquery_id.0)
}
Mem(field_id) => model::CgroupMemoryModel::get_render_config_builder(field_id),
Pressure(field_id) => model::CgroupPressureModel::get_render_config_builder(field_id),
CgroupStat(field_id) => model::CgroupStatModel::get_render_config_builder(field_id),
MemNuma(field_id) => {
- model::CgroupMemoryNumaModel::get_render_config_builder(&field_id.subquery_id)
+ model::CgroupMemoryNumaModel::get_render_config_builder(&field_id.subquery_id.0)
}
Props(field_id) => model::CgroupProperties::get_render_config_builder(field_id),
Pids(field_id) => model::CgroupPidsModel::get_render_config_builder(field_id),
@@ -394,7 +394,7 @@ impl HasRenderConfig for model::NetworkModel {
use model::NetworkModelFieldId::*;
match field_id {
Interfaces(field_id) => {
- model::SingleNetModel::get_render_config_builder(&field_id.subquery_id)
+ model::SingleNetModel::get_render_config_builder(&field_id.subquery_id.0)
}
Tcp(field_id) => model::TcpModel::get_render_config_builder(field_id),
Ip(field_id) => model::IpModel::get_render_config_builder(field_id),
@@ -812,7 +812,7 @@ impl HasRenderConfigForDump for model::SingleNetModel {
impl HasRenderConfig for Vec<model::SingleQueueModel> {
fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
let mut rc =
- model::SingleQueueModel::get_render_config_builder(&field_id.subquery_id).get();
+ model::SingleQueueModel::get_render_config_builder(&field_id.subquery_id.0).get();
rc.title = rc.title.map(|title| title.to_string());
rc.into()
}
@@ -827,7 +827,7 @@ impl HasRenderConfigForDump for Vec<model::SingleQueueModel> {
.idx
.expect("VecFieldId without index should not have render config");
self.get(idx)
- .map(|queue| queue.get_openmetrics_config_for_dump(&field_id.subquery_id))?
+ .map(|queue| queue.get_openmetrics_config_for_dump(&field_id.subquery_id.0))?
}
}
@@ -1042,12 +1042,14 @@ impl HasRenderConfig for model::SystemModel {
Mem(field_id) => model::MemoryModel::get_render_config_builder(field_id),
Vm(field_id) => model::VmModel::get_render_config_builder(field_id),
Slab(field_id) => {
- model::SingleSlabModel::get_render_config_builder(&field_id.subquery_id)
+ model::SingleSlabModel::get_render_config_builder(&field_id.subquery_id.0)
}
Disks(field_id) => {
- model::SingleDiskModel::get_render_config_builder(&field_id.subquery_id)
+ model::SingleDiskModel::get_render_config_builder(&field_id.subquery_id.0)
+ }
+ Btrfs(field_id) => {
+ model::BtrfsModel::get_render_config_builder(&field_id.subquery_id.0)
}
- Btrfs(field_id) => model::BtrfsModel::get_render_config_builder(&field_id.subquery_id),
}
}
}
@@ -1159,12 +1161,13 @@ impl HasRenderConfigForDump for model::SingleCpuModel {
impl HasRenderConfig for BTreeMap<u32, model::SingleCpuModel> {
fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
- let mut rc = model::SingleCpuModel::get_render_config_builder(&field_id.subquery_id).get();
+ let mut rc =
+ model::SingleCpuModel::get_render_config_builder(&field_id.subquery_id.0).get();
rc.title = rc.title.map(|title| {
format!(
"CPU {} {}",
field_id
- .key
+ .idx
.expect("BTreeMapFieldId without key should not have render config"),
title
)
@@ -1179,10 +1182,10 @@ impl HasRenderConfigForDump for BTreeMap<u32, model::SingleCpuModel> {
field_id: &Self::FieldId,
) -> Option<RenderOpenMetricsConfigBuilder> {
let key = field_id
- .key
+ .idx
.expect("BTreeMapFieldId without key should not have render config");
self.get(&key)
- .map(|cpu| cpu.get_openmetrics_config_for_dump(&field_id.subquery_id))?
+ .map(|cpu| cpu.get_openmetrics_config_for_dump(&field_id.subquery_id.0))?
}
}
diff --git a/below/view/src/cgroup_tabs.rs b/below/view/src/cgroup_tabs.rs
index b771bc76..2e79f1c4 100644
--- a/below/view/src/cgroup_tabs.rs
+++ b/below/view/src/cgroup_tabs.rs
@@ -134,10 +134,10 @@ impl CgroupTab {
let mut children = Vec::from_iter(&cgroup.children);
if let Some(sort_order) = state.sort_order.as_ref() {
// field_id that query its own data
- let field_id = CgroupModelFieldId {
- path: Some(vec![]),
- subquery_id: sort_order.clone(),
- };
+ let field_id = CgroupModelFieldId::new(
+ Some(model::CgroupPath { path: vec![] }),
+ sort_order.clone(),
+ );
sort_queriables(&mut children, &field_id, state.reverse);
}