use crate::error::{DaosError, Result};
use crate::runtime::require_runtime;
use crate::unsafe_inner::ffi::{daos_pool_connect, daos_pool_disconnect};
use crate::unsafe_inner::handle::DaosHandle;
pub mod flags {
pub const POOL_CONNECT_NONE: u32 = 0;
pub const POOL_CONNECT_READONLY: u32 = daos::DAOS_PC_RO;
pub const POOL_CONNECT_QUERY_ONLY: u32 = daos::DAOS_PC_RW;
pub const POOL_CONNECT_READWRITE: u32 = daos::DAOS_PC_RW;
pub const POOL_CONNECT_EXCLUSIVE: u32 = daos::DAOS_PC_EX;
}
#[derive(Debug)]
pub struct Pool {
handle: Option<DaosHandle>,
}
impl Pool {
#[inline]
pub fn builder() -> PoolBuilder {
PoolBuilder::new()
}
#[allow(dead_code)]
pub(crate) fn as_handle(&self) -> Option<DaosHandle> {
self.handle
}
#[cfg(test)]
pub(crate) fn from_handle(handle: DaosHandle) -> Self {
Self {
handle: Some(handle),
}
}
pub fn disconnect(&mut self) -> Result<()> {
if let Some(handle) = self.handle.take() {
daos_pool_disconnect(handle)
} else {
Err(DaosError::InvalidArg)
}
}
}
#[derive(Debug, Default)]
pub struct PoolBuilder {
label: Option<String>,
uuid: Option<String>,
sys: Option<String>,
flags: u32,
}
impl PoolBuilder {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
#[inline]
pub fn uuid(mut self, uuid: impl Into<String>) -> Self {
self.uuid = Some(uuid.into());
self
}
#[inline]
pub fn system(mut self, sys: impl Into<String>) -> Self {
self.sys = Some(sys.into());
self
}
#[inline]
pub fn flags(mut self, flags: u32) -> Self {
self.flags = flags;
self
}
fn validate(&self) -> Result<()> {
match (&self.label, &self.uuid) {
(Some(_), Some(_)) => Err(DaosError::InvalidArg),
(None, None) => Err(DaosError::InvalidArg),
_ => Ok(()),
}
}
pub fn build(&self) -> Result<Pool> {
require_runtime()?;
self.validate()?;
let pool_id = self.label.as_deref().or(self.uuid.as_deref());
let pool_id = pool_id.ok_or(DaosError::InvalidArg)?;
let sys = self.sys.as_deref();
let handle = daos_pool_connect(pool_id, sys, self.flags)?;
Ok(Pool {
handle: Some(handle),
})
}
}
impl Drop for Pool {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
if let Err(e) = daos_pool_disconnect(handle) {
eprintln!(
"Pool::drop: daos_pool_disconnect() failed with {:?}, continuing with drop anyway",
e
);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pool_builder_default() {
let builder = PoolBuilder::new();
assert!(builder.label.is_none());
assert!(builder.uuid.is_none());
assert!(builder.sys.is_none());
assert_eq!(builder.flags, 0);
}
#[test]
fn test_pool_builder_with_label() {
let builder = PoolBuilder::new().label("mypool");
assert_eq!(builder.label.as_deref(), Some("mypool"));
}
#[test]
fn test_pool_builder_with_uuid() {
let builder = PoolBuilder::new().uuid("12345678-1234-1234-1234-123456789012");
assert_eq!(
builder.uuid.as_deref(),
Some("12345678-1234-1234-1234-123456789012")
);
}
#[test]
fn test_pool_builder_with_system() {
let builder = PoolBuilder::new().system("daos_server");
assert_eq!(builder.sys.as_deref(), Some("daos_server"));
}
#[test]
fn test_pool_builder_with_flags() {
let builder = PoolBuilder::new().flags(42);
assert_eq!(builder.flags, 42);
}
#[test]
fn test_pool_builder_chaining() {
let builder = PoolBuilder::new()
.label("mypool")
.system("daos_server")
.flags(flags::POOL_CONNECT_READONLY);
assert_eq!(builder.label.as_deref(), Some("mypool"));
assert_eq!(builder.sys.as_deref(), Some("daos_server"));
assert_eq!(builder.flags, flags::POOL_CONNECT_READONLY);
}
#[test]
fn test_pool_builder_validate_neither_label_nor_uuid() {
let builder = PoolBuilder::new().system("daos_server");
let result = builder.validate();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DaosError::InvalidArg));
}
#[test]
fn test_pool_builder_validate_both_label_and_uuid() {
let builder = PoolBuilder::new()
.label("mypool")
.uuid("12345678-1234-1234-1234-123456789012");
let result = builder.validate();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DaosError::InvalidArg));
}
#[test]
fn test_pool_builder_validate_label_only() {
let builder = PoolBuilder::new().label("mypool");
assert!(builder.validate().is_ok());
}
#[test]
fn test_pool_builder_validate_uuid_only() {
let builder = PoolBuilder::new().uuid("12345678-1234-1234-1234-123456789012");
assert!(builder.validate().is_ok());
}
#[test]
fn test_pool_disconnect_without_connect() {
let mut pool = Pool { handle: None };
let result = pool.disconnect();
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), DaosError::InvalidArg));
}
#[test]
fn test_require_runtime_error_when_not_init() {
while crate::runtime::is_runtime_initialized() {
drop(crate::runtime::DaosRuntime::new());
}
let builder = PoolBuilder::new().label("mypool");
let result = builder.build();
assert!(result.is_err());
}
#[test]
fn test_pool_builder_flags_constants() {
assert_eq!(flags::POOL_CONNECT_NONE, 0);
assert_eq!(flags::POOL_CONNECT_READONLY, 1);
assert_eq!(flags::POOL_CONNECT_QUERY_ONLY, 2);
}
}