use crate::storage::lsm::columnar::{ColumnTypeTag, ColumnarSSTable, FixedSegment, TextSegment};
use parking_lot::RwLock;
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Instant;
enum CachedCol {
Fixed(FixedSegment),
Text(TextSegment),
}
pub struct Segment {
pub sst: Arc<ColumnarSSTable>,
pub id: u64,
pub row_count: usize,
pub created_at: Instant,
col_cache: RwLock<HashMap<usize, CachedCol>>,
}
impl Segment {
pub fn clear_cache(&self) {
self.col_cache.write().clear();
}
pub fn release_pages(&self) {
self.sst.release_pages();
}
pub fn open(path: &std::path::Path, id: u64) -> crate::Result<Self> {
let sst = ColumnarSSTable::open(path)?;
let row_count = sst.num_rows;
Ok(Self {
sst: Arc::new(sst),
id,
row_count,
created_at: Instant::now(),
col_cache: RwLock::new(HashMap::new()),
})
}
pub fn get_row_cached(
&self,
key: u64,
col_types: &[crate::types::ColumnType],
) -> Option<Vec<crate::types::Value>> {
use crate::types::Value;
let idx = self.sst.row_map.find_key(key)?;
if self.sst.row_map.is_deleted(idx) {
return None;
}
let mut row = Vec::with_capacity(col_types.len());
for (ci, ct) in col_types.iter().enumerate() {
{
let cache = self.col_cache.read();
if let Some(cached) = cache.get(&ci) {
row.push(decode_cached_value(cached, idx, ct));
continue;
}
}
let tag = self.sst.column_tags.get(ci).copied();
let decoded = if matches!(tag, Some(t) if t.is_fixed()) {
self.sst.read_fixed_i64(ci).ok().map(CachedCol::Fixed)
} else if matches!(tag, Some(ColumnTypeTag::Text)) {
self.sst.read_text(ci).ok().map(CachedCol::Text)
} else {
None
};
if let Some(d) = decoded {
row.push(decode_cached_value(&d, idx, ct));
self.col_cache.write().insert(ci, d);
} else {
row.push(Value::Null);
}
}
Some(row)
}
}
fn decode_cached_value(
cached: &CachedCol,
idx: usize,
ct: &crate::types::ColumnType,
) -> crate::types::Value {
use crate::types::{ColumnType, Value};
match (cached, ct) {
(CachedCol::Fixed(f), ColumnType::Integer) => {
f.get_i64(idx).map(Value::Integer).unwrap_or(Value::Null)
}
(CachedCol::Fixed(f), ColumnType::Float) => {
f.get_f64(idx).map(Value::Float).unwrap_or(Value::Null)
}
(CachedCol::Fixed(f), ColumnType::Boolean) => {
f.get_bool(idx).map(Value::Bool).unwrap_or(Value::Null)
}
(CachedCol::Fixed(f), ColumnType::Timestamp) => f
.get_i64(idx)
.map(|v| Value::Timestamp(crate::types::Timestamp::from_micros(v)))
.unwrap_or(Value::Null),
(CachedCol::Text(t), ColumnType::Text) => t
.get_str(idx)
.map(|s| Value::Text(s.into()))
.unwrap_or(Value::Null),
_ => Value::Null,
}
}