use std::collections::HashMap;
use nodedb_types::timeseries::{SeriesId, SymbolDictionary};
use serde::{Deserialize, Serialize};
use super::types::{ColumnData, ColumnType};
#[derive(
Debug, PartialEq, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
pub struct MemtableSnapshot {
pub schema_columns: Vec<(String, ColumnType)>,
pub timestamp_idx: usize,
pub columns: Vec<ColumnSnapshot>,
pub symbol_dicts: Vec<(usize, SymbolDictionary)>,
pub series_row_counts: Vec<(SeriesId, u64)>,
pub row_count: u64,
pub min_ts: i64,
pub max_ts: i64,
}
#[derive(
Debug, PartialEq, Serialize, Deserialize, zerompk::ToMessagePack, zerompk::FromMessagePack,
)]
pub enum ColumnSnapshot {
Timestamp(Vec<i64>),
Float64(Vec<f64>),
Int64(Vec<i64>),
Symbol(Vec<u32>),
DictEncoded {
ids: Vec<u32>,
dictionary: Vec<String>,
valid: Vec<bool>,
},
}
pub(super) fn column_to_snapshot(col: &ColumnData) -> ColumnSnapshot {
match col {
ColumnData::Timestamp(v) => ColumnSnapshot::Timestamp(v.clone()),
ColumnData::Float64(v) => ColumnSnapshot::Float64(v.clone()),
ColumnData::Int64(v) => ColumnSnapshot::Int64(v.clone()),
ColumnData::Symbol(v) => ColumnSnapshot::Symbol(v.clone()),
ColumnData::DictEncoded {
ids,
dictionary,
valid,
..
} => ColumnSnapshot::DictEncoded {
ids: ids.clone(),
dictionary: dictionary.clone(),
valid: valid.clone(),
},
}
}
pub(super) fn rebuild_columns(
columns: Vec<ColumnSnapshot>,
schema_columns: &[(String, ColumnType)],
row_count: u64,
) -> crate::Result<Vec<ColumnData>> {
if columns.len() != schema_columns.len() {
return Err(crate::Error::BadRequest {
detail: format!(
"snapshot column count mismatch: schema has {} columns but data has {}",
schema_columns.len(),
columns.len(),
),
});
}
let mut result = Vec::with_capacity(columns.len());
for (i, (snap_col, (col_name, _col_type))) in
columns.into_iter().zip(schema_columns.iter()).enumerate()
{
let col_len = match &snap_col {
ColumnSnapshot::Timestamp(v) => v.len(),
ColumnSnapshot::Float64(v) => v.len(),
ColumnSnapshot::Int64(v) => v.len(),
ColumnSnapshot::Symbol(v) => v.len(),
ColumnSnapshot::DictEncoded { ids, .. } => ids.len(),
};
if col_len as u64 != row_count {
return Err(crate::Error::BadRequest {
detail: format!(
"snapshot column {} ('{}') has {} rows but row_count is {}",
i, col_name, col_len, row_count,
),
});
}
let col_data = match snap_col {
ColumnSnapshot::Timestamp(v) => ColumnData::Timestamp(v),
ColumnSnapshot::Float64(v) => ColumnData::Float64(v),
ColumnSnapshot::Int64(v) => ColumnData::Int64(v),
ColumnSnapshot::Symbol(v) => ColumnData::Symbol(v),
ColumnSnapshot::DictEncoded {
ids,
dictionary,
valid,
} => {
let reverse: HashMap<String, u32> = dictionary
.iter()
.enumerate()
.map(|(idx, s)| (s.clone(), idx as u32))
.collect();
ColumnData::DictEncoded {
ids,
dictionary,
reverse,
valid,
}
}
};
result.push(col_data);
}
Ok(result)
}