pagecache 0.4.2

lock-free pagecache and log for high-performance databases
Documentation
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::{Acquire, Relaxed};
use std::iter::repeat;

use historian::Histo;

#[derive(Default, Debug)]
pub struct Metrics {
    pub advance_snapshot: Histo,
    pub tree_set: Histo,
    pub tree_get: Histo,
    pub tree_del: Histo,
    pub tree_cas: Histo,
    pub tree_scan: Histo,
    pub page_in: Histo,
    pub merge_page: Histo,
    pub page_out: Histo,
    pub pull: Histo,
    pub serialize: Histo,
    pub deserialize: Histo,
    pub compress: Histo,
    pub decompress: Histo,
    pub make_stable: Histo,
    pub reserve: Histo,
    pub write_to_log: Histo,
    pub written_bytes: Histo,
    pub read: Histo,
    pub tree_loops: AtomicUsize,
    pub log_loops: AtomicUsize,
    pub accountant_lock: Histo,
    pub accountant_hold: Histo,
}

impl Metrics {
    pub fn tree_looped(&self) {
        self.tree_loops.fetch_add(1, Relaxed);
    }

    pub fn log_looped(&self) {
        self.log_loops.fetch_add(1, Relaxed);
    }

    pub fn print_profile(&self) {
        println!(
            "pagecache profile:\n\
            {0: >17} | {1: >10} | {2: >10} | {3: >10} | {4: >10} | {5: >10} | {6: >10} | {7: >10}",
            "op",
            "min (us)",
            "90 (us)",
            "99 (us)",
            "99.9 (us)",
            "max (us)",
            "count",
            "sum (s)"
        );
        println!("{}", repeat("-").take(103).collect::<String>());

        let p = |mut tuples: Vec<(String, _, _, _, _, _, _, _)>| {
            tuples.sort_by_key(|t| (t.7 * -1. * 1e3) as i64);
            for v in tuples {
                println!(
                    "{0: >17} | {1: >10.1} | {2: >10.1} | {3: >10.1} \
                | {4: >10.1} | {5: >10.1} | {6: >10.1} | {7: >10.3}",
                    v.0,
                    v.1,
                    v.2,
                    v.3,
                    v.4,
                    v.5,
                    v.6,
                    v.7
                );
            }
        };

        let f = |name: &str, histo: &Histo| {
            (
                name.to_string(),
                histo.percentile(0.) / 1e3,
                histo.percentile(90.) / 1e3,
                histo.percentile(99.) / 1e3,
                histo.percentile(99.9) / 1e3,
                histo.percentile(100.) / 1e3,
                histo.count(),
                histo.sum() as f64 / 1e9,
            )
        };

        println!("tree:");
        p(vec![
            f("get", &self.tree_get),
            f("set", &self.tree_set),
            f("del", &self.tree_del),
            f("cas", &self.tree_cas),
            f("scan", &self.tree_scan),
        ]);
        println!("tree contention loops: {}", self.tree_loops.load(Acquire));

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("pagecache:");
        p(vec![
            f("snapshot", &self.advance_snapshot),
            f("page_in", &self.page_in),
            f("merge", &self.merge_page),
            f("pull", &self.pull),
            f("page_out", &self.page_out),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("serialization and compression:");
        p(vec![
            f("serialize", &self.serialize),
            f("deserialize", &self.deserialize),
            f("compress", &self.compress),
            f("decompress", &self.decompress),
        ]);

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("log:");
        p(vec![
            f("make_stable", &self.make_stable),
            f("read", &self.read),
            f("write", &self.write_to_log),
            f("written bytes", &self.written_bytes),
            f("reserve", &self.reserve),
        ]);
        println!("log contention loops: {}", self.log_loops.load(Acquire));

        println!("{}", repeat("-").take(103).collect::<String>());
        println!("segment accountant:");
        p(vec![
            f("acquire", &self.accountant_lock),
            f("hold", &self.accountant_hold),
        ]);
    }
}