HeliosDB Nano v2.3.0 System Views - Integration Guide
HeliosDB Nano v2.3.0 System Views - Integration Guide
Overview
This document provides technical guidance for integrating with the v2.3.0 system views infrastructure, implementing new views, and extending the monitoring capabilities.
Architecture
System View Registry Pattern
pub struct SystemViewRegistry { views: HashMap<String, SystemView>, session_registry: Option<Arc<SessionRegistry>>, cache: Arc<Mutex<LruCache<CacheKey, CachedResult>>>, default_ttl: Duration,}Components:
- View Registry: Stores schema definitions for all system views
- Session Registry: Optional integration with active session tracking
- LRU Cache: 100-entry cache with configurable TTL (default 5 seconds)
- Execution Pipeline: Handles query execution with caching
View Categories
pub enum ViewCategory { Core, // PostgreSQL standard catalog views Session, // Session and activity monitoring Feature, // HeliosDB feature-specific views Statistics, // Performance and resource metrics}Implementing New System Views
Step 1: Define View Schema
Add view registration in the appropriate category method:
fn register_custom_view(&mut self) { self.register(SystemView { name: "helios_custom_view".to_string(), category: ViewCategory::Feature, description: "Custom view description".to_string(), schema: Schema { columns: vec![ Column::new("column1", DataType::Int8), Column::new("column2", DataType::Text), Column::new("timestamp", DataType::Timestamptz), ], }, });}Best Practices:
- Use snake_case for view names
- Use TEXT for string columns unless size is known
- Always include timestamps in monitoring views
- Include count/ID columns for aggregation
Step 2: Implement Execution Logic
fn execute_helios_custom_view(&self, storage: &StorageEngine) -> Result<Vec<Tuple>> { let mut results = Vec::new();
// Fetch data from storage or other sources let data = storage.get_custom_data()?;
// Convert to tuples for item in data { let tuple = Tuple::new(vec![ Value::Int8(item.id), Value::String(item.name), Value::Timestamp(item.timestamp), ]); results.push(tuple); }
Ok(results)}Guidelines:
- Return empty Vec if feature is disabled (graceful degradation)
- Handle errors with proper logging
- Respect timeouts for long-running operations
- Batch operations for performance
Step 3: Register Execution Handler
Add to execute_uncached match statement:
"helios_custom_view" => self.execute_helios_custom_view(storage),Step 4: Add Tests
#[test]fn test_execute_helios_custom_view() { let config = Config::in_memory(); let storage = StorageEngine::open_in_memory(&config).unwrap();
let registry = SystemViewRegistry::new(); let results = registry.execute("helios_custom_view", &storage).unwrap();
// Verify structure assert!(!results.is_empty()); assert_eq!(results[0].values.len(), 3);}
#[test]fn test_custom_view_schema() { let registry = SystemViewRegistry::new(); let schema = registry.get_schema("helios_custom_view").unwrap();
assert_eq!(schema.columns.len(), 3); assert_eq!(schema.columns[0].name, "column1");}Data Collection Integration
Collecting Query History
// In query executorlet query_id = storage.get_next_query_id()?;let start = Instant::now();
let result = execute_query(plan)?;
let duration_ms = start.elapsed().as_secs_f64() * 1000.0;storage.record_query_history(QueryRecord { query_id, query_hash: hash_query(&query_text), query_text, start_time: Utc::now(), end_time: Utc::now(), duration_ms, rows_returned: result.len() as i64, status: "success".to_string(),})?;Collecting Replication Metrics
// In replication managerpub struct ReplicationClient { client_id: String, last_sync_time: SystemTime, sent_lsn: u64, replay_lsn: u64,}
impl ReplicationClient { pub fn to_tuple(&self) -> Tuple { Tuple::new(vec![ Value::String(self.client_id.clone()), Value::Int8(self.sent_lsn as i64), Value::Int8(self.replay_lsn as i64), Value::Timestamp(DateTime::<Utc>::from(self.last_sync_time)), ]) }}Collecting Memory Statistics
// In storage enginepub fn get_table_memory_stats(&self, table_name: &str) -> Result<MemoryStats> { let heap_size = self.estimate_table_size(table_name)?; let cache_stats = self.cache.get_stats(&table_name)?;
Ok(MemoryStats { heap_size_bytes: heap_size, cache_size_bytes: cache_stats.cached_bytes, cache_hit_ratio: cache_stats.hit_ratio, cache_accesses: cache_stats.accesses, cache_hits: cache_stats.hits, })}Caching Strategy
View Query Execution
pub fn execute(&self, view_name: &str, storage: &StorageEngine) -> Result<Vec<Tuple>> { let cache_key = CacheKey::new(view_name);
// Check cache if let Some(cached) = self.get_cached(cache_key)? { if cached.is_valid() { return Ok(cached.tuples.clone()); } }
// Execute and cache let tuples = self.execute_uncached(view_name, storage)?; self.cache_result(cache_key, tuples.clone())?;
Ok(tuples)}Cache Configuration
// At startuplet registry = SystemViewRegistry::with_cache_config( 200, // cache size: 200 entries 10, // TTL: 10 seconds)?;Cache Invalidation
// After DDL operationsregistry.invalidate_category(ViewCategory::Feature)?;
// After specific table changesregistry.invalidate_view("helios_table_memory_stats")?;
// Full invalidation if neededregistry.invalidate_all()?;SQL Integration
Query Executor Integration
// In sql/executor/scan.rsfn execute_system_view( view_name: &str, storage: &StorageEngine, registry: &SystemViewRegistry,) -> Result<Vec<Tuple>> { // Check if view exists if !registry.is_system_view(view_name) { return Err(Error::query_execution(format!( "Unknown view: {}", view_name ))); }
// Execute with proper schema let schema = registry.get_schema(view_name)?; let tuples = registry.execute(view_name, storage)?;
Ok(tuples)}Protocol Handler Integration
// In protocol/postgres/handler.rsfn handle_select(query: &SelectQuery) -> Result<QueryResult> { // Check if table is a system view let system_registry = self.storage.system_view_registry();
if system_registry.is_system_view(&query.table_name) { return handle_system_view_query(query, system_registry)?; }
// Normal table handling handle_table_query(query)}Performance Optimization
Efficient Query Patterns
-- Good: Use indexes on common filtersSELECT * FROM helios_query_historyWHERE status = 'error' AND start_time > NOW() - INTERVAL '1 hour';
-- Good: Aggregate before returningSELECT query_hash, COUNT(*), AVG(duration_ms)FROM helios_query_historyGROUP BY query_hash;
-- Avoid: Large result setsSELECT * FROM helios_query_history; -- Returns 1000 rows
-- Better: PaginationSELECT * FROM helios_query_historyLIMIT 100 OFFSET 0;Monitoring View Performance
// Track execution metricspub struct ViewMetrics { view_name: String, execution_time_ms: f64, result_count: usize, cache_hit: bool,}
// Log metricsinfo!( view = view_name, duration_ms = execution_time_ms, results = result_count, cached = cache_hit, "System view executed");Testing Strategy
Unit Tests
#[test]fn test_view_registration() { let registry = SystemViewRegistry::new(); assert!(registry.is_system_view("helios_sync_status"));}
#[test]fn test_view_schema() { let registry = SystemViewRegistry::new(); let schema = registry.get_schema("helios_sync_status").unwrap(); assert_eq!(schema.columns.len(), 11);}
#[test]fn test_view_execution() { let storage = create_test_storage(); let registry = SystemViewRegistry::new(); let results = registry.execute("helios_sync_status", &storage).unwrap(); assert_eq!(results.len(), 1); // One node}Integration Tests
#[test]fn test_system_view_via_sql() { let storage = create_test_storage(); let query = "SELECT * FROM helios_table_memory_stats";
let results = execute_sql(&storage, query).unwrap(); assert!(!results.is_empty());}
#[test]fn test_system_view_caching() { let storage = create_test_storage(); let registry = SystemViewRegistry::with_cache_config(100, 5).unwrap();
let start = Instant::now(); let _ = registry.execute("helios_sync_status", &storage).unwrap(); let first_duration = start.elapsed();
let start = Instant::now(); let _ = registry.execute("helios_sync_status", &storage).unwrap(); let second_duration = start.elapsed();
// Second call should be much faster (cached) assert!(second_duration < first_duration / 2);}Monitoring & Debugging
View Availability Check
-- Check which views are availableSELECT view_name FROM information_schema.viewsWHERE table_schema = 'pg_catalog' OR table_schema = 'public'ORDER BY view_name;
-- Verify v2.3.0 views existSELECT COUNT(*) FROM information_schema.viewsWHERE view_name IN ( 'pg_stat_replication', 'helios_sync_status', 'helios_query_history', 'helios_table_memory_stats');Cache Performance
// Get cache statisticslet (entries, capacity) = registry.cache_stats()?;info!("View cache: {}/{} entries", entries, capacity);
// Monitor cache hit ratefor view_name in registry.list_views() { let hit_rate = registry.get_cache_hit_rate(view_name)?; info!("Cache hit rate for {}: {:.1}%", view_name, hit_rate * 100.0);}Debug Logging
Enable debug logging for system views:
RUST_LOG=heliosdb::sql::system_views=debug cargo runLog Output:
DEBUG heliosdb::sql::system_views: System view cache MISS for 'helios_sync_status'DEBUG heliosdb::sql::system_views: System view cached 'helios_sync_status' (1 tuples, ttl: 5s)DEBUG heliosdb::sql::system_views: System view cache HIT for 'helios_sync_status' (age: 2s, ttl: 5s)Migration Path
From v2.2 to v2.3
- Existing Views: All v2.0-v2.2 views continue to work unchanged
- New Features: Gradual migration to v2.3 views
- Backward Compatibility: No breaking changes to existing schemas
-- All these continue to work in v2.3SELECT * FROM pg_tables;SELECT * FROM pg_stat_activity;SELECT * FROM pg_compression_stats;
-- New views available in v2.3SELECT * FROM helios_sync_status;SELECT * FROM helios_query_history;SELECT * FROM helios_table_memory_stats;Troubleshooting Integration
View Registration Issues
// Verify view is registeredassert!(registry.is_system_view("my_view"));
// Check schema validityif let Some(schema) = registry.get_schema("my_view") { println!("View has {} columns", schema.columns.len());} else { eprintln!("View not found");}Execution Errors
// Check error detailsmatch registry.execute("helios_sync_status", &storage) { Ok(results) => println!("Got {} results", results.len()), Err(e) => eprintln!("Execution failed: {}", e),}Cache Issues
// Invalidate specific viewregistry.invalidate_view("helios_query_history")?;
// Check if issue is cache-relatedlet results_cached = registry.execute("view", &storage)?;let results_uncached = registry.execute_uncached("view", &storage)?;assert_eq!(results_cached, results_uncached);See Also
- V2_3_SYSTEM_VIEWS.md - User documentation
- src/sql/system_views.rs - Implementation
- FEATURE_DEVELOPMENT_PROTOCOL.md - Development guidelines