1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! A thread local context for gathering io-stats efficiently and transparently.
//!
//! Use `SetPerfLevel(PerfLevel::kEnableTime)` to enable time stats.

use std::fmt;

use rocks_sys as ll;

/// A thread local context for gathering io-stats efficiently and transparently.
#[derive(Debug)]
#[repr(C)]
pub struct IOStatsContext {
    /// the thread pool id
    pub thread_pool_id: u64,

    /// number of bytes that has been written.
    pub bytes_written: u64,
    /// number of bytes that has been read.
    pub bytes_read: u64,

    /// time spent in `open()` and `fopen()`.
    pub open_nanos: u64,
    /// time spent in `fallocate()`.
    pub allocate_nanos: u64,
    /// time spent in `write()` and `pwrite()`.
    pub write_nanos: u64,
    /// time spent in `read()` and `pread()`
    pub read_nanos: u64,
    /// time spent in `sync_file_range()`.
    pub range_sync_nanos: u64,
    /// time spent in fsync
    pub fsync_nanos: u64,
    /// time spent in preparing write (fallocate etc).
    pub prepare_write_nanos: u64,
    /// time spent in `Logger::Logv()`.
    pub logger_nanos: u64,
}

impl IOStatsContext {
    /// IOStatsContext for current thread
    pub fn current() -> &'static mut IOStatsContext {
        unsafe {
            let ptr = ll::rocks_get_iostats_context() as *mut IOStatsContext;
            ptr.as_mut().unwrap()
        }
    }

    /// reset all io-stats counter to zero
    pub fn reset(&mut self) {
        unsafe {
            let ptr = self as *mut IOStatsContext as *mut ll::rocks_iostats_context_t;
            ll::rocks_iostats_context_reset(ptr);
        }
    }
}

impl fmt::Display for IOStatsContext {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s = String::new();
        let ptr = self as *const IOStatsContext as *const ll::rocks_iostats_context_t;
        let exclude_zero_counters = false;
        unsafe {
            ll::rocks_iostats_context_to_string(ptr, exclude_zero_counters as u8, &mut s as *mut String as *mut _);
        }
        write!(f, "{}", s)
    }
}


#[cfg(test)]
mod tests {
    use super::*;
    use super::super::rocksdb::*;

    #[test]
    fn iostats_context() {
        set_perf_level(PerfLevel::EnableTime);

        let tmp_dir = ::tempdir::TempDir::new_in(".", "rocks").unwrap();
        let db = DB::open(Options::default().map_db_options(|db| db.create_if_missing(true)), &tmp_dir).unwrap();

        assert!(
            db.put(&Default::default(), b"long-key", vec![b'A'; 1024 * 1024].as_ref())
                .is_ok()
        );
        assert!(db.put(&Default::default(), b"a", b"1").is_ok());
        assert!(db.put(&Default::default(), b"b", b"2").is_ok());
        assert!(db.put(&Default::default(), b"c", b"3").is_ok());

        assert!(db.compact_range(&Default::default(), ..).is_ok());

        let stat = IOStatsContext::current();

        assert!(stat.bytes_written > 1024);

        println!("dbg => {:?}", stat);
        println!("show => {}", stat);

        stat.reset();
        assert_eq!(stat.bytes_written, 0);

        println!("dbg => {:?}", stat);
        println!("show => {}", stat);

        // FIXME: why thread_pool changes?
    }
}