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
108
109
110
111
112
113
114
115
116
use ::std::ffi::CString;
use ::std::path::Path;
use ::std::io;

use ::libc::iovec;
use ::libc::{size_t, mode_t};
use ::libc::{c_void, c_int};

use pmemlog_sys::{self as ffi, PMEMlogpool};

pub struct Log {
    inner: *mut PMEMlogpool,
}

extern "C" fn visit_log<F>(buf: *const c_void, len: size_t, arg: *mut c_void) -> c_int
    where F: Fn(&[u8]) -> Option<()>
{
    let callback = arg as *const F;
    let buf = buf as *mut u8;
    unsafe {
        let item = ::std::slice::from_raw_parts(buf, len);
        match (*callback)(item) {
            Some(()) => 1,
            None => 0,
        }
    }
}

impl Log {
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, io::Error> {
        let path = CString::new(path.as_ref().to_str().unwrap()).unwrap();

        let objpool = unsafe { ffi::pmemlog_open(path.as_ptr()) };

        if objpool.is_null() {
            Err(io::Error::last_os_error())
        } else {
            Ok(Log { inner: objpool })
        }
    }

    pub fn create<P: AsRef<Path>>(path: P, size: usize) -> Result<Self, io::Error> {
        let path = path.as_ref().to_str().unwrap();
        let path = CString::new(path).unwrap();

        let mode = 0o666;

        let objpool = unsafe { ffi::pmemlog_create(path.as_ptr(), size as size_t, mode as mode_t) };

        if objpool.is_null() {
            Err(io::Error::last_os_error())
        } else {
            Ok(Log { inner: objpool })
        }
    }

    pub fn append<T: AsRef<[u8]>>(&mut self, entry: T) -> Result<(), io::Error> {
        let buf = entry.as_ref();
        let len = buf.len();

        let r = unsafe {
            let buf = buf.as_ptr() as *mut c_void;
            ffi::pmemlog_append(self.inner, buf, len as size_t)
        };

        if r == 0 {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn append_many<T: AsRef<[u8]>>(&mut self, entries: &[T]) -> Result<(), io::Error> {
        let count = entries.len();
        let mut io_vecs = Vec::with_capacity(count);
        for entry in entries {
            let buf = entry.as_ref();
            io_vecs.push(iovec { iov_base: buf.as_ptr() as *mut c_void,
                                 iov_len: buf.len() as size_t, });
        }

        let r = unsafe {
            let io_vecs = io_vecs.as_slice().as_ptr() as *const iovec;
            ffi::pmemlog_appendv(self.inner, io_vecs, count as c_int)
        };

        if r == 0 {
            Ok(())
        } else {
            Err(io::Error::last_os_error())
        }
    }

    pub fn len(&self) -> usize {
        unsafe { ffi::pmemlog_tell(self.inner) as usize }
    }

    pub fn capacity(&self) -> usize { unsafe { ffi::pmemlog_nbyte(self.inner) as usize } }

    pub fn walk<F>(&self, chunk_size: usize, callback: F)
        where F: Fn(&[u8]) -> Option<()>
    {
        unsafe {
            let arg = &callback as *const _ as *mut c_void;
            ffi::pmemlog_walk(self.inner, chunk_size as size_t, visit_log::<F>, arg)
        };
    }
}

impl Drop for Log {
    fn drop(&mut self) {
        unsafe {
            ffi::pmemlog_close(self.inner);
        }
    }
}