summaryrefslogtreecommitdiff
path: root/src/c_lang/fs4.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/c_lang/fs4.rs')
-rw-r--r--src/c_lang/fs4.rs599
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