Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3152856
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
55 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/bindings/rust/src/cmap.rs b/bindings/rust/src/cmap.rs
index f35f58f9..93539db3 100644
--- a/bindings/rust/src/cmap.rs
+++ b/bindings/rust/src/cmap.rs
@@ -1,898 +1,898 @@
// libcmap interface for Rust
// Copyright (c) 2021 Red Hat, Inc.
//
// All rights reserved.
//
// Author: Christine Caulfield (ccaulfi@redhat.com)
//
#![allow(clippy::type_complexity)]
// For the code generated by bindgen
use crate::sys::cmap as ffi;
use num_enum::TryFromPrimitive;
use std::any::type_name;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::ffi::CString;
use std::fmt;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr::copy_nonoverlapping;
use std::sync::Mutex;
use crate::string_from_bytes;
use crate::{CsError, DispatchFlags, Result};
// Maps:
/// "Maps" available to [initialize]
pub enum Map {
Icmap,
Stats,
}
bitflags! {
/// Tracker types for cmap, both passed into [track_add]
/// and returned from its callback.
pub struct TrackType: i32
{
const DELETE = 1;
const MODIFY = 2;
const ADD = 4;
const PREFIX = 8;
}
}
impl fmt::Display for TrackType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.contains(TrackType::DELETE) {
write!(f, "DELETE ")?
}
if self.contains(TrackType::MODIFY) {
write!(f, "MODIFY ")?
}
if self.contains(TrackType::ADD) {
write!(f, "ADD ")?
}
if self.contains(TrackType::PREFIX) {
write!(f, "PREFIX ")
} else {
Ok(())
}
}
}
#[derive(Copy, Clone)]
/// A handle returned from [initialize], needs to be passed to all other cmap API calls
pub struct Handle {
cmap_handle: u64,
}
#[derive(Copy, Clone)]
/// A handle for a specific CMAP tracker. returned from [track_add].
/// There may be multiple TrackHandles per [Handle]
pub struct TrackHandle {
track_handle: u64,
notify_callback: NotifyCallback,
}
// Used to convert CMAP handles into one of ours, for callbacks
lazy_static! {
static ref TRACKHANDLE_HASH: Mutex<HashMap<u64, TrackHandle>> = Mutex::new(HashMap::new());
static ref HANDLE_HASH: Mutex<HashMap<u64, Handle>> = Mutex::new(HashMap::new());
}
/// Initialize a connection to the cmap subsystem.
/// map specifies which cmap "map" to use.
/// Returns a [Handle] into the cmap library
pub fn initialize(map: Map) -> Result<Handle> {
let mut handle: ffi::cmap_handle_t = 0;
let c_map = match map {
Map::Icmap => ffi::CMAP_MAP_ICMAP,
Map::Stats => ffi::CMAP_MAP_STATS,
};
unsafe {
let res = ffi::cmap_initialize_map(&mut handle, c_map);
if res == ffi::CS_OK {
let rhandle = Handle {
cmap_handle: handle,
};
HANDLE_HASH.lock().unwrap().insert(handle, rhandle);
Ok(rhandle)
} else {
Err(CsError::from_c(res))
}
}
}
/// Finish with a connection to corosync.
/// Takes a [Handle] as returned from [initialize]
pub fn finalize(handle: Handle) -> Result<()> {
let res = unsafe { ffi::cmap_finalize(handle.cmap_handle) };
if res == ffi::CS_OK {
HANDLE_HASH.lock().unwrap().remove(&handle.cmap_handle);
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Return a file descriptor to use for poll/select on the CMAP handle.
/// Takes a [Handle] as returned from [initialize],
/// returns a C file descriptor as i32
pub fn fd_get(handle: Handle) -> Result<i32> {
let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
let res = unsafe { ffi::cmap_fd_get(handle.cmap_handle, c_fd) };
if res == ffi::CS_OK {
Ok(c_fd as i32)
} else {
Err(CsError::from_c(res))
}
}
/// Dispatch any/all active CMAP callbacks.
/// Takes a [Handle] as returned from [initialize],
/// flags [DispatchFlags] tells it how many items to dispatch before returning
pub fn dispatch(handle: Handle, flags: DispatchFlags) -> Result<()> {
let res = unsafe { ffi::cmap_dispatch(handle.cmap_handle, flags as u32) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Get the current 'context' value for this handle
/// The context value is an arbitrary value that is always passed
/// back to callbacks to help identify the source
pub fn context_get(handle: Handle) -> Result<u64> {
let (res, context) = unsafe {
let mut context: u64 = 0;
let c_context: *mut c_void = &mut context as *mut _ as *mut c_void;
let r = ffi::cmap_context_get(handle.cmap_handle, c_context as *mut *const c_void);
(r, context)
};
if res == ffi::CS_OK {
Ok(context)
} else {
Err(CsError::from_c(res))
}
}
/// Set the current 'context' value for this handle
/// The context value is an arbitrary value that is always passed
/// back to callbacks to help identify the source.
/// Normally this is set in [initialize], but this allows it to be changed
pub fn context_set(handle: Handle, context: u64) -> Result<()> {
let res = unsafe {
let c_context = context as *mut c_void;
ffi::cmap_context_set(handle.cmap_handle, c_context)
};
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// The type of data returned from [get] or in a
/// tracker callback or iterator, part of the [Data] struct
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
#[repr(u32)]
pub enum DataType {
Int8 = ffi::CMAP_VALUETYPE_INT8,
UInt8 = ffi::CMAP_VALUETYPE_UINT8,
Int16 = ffi::CMAP_VALUETYPE_INT16,
UInt16 = ffi::CMAP_VALUETYPE_UINT16,
Int32 = ffi::CMAP_VALUETYPE_INT32,
UInt32 = ffi::CMAP_VALUETYPE_UINT32,
Int64 = ffi::CMAP_VALUETYPE_INT64,
UInt64 = ffi::CMAP_VALUETYPE_UINT64,
Float = ffi::CMAP_VALUETYPE_FLOAT,
Double = ffi::CMAP_VALUETYPE_DOUBLE,
String = ffi::CMAP_VALUETYPE_STRING,
Binary = ffi::CMAP_VALUETYPE_BINARY,
Unknown = 999,
}
fn cmap_to_enum(cmap_type: u32) -> DataType {
match DataType::try_from(cmap_type) {
Ok(e) => e,
Err(_) => DataType::Unknown,
}
}
/// Data returned from the cmap::get() call and tracker & iterators.
/// Contains the data itself and the type of that data.
pub enum Data {
Int8(i8),
UInt8(u8),
Int16(i16),
UInt16(u16),
Int32(i32),
UInt32(u32),
Int64(i64),
UInt64(u64),
Float(f32),
Double(f64),
String(String),
Binary(Vec<u8>),
Unknown,
}
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DataType::Int8 => write!(f, "Int8"),
DataType::UInt8 => write!(f, "UInt8"),
DataType::Int16 => write!(f, "Int16"),
DataType::UInt16 => write!(f, "UInt16"),
DataType::Int32 => write!(f, "Int32"),
DataType::UInt32 => write!(f, "UInt32"),
DataType::Int64 => write!(f, "Int64"),
DataType::UInt64 => write!(f, "UInt64"),
DataType::Float => write!(f, "Float"),
DataType::Double => write!(f, "Double"),
DataType::String => write!(f, "String"),
DataType::Binary => write!(f, "Binary"),
DataType::Unknown => write!(f, "Unknown"),
}
}
}
impl fmt::Display for Data {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
- Data::Int8(v) => write!(f, "{} (Int8)", v),
- Data::UInt8(v) => write!(f, "{} (UInt8)", v),
- Data::Int16(v) => write!(f, "{} (Int16)", v),
- Data::UInt16(v) => write!(f, "{} (UInt16)", v),
- Data::Int32(v) => write!(f, "{} (Int32)", v),
- Data::UInt32(v) => write!(f, "{} (UInt32)", v),
- Data::Int64(v) => write!(f, "{} (Int64)", v),
- Data::UInt64(v) => write!(f, "{} (UInt64)", v),
- Data::Float(v) => write!(f, "{} (Float)", v),
- Data::Double(v) => write!(f, "{} (Double)", v),
- Data::String(v) => write!(f, "{} (String)", v),
- Data::Binary(v) => write!(f, "{:?} (Binary)", v),
+ Data::Int8(v) => write!(f, "{v} (Int8)"),
+ Data::UInt8(v) => write!(f, "{v} (UInt8)"),
+ Data::Int16(v) => write!(f, "{v} (Int16)"),
+ Data::UInt16(v) => write!(f, "{v} (UInt16)"),
+ Data::Int32(v) => write!(f, "{v} (Int32)"),
+ Data::UInt32(v) => write!(f, "{v} (UInt32)"),
+ Data::Int64(v) => write!(f, "{v} (Int64)"),
+ Data::UInt64(v) => write!(f, "{v} (UInt64)"),
+ Data::Float(v) => write!(f, "{v} (Float)"),
+ Data::Double(v) => write!(f, "{v} (Double)"),
+ Data::String(v) => write!(f, "{v} (String)"),
+ Data::Binary(v) => write!(f, "{v:?} (Binary)"),
Data::Unknown => write!(f, "Unknown)"),
}
}
}
const CMAP_KEYNAME_MAXLENGTH: usize = 255;
fn string_to_cstring_validated(key: &str, maxlen: usize) -> Result<CString> {
if maxlen > 0 && key.chars().count() >= maxlen {
return Err(CsError::CsErrInvalidParam);
}
match CString::new(key) {
Ok(n) => Ok(n),
Err(_) => Err(CsError::CsErrLibrary),
}
}
fn set_value(
handle: Handle,
key_name: &str,
datatype: DataType,
value: *mut c_void,
length: usize,
) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe {
ffi::cmap_set(
handle.cmap_handle,
csname.as_ptr(),
value,
length,
datatype as u32,
)
};
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
// Returns type and size
fn generic_to_cmap<T>(_value: T) -> (DataType, usize) {
match type_name::<T>() {
"u8" => (DataType::UInt8, 1),
"i8" => (DataType::Int8, 1),
"u16" => (DataType::UInt16, 2),
"i16" => (DataType::Int16, 2),
"u32" => (DataType::UInt32, 4),
"i32" => (DataType::Int32, 4),
"u64" => (DataType::UInt64, 4),
"f32" => (DataType::Float, 4),
"f64" => (DataType::Double, 8),
"&str" => (DataType::String, 0),
// Binary not currently supported here
_ => (DataType::Unknown, 0),
}
}
fn is_numeric_type(dtype: DataType) -> bool {
matches!(
dtype,
DataType::UInt8
| DataType::Int8
| DataType::UInt16
| DataType::Int16
| DataType::UInt32
| DataType::Int32
| DataType::UInt64
| DataType::Int64
| DataType::Float
| DataType::Double
)
}
/// Function to set a generic numeric value
/// This doesn't work for strings or binaries
pub fn set_number<T: Copy>(handle: Handle, key_name: &str, value: T) -> Result<()> {
let (c_type, c_size) = generic_to_cmap(value);
if is_numeric_type(c_type) {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, c_type, c_value as *mut c_void, c_size)
} else {
Err(CsError::CsErrNotSupported)
}
}
pub fn set_u8(handle: Handle, key_name: &str, value: u8) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::UInt8, c_value as *mut c_void, 1)
}
/// Sets an i8 value into cmap
pub fn set_i8(handle: Handle, key_name: &str, value: i8) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int8, c_value as *mut c_void, 1)
}
/// Sets a u16 value into cmap
pub fn set_u16(handle: Handle, key_name: &str, value: u16) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(
handle,
key_name,
DataType::UInt16,
c_value as *mut c_void,
2,
)
}
/// Sets an i16 value into cmap
pub fn set_i16(handle: Handle, key_name: &str, value: i16) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int16, c_value as *mut c_void, 2)
}
/// Sets a u32 value into cmap
pub fn set_u32(handle: Handle, key_name: &str, value: u32) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::UInt32, c_value, 4)
}
/// Sets an i32 value into cmap
pub fn set_i132(handle: Handle, key_name: &str, value: i32) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int32, c_value as *mut c_void, 4)
}
/// Sets a u64 value into cmap
pub fn set_u64(handle: Handle, key_name: &str, value: u64) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(
handle,
key_name,
DataType::UInt64,
c_value as *mut c_void,
8,
)
}
/// Sets an i64 value into cmap
pub fn set_i164(handle: Handle, key_name: &str, value: i64) -> Result<()> {
let mut tmp = value;
let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
set_value(handle, key_name, DataType::Int64, c_value as *mut c_void, 8)
}
/// Sets a string value into cmap
pub fn set_string(handle: Handle, key_name: &str, value: &str) -> Result<()> {
let v_string = string_to_cstring_validated(value, 0)?;
set_value(
handle,
key_name,
DataType::String,
v_string.as_ptr() as *mut c_void,
value.chars().count(),
)
}
/// Sets a binary value into cmap
pub fn set_binary(handle: Handle, key_name: &str, value: &[u8]) -> Result<()> {
set_value(
handle,
key_name,
DataType::Binary,
value.as_ptr() as *mut c_void,
value.len(),
)
}
/// Sets a [Data] type into cmap
pub fn set(handle: Handle, key_name: &str, data: &Data) -> Result<()> {
let (datatype, datalen, c_value) = match data {
Data::Int8(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int8, 1, cv)
}
Data::UInt8(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt8, 1, cv)
}
Data::Int16(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int16, 2, cv)
}
Data::UInt16(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt8, 2, cv)
}
Data::Int32(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int32, 4, cv)
}
Data::UInt32(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt32, 4, cv)
}
Data::Int64(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Int64, 8, cv)
}
Data::UInt64(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::UInt64, 8, cv)
}
Data::Float(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Float, 4, cv)
}
Data::Double(v) => {
let mut tmp = *v;
let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
(DataType::Double, 8, cv)
}
Data::String(v) => {
let cv = string_to_cstring_validated(v, 0)?;
// Can't let cv go out of scope
return set_value(
handle,
key_name,
DataType::String,
cv.as_ptr() as *mut c_void,
v.chars().count(),
);
}
Data::Binary(v) => {
// Vec doesn't return quite the right types.
return set_value(
handle,
key_name,
DataType::Binary,
v.as_ptr() as *mut c_void,
v.len(),
);
}
Data::Unknown => return Err(CsError::CsErrInvalidParam),
};
set_value(handle, key_name, datatype, c_value, datalen)
}
// Local function to parse out values from the C mess
// Assumes the c_value is complete. So cmap::get() will need to check the size
// and re-get before calling us with a resized buffer
fn c_to_data(value_size: usize, c_key_type: u32, c_value: *const u8) -> Result<Data> {
unsafe {
match cmap_to_enum(c_key_type) {
DataType::UInt8 => {
let mut ints = [0u8; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt8(ints[0]))
}
DataType::Int8 => {
let mut ints = [0i8; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int8(ints[0]))
}
DataType::UInt16 => {
let mut ints = [0u16; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt16(ints[0]))
}
DataType::Int16 => {
let mut ints = [0i16; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int16(ints[0]))
}
DataType::UInt32 => {
let mut ints = [0u32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt32(ints[0]))
}
DataType::Int32 => {
let mut ints = [0i32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int32(ints[0]))
}
DataType::UInt64 => {
let mut ints = [0u64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::UInt64(ints[0]))
}
DataType::Int64 => {
let mut ints = [0i64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Int64(ints[0]))
}
DataType::Float => {
let mut ints = [0f32; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Float(ints[0]))
}
DataType::Double => {
let mut ints = [0f64; 1];
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Double(ints[0]))
}
DataType::String => {
let mut ints = Vec::<u8>::new();
ints.resize(value_size, 0u8);
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
// -1 here so CString doesn't see the NUL
let cs = match CString::new(&ints[0..value_size - 1_usize]) {
Ok(c1) => c1,
Err(_) => return Err(CsError::CsErrLibrary),
};
match cs.into_string() {
Ok(s) => Ok(Data::String(s)),
Err(_) => Err(CsError::CsErrLibrary),
}
}
DataType::Binary => {
let mut ints = Vec::<u8>::new();
ints.resize(value_size, 0u8);
copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
Ok(Data::Binary(ints))
}
DataType::Unknown => Ok(Data::Unknown),
}
}
}
const INITIAL_SIZE: usize = 256;
/// Get a value from cmap, returned as a [Data] struct, so could be anything
pub fn get(handle: Handle, key_name: &str) -> Result<Data> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let mut value_size: usize = 16;
let mut c_key_type: u32 = 0;
let mut c_value = Vec::<u8>::new();
// First guess at a size for Strings and Binaries. Expand if needed
c_value.resize(INITIAL_SIZE, 0u8);
unsafe {
let res = ffi::cmap_get(
handle.cmap_handle,
csname.as_ptr(),
c_value.as_mut_ptr() as *mut c_void,
&mut value_size,
&mut c_key_type,
);
if res == ffi::CS_OK {
if value_size > INITIAL_SIZE {
// Need to try again with a bigger buffer
c_value.resize(value_size, 0u8);
let res2 = ffi::cmap_get(
handle.cmap_handle,
csname.as_ptr(),
c_value.as_mut_ptr() as *mut c_void,
&mut value_size,
&mut c_key_type,
);
if res2 != ffi::CS_OK {
return Err(CsError::from_c(res2));
}
}
// Convert to Rust type and return as a Data enum
c_to_data(value_size, c_key_type, c_value.as_ptr())
} else {
Err(CsError::from_c(res))
}
}
}
/// increment the value in a cmap key (must be a numeric type)
pub fn inc(handle: Handle, key_name: &str) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe { ffi::cmap_inc(handle.cmap_handle, csname.as_ptr()) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// decrement the value in a cmap key (must be a numeric type)
pub fn dec(handle: Handle, key_name: &str) -> Result<()> {
let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let res = unsafe { ffi::cmap_dec(handle.cmap_handle, csname.as_ptr()) };
if res == ffi::CS_OK {
Ok(())
} else {
Err(CsError::from_c(res))
}
}
// Callback for CMAP notify events from corosync, convert params to Rust and pass on.
extern "C" fn rust_notify_fn(
cmap_handle: ffi::cmap_handle_t,
cmap_track_handle: ffi::cmap_track_handle_t,
event: i32,
key_name: *const ::std::os::raw::c_char,
new_value: ffi::cmap_notify_value,
old_value: ffi::cmap_notify_value,
user_data: *mut ::std::os::raw::c_void,
) {
// If cmap_handle doesn't match then throw away the callback.
if let Some(r_cmap_handle) = HANDLE_HASH.lock().unwrap().get(&cmap_handle) {
if let Some(h) = TRACKHANDLE_HASH.lock().unwrap().get(&cmap_track_handle) {
let r_keyname = match string_from_bytes(key_name, CMAP_KEYNAME_MAXLENGTH) {
Ok(s) => s,
Err(_) => return,
};
let r_old = match c_to_data(old_value.len, old_value.type_, old_value.data as *const u8)
{
Ok(v) => v,
Err(_) => return,
};
let r_new = match c_to_data(new_value.len, new_value.type_, new_value.data as *const u8)
{
Ok(v) => v,
Err(_) => return,
};
if let Some(cb) = h.notify_callback.notify_fn {
(cb)(
r_cmap_handle,
h,
TrackType { bits: event },
&r_keyname,
&r_old,
&r_new,
user_data as u64,
);
}
}
}
}
/// Callback function called every time a tracker reports a change in a tracked value
#[derive(Copy, Clone)]
pub struct NotifyCallback {
pub notify_fn: Option<
fn(
handle: &Handle,
track_handle: &TrackHandle,
event: TrackType,
key_name: &str,
new_value: &Data,
old_value: &Data,
user_data: u64,
),
>,
}
/// Track changes in cmap values, multiple [TrackHandle]s per [Handle] are allowed
pub fn track_add(
handle: Handle,
key_name: &str,
track_type: TrackType,
notify_callback: &NotifyCallback,
user_data: u64,
) -> Result<TrackHandle> {
let c_name = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
let mut c_trackhandle = 0u64;
let res = unsafe {
ffi::cmap_track_add(
handle.cmap_handle,
c_name.as_ptr(),
track_type.bits,
Some(rust_notify_fn),
user_data as *mut c_void,
&mut c_trackhandle,
)
};
if res == ffi::CS_OK {
let rhandle = TrackHandle {
track_handle: c_trackhandle,
notify_callback: *notify_callback,
};
TRACKHANDLE_HASH
.lock()
.unwrap()
.insert(c_trackhandle, rhandle);
Ok(rhandle)
} else {
Err(CsError::from_c(res))
}
}
/// Remove a tracker frm this [Handle]
pub fn track_delete(handle: Handle, track_handle: TrackHandle) -> Result<()> {
let res = unsafe { ffi::cmap_track_delete(handle.cmap_handle, track_handle.track_handle) };
if res == ffi::CS_OK {
TRACKHANDLE_HASH
.lock()
.unwrap()
.remove(&track_handle.track_handle);
Ok(())
} else {
Err(CsError::from_c(res))
}
}
/// Create one of these to start iterating over cmap values.
pub struct CmapIterStart {
iter_handle: u64,
cmap_handle: u64,
}
pub struct CmapIntoIter {
cmap_handle: u64,
iter_handle: u64,
}
/// Value returned from the iterator. contains the key name and the [Data]
pub struct CmapIter {
key_name: String,
data: Data,
}
impl CmapIter {
pub fn key_name(&self) -> &str {
&self.key_name
}
pub fn data(&self) -> &Data {
&self.data
}
}
impl fmt::Debug for CmapIter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.key_name, self.data)
}
}
impl Iterator for CmapIntoIter {
type Item = CmapIter;
fn next(&mut self) -> Option<CmapIter> {
let mut c_key_name = [0u8; CMAP_KEYNAME_MAXLENGTH + 1];
let mut c_value_len = 0usize;
let mut c_value_type = 0u32;
let res = unsafe {
ffi::cmap_iter_next(
self.cmap_handle,
self.iter_handle,
c_key_name.as_mut_ptr() as *mut c_char,
&mut c_value_len,
&mut c_value_type,
)
};
if res == ffi::CS_OK {
// Return the Data for this iteration
let mut c_value = Vec::<u8>::new();
c_value.resize(c_value_len, 0u8);
let res = unsafe {
ffi::cmap_get(
self.cmap_handle,
c_key_name.as_ptr() as *mut c_char,
c_value.as_mut_ptr() as *mut c_void,
&mut c_value_len,
&mut c_value_type,
)
};
if res == ffi::CS_OK {
match c_to_data(c_value_len, c_value_type, c_value.as_ptr()) {
Ok(d) => {
let r_keyname = match string_from_bytes(
c_key_name.as_ptr() as *mut c_char,
CMAP_KEYNAME_MAXLENGTH,
) {
Ok(s) => s,
Err(_) => return None,
};
Some(CmapIter {
key_name: r_keyname,
data: d,
})
}
Err(_) => None,
}
} else {
// cmap_get returned error
None
}
} else if res == ffi::CS_ERR_NO_SECTIONS {
// End of list
unsafe {
// Yeah, we don't check this return code. There's nowhere to report it.
ffi::cmap_iter_finalize(self.cmap_handle, self.iter_handle)
};
None
} else {
None
}
}
}
impl CmapIterStart {
/// Create a new [CmapIterStart] object for iterating over a list of cmap keys
pub fn new(cmap_handle: Handle, prefix: &str) -> Result<CmapIterStart> {
let mut iter_handle: u64 = 0;
let res = unsafe {
let c_prefix = string_to_cstring_validated(prefix, CMAP_KEYNAME_MAXLENGTH)?;
ffi::cmap_iter_init(cmap_handle.cmap_handle, c_prefix.as_ptr(), &mut iter_handle)
};
if res == ffi::CS_OK {
Ok(CmapIterStart {
cmap_handle: cmap_handle.cmap_handle,
iter_handle,
})
} else {
Err(CsError::from_c(res))
}
}
}
impl IntoIterator for CmapIterStart {
type Item = CmapIter;
type IntoIter = CmapIntoIter;
fn into_iter(self) -> Self::IntoIter {
CmapIntoIter {
iter_handle: self.iter_handle,
cmap_handle: self.cmap_handle,
}
}
}
diff --git a/bindings/rust/tests/src/bin/cfg-test.rs b/bindings/rust/tests/src/bin/cfg-test.rs
index 02eda099..cd70d388 100644
--- a/bindings/rust/tests/src/bin/cfg-test.rs
+++ b/bindings/rust/tests/src/bin/cfg-test.rs
@@ -1,136 +1,135 @@
// Test the CFG library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{cfg, NodeId};
use std::thread::spawn;
fn dispatch_thread(handle: cfg::Handle) {
loop {
if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
return;
}
}
}
// Test the shutdown callback
fn shutdown_check_fn(handle: &cfg::Handle, _flags: u32) {
println!("in shutdown callback");
// DON'T shutdown corosync - we're just testing
if let Err(e) = cfg::reply_to_shutdown(*handle, cfg::ShutdownReply::No) {
- println!("Error in CFG replyto_shutdown: {}", e);
+ println!("Error in CFG replyto_shutdown: {e}");
}
}
fn main() {
// Initialise the callbacks data
let cb = cfg::Callbacks {
corosync_cfg_shutdown_callback_fn: Some(shutdown_check_fn),
};
let handle = match cfg::initialize(&cb) {
Ok(h) => {
println!("cfg initialized.");
h
}
Err(e) => {
- println!("Error in CFG init: {}", e);
+ println!("Error in CFG init: {e}");
return;
}
};
// Open two handles to CFG so that the second one can refuse shutdown
let handle2 = match cfg::initialize(&cb) {
Ok(h) => {
println!("cfg2 initialized.");
h
}
Err(e) => {
- println!("Error in CFG init: {}", e);
+ println!("Error in CFG init: {e}");
return;
}
};
match cfg::track_start(handle2, cfg::TrackFlags::None) {
Ok(_) => {
// Run handle2 dispatch in its own thread
spawn(move || dispatch_thread(handle2));
}
Err(e) => {
- println!("Error in CFG track_start: {}", e);
+ println!("Error in CFG track_start: {e}");
}
};
let local_nodeid = {
match cfg::local_get(handle) {
Ok(n) => {
- println!("Local nodeid is {}", n);
+ println!("Local nodeid is {n}");
Some(n)
}
Err(e) => {
- println!("Error in CFG local_get: {}", e);
+ println!("Error in CFG local_get: {e}");
None
}
}
};
// Test node_status_get.
// node status for the local node looks odd (cos it's the loopback connection), so
// we try for a node ID one less or more than us just to get output that looks
// sensible to the user.
if let Some(our_nodeid) = local_nodeid {
let us_plus1 = NodeId::from(u32::from(our_nodeid) + 1);
let us_less1 = NodeId::from(u32::from(our_nodeid) - 1);
let mut res = cfg::node_status_get(handle, us_plus1, cfg::NodeStatusVersion::V1);
if let Err(e) = res {
- println!("Error from node_status_get on nodeid {}: {}", us_plus1, e);
+ println!("Error from node_status_get on nodeid {us_plus1}: {e}");
res = cfg::node_status_get(handle, us_less1, cfg::NodeStatusVersion::V1);
};
match res {
Ok(ns) => {
println!("Node Status for nodeid {}", ns.nodeid);
println!(" reachable: {}", ns.reachable);
println!(" remote: {}", ns.remote);
println!(" onwire_min: {}", ns.onwire_min);
println!(" onwire_max: {}", ns.onwire_max);
println!(" onwire_ver: {}", ns.onwire_ver);
for (ls_num, ls) in ns.link_status.iter().enumerate() {
if ls.enabled {
- println!(" Link {}", ls_num);
+ println!(" Link {ls_num}");
println!(" connected: {}", ls.connected);
println!(" mtu: {}", ls.mtu);
println!(" src: {}", ls.src_ipaddr);
println!(" dst: {}", ls.dst_ipaddr);
}
}
}
Err(e) => {
println!(
- "Error in CFG node_status get: {} (tried nodeids {} & {})",
- e, us_plus1, us_less1
+ "Error in CFG node_status get: {e} (tried nodeids {us_plus1} & {us_less1})"
);
}
}
}
// This should not shutdown corosync because the callback on handle2 will refuse it.
match cfg::try_shutdown(handle, cfg::ShutdownFlags::Request) {
Ok(_) => {
println!("CFG try_shutdown suceeded, should return busy");
}
Err(e) => {
if e != corosync::CsError::CsErrBusy {
- println!("Error in CFG try_shutdown: {}", e);
+ println!("Error in CFG try_shutdown: {e}");
}
}
}
// Wait for events
loop {
if cfg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/cmap-test.rs b/bindings/rust/tests/src/bin/cmap-test.rs
index 5747ba35..f4356536 100644
--- a/bindings/rust/tests/src/bin/cmap-test.rs
+++ b/bindings/rust/tests/src/bin/cmap-test.rs
@@ -1,198 +1,195 @@
// Test the CMAP library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::cmap;
fn track_notify_fn(
_handle: &cmap::Handle,
_track_handle: &cmap::TrackHandle,
event: cmap::TrackType,
key_name: &str,
old_value: &cmap::Data,
new_value: &cmap::Data,
user_data: u64,
) {
println!("Track notify callback");
- println!(
- "Key: {}, event: {}, user_data: {}",
- key_name, event, user_data
- );
- println!(" Old value: {}", old_value);
- println!(" New value: {}", new_value);
+ println!("Key: {key_name}, event: {event}, user_data: {user_data}");
+ println!(" Old value: {old_value}");
+ println!(" New value: {new_value}");
}
fn main() {
let handle = match cmap::initialize(cmap::Map::Icmap) {
Ok(h) => {
println!("cmap initialized.");
h
}
Err(e) => {
- println!("Error in CMAP (Icmap) init: {}", e);
+ println!("Error in CMAP (Icmap) init: {e}");
return;
}
};
// Test some SETs
if let Err(e) = cmap::set_u32(handle, "test.test_uint32", 456) {
- println!("Error in CMAP set_u32: {}", e);
+ println!("Error in CMAP set_u32: {e}");
return;
};
if let Err(e) = cmap::set_i16(handle, "test.test_int16", -789) {
- println!("Error in CMAP set_i16: {}", e);
+ println!("Error in CMAP set_i16: {e}");
return;
};
if let Err(e) = cmap::set_number(handle, "test.test_num_1", 6809u32) {
- println!("Error in CMAP set_number(u32): {}", e);
+ println!("Error in CMAP set_number(u32): {e}");
return;
};
// NOT PI (just to avoid clippy whingeing)
if let Err(e) = cmap::set_number(handle, "test.test_num_2", 3.24159265) {
- println!("Error in CMAP set_number(f32): {}", e);
+ println!("Error in CMAP set_number(f32): {e}");
return;
};
if let Err(e) = cmap::set_string(handle, "test.test_string", "Hello from Rust") {
- println!("Error in CMAP set_string: {}", e);
+ println!("Error in CMAP set_string: {e}");
return;
};
let test_d = cmap::Data::UInt64(0xdeadbeefbacecafe);
if let Err(e) = cmap::set(handle, "test.test_data", &test_d) {
- println!("Error in CMAP set_data: {}", e);
+ println!("Error in CMAP set_data: {e}");
return;
};
// let test_d2 = cmap::Data::UInt32(6809);
let test_d2 = cmap::Data::String("Test string in data 12345".to_string());
if let Err(e) = cmap::set(handle, "test.test_again", &test_d2) {
- println!("Error in CMAP set_data2: {}", e);
+ println!("Error in CMAP set_data2: {e}");
return;
};
// get them back again
match cmap::get(handle, "test.test_uint32") {
Ok(v) => {
- println!("GOT uint32 {}", v);
+ println!("GOT uint32 {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_int16") {
Ok(v) => {
- println!("GOT uint16 {}", v);
+ println!("GOT uint16 {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_num_1") {
Ok(v) => {
- println!("GOT num {}", v);
+ println!("GOT num {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_num_2") {
Ok(v) => {
- println!("GOT num {}", v);
+ println!("GOT num {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_string") {
Ok(v) => {
- println!("GOT string {}", v);
+ println!("GOT string {v}");
}
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
match cmap::get(handle, "test.test_data") {
Ok(v) => match v {
- cmap::Data::UInt64(u) => println!("GOT data value {:x}", u),
- _ => println!("ERROR type was not UInt64, got {}", v),
+ cmap::Data::UInt64(u) => println!("GOT data value {u:x}"),
+ _ => println!("ERROR type was not UInt64, got {v}"),
},
Err(e) => {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
}
};
// Test an iterator
match cmap::CmapIterStart::new(handle, "totem.") {
Ok(cmap_iter) => {
for i in cmap_iter {
- println!("ITER: {:?}", i);
+ println!("ITER: {i:?}");
}
println!();
}
Err(e) => {
- println!("Error in CMAP iter start: {}", e);
+ println!("Error in CMAP iter start: {e}");
}
}
// Close this handle
if let Err(e) = cmap::finalize(handle) {
- println!("Error in CMAP get: {}", e);
+ println!("Error in CMAP get: {e}");
return;
};
// Test notifications on the stats map
let handle = match cmap::initialize(cmap::Map::Stats) {
Ok(h) => h,
Err(e) => {
- println!("Error in CMAP (Stats) init: {}", e);
+ println!("Error in CMAP (Stats) init: {e}");
return;
}
};
let cb = cmap::NotifyCallback {
notify_fn: Some(track_notify_fn),
};
let _track_handle = match cmap::track_add(
handle,
"stats.srp.memb_merge_detect_tx",
cmap::TrackType::MODIFY | cmap::TrackType::ADD | cmap::TrackType::DELETE,
&cb,
997u64,
) {
Ok(th) => th,
Err(e) => {
- println!("Error in CMAP track_add {}", e);
+ println!("Error in CMAP track_add {e}");
return;
}
};
// Wait for events
let mut event_num = 0;
loop {
if let Err(e) = cmap::dispatch(handle, corosync::DispatchFlags::One) {
- println!("Error from CMAP dispatch: {}", e);
+ println!("Error from CMAP dispatch: {e}");
}
// Just do 5
event_num += 1;
if event_num > 5 {
break;
}
}
}
diff --git a/bindings/rust/tests/src/bin/cpg-test.rs b/bindings/rust/tests/src/bin/cpg-test.rs
index f5f336c4..df83c2d5 100644
--- a/bindings/rust/tests/src/bin/cpg-test.rs
+++ b/bindings/rust/tests/src/bin/cpg-test.rs
@@ -1,146 +1,142 @@
// Test the CPG library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{cpg, NodeId};
use std::str;
fn deliver_fn(
_handle: &cpg::Handle,
group_name: String,
nodeid: NodeId,
pid: u32,
msg: &[u8],
msg_len: usize,
) {
println!(
- "TEST deliver_fn called for {}, from nodeid/pid {}/{}. len={}",
- group_name, nodeid, pid, msg_len
+ "TEST deliver_fn called for {group_name}, from nodeid/pid {nodeid}/{pid}. len={msg_len}"
);
// Print as text if it's valid UTF8
match str::from_utf8(msg) {
- Ok(s) => println!(" {}", s),
+ Ok(s) => println!(" {s}"),
Err(_) => {
for i in msg {
- print!("{:02x} ", i);
+ print!("{i:02x} ");
}
println!();
}
}
}
fn confchg_fn(
_handle: &cpg::Handle,
group_name: &str,
member_list: Vec<cpg::Address>,
left_list: Vec<cpg::Address>,
joined_list: Vec<cpg::Address>,
) {
- println!("TEST confchg_fn called for {}", group_name);
- println!(" members: {:?}", member_list);
- println!(" left: {:?}", left_list);
- println!(" joined: {:?}", joined_list);
+ println!("TEST confchg_fn called for {group_name}");
+ println!(" members: {member_list:?}");
+ println!(" left: {left_list:?}");
+ println!(" joined: {joined_list:?}");
}
fn totem_confchg_fn(_handle: &cpg::Handle, ring_id: cpg::RingId, member_list: Vec<NodeId>) {
println!(
"TEST totem_confchg_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn main() {
// Initialise the model data
let md = cpg::ModelData::ModelV1(cpg::Model1Data {
flags: cpg::Model1Flags::None,
deliver_fn: Some(deliver_fn),
confchg_fn: Some(confchg_fn),
totem_confchg_fn: Some(totem_confchg_fn),
});
let handle = match cpg::initialize(&md, 99_u64) {
Ok(h) => h,
Err(e) => {
- println!("Error in CPG init: {}", e);
+ println!("Error in CPG init: {e}");
return;
}
};
if let Err(e) = cpg::join(handle, "TEST") {
- println!("Error in CPG join: {}", e);
+ println!("Error in CPG join: {e}");
return;
}
match cpg::local_get(handle) {
Ok(n) => {
- println!("Local nodeid is {}", n);
+ println!("Local nodeid is {n}");
}
Err(e) => {
- println!("Error in CPG local_get: {}", e);
+ println!("Error in CPG local_get: {e}");
}
}
// Test membership_get()
match cpg::membership_get(handle, "TEST") {
Ok(m) => {
- println!(" members: {:?}", m);
+ println!(" members: {m:?}");
println!();
}
Err(e) => {
- println!("Error in CPG membership_get: {}", e);
+ println!("Error in CPG membership_get: {e}");
}
}
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = cpg::context_set(handle, set_context) {
- println!("Error in CPG context_set: {}", e);
+ println!("Error in CPG context_set: {e}");
return;
}
// NOTE This will fail on 32 bit systems because void* is not u64
match cpg::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in CPG context_get: {}", e);
+ println!("Error in CPG context_get: {e}");
}
}
// Test iterator
match cpg::CpgIterStart::new(handle, "", cpg::CpgIterType::All) {
Ok(cpg_iter) => {
for i in cpg_iter {
- println!("ITER: {:?}", i);
+ println!("ITER: {i:?}");
}
println!();
}
Err(e) => {
- println!("Error in CPG iter start: {}", e);
+ println!("Error in CPG iter start: {e}");
}
}
// We should receive our own message (at least) in the event loop
if let Err(e) = cpg::mcast_joined(
handle,
cpg::Guarantee::TypeAgreed,
&"This is a test".to_string().into_bytes(),
) {
- println!("Error in CPG mcast_joined: {}", e);
+ println!("Error in CPG mcast_joined: {e}");
}
// Wait for events
loop {
if cpg::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/quorum-test.rs b/bindings/rust/tests/src/bin/quorum-test.rs
index c65bfba8..5797b7d0 100644
--- a/bindings/rust/tests/src/bin/quorum-test.rs
+++ b/bindings/rust/tests/src/bin/quorum-test.rs
@@ -1,86 +1,83 @@
// Test the QUORUM library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::{quorum, NodeId};
fn quorum_fn(
_handle: &quorum::Handle,
quorate: bool,
ring_id: quorum::RingId,
member_list: Vec<NodeId>,
) {
- println!("TEST quorum_fn called. quorate = {}", quorate);
+ println!("TEST quorum_fn called. quorate = {quorate}");
println!(" ring_id: {}/{}", ring_id.nodeid, ring_id.seq);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn nodelist_fn(
_handle: &quorum::Handle,
ring_id: quorum::RingId,
member_list: Vec<NodeId>,
joined_list: Vec<NodeId>,
left_list: Vec<NodeId>,
) {
println!(
"TEST nodelist_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
- println!(" joined: {:?}", joined_list);
- println!(" left: {:?}", left_list);
+ println!(" members: {member_list:?}");
+ println!(" joined: {joined_list:?}");
+ println!(" left: {left_list:?}");
}
fn main() {
// Initialise the model data
let md = quorum::ModelData::ModelV1(quorum::Model1Data {
flags: quorum::Model1Flags::None,
quorum_notification_fn: Some(quorum_fn),
nodelist_notification_fn: Some(nodelist_fn),
});
let handle = match quorum::initialize(&md, 99_u64) {
Ok((h, t)) => {
println!("Quorum initialized; type = {}", t as u32);
h
}
Err(e) => {
- println!("Error in QUORUM init: {}", e);
+ println!("Error in QUORUM init: {e}");
return;
}
};
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = quorum::context_set(handle, set_context) {
- println!("Error in QUORUM context_set: {}", e);
+ println!("Error in QUORUM context_set: {e}");
return;
}
// NOTE This will fail on 32 bit systems because void* is not u64
match quorum::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in QUORUM context_get: {}", e);
+ println!("Error in QUORUM context_get: {e}");
}
}
if let Err(e) = quorum::trackstart(handle, corosync::TrackFlags::Changes) {
- println!("Error in QUORUM trackstart: {}", e);
+ println!("Error in QUORUM trackstart: {e}");
return;
}
// Wait for events
loop {
if quorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
diff --git a/bindings/rust/tests/src/bin/votequorum-test.rs b/bindings/rust/tests/src/bin/votequorum-test.rs
index 59c50b2e..cf9746b6 100644
--- a/bindings/rust/tests/src/bin/votequorum-test.rs
+++ b/bindings/rust/tests/src/bin/votequorum-test.rs
@@ -1,123 +1,117 @@
// Test the VOTEQUORUM library. Requires that corosync is running and that we are root.
extern crate rust_corosync as corosync;
use corosync::votequorum;
fn quorum_fn(
_handle: &votequorum::Handle,
_context: u64,
quorate: bool,
member_list: Vec<votequorum::Node>,
) {
- println!("TEST votequorum_quorum_fn called. quorate = {}", quorate);
- println!(" members: {:?}", member_list);
+ println!("TEST votequorum_quorum_fn called. quorate = {quorate}");
+ println!(" members: {member_list:?}");
}
fn nodelist_fn(
_handle: &votequorum::Handle,
_context: u64,
ring_id: votequorum::RingId,
member_list: Vec<corosync::NodeId>,
) {
println!(
"TEST nodelist_fn called for {}/{}",
ring_id.nodeid, ring_id.seq
);
- println!(" members: {:?}", member_list);
+ println!(" members: {member_list:?}");
}
fn expectedvotes_fn(_handle: &votequorum::Handle, _context: u64, expected_votes: u32) {
- println!("TEST expected_votes_fn called: value is {}", expected_votes);
+ println!("TEST expected_votes_fn called: value is {expected_votes}");
}
fn main() {
// Initialise the model data
let cb = votequorum::Callbacks {
quorum_notification_fn: Some(quorum_fn),
nodelist_notification_fn: Some(nodelist_fn),
expectedvotes_notification_fn: Some(expectedvotes_fn),
};
let handle = match votequorum::initialize(&cb) {
Ok(h) => {
println!("Votequorum initialized.");
h
}
Err(e) => {
- println!("Error in VOTEQUORUM init: {}", e);
+ println!("Error in VOTEQUORUM init: {e}");
return;
}
};
// Test context APIs
let set_context: u64 = 0xabcdbeefcafe;
if let Err(e) = votequorum::context_set(handle, set_context) {
- println!("Error in VOTEQUORUM context_set: {}", e);
+ println!("Error in VOTEQUORUM context_set: {e}");
}
// NOTE This will fail on 32 bit systems because void* is not u64
match votequorum::context_get(handle) {
Ok(c) => {
if c != set_context {
- println!(
- "Error: context_get() returned {:x}, context should be {:x}",
- c, set_context
- );
+ println!("Error: context_get() returned {c:x}, context should be {set_context:x}");
}
}
Err(e) => {
- println!("Error in VOTEQUORUM context_get: {}", e);
+ println!("Error in VOTEQUORUM context_get: {e}");
}
}
const QDEVICE_NAME: &str = "RustQdevice";
if let Err(e) = votequorum::qdevice_register(handle, QDEVICE_NAME) {
- println!("Error in VOTEQUORUM qdevice_register: {}", e);
+ println!("Error in VOTEQUORUM qdevice_register: {e}");
}
match votequorum::get_info(handle, corosync::NodeId::from(1u32)) {
Ok(i) => {
println!("Node info for nodeid 1");
println!(" nodeid: {}", i.node_id);
println!(" node_state: {:?}", i.node_state);
println!(" node_votes: {}", i.node_votes);
println!(" node_expected: {}", i.node_expected_votes);
println!(" highest_expected: {}", i.highest_expected);
println!(" quorum: {}", i.quorum);
println!(" flags: {:x}", i.flags);
println!(" qdevice_votes: {}", i.qdevice_votes);
println!(" qdevice_name: {}", i.qdevice_name);
if i.qdevice_name != QDEVICE_NAME {
println!(
"qdevice names do not match: s/b: \"{}\" is: \"{}\"",
QDEVICE_NAME, i.qdevice_name
);
}
}
Err(e) => {
- println!(
- "Error in VOTEQUORUM get_info: {} (check nodeid 1 has been online)",
- e
- );
+ println!("Error in VOTEQUORUM get_info: {e} (check nodeid 1 has been online)");
}
}
if let Err(e) = votequorum::qdevice_unregister(handle, QDEVICE_NAME) {
- println!("Error in VOTEQUORUM qdevice_unregister: {}", e);
+ println!("Error in VOTEQUORUM qdevice_unregister: {e}");
}
if let Err(e) = votequorum::trackstart(handle, 99_u64, corosync::TrackFlags::Changes) {
- println!("Error in VOTEQUORUM trackstart: {}", e);
+ println!("Error in VOTEQUORUM trackstart: {e}");
return;
}
// Wait for events
loop {
if votequorum::dispatch(handle, corosync::DispatchFlags::One).is_err() {
break;
}
}
println!("ERROR: Corosync quit");
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Feb 25, 4:57 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464681
Default Alt Text
(55 KB)
Attached To
Mode
rC Corosync
Attached
Detach File
Event Timeline
Log In to Comment