Repository: microsoft/onefuzz
File: src/agent/onefuzz-task/src/tasks/coverage/generic.rs (Rust)

Code before:
            }
        }

        Ok(count)
    }

    pub async fn report_coverage_stats(&self) -> Result<()> {
        use EventData::*;

        let s = CoverageStats::new(&self.coverage);
        event!(coverage_data; Covered = s.covered, Features = s.features, Rate = s.rate);
        metric!(coverage_data; 1.0; Covered = s.covered, Features = s.features, Rate = s.rate);

        Ok(())
    }

    pub async fn save_coverage(
        coverage: &BinaryCoverage,
        source_allowlist: &AllowList,
        binary_coverage_path: &Path,
        source_coverage_path: &Path,
        copbertura_file_path: &Path,
    ) -> Result<()> {
        Self::save_binary_coverage(coverage, binary_coverage_path)?;

        let source = binary_to_source_coverage(coverage, source_allowlist.clone())?;

        Self::save_source_coverage(&source, source_coverage_path).await?;

        Self::save_cobertura_xml(&source, copbertura_file_path).await?;
        Ok(())
    }

    pub async fn save_and_sync_coverage(&self) -> Result<()> {
        let copbertura_file_path = self
            .config
            .coverage
            .local_path
            .join(COBERTURA_COVERAGE_FILE);

        let source_coverage_path = self.config.coverage.local_path.join(SOURCE_COVERAGE_FILE);
        let binary_coverage_path = self.config.coverage.local_path.join(COVERAGE_FILE);

        Self::save_coverage(
            &self.coverage,
            &self.source_allowlist,
            &binary_coverage_path,
            &source_coverage_path,
            &copbertura_file_path,
        )
        .await?;

Review comment (suggestion):
We used to do this in a `spawn_blocking` call, was that intentionally removed? I think we're still doing the same amount of blocking I/O as before

Code after:
                }
            }
        }

        Ok(count)
    }

    pub async fn report_coverage_stats(&self) -> Result<()> {
        use EventData::*;

        let coverage = RwLock::read(&self.coverage).await;
        let s = CoverageStats::new(&coverage);
        event!(coverage_data; Covered = s.covered, Features = s.features, Rate = s.rate);
        metric!(coverage_data; 1.0; Covered = s.covered, Features = s.features, Rate = s.rate);

        Ok(())
    }

    pub async fn save_coverage(
        coverage: &RwLock<BinaryCoverage>,
        source_allowlist: &Arc<AllowList>,
        binary_coverage_path: &Path,
        source_coverage_path: &Path,
        copbertura_file_path: &Path,
    ) -> Result<()> {
        let source = Self::source_coverage(coverage, source_allowlist.clone()).await?;
        let coverage = coverage.read().await;

        Self::save_binary_coverage(&coverage, binary_coverage_path)?;
        Self::save_source_coverage(&source, source_coverage_path).await?;
        Self::save_cobertura_xml(&source, copbertura_file_path).await?;
        Ok(())
    }

    async fn source_coverage(
        coverage: &RwLock<BinaryCoverage>,
        source_allowlist: Arc<AllowList>,
    ) -> Result<SourceCoverage> {
        // Must be owned due to `spawn_blocking()` lifetimes.
        let allowlist = source_allowlist.clone();
        let binary = Arc::new(coverage.read().await.clone());
        // Conversion to source coverage heavy on blocking I/O.
        spawn_blocking(move || binary_to_source_coverage(&binary, &allowlist)).await?
    }

    pub async fn save_and_sync_coverage(&self) -> Result<()> {
        let copbertura_file_path = self
            .config
            .coverage
            .local_path
            .join(COBERTURA_COVERAGE_FILE);