use psrdada_sys::*;
use tracing::{debug, error, warn};
use crate::{
client::DadaClient,
errors::{PsrdadaError, PsrdadaResult},
};
#[derive(Debug)]
pub struct DadaClientBuilder {
key: i32,
num_bufs: Option<u64>,
buf_size: Option<u64>,
num_headers: Option<u64>,
header_size: Option<u64>,
lock: Option<bool>,
page: Option<bool>,
}
impl DadaClientBuilder {
pub fn new(key: i32) -> Self {
Self {
key,
num_bufs: None,
buf_size: None,
num_headers: None,
header_size: None,
lock: None,
page: None,
}
}
pub fn num_bufs(mut self, value: u64) -> Self {
self.num_bufs = Some(value);
self
}
pub fn buf_size(mut self, value: u64) -> Self {
self.buf_size = Some(value);
self
}
pub fn num_headers(mut self, value: u64) -> Self {
self.num_headers = Some(value);
self
}
pub fn header_size(mut self, value: u64) -> Self {
self.header_size = Some(value);
self
}
pub fn lock(mut self, value: bool) -> Self {
self.lock = Some(value);
self
}
pub fn page(mut self, value: bool) -> Self {
self.page = Some(value);
self
}
#[tracing::instrument]
pub fn build(self) -> PsrdadaResult<DadaClient> {
let num_bufs = self.num_bufs.unwrap_or(4);
let buf_size = self.buf_size.unwrap_or((page_size::get() as u64) * 128);
let num_headers = self.num_headers.unwrap_or(8);
let header_size = self.header_size.unwrap_or(page_size::get() as u64);
let lock = self.lock.unwrap_or(false);
let page = self.page.unwrap_or(false);
debug!("Creating data ringbuffer");
let data = Box::into_raw(Box::default());
unsafe {
if ipcbuf_create_work(data, self.key, num_bufs, buf_size, 1, -1) != 0 {
error!("Error creating data ringbuffer");
return Err(PsrdadaError::DadaInitError);
}
}
debug!("Creating header ringbuffer");
let header = Box::into_raw(Box::default());
unsafe {
if ipcbuf_create(header, self.key + 1, num_headers, header_size, 1) != 0 {
error!("Error creating header ringbuffer");
if ipcbuf_destroy(data) != 0 {
error!("Error destroying data ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
return Err(PsrdadaError::DadaInitError);
}
}
if lock {
debug!("Locking both ring and data buffers in shared memory");
unsafe {
if ipcbuf_lock(data) != 0 {
error!("Error locking data rinngbuffer");
if ipcbuf_destroy(data) != 0 {
error!("Error destroying data ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
if ipcbuf_destroy(header) != 0 {
error!("Error destroying header ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
return Err(PsrdadaError::DadaShmemLockError);
}
if ipcbuf_lock(header) != 0 {
error!("Error locking header ringbuffer");
if ipcbuf_destroy(data) != 0 {
error!("Error destroying data ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
if ipcbuf_destroy(header) != 0 {
error!("Error destroying header ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
return Err(PsrdadaError::DadaShmemLockError);
}
}
}
if page {
debug!("Paging both ring and data buffers in RAM");
unsafe {
if ipcbuf_page(data) != 0 {
error!("Error locking data rinngbuffer");
if ipcbuf_destroy(data) != 0 {
error!("Error destroying data ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
if ipcbuf_destroy(header) != 0 {
error!("Error destroying header ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
return Err(PsrdadaError::DadaShmemLockError);
}
if ipcbuf_page(header) != 0 {
error!("Error locking header ringbuffer");
if ipcbuf_destroy(data) != 0 {
error!("Error destroying data ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
if ipcbuf_destroy(header) != 0 {
error!("Error destroying header ringbuffer");
return Err(PsrdadaError::DadaDestroyError);
}
return Err(PsrdadaError::DadaShmemLockError);
}
}
}
let client = DadaClient::build(data, header)?;
Ok(client)
}
}
#[cfg(test)]
mod tests {
use test_log::test;
use super::*;
use crate::tests::next_key;
#[test]
fn test_construct_client() {
let key = next_key();
let _client = DadaClientBuilder::new(key).build().unwrap();
}
}