Skip to content

HeliosDB Multi-Tenancy

HeliosDB Multi-Tenancy

A comprehensive multi-tenancy system with logical isolation, resource quotas, and Quality of Service (QoS) tiers for HeliosDB v3.0.

Features

Core Capabilities

  • Logical Isolation: Separate database namespaces for each tenant with strict access control
  • Resource Quotas: CPU, memory, storage, table, and index limits per tenant
  • QoS Tiers: Free, Pro, and Enterprise tiers with different resource allocations
  • Fair Scheduling: Weighted fair queuing to prevent starvation
  • Usage Tracking: Real-time metering for billing and monitoring
  • Rate Limiting: Per-tenant query, write, and bandwidth limits
  • Dynamic Tier Management: Upgrade/downgrade tenants on the fly

Isolation Guarantees

  • Logical: Separate database namespaces per tenant
  • Performance: Resource quotas prevent noisy neighbor problems
  • Security: Separate credentials and access control per tenant
  • Data: Complete isolation - no cross-tenant data access

Architecture

┌─────────────────────────────────────────────┐
│ MultiTenantManager │
├─────────────────────────────────────────────┤
│ - Tenant Management │
│ - Quota Enforcement │
│ - Usage Tracking │
│ - Scheduling Coordination │
└─────────────────────────────────────────────┘
├─────────────┬──────────────┬──────────────┬──────────────┬──────────────┐
│ │ │ │ │ │
┌─────▼─────┐ ┌────▼────┐ ┌──────▼──────┐ ┌────▼────┐ ┌─────▼──────┐ ┌────▼─────┐
│ Isolation │ │ Quotas │ │ Scheduler │ │ Limits │ │ Accounting │ │ Tier │
│ Manager │ │ Manager │ │ (Fair) │ │ Manager │ │ Manager │ │ Manager │
└───────────┘ └─────────┘ └─────────────┘ └─────────┘ └────────────┘ └──────────┘

QoS Tiers

Free Tier

  • CPU: 5% max, 0.5% guaranteed
  • Memory: 512 MB
  • Storage: 1 GB
  • Tables: 10 max
  • Indexes: 20 max
  • Query Timeout: 30 seconds
  • Rate Limits: 10 queries/sec, 5 writes/sec, 1 Mbps

Pro Tier

  • CPU: 20% max, 2% guaranteed
  • Memory: 4 GB
  • Storage: 100 GB
  • Tables: 100 max
  • Indexes: 200 max
  • Query Timeout: 300 seconds
  • Rate Limits: 100 queries/sec, 50 writes/sec, 10 Mbps

Enterprise Tier

  • CPU: 50% max, 5% guaranteed
  • Memory: 32 GB
  • Storage: 1 TB
  • Tables: 1000 max
  • Indexes: 2000 max
  • Query Timeout: 3600 seconds
  • Rate Limits: 1000 queries/sec, 500 writes/sec, 100 Mbps

Usage

Basic Example

use heliosdb_multitenancy::*;
#[tokio::main]
async fn main() -> Result<()> {
// Create manager
let manager = MultiTenantManager::new().await?;
// Create a tenant
let config = TenantConfig::new("my_tenant".to_string(), TenantTier::Pro);
manager.create_tenant(config).await?;
// Schedule a query
let query = Query::new(
"my_tenant".to_string(),
"SELECT * FROM users".to_string(),
5
);
let handle = manager.schedule_query("my_tenant", query).await?;
// Record usage
manager.record_usage("my_tenant", Usage::Query).await?;
manager.record_usage("my_tenant", Usage::Cpu { seconds: 10.0 }).await?;
// Get usage metrics
let usage = manager.get_usage("my_tenant").await?;
println!("CPU used: {} seconds", usage.cpu_seconds);
println!("Queries: {}", usage.queries_count);
Ok(())
}

Tier Management

// Create with Free tier
let config = TenantConfig::new("tenant1".to_string(), TenantTier::Free);
manager.create_tenant(config).await?;
// Upgrade to Pro
manager.update_tier("tenant1", TenantTier::Pro).await?;
// Upgrade to Enterprise
manager.update_tier("tenant1", TenantTier::Enterprise).await?;

Custom Quotas

// Assign custom quotas (overrides tier defaults)
let custom = ResourceQuotas {
max_cpu_percent: 30.0,
max_memory_mb: 8192,
max_storage_gb: 200,
max_tables: 150,
max_indexes: 300,
query_timeout_secs: 600,
};
manager.set_quotas("tenant1", custom).await?;

Usage Tracking

// Record different types of usage
manager.record_usage("tenant1", Usage::Cpu { seconds: 100.0 }).await?;
manager.record_usage("tenant1", Usage::Memory { mb: 2048, duration_hours: 1.0 }).await?;
manager.record_usage("tenant1", Usage::Storage { gb: 50 }).await?;
manager.record_usage("tenant1", Usage::Query).await?;
manager.record_usage("tenant1", Usage::Write).await?;
manager.record_usage("tenant1", Usage::Bandwidth { mb: 500 }).await?;
// Get usage metrics
let usage = manager.get_usage("tenant1").await?;
// Calculate cost
let pricing = PricingModel::new();
let cost = pricing.calculate(&usage);

Fair Scheduling

// Queries from higher tier tenants get scheduled first
// but lower tier tenants are never starved
let query1 = Query::new("free_tenant".to_string(), "SELECT 1".to_string(), 1);
let query2 = Query::new("enterprise_tenant".to_string(), "SELECT 2".to_string(), 10);
manager.schedule_query("free_tenant", query1).await?;
manager.schedule_query("enterprise_tenant", query2).await?;
// Enterprise query will be scheduled first due to higher weight
// But free tier queries get aging boost to prevent starvation

Quota Checking

// Check if tenant is within quota
let within_cpu = manager.check_quota("tenant1", Resource::Cpu).await?;
let within_memory = manager.check_quota("tenant1", Resource::Memory).await?;
let within_storage = manager.check_quota("tenant1", Resource::Storage).await?;
if !within_cpu {
println!("Tenant has exceeded CPU quota");
}

API Reference

MultiTenantManager

Tenant Management

  • create_tenant(config: TenantConfig) -> Result<()>
  • delete_tenant(tenant_id: &str) -> Result<()>
  • update_tier(tenant_id: &str, tier: TenantTier) -> Result<()>
  • get_tenant(tenant_id: &str) -> Result<TenantConfig>
  • list_tenants() -> Vec<String>

Quota Management

  • set_quotas(tenant_id: &str, quotas: ResourceQuotas) -> Result<()>
  • check_quota(tenant_id: &str, resource: Resource) -> Result<bool>

Usage Tracking

  • record_usage(tenant_id: &str, usage: Usage) -> Result<()>
  • get_usage(tenant_id: &str) -> Result<UsageMetrics>

Scheduling

  • schedule_query(tenant_id: &str, query: Query) -> Result<QueryHandle>

Types

TenantTier

pub enum TenantTier {
Free,
Pro,
Enterprise,
}

Resource

pub enum Resource {
Cpu,
Memory,
Storage,
Tables,
Indexes,
}

Usage

pub enum Usage {
Cpu { seconds: f64 },
Memory { mb: u64, duration_hours: f64 },
Storage { gb: u64 },
Query,
Write,
Bandwidth { mb: u64 },
}

Fair Scheduling Algorithm

The scheduler uses Weighted Fair Queuing (WFQ) with anti-starvation:

  1. Weight Calculation: Each tier has a weight (Free: 1.0, Pro: 5.0, Enterprise: 10.0)
  2. Priority Boosting: Queries get priority boost based on age (max +5 after 5 minutes)
  3. Effective Priority: base_priority × weight + age_boost
  4. Guaranteed CPU: Each tier gets minimum CPU even under contention

This ensures:

  • Higher tier tenants get preferential treatment
  • Lower tier tenants are never completely starved
  • Fairness across all tenants over time

Usage Metrics

The system tracks the following metrics per tenant:

  • CPU Seconds: Total CPU time consumed
  • Memory MB-Hours: Memory usage over time
  • Storage GB: Current storage utilization
  • Query Count: Total queries executed
  • Write Count: Total write operations
  • Bandwidth MB: Total data transferred

Billing Integration

// Define pricing model
let pricing = PricingModel {
cpu_per_second: 0.0001, // $0.0001 per CPU second
memory_per_mb_hour: 0.00001, // $0.00001 per MB-hour
storage_per_gb: 0.10, // $0.10 per GB/month
query_per_1000: 0.001, // $0.001 per 1000 queries
write_per_1000: 0.002, // $0.002 per 1000 writes
bandwidth_per_gb: 0.09, // $0.09 per GB bandwidth
};
// Calculate cost
let usage = manager.get_usage("tenant1").await?;
let cost = pricing.calculate(&usage);

Testing

Run unit tests:

Terminal window
cargo test

Run integration tests:

Terminal window
cargo test --test integration_test

Run with logging:

Terminal window
RUST_LOG=debug cargo test

Examples

Run the example:

Terminal window
cargo run --example multi_tenant

Performance

  • Tenant Creation: O(1)
  • Query Scheduling: O(log n) where n = queue size
  • Quota Checking: O(1)
  • Usage Recording: O(1)
  • Rate Limiting: O(1)

All operations are designed for high concurrency using lock-free data structures where possible.

Thread Safety

All components are thread-safe and can be safely shared across multiple threads:

  • Uses Arc for shared ownership
  • Uses DashMap for concurrent hash maps
  • Uses RwLock for read-heavy workloads
  • Uses atomic operations for counters

Error Handling

pub enum MultiTenancyError {
TenantNotFound(String),
TenantAlreadyExists(String),
QuotaExceeded { tenant_id: String, resource: String },
RateLimitExceeded(String),
InvalidConfiguration(String),
IsolationViolation(String),
SchedulingError(String),
InternalError(String),
}

Best Practices

  1. Always check quotas before allowing resource-intensive operations
  2. Record usage immediately after operations complete
  3. Use appropriate tier for each tenant’s needs
  4. Monitor usage metrics regularly to detect anomalies
  5. Set custom quotas when standard tiers don’t fit
  6. Clean up tenants properly using delete_tenant()
  7. Handle errors appropriately (especially QuotaExceeded)

License

MIT OR Apache-2.0