use std::alloc::{self, Layout};
use std::ffi::{c_void, CStr};
use std::mem;
use std::ptr;
use crate::runtime;
use crate::{exdb_sys, mco_ret, Error, Result};
#[doc(hidden)]
pub mod util;
type McoDeviceTypeUnion = exdb_sys::mco_device_t_dev;
type McoDeviceTypeConv = exdb_sys::mco_device_t_dev_conv;
type McoDeviceTypeNamed = exdb_sys::mco_device_t_dev_named;
type McoDeviceTypeFile = exdb_sys::mco_device_t_dev_file;
type McoDeviceTypeMultiFile = exdb_sys::mco_device_t_dev_multifile;
type McoDeviceTypeRaid = exdb_sys::mco_device_t_dev_raid;
mod mco_dev_type {
pub const MCO_MEMORY_CONV: u32 = 1;
pub const MCO_MEMORY_NAMED: u32 = 2;
pub const MCO_MEMORY_FILE: u32 = 3;
pub const MCO_MEMORY_MULTIFILE: u32 = 4;
pub const MCO_MEMORY_RAID: u32 = 5;
}
#[derive(Copy, Clone, Debug)]
pub enum Assignment {
Database,
Cache,
Persistent,
Log,
}
impl Assignment {
fn to_mco(&self) -> u32 {
match self {
Assignment::Database => 0, Assignment::Cache => 1, Assignment::Persistent => 2, Assignment::Log => 3, }
}
}
macro_rules! flags_builder_method {
($(#[$outer:meta])* $method:ident, $ns:path, $flag:expr) => {
$(#[$outer])*
pub fn $method(&mut self) -> &mut Self {
use $ns::*;
self.0 |= $flag;
self
}
}
}
macro_rules! named_mem_flags_builder_method {
($(#[$outer:meta])* $method:ident, $flag:expr) => {
flags_builder_method!(
$(#[$outer])*
$method,
runtime::options::mco_rt_defines::values::shm_posix,
$flag
);
};
}
pub struct NamedMemFlags(u32);
impl NamedMemFlags {
pub fn new() -> Self {
NamedMemFlags(0)
}
named_mem_flags_builder_method!(
anonymous,
MCO_RT_POSIX_SHM_ANONYMOUS
);
named_mem_flags_builder_method!(
shared,
MCO_RT_POSIX_SHM_SHARED
);
named_mem_flags_builder_method!(
huge_tlb,
MCO_RT_POSIX_SHM_HUGETLB
);
}
macro_rules! file_open_flags_builder_method {
($(#[$outer:meta])* $method:ident, $flag:expr) => {
flags_builder_method!(
$(#[$outer])*
$method,
exdb_sys::mco_file_open_flags,
$flag
);
};
}
pub struct FileOpenFlags(u32);
impl FileOpenFlags {
pub fn new() -> Self {
FileOpenFlags(exdb_sys::mco_file_open_flags::MCO_FILE_OPEN_DEFAULT as u32)
}
file_open_flags_builder_method!(
read_only,
MCO_FILE_OPEN_READ_ONLY as u32
);
file_open_flags_builder_method!(
truncate,
MCO_FILE_OPEN_TRUNCATE as u32
);
file_open_flags_builder_method!(
no_buffering,
MCO_FILE_OPEN_NO_BUFFERING as u32
);
file_open_flags_builder_method!(
existing,
MCO_FILE_OPEN_EXISTING as u32
);
file_open_flags_builder_method!(
temporary,
MCO_FILE_OPEN_TEMPORARY as u32
);
file_open_flags_builder_method!(
fsync_fix,
MCO_FILE_OPEN_FSYNC_FIX as u32
);
file_open_flags_builder_method!(
subpartition,
MCO_FILE_OPEN_SUBPARTITION as u32
);
file_open_flags_builder_method!(
fsync_aio_barrier,
MCO_FILE_OPEN_FSYNC_AIO_BARRIER as u32
);
file_open_flags_builder_method!(
compressed,
MCO_FILE_OPEN_COMPRESSED as u32
);
file_open_flags_builder_method!(
lock,
MCO_FILE_OPEN_LOCK as u32
);
file_open_flags_builder_method!(
no_read_buffering,
MCO_FILE_OPEN_NO_READ_BUFFERING as u32
);
file_open_flags_builder_method!(
no_write_buffering,
MCO_FILE_OPEN_NO_WRITE_BUFFERING as u32
);
}
#[repr(transparent)]
pub struct Device(exdb_sys::mco_device_t);
impl Device {
pub fn new_mem_conv(a: Assignment, s: usize) -> Result<Self> {
let l = Layout::from_size_align(s, 1).unwrap();
let p = unsafe { alloc::alloc(l) };
if p.is_null() {
Err(Error::new_core(mco_ret::MCO_E_NOMEM))
} else {
Ok(Device(exdb_sys::mco_device_t {
type_: mco_dev_type::MCO_MEMORY_CONV,
assignment: a.to_mco(),
size: s as exdb_sys::mco_size_t,
dev: McoDeviceTypeUnion {
conv: McoDeviceTypeConv {
ptr: p as *mut c_void,
flags: 0,
},
},
}))
}
}
pub fn new_mem_named(
a: Assignment,
s: usize,
name: &str,
flags: NamedMemFlags,
hint: usize,
) -> Result<Self> {
let mut named = unsafe { mem::zeroed::<McoDeviceTypeNamed>() };
if name.len() >= named.name.len() {
return Err(Error::new_core(mco_ret::MCO_E_ILLEGAL_PARAM));
}
unsafe {
ptr::copy_nonoverlapping(
name.as_ptr(),
named.name.as_mut_ptr() as *mut u8,
name.len(),
)
}
named.flags = flags.0;
named.hint = hint as *mut c_void;
Ok(Device(exdb_sys::mco_device_t {
type_: mco_dev_type::MCO_MEMORY_NAMED,
assignment: a.to_mco(),
size: s as exdb_sys::mco_size_t,
dev: McoDeviceTypeUnion { named },
}))
}
pub fn new_file(a: Assignment, flags: FileOpenFlags, name: &str) -> Result<Self> {
let mut file = unsafe { mem::zeroed::<McoDeviceTypeFile>() };
if name.len() >= file.name.len() {
return Err(Error::new_core(mco_ret::MCO_E_ILLEGAL_PARAM));
}
unsafe {
ptr::copy_nonoverlapping(name.as_ptr(), file.name.as_mut_ptr() as *mut u8, name.len())
}
file.flags = flags.0 as i32;
Ok(Device(exdb_sys::mco_device_t {
type_: mco_dev_type::MCO_MEMORY_FILE,
assignment: a.to_mco(),
size: 0,
dev: McoDeviceTypeUnion { file },
}))
}
pub fn new_multifile(
a: Assignment,
flags: FileOpenFlags,
name: &str,
segment_size: isize,
) -> Result<Self> {
let mut multifile = unsafe { mem::zeroed::<McoDeviceTypeMultiFile>() };
if name.len() >= multifile.name.len() {
return Err(Error::new_core(mco_ret::MCO_E_ILLEGAL_PARAM));
}
unsafe {
ptr::copy_nonoverlapping(
name.as_ptr(),
multifile.name.as_mut_ptr() as *mut u8,
name.len(),
)
}
multifile.flags = flags.0 as i32;
multifile.segment_size = segment_size as exdb_sys::mco_offs_t;
Ok(Device(exdb_sys::mco_device_t {
type_: mco_dev_type::MCO_MEMORY_MULTIFILE,
assignment: a.to_mco(),
size: 0,
dev: McoDeviceTypeUnion { multifile },
}))
}
pub fn new_raid(
a: Assignment,
flags: FileOpenFlags,
name: &str,
level: i32,
offset: isize,
) -> Result<Self> {
let mut raid = unsafe { mem::zeroed::<McoDeviceTypeRaid>() };
if name.len() >= raid.name.len() {
return Err(Error::new_core(mco_ret::MCO_E_ILLEGAL_PARAM));
}
unsafe {
ptr::copy_nonoverlapping(name.as_ptr(), raid.name.as_mut_ptr() as *mut u8, name.len())
}
raid.flags = flags.0 as i32;
raid.level = level;
raid.offset = offset as exdb_sys::mco_offs_t;
Ok(Device(exdb_sys::mco_device_t {
type_: mco_dev_type::MCO_MEMORY_RAID,
assignment: a.to_mco(),
size: 0,
dev: McoDeviceTypeUnion { raid },
}))
}
fn file_name(&self) -> Option<&str> {
match self.0.type_ {
mco_dev_type::MCO_MEMORY_FILE => {
let cname = unsafe { CStr::from_ptr(self.0.dev.file.name.as_ptr()) };
cname.to_str().ok()
}
_ => None,
}
}
}
impl Drop for Device {
fn drop(&mut self) {
if self.0.type_ == mco_dev_type::MCO_MEMORY_CONV {
let l = Layout::from_size_align(self.0.size as usize, 1).unwrap();
unsafe { alloc::dealloc(self.0.dev.conv.ptr as *mut u8, l) };
}
}
}