Skip to content

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 executor
let 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 manager
pub 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 engine
pub 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 startup
let registry = SystemViewRegistry::with_cache_config(
200, // cache size: 200 entries
10, // TTL: 10 seconds
)?;

Cache Invalidation

// After DDL operations
registry.invalidate_category(ViewCategory::Feature)?;
// After specific table changes
registry.invalidate_view("helios_table_memory_stats")?;
// Full invalidation if needed
registry.invalidate_all()?;

SQL Integration

Query Executor Integration

// In sql/executor/scan.rs
fn 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.rs
fn 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 filters
SELECT * FROM helios_query_history
WHERE status = 'error'
AND start_time > NOW() - INTERVAL '1 hour';
-- Good: Aggregate before returning
SELECT query_hash, COUNT(*), AVG(duration_ms)
FROM helios_query_history
GROUP BY query_hash;
-- Avoid: Large result sets
SELECT * FROM helios_query_history; -- Returns 1000 rows
-- Better: Pagination
SELECT * FROM helios_query_history
LIMIT 100 OFFSET 0;

Monitoring View Performance

// Track execution metrics
pub struct ViewMetrics {
view_name: String,
execution_time_ms: f64,
result_count: usize,
cache_hit: bool,
}
// Log metrics
info!(
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 available
SELECT view_name FROM information_schema.views
WHERE table_schema = 'pg_catalog'
OR table_schema = 'public'
ORDER BY view_name;
-- Verify v2.3.0 views exist
SELECT COUNT(*) FROM information_schema.views
WHERE view_name IN (
'pg_stat_replication',
'helios_sync_status',
'helios_query_history',
'helios_table_memory_stats'
);

Cache Performance

// Get cache statistics
let (entries, capacity) = registry.cache_stats()?;
info!("View cache: {}/{} entries", entries, capacity);
// Monitor cache hit rate
for 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 run

Log 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

  1. Existing Views: All v2.0-v2.2 views continue to work unchanged
  2. New Features: Gradual migration to v2.3 views
  3. Backward Compatibility: No breaking changes to existing schemas
-- All these continue to work in v2.3
SELECT * FROM pg_tables;
SELECT * FROM pg_stat_activity;
SELECT * FROM pg_compression_stats;
-- New views available in v2.3
SELECT * FROM helios_sync_status;
SELECT * FROM helios_query_history;
SELECT * FROM helios_table_memory_stats;

Troubleshooting Integration

View Registration Issues

// Verify view is registered
assert!(registry.is_system_view("my_view"));
// Check schema validity
if let Some(schema) = registry.get_schema("my_view") {
println!("View has {} columns", schema.columns.len());
} else {
eprintln!("View not found");
}

Execution Errors

// Check error details
match registry.execute("helios_sync_status", &storage) {
Ok(results) => println!("Got {} results", results.len()),
Err(e) => eprintln!("Execution failed: {}", e),
}

Cache Issues

// Invalidate specific view
registry.invalidate_view("helios_query_history")?;
// Check if issue is cache-related
let results_cached = registry.execute("view", &storage)?;
let results_uncached = registry.execute_uncached("view", &storage)?;
assert_eq!(results_cached, results_uncached);

See Also