use crate::error::{Error, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyMetadata {
pub num_shards: usize,
pub shard_sizes: Vec<usize>,
pub shard_names: Vec<String>,
pub version: u32,
}
impl KeyMetadata {
pub const VERSION: u32 = 1;
pub const SHARD_NAMES: [&'static str; 8] = [
".key_data_00",
".key_data_01",
".key_data_02",
".key_data_03",
".key_data_04",
".key_data_05",
".key_data_06",
".key_data_07",
];
pub const SHARD_SIZE: usize = 1024;
pub fn generate() -> Self {
use rand::Rng;
let mut rng = rand::thread_rng();
let num_shards = rng.gen_range(4..=8);
use rand::seq::SliceRandom;
let mut available_indices: Vec<usize> = (0..8).collect();
available_indices.shuffle(&mut rng);
let shard_names: Vec<String> = available_indices
.iter()
.take(num_shards)
.map(|&i| Self::SHARD_NAMES[i].to_string())
.collect();
let shard_sizes = vec![Self::SHARD_SIZE; num_shards];
Self {
num_shards,
shard_sizes,
shard_names,
version: Self::VERSION,
}
}
pub fn from_bytes(data: &[u8]) -> Result<Self> {
let json_start = data
.iter()
.position(|&b| b == b'{')
.ok_or_else(|| Error::Parse("未找到元数据JSON开始标记".to_string()))?;
let json_end = data
.iter()
.rposition(|&b| b == b'}')
.ok_or_else(|| Error::Parse("未找到元数据JSON结束标记".to_string()))?;
if json_start > json_end {
return Err(Error::Parse("无效的JSON范围".to_string()));
}
let json_bytes = &data[json_start..=json_end];
serde_json::from_slice(json_bytes).map_err(Error::from)
}
pub fn to_bytes(&self) -> Result<Vec<u8>> {
serde_json::to_vec(self).map_err(Error::from)
}
pub fn total_capacity(&self) -> usize {
self.shard_sizes.iter().sum()
}
pub fn validate(&self) -> Result<()> {
if self.num_shards == 0 {
return Err(Error::Config("分片数量不能为0".to_string()));
}
if self.num_shards > 8 {
return Err(Error::Config(format!(
"分片数量不能超过8: {}",
self.num_shards
)));
}
if self.shard_sizes.len() != self.num_shards {
return Err(Error::Config(format!(
"分片大小数量({})与分片数量({})不匹配",
self.shard_sizes.len(),
self.num_shards
)));
}
if self.shard_names.len() != self.num_shards {
return Err(Error::Config(format!(
"分片名称数量({})与分片数量({})不匹配",
self.shard_names.len(),
self.num_shards
)));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_metadata_generation() {
let meta = KeyMetadata::generate();
assert!(meta.num_shards >= 4 && meta.num_shards <= 8);
assert_eq!(meta.shard_sizes.len(), meta.num_shards);
assert_eq!(meta.shard_names.len(), meta.num_shards);
meta.validate().unwrap();
}
#[test]
fn test_metadata_serialization() {
let meta = KeyMetadata::generate();
let bytes = meta.to_bytes().unwrap();
let meta2 = KeyMetadata::from_bytes(&bytes).unwrap();
assert_eq!(meta.num_shards, meta2.num_shards);
assert_eq!(meta.shard_sizes, meta2.shard_sizes);
assert_eq!(meta.shard_names, meta2.shard_names);
}
#[test]
fn test_total_capacity() {
let meta = KeyMetadata::generate();
let expected = meta.shard_sizes.iter().sum::<usize>();
assert_eq!(meta.total_capacity(), expected);
}
}