summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Schatzberg <dschatzberg@fb.com>2022-04-15 09:49:15 -0700
committerFacebook GitHub Bot <facebook-github-bot@users.noreply.github.com>2022-04-15 09:49:15 -0700
commit603d8e0d82cede43cc1aac2853391b656126624c (patch)
treed7cd99a432b24c8653c592ba820a7572b18f62bd
parent490411af8446bb6fd57f01809b37b4f02a1d7626 (diff)
Handle unsupported pressure metrics gracefully
Summary: Capture the error and report it nicely in cgroupfs and then squash it in below. Reviewed By: brianc118 Differential Revision: D35560379 fbshipit-source-id: d64699cfac457536adb2f98522b55a64b09524f0
-rw-r--r--below/cgroupfs/src/lib.rs32
-rw-r--r--below/model/src/collector.rs14
2 files changed, 40 insertions, 6 deletions
diff --git a/below/cgroupfs/src/lib.rs b/below/cgroupfs/src/lib.rs
index 672e6544..de529ad8 100644
--- a/below/cgroupfs/src/lib.rs
+++ b/below/cgroupfs/src/lib.rs
@@ -40,6 +40,8 @@ pub enum Error {
UnexpectedLine(PathBuf, String),
#[error("Not cgroup2 filesystem: {0:?}")]
NotCgroup2(PathBuf),
+ #[error("Pressure metrics not supported: {0:?}")]
+ PressureNotSupported(PathBuf),
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -273,6 +275,12 @@ impl CgroupReader {
p.push(file_name);
Error::UnexpectedLine(p, line)
}
+
+ fn pressure_not_supported<P: AsRef<Path>>(&self, file_name: P) -> Error {
+ let mut p = self.relative_path.clone();
+ p.push(file_name);
+ Error::PressureNotSupported(p)
+ }
}
// Trait to add a read() method for `key value` formatted files
@@ -374,15 +382,29 @@ trait NameKVRead: Sized {
) -> Result<BTreeMap<String, Self>>;
}
+struct AllowsEmpty(bool);
+struct AllowsPressureEOpNotSupp(bool);
+
macro_rules! name_key_equal_value_format {
- ($struct:ident; $allows_empty:expr; [ $($field:ident,)+ ]) => (
+ ($struct:ident; $allows_empty:expr; $allows_pressure_eopnotsupp:expr; [ $($field:ident,)+ ]) => (
impl NameKVRead for $struct {
fn read<P: AsRef<Path> + AsPath + Clone>(r: &CgroupReader, file_name: P) -> Result<BTreeMap<String, $struct>> {
let mut map = BTreeMap::new();
let file = r.dir.open_file(file_name.clone()).map_err(|e| r.io_error(file_name.clone(), e))?;
let buf_reader = BufReader::new(file);
for line in buf_reader.lines() {
- let line = line.map_err(|e| r.io_error(file_name.clone(), e))?;
+ let line = line.map_err(|e| {
+ // Capture a different error if pressure
+ // metrics aren't supported
+ if $allows_pressure_eopnotsupp.0 {
+ if let Some(errno) = e.raw_os_error() {
+ if errno == /* EOPNOTSUPP */ 95 {
+ return r.pressure_not_supported(file_name.clone());
+ }
+ }
+ }
+ r.io_error(file_name.clone(), e)
+ })?;
let items = line.split_whitespace().collect::<Vec<_>>();
// as an example, io.stat looks like:
// 253:0 rbytes=531745786880 wbytes=1623798909952 ...
@@ -405,7 +427,7 @@ macro_rules! name_key_equal_value_format {
}
map.insert(items[0].to_string(), s);
}
- if !$allows_empty && map.is_empty() {
+ if !$allows_empty.0 && map.is_empty() {
Err(r.invalid_file_format(file_name))
} else {
Ok(map)
@@ -415,7 +437,7 @@ macro_rules! name_key_equal_value_format {
);
}
-name_key_equal_value_format!(IoStat; true; [
+name_key_equal_value_format!(IoStat; AllowsEmpty(true); AllowsPressureEOpNotSupp(false); [
rbytes,
wbytes,
rios,
@@ -424,7 +446,7 @@ name_key_equal_value_format!(IoStat; true; [
dios,
]);
-name_key_equal_value_format!(PressureMetrics; false; [
+name_key_equal_value_format!(PressureMetrics; AllowsEmpty(false); AllowsPressureEOpNotSupp(true); [
avg10,
avg60,
avg300,
diff --git a/below/model/src/collector.rs b/below/model/src/collector.rs
index 88a544ee..b0661466 100644
--- a/below/model/src/collector.rs
+++ b/below/model/src/collector.rs
@@ -296,6 +296,18 @@ fn io_stat_wrap<S: Sized>(
}
}
+/// Pressure metrics may not be supported, in which case cgroupfs will
+/// return a specific error. We don't fail all data collection, just
+/// omit pressure metrics.
+fn pressure_wrap<S: Sized>(
+ v: std::result::Result<S, cgroupfs::Error>,
+) -> std::result::Result<Option<S>, cgroupfs::Error> {
+ match wrap(v) {
+ Err(cgroupfs::Error::PressureNotSupported(_)) => Ok(None),
+ wrapped => wrapped,
+ }
+}
+
fn collect_cgroup_sample(
reader: &cgroupfs::CgroupReader,
collect_io_stat: bool,
@@ -312,7 +324,7 @@ fn collect_cgroup_sample(
io_stat: io_stat.map(|m| m.into_iter().map(|(k, v)| (k, v.into())).collect()),
memory_current: wrap(reader.read_memory_current().map(|v| v as i64))?,
memory_stat: wrap(reader.read_memory_stat())?.map(Into::into),
- pressure: wrap(reader.read_pressure())?.map(Into::into),
+ pressure: pressure_wrap(reader.read_pressure())?.map(Into::into),
// We transpose at the end here to convert the
// Option<Result<BTreeMap... into Result<Option<BTreeMap and
// then bail any errors with `?` - leaving us with the