diff options
Diffstat (limited to 'src/c_lang/fs4.rs')
| -rw-r--r-- | src/c_lang/fs4.rs | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/src/c_lang/fs4.rs b/src/c_lang/fs4.rs new file mode 100644 index 0000000..6668ba7 --- /dev/null +++ b/src/c_lang/fs4.rs @@ -0,0 +1,599 @@ + +use std::ffi::{CString, CStr}; +use std::os::raw::{c_longlong, c_char}; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::mem; +use libc; + +use super::fs4_binding; + + +pub struct Fieldstat { + content: *mut fs4_binding::fieldstat, +} + +#[derive(Clone, Debug)] +pub enum FieldstatTagType { + LongLong, + Double, + String, +} + +pub enum SampleMode { + Comprehensive, + TopK, +} + +pub enum CounterMergeMode { + BySum, + ByMax, + ByMin, +} + +pub enum MetricType { + Counter, + HLL, + Histogram, +} + +#[derive(Debug, Clone)] +pub enum FieldstatErr { + WrongCube, + WrongCell, + WrongMetric, + WrongCubeOrParameter, // todo: 现在C 上不做区别,抽空调一下 + // todo: anyhow 替代result + // todo: 删fs4_binding 里的东西 + // todo: 改名字就叫fieldstat + WrongParameter, + CubeIsFull, + DuplicateKey, +} + +impl FieldstatTagType { + fn as_c_corresponding_type(&self) -> fs4_binding::fs_tag_type { + match self { + FieldstatTagType::LongLong => 0 as fs4_binding::fs_tag_type, + FieldstatTagType::Double => 1 as fs4_binding::fs_tag_type, + FieldstatTagType::String => 2 as fs4_binding::fs_tag_type, + } + } +} + +pub struct FieldstatTag<T: Taggable> { + content: fs4_binding::fieldstat_tag, + value_type: FieldstatTagType, + + phantom: PhantomData<T>, +} + +pub trait Taggable: Clone + Debug{ + type Output; + fn type_id(&self) -> FieldstatTagType; + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1; +} + +impl Taggable for i64 { + type Output = i64; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::LongLong + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_longlong: self as c_longlong, + } + } +} + +impl Taggable for f64 { + type Output = f64; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::Double + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_double: self as f64 + } + } +} + +impl Taggable for String { + type Output = String; + + fn type_id(&self) -> FieldstatTagType { + FieldstatTagType::String + } + fn into_c_corresponding(self) -> fs4_binding::fieldstat_tag__bindgen_ty_1 { + fs4_binding::fieldstat_tag__bindgen_ty_1 { + value_str: CString::new(self).unwrap().into_raw() as *mut c_char, + } + } +} + +impl<T: Taggable> FieldstatTag<T> { + fn new(name: &str, value: T) -> Self { + let c_string = CString::new(name).unwrap(); + let typeid = value.type_id(); + Self { + content: fs4_binding::fieldstat_tag { + key: c_string.into_raw(), + type_: value.type_id().as_c_corresponding_type(), + __bindgen_anon_1: value.into_c_corresponding(), + }, + value_type: typeid, + + phantom: PhantomData, + } + } + + fn value_type(&self) -> FieldstatTagType { + self.value_type.clone() + } + + fn key(&self) -> String { + unsafe { + let rust_str = CStr::from_ptr(self.content.key).to_owned(); + rust_str.to_str().unwrap().to_string() + } + } +} + +impl FieldstatTag<i64> +{ + fn value(&self) -> i64 { + unsafe { + self.content.__bindgen_anon_1.value_longlong + } + } +} + +impl FieldstatTag<f64> +{ + fn value(&self) -> f64 { + unsafe { + self.content.__bindgen_anon_1.value_double + } + } +} + +impl FieldstatTag<String> +{ + fn value(&self) -> String { + unsafe { + let rust_str = CStr::from_ptr(self.content.__bindgen_anon_1.value_str).to_owned(); + rust_str.to_str().unwrap().to_string() + } + } +} + + +pub enum FieldstatTagWrapper { + LongLong(FieldstatTag<i64>), + Double(FieldstatTag<f64>), + String(FieldstatTag<String>), +} + +impl Fieldstat { + pub fn new() -> Self { + Self { + content: unsafe { fs4_binding::fieldstat_new() }, + } + } + pub fn register_counter(&mut self, name: &str, cube_id: i64, mode: CounterMergeMode) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_counter( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + mode as fs4_binding::counter_mode, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn register_hll(&mut self, name: &str, cube_id: i64, precision: u8) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_hll( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + precision as std::os::raw::c_uchar, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCubeOrParameter), + _ => Ok(ret), + } + } + } + pub fn register_histogram(&mut self, name: &str, cube_id: i64, + lowest_trackable_value: i64, highest_trackable_value: i64, significant_figures: i32) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_register_hist( + self.content, + cube_id as std::os::raw::c_int, + CString::new(name).unwrap().into_raw(), + lowest_trackable_value as std::os::raw::c_longlong, + highest_trackable_value as std::os::raw::c_longlong, + significant_figures as std::os::raw::c_int, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCubeOrParameter), + _ => Ok(ret), + } + } + } + pub fn new_with_same_config(&self) -> Self { + Self { + content: unsafe { fs4_binding::fieldstat_dup(self.content) }, + } + } + pub fn register_cube<T: Taggable>(&mut self, shared_tags: &[FieldstatTag<T>], mode: SampleMode, max_n_cell: usize) -> Result<i32, FieldstatErr> { + let c_mode = match mode { + SampleMode::Comprehensive => fs4_binding::sampling_mode_SAMPLING_MODE_COMPREHENSIVE, + SampleMode::TopK => fs4_binding::sampling_mode_SAMPLING_MODE_TOPK, + }; + let mut c_tag_structs = Vec::with_capacity(shared_tags.len()); + for tag in shared_tags { + c_tag_structs.push(tag.content); + } + + unsafe { + let ret = fs4_binding::fieldstat_register_cube( + self.content, + c_tag_structs.as_ptr(), + shared_tags.len(), + c_mode, + max_n_cell); + + match ret { + -1 => Err(FieldstatErr::WrongParameter), + -2 => Err(FieldstatErr::DuplicateKey), + _ => Ok(ret), + } + } + } + pub fn unregister_cube(&mut self, cube_id: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_unregister_cube(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(()), + } + } + } + pub fn get_cube_version(&self, cube_id: i64) -> Result<i64, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_cube_version(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 | -2 | -3 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn cube_add<T: Taggable>(&mut self, cube_id: i64, tags: &[FieldstatTag<T>], value: i64) -> Result<i32, FieldstatErr> { + let mut c_tag_structs = Vec::with_capacity(tags.len()); + for tag in tags { + c_tag_structs.push(tag.content); + } + + unsafe { + let ret = fs4_binding::fieldstat_cube_add( + self.content, + cube_id as std::os::raw::c_int, + c_tag_structs.as_ptr(), + tags.len(), + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::CubeIsFull), + -2 => Err(FieldstatErr::WrongCell), + _ => Ok(ret), + } + } + } + pub fn counter_incrby(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, increment: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_counter_incrby( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + increment as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn counter_set(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, value: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_counter_set( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn hll_add(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, key: &str) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_hll_add( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + CString::new(key).unwrap().into_raw(), + key.len(), + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn histogram_record(&mut self, cube_id: i32, metric_id: i32, cell_id: i32, value: i64) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_hist_record( + self.content, + cube_id as std::os::raw::c_int, + metric_id as std::os::raw::c_int, + cell_id as std::os::raw::c_int, + value as std::os::raw::c_longlong, + ); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + -2 => Err(FieldstatErr::WrongMetric), + -3 => Err(FieldstatErr::WrongCell), + -4 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn reset(&mut self) { + unsafe { + fs4_binding::fieldstat_reset(self.content); + } + } + pub fn get_cell_version(&self) -> u64 { + unsafe { + fs4_binding::fieldstat_get_cell_version(self.content) + } + } + pub fn merge(&mut self, other: &Fieldstat) -> Result<(), FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_merge(self.content, other.content); + + match ret { + -1 => Err(FieldstatErr::WrongParameter), + _ => Ok(()), + } + } + } + pub fn serialize(&self) -> Vec<u8> { + unsafe { + let mut blob_out: *mut ::std::os::raw::c_char = std::ptr::null_mut(); + let mut blob_size_out: usize = 0; + + fs4_binding::fieldstat_serialize(self.content, &mut blob_out, &mut blob_size_out); + let vec = Vec::from_raw_parts(blob_out as *mut u8, blob_size_out, blob_size_out); + + libc::free(blob_out as *mut libc::c_void); + vec + } + } + pub fn deserialize(&mut self, blob: &[u8]) -> Option<Self> { + unsafe { + let ret = fs4_binding::fieldstat_deserialize(blob.as_ptr() as *const ::std::os::raw::c_char, blob.len()); + + if ret == std::ptr::null_mut() { + None + } else { + Some(Self { + content: ret, + }) + } + } + } + + /* ---------------------------------- query --------------------------------- */ + pub fn get_cubes(&self) -> Vec<i32> { + unsafe { + let mut cubes: *mut i32 = std::ptr::null_mut(); + // int *cube = NULL; + let mut n_cubes: i32 = 0; + + fs4_binding::fieldstat_get_cubes(self.content, &mut cubes, &mut n_cubes); + let vec = Vec::from_raw_parts(cubes, n_cubes as usize, n_cubes as usize); + + libc::free(cubes as *mut libc::c_void); + vec + } + } + pub fn get_max_metric_id(&self, cube_id: i32) -> Result<i32, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_max_metric_id(self.content, cube_id as std::os::raw::c_int); + + match ret { + -1 => Err(FieldstatErr::WrongCube), + _ => Ok(ret), + } + } + } + pub fn get_metric_name(&self, cube_id: i32, metric_id: i32) -> Result<String, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_metric_name(self.content, cube_id as std::os::raw::c_int, metric_id as std::os::raw::c_int); + if ret == std::ptr::null_mut() { + Err(FieldstatErr::WrongMetric) + } else { + let rust_str = CStr::from_ptr(ret).to_owned(); + Ok(rust_str.to_str().unwrap().to_string()) + } + } + } + pub fn get_metric_type(&self, cube_id: i32, metric_id: i32) -> Result<MetricType, FieldstatErr> { + unsafe { + let ret = fs4_binding::fieldstat_get_metric_type(self.content, cube_id as std::os::raw::c_int, metric_id as std::os::raw::c_int); + + match ret { + fs4_binding::metric_type_METRIC_TYPE_COUNTER => Ok(MetricType::Counter), + fs4_binding::metric_type_METRIC_TYPE_HLL => Ok(MetricType::HLL), + fs4_binding::metric_type_METRIC_TYPE_HISTOGRAM => Ok(MetricType::Histogram), + _ => Err(FieldstatErr::WrongMetric), + } + } + } + pub fn cube_read_cell(&self, cube_id: i32) -> Option<Vec< (i32, Vec<FieldstatTagWrapper>)>> { + unsafe { + let mut cell_id: *mut std::os::raw::c_int = std::ptr::null_mut(); + let mut tags: *mut fs4_binding::fieldstat_tag_list = std::ptr::null_mut(); + let mut n_cell: usize = 0; + + fs4_binding::fieldstat_cube_read_cell(self.content, + cube_id as std::os::raw::c_int, + &mut cell_id, + &mut tags, + &mut n_cell); + + if n_cell == 0 { + return None; + } + + let mut ret = Vec::with_capacity(n_cell); + let tags_list_vec = Vec::from_raw_parts(tags, n_cell, n_cell); + let cell_id_vec = Vec::from_raw_parts(cell_id, n_cell, n_cell); + + for i in 0..n_cell { + let tag_vec = fieldstat_tag_list_to_vec(tags_list_vec.get_unchecked(i)); + ret.push((cell_id_vec[i], tag_vec)); + } + + libc::free(cell_id as *mut libc::c_void); + fs4_binding::fieldstat_tag_list_arr_free(tags, n_cell); + + Some(ret) + } + } + +} + +impl Drop for Fieldstat { + fn drop(&mut self) { + unsafe { + fs4_binding::fieldstat_free(self.content); + } + } +} + +fn fieldstat_tag_list_to_vec(tag_list_p: *const fs4_binding::fieldstat_tag_list) + -> Vec<FieldstatTagWrapper> { + unsafe { + let tag_p_vec = Vec::from_raw_parts((*tag_list_p).tag, (*tag_list_p).n_tag, (*tag_list_p).n_tag); + let mut ret = Vec::with_capacity(tag_p_vec.len()); + for item in tag_p_vec { + let value_type = match item.type_ { + fs4_binding::fs_tag_type_TAG_INTEGER => { + FieldstatTagType::LongLong + }, + fs4_binding::fs_tag_type_TAG_DOUBLE => { + FieldstatTagType::Double + }, + fs4_binding::fs_tag_type_TAG_CSTRING => { + FieldstatTagType::String + }, + _ => panic!("unknown tag type"), + }; + + ret.push(match value_type { + FieldstatTagType::LongLong => FieldstatTagWrapper::LongLong( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + FieldstatTagType::Double => FieldstatTagWrapper::Double( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + FieldstatTagType::String => FieldstatTagWrapper::String( + FieldstatTag { content: item, value_type: value_type, phantom: PhantomData }), + }); + } + ret + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_tag_int() { + let tag = FieldstatTag::new("test", 1); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), 1); + } + + #[test] + fn new_tag_float() { + let tag = FieldstatTag::new("test", 1.0); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), 1.0); + } + + #[test] + fn new_tag_str() { + let tag = FieldstatTag::new("test", "hello1".to_string()); + assert_eq!(tag.key(), "test"); + assert_eq!(tag.value(), "hello1"); + } + + #[test] + fn query_cell() { + let mut fs = Fieldstat::new(); + let shared_tags = vec![ + FieldstatTag::new("tag1", 1), + ]; + let cell_tag = vec![ + FieldstatTag::new("tag cell", 123), + ]; + + fs.register_cube(shared_tags.as_slice(), SampleMode::Comprehensive, 100).unwrap(); + fs.cube_add(0, cell_tag.as_slice(), 1).unwrap(); + + let cell = fs.cube_read_cell(0).unwrap(); + assert_eq!(cell.len(), 1); + assert_eq!(cell[0].0, 0); // cell id + assert_eq!(cell[0].1.len(), 1); + if let FieldstatTagWrapper::LongLong(tag) = &cell[0].1[0] { + assert_eq!(tag.key(), "tag cell"); + assert_eq!(tag.value(), 123); + } else { + panic!("wrong tag type"); + } + } +}
\ No newline at end of file |
