Skip to content

Commit

Permalink
QueriableContainer
Browse files Browse the repository at this point in the history
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
  • Loading branch information
lnyng authored and facebook-github-bot committed Apr 11, 2024
1 parent f3d3d29 commit b4bb5b5
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 233 deletions.
8 changes: 4 additions & 4 deletions below/dump/src/cgroup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
5 changes: 1 addition & 4 deletions below/dump/src/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
)));
}
}
Expand Down
12 changes: 4 additions & 8 deletions below/dump/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
76 changes: 24 additions & 52 deletions below/model/src/cgroup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down Expand Up @@ -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")),
Expand Down
Loading

0 comments on commit b4bb5b5

Please sign in to comment.