562 lines
16 KiB
Rust
562 lines
16 KiB
Rust
///! 状态分片优化模块
|
||
///!
|
||
///! 优化分片状态存储和访问性能
|
||
///!
|
||
///! **NAC原生设计原则**:
|
||
///! - 使用Asset(资产),不是Token
|
||
///! - 使用Certificate(证书),不是Contract
|
||
///! - 使用SHA3-384哈希,不是SHA256/Keccak256
|
||
///! - 通过CBPP共识协调
|
||
|
||
use crate::primitives::{Address, Hash};
|
||
use std::collections::HashMap;
|
||
use serde::{Deserialize, Serialize};
|
||
|
||
/// 状态分片优化器
|
||
#[derive(Debug, Clone)]
|
||
/// StateShardOptimizer
|
||
pub struct StateShardOptimizer {
|
||
/// 分片ID
|
||
shard_id: u64,
|
||
/// 状态缓存
|
||
state_cache: HashMap<Hash, StateEntry>,
|
||
/// 热点账户追踪
|
||
hot_accounts: HashMap<Address, HotAccountStats>,
|
||
/// 冷数据归档阈值(秒)
|
||
cold_threshold: u64,
|
||
/// 缓存大小限制(字节)
|
||
max_cache_size: u64,
|
||
/// 当前缓存大小
|
||
current_cache_size: u64,
|
||
/// 优化统计
|
||
stats: OptimizationStats,
|
||
}
|
||
|
||
/// 状态条目
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
/// StateEntry
|
||
pub struct StateEntry {
|
||
/// 状态键
|
||
pub key: Hash,
|
||
/// 状态值
|
||
pub value: Vec<u8>,
|
||
/// 最后访问时间
|
||
pub last_access: u64,
|
||
/// 访问次数
|
||
pub access_count: u64,
|
||
/// 是否为热点数据
|
||
pub is_hot: bool,
|
||
/// 数据大小(字节)
|
||
pub size: u64,
|
||
}
|
||
|
||
impl StateEntry {
|
||
/// 创建新的状态条目
|
||
pub fn new(key: Hash, value: Vec<u8>, timestamp: u64) -> Self {
|
||
let size = value.len() as u64;
|
||
Self {
|
||
key,
|
||
value,
|
||
last_access: timestamp,
|
||
access_count: 1,
|
||
is_hot: false,
|
||
size,
|
||
}
|
||
}
|
||
|
||
/// 更新访问信息
|
||
pub fn update_access(&mut self, timestamp: u64) {
|
||
self.last_access = timestamp;
|
||
self.access_count += 1;
|
||
|
||
// 访问次数超过阈值标记为热点
|
||
if self.access_count > 100 {
|
||
self.is_hot = true;
|
||
}
|
||
}
|
||
|
||
/// 检查是否为冷数据
|
||
pub fn is_cold(&self, current_time: u64, threshold: u64) -> bool {
|
||
current_time - self.last_access > threshold
|
||
}
|
||
}
|
||
|
||
/// 热点账户统计
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
/// HotAccountStats
|
||
pub struct HotAccountStats {
|
||
/// 账户地址
|
||
pub address: Address,
|
||
/// 读取次数
|
||
pub read_count: u64,
|
||
/// 写入次数
|
||
pub write_count: u64,
|
||
/// 最后活动时间
|
||
pub last_activity: u64,
|
||
/// 平均交易大小
|
||
pub avg_tx_size: u64,
|
||
/// 是否为高频账户
|
||
pub is_high_frequency: bool,
|
||
}
|
||
|
||
impl HotAccountStats {
|
||
/// 创建新的热点账户统计
|
||
pub fn new(address: Address, timestamp: u64) -> Self {
|
||
Self {
|
||
address,
|
||
read_count: 0,
|
||
write_count: 0,
|
||
last_activity: timestamp,
|
||
avg_tx_size: 0,
|
||
is_high_frequency: false,
|
||
}
|
||
}
|
||
|
||
/// 记录读取操作
|
||
pub fn record_read(&mut self, timestamp: u64) {
|
||
self.read_count += 1;
|
||
self.last_activity = timestamp;
|
||
self.update_frequency();
|
||
}
|
||
|
||
/// 记录写入操作
|
||
pub fn record_write(&mut self, timestamp: u64, tx_size: u64) {
|
||
self.write_count += 1;
|
||
self.last_activity = timestamp;
|
||
|
||
// 更新平均交易大小
|
||
let total_count = self.read_count + self.write_count;
|
||
self.avg_tx_size = (self.avg_tx_size * (total_count - 1) + tx_size) / total_count;
|
||
|
||
self.update_frequency();
|
||
}
|
||
|
||
/// 更新频率标记
|
||
fn update_frequency(&mut self) {
|
||
// 读写总次数超过1000标记为高频
|
||
if self.read_count + self.write_count > 1000 {
|
||
self.is_high_frequency = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 优化统计
|
||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||
/// OptimizationStats
|
||
pub struct OptimizationStats {
|
||
/// 缓存命中次数
|
||
pub cache_hits: u64,
|
||
/// 缓存未命中次数
|
||
pub cache_misses: u64,
|
||
/// 冷数据归档次数
|
||
pub cold_data_archived: u64,
|
||
/// 热点数据提升次数
|
||
pub hot_data_promoted: u64,
|
||
/// 缓存驱逐次数
|
||
pub cache_evictions: u64,
|
||
/// 总状态访问次数
|
||
pub total_accesses: u64,
|
||
}
|
||
|
||
impl OptimizationStats {
|
||
/// 计算缓存命中率
|
||
pub fn cache_hit_rate(&self) -> f64 {
|
||
if self.total_accesses == 0 {
|
||
return 0.0;
|
||
}
|
||
self.cache_hits as f64 / self.total_accesses as f64
|
||
}
|
||
}
|
||
|
||
impl StateShardOptimizer {
|
||
/// 创建新的状态分片优化器
|
||
pub fn new(shard_id: u64, cold_threshold: u64, max_cache_size: u64) -> Self {
|
||
Self {
|
||
shard_id,
|
||
state_cache: HashMap::new(),
|
||
hot_accounts: HashMap::new(),
|
||
cold_threshold,
|
||
max_cache_size,
|
||
current_cache_size: 0,
|
||
stats: OptimizationStats::default(),
|
||
}
|
||
}
|
||
|
||
/// 读取状态
|
||
pub fn read_state(&mut self, key: &Hash, current_time: u64) -> Option<Vec<u8>> {
|
||
self.stats.total_accesses += 1;
|
||
|
||
if let Some(entry) = self.state_cache.get_mut(key) {
|
||
// 缓存命中
|
||
self.stats.cache_hits += 1;
|
||
entry.update_access(current_time);
|
||
Some(entry.value.clone())
|
||
} else {
|
||
// 缓存未命中
|
||
self.stats.cache_misses += 1;
|
||
None
|
||
}
|
||
}
|
||
|
||
/// 写入状态
|
||
pub fn write_state(&mut self, key: Hash, value: Vec<u8>, current_time: u64) -> Result<(), String> {
|
||
let entry_size = value.len() as u64;
|
||
|
||
// 检查缓存大小限制
|
||
if self.current_cache_size + entry_size > self.max_cache_size {
|
||
// 驱逐冷数据
|
||
self.evict_cold_data(current_time)?;
|
||
}
|
||
|
||
// 创建或更新状态条目
|
||
if let Some(existing) = self.state_cache.get_mut(&key) {
|
||
self.current_cache_size -= existing.size;
|
||
existing.value = value;
|
||
existing.size = entry_size;
|
||
existing.update_access(current_time);
|
||
self.current_cache_size += entry_size;
|
||
} else {
|
||
let entry = StateEntry::new(key.clone(), value, current_time);
|
||
self.state_cache.insert(key, entry);
|
||
self.current_cache_size += entry_size;
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 驱逐冷数据
|
||
pub fn evict_cold_data(&mut self, current_time: u64) -> Result<(), String> {
|
||
let mut cold_keys = Vec::new();
|
||
|
||
// 查找冷数据
|
||
for (key, entry) in &self.state_cache {
|
||
if entry.is_cold(current_time, self.cold_threshold) && !entry.is_hot {
|
||
cold_keys.push(key.clone());
|
||
}
|
||
}
|
||
|
||
if cold_keys.is_empty() {
|
||
return Err("No cold data to evict".to_string());
|
||
}
|
||
|
||
// 驱逐冷数据
|
||
for key in cold_keys {
|
||
if let Some(entry) = self.state_cache.remove(&key) {
|
||
self.current_cache_size -= entry.size;
|
||
self.stats.cache_evictions += 1;
|
||
self.stats.cold_data_archived += 1;
|
||
}
|
||
}
|
||
|
||
Ok(())
|
||
}
|
||
|
||
/// 提升热点数据
|
||
pub fn promote_hot_data(&mut self, key: &Hash) -> Result<(), String> {
|
||
if let Some(entry) = self.state_cache.get_mut(key) {
|
||
if !entry.is_hot {
|
||
entry.is_hot = true;
|
||
self.stats.hot_data_promoted += 1;
|
||
}
|
||
Ok(())
|
||
} else {
|
||
Err("State entry not found".to_string())
|
||
}
|
||
}
|
||
|
||
/// 记录账户活动
|
||
pub fn record_account_activity(
|
||
&mut self,
|
||
address: Address,
|
||
is_write: bool,
|
||
tx_size: u64,
|
||
timestamp: u64,
|
||
) {
|
||
let stats = self.hot_accounts
|
||
.entry(address.clone())
|
||
.or_insert_with(|| HotAccountStats::new(address, timestamp));
|
||
|
||
if is_write {
|
||
stats.record_write(timestamp, tx_size);
|
||
} else {
|
||
stats.record_read(timestamp);
|
||
}
|
||
}
|
||
|
||
/// 获取热点账户列表
|
||
pub fn get_hot_accounts(&self) -> Vec<Address> {
|
||
self.hot_accounts
|
||
.values()
|
||
.filter(|stats| stats.is_high_frequency)
|
||
.map(|stats| stats.address.clone())
|
||
.collect()
|
||
}
|
||
|
||
/// 获取优化统计
|
||
pub fn get_stats(&self) -> OptimizationStats {
|
||
self.stats.clone()
|
||
}
|
||
|
||
/// 获取缓存使用率
|
||
pub fn get_cache_usage(&self) -> f64 {
|
||
if self.max_cache_size == 0 {
|
||
return 0.0;
|
||
}
|
||
self.current_cache_size as f64 / self.max_cache_size as f64
|
||
}
|
||
|
||
/// 清理过期数据
|
||
pub fn cleanup_expired(&mut self, current_time: u64) -> usize {
|
||
let mut expired_keys = Vec::new();
|
||
|
||
// 查找过期数据(超过冷数据阈值的2倍)
|
||
let expiry_threshold = self.cold_threshold * 2;
|
||
for (key, entry) in &self.state_cache {
|
||
if current_time - entry.last_access > expiry_threshold {
|
||
expired_keys.push(key.clone());
|
||
}
|
||
}
|
||
|
||
let count = expired_keys.len();
|
||
|
||
// 删除过期数据
|
||
for key in expired_keys {
|
||
if let Some(entry) = self.state_cache.remove(&key) {
|
||
self.current_cache_size -= entry.size;
|
||
}
|
||
}
|
||
|
||
count
|
||
}
|
||
|
||
/// 优化分片状态
|
||
pub fn optimize(&mut self, current_time: u64) -> Result<OptimizationReport, String> {
|
||
let initial_cache_size = self.current_cache_size;
|
||
let initial_entry_count = self.state_cache.len();
|
||
|
||
// 1. 清理过期数据
|
||
let expired_count = self.cleanup_expired(current_time);
|
||
|
||
// 2. 驱逐冷数据(如果缓存使用率超过80%)
|
||
let evicted_count = if self.get_cache_usage() > 0.8 {
|
||
let before = self.state_cache.len();
|
||
self.evict_cold_data(current_time)?;
|
||
before - self.state_cache.len()
|
||
} else {
|
||
0
|
||
};
|
||
|
||
// 3. 提升热点数据
|
||
let hot_keys: Vec<Hash> = self.state_cache
|
||
.iter()
|
||
.filter(|(_, entry)| entry.access_count > 50 && !entry.is_hot)
|
||
.map(|(key, _)| key.clone())
|
||
.collect();
|
||
|
||
for key in &hot_keys {
|
||
let _ = self.promote_hot_data(key);
|
||
}
|
||
|
||
Ok(OptimizationReport {
|
||
shard_id: self.shard_id,
|
||
expired_count,
|
||
evicted_count,
|
||
promoted_count: hot_keys.len(),
|
||
space_freed: initial_cache_size - self.current_cache_size,
|
||
entries_before: initial_entry_count,
|
||
entries_after: self.state_cache.len(),
|
||
cache_hit_rate: self.stats.cache_hit_rate(),
|
||
})
|
||
}
|
||
}
|
||
|
||
/// 优化报告
|
||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||
/// OptimizationReport
|
||
pub struct OptimizationReport {
|
||
/// 分片ID
|
||
pub shard_id: u64,
|
||
/// 清理的过期数据数量
|
||
pub expired_count: usize,
|
||
/// 驱逐的冷数据数量
|
||
pub evicted_count: usize,
|
||
/// 提升的热点数据数量
|
||
pub promoted_count: usize,
|
||
/// 释放的空间(字节)
|
||
pub space_freed: u64,
|
||
/// 优化前条目数
|
||
pub entries_before: usize,
|
||
/// 优化后条目数
|
||
pub entries_after: usize,
|
||
/// 缓存命中率
|
||
pub cache_hit_rate: f64,
|
||
}
|
||
|
||
#[cfg(test)]
|
||
mod tests {
|
||
use super::*;
|
||
|
||
#[test]
|
||
fn test_state_entry_creation() {
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
let value = vec![1, 2, 3, 4];
|
||
let entry = StateEntry::new(key, value.clone(), 1000);
|
||
|
||
assert_eq!(entry.value, value);
|
||
assert_eq!(entry.last_access, 1000);
|
||
assert_eq!(entry.access_count, 1);
|
||
assert!(!entry.is_hot);
|
||
assert_eq!(entry.size, 4);
|
||
}
|
||
|
||
#[test]
|
||
fn test_state_entry_hot_promotion() {
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
let value = vec![1, 2, 3];
|
||
let mut entry = StateEntry::new(key, value, 1000);
|
||
|
||
// 访问101次应该变为热点
|
||
for i in 0..101 {
|
||
entry.update_access(1000 + i);
|
||
}
|
||
|
||
assert!(entry.is_hot);
|
||
assert_eq!(entry.access_count, 102); // 初始1次 + 101次
|
||
}
|
||
|
||
#[test]
|
||
fn test_state_entry_cold_detection() {
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
let value = vec![1, 2, 3];
|
||
let entry = StateEntry::new(key, value, 1000);
|
||
|
||
// 在阈值内不是冷数据
|
||
assert!(!entry.is_cold(1500, 1000));
|
||
|
||
// 超过阈值是冷数据
|
||
assert!(entry.is_cold(2001, 1000));
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_read_write() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 3600, 1024 * 1024);
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
let value = vec![1, 2, 3, 4];
|
||
|
||
// 写入状态
|
||
assert!(optimizer.write_state(key.clone(), value.clone(), 1000).is_ok());
|
||
|
||
// 读取状态
|
||
let read_value = optimizer.read_state(&key, 1001);
|
||
assert_eq!(read_value, Some(value));
|
||
|
||
// 验证统计
|
||
assert_eq!(optimizer.stats.cache_hits, 1);
|
||
assert_eq!(optimizer.stats.total_accesses, 1);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_cache_miss() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 3600, 1024 * 1024);
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
|
||
// 读取不存在的状态
|
||
let result = optimizer.read_state(&key, 1000);
|
||
assert!(result.is_none());
|
||
|
||
// 验证统计
|
||
assert_eq!(optimizer.stats.cache_misses, 1);
|
||
assert_eq!(optimizer.stats.total_accesses, 1);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_evict_cold_data() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 1000, 1024);
|
||
|
||
// 写入一些数据
|
||
for i in 0..5 {
|
||
let key = Hash::from_slice(&[i; 32]).unwrap();
|
||
let value = vec![i; 100];
|
||
optimizer.write_state(key, value, 1000 + i as u64).unwrap();
|
||
}
|
||
|
||
// 等待一段时间后驱逐冷数据
|
||
assert!(optimizer.evict_cold_data(3000).is_ok());
|
||
|
||
// 验证统计
|
||
assert!(optimizer.stats.cold_data_archived > 0);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_hot_account_tracking() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 3600, 1024 * 1024);
|
||
let address = Address::from_slice(&[1u8; 32]).unwrap();
|
||
|
||
// 记录大量活动
|
||
for i in 0..1001 {
|
||
optimizer.record_account_activity(address.clone(), i % 2 == 0, 100, 1000 + i);
|
||
}
|
||
|
||
// 验证热点账户
|
||
let hot_accounts = optimizer.get_hot_accounts();
|
||
assert_eq!(hot_accounts.len(), 1);
|
||
assert_eq!(hot_accounts[0], address);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_cache_usage() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 3600, 1000);
|
||
|
||
// 写入500字节数据
|
||
let key = Hash::from_slice(&[1u8; 32]).unwrap();
|
||
let value = vec![1u8; 500];
|
||
optimizer.write_state(key, value, 1000).unwrap();
|
||
|
||
// 验证缓存使用率
|
||
assert_eq!(optimizer.get_cache_usage(), 0.5);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_cleanup_expired() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 1000, 1024 * 1024);
|
||
|
||
// 写入一些数据
|
||
for i in 0..5 {
|
||
let key = Hash::from_slice(&[i; 32]).unwrap();
|
||
let value = vec![i; 10];
|
||
optimizer.write_state(key, value, 1000).unwrap();
|
||
}
|
||
|
||
// 清理过期数据(超过2000秒)
|
||
let expired = optimizer.cleanup_expired(4000);
|
||
assert_eq!(expired, 5);
|
||
}
|
||
|
||
#[test]
|
||
fn test_optimizer_full_optimization() {
|
||
let mut optimizer = StateShardOptimizer::new(1, 1000, 1024 * 1024);
|
||
|
||
// 写入一些数据
|
||
for i in 0..10 {
|
||
let key = Hash::from_slice(&[i; 32]).unwrap();
|
||
let value = vec![i; 100];
|
||
optimizer.write_state(key, value, 1000 + i as u64).unwrap();
|
||
}
|
||
|
||
// 访问部分数据使其成为热点(但不超过100次,避免自动标记为hot)
|
||
for i in 0..3 {
|
||
let key = Hash::from_slice(&[i; 32]).unwrap();
|
||
for _ in 0..50 {
|
||
optimizer.read_state(&key, 2000);
|
||
}
|
||
}
|
||
|
||
// 执行优化
|
||
let report = optimizer.optimize(4000).unwrap();
|
||
|
||
assert_eq!(report.shard_id, 1);
|
||
assert!(report.promoted_count > 0);
|
||
assert!(report.cache_hit_rate > 0.0);
|
||
}
|
||
}
|