# GPU Implementation Summary ## Overview Implemented dedicated GPU instance tables and code infrastructure for Linode GPU instances in the cloud-server project. ## Files Modified ### 1. Database Schema (`schema.sql`) Added two new tables with full indexing and triggers: #### `gpu_instances` Table - **Purpose**: GPU-specific instance types separate from regular instances - **Key Fields**: - Standard fields: id, provider_id, instance_id, instance_name, vcpu, memory_mb, storage_gb, transfer_tb, network_speed_gbps - GPU-specific: gpu_count (NOT NULL, CHECK > 0), gpu_type (NOT NULL), gpu_memory_gb - Metadata: JSON string for provider-specific additional data - **Indexes**: - `idx_gpu_instances_provider_id` - Provider lookups - `idx_gpu_instances_gpu_type` - GPU type filtering - `idx_gpu_instances_gpu_count` - GPU count filtering - `idx_gpu_instances_provider_type` - Composite index for provider + GPU type queries - **Triggers**: `update_gpu_instances_updated_at` - Auto-update timestamp #### `gpu_pricing` Table - **Purpose**: Region-specific pricing for GPU instances - **Key Fields**: gpu_instance_id, region_id, hourly_price, monthly_price, currency, available - **Indexes**: - `idx_gpu_pricing_instance_id` - Instance lookups - `idx_gpu_pricing_region_id` - Region lookups - `idx_gpu_pricing_hourly_price` - Price sorting - `idx_gpu_pricing_monthly_price` - Price sorting - `idx_gpu_pricing_available` - Availability filtering - **Triggers**: `update_gpu_pricing_updated_at` - Auto-update timestamp ### 2. Type Definitions (`src/types.ts`) Added new types following existing patterns: ```typescript export interface GpuInstance { id: number; provider_id: number; instance_id: string; instance_name: string; vcpu: number; memory_mb: number; storage_gb: number; transfer_tb: number | null; network_speed_gbps: number | null; gpu_count: number; gpu_type: string; gpu_memory_gb: number | null; metadata: string | null; created_at: string; updated_at: string; } export interface GpuPricing { id: number; gpu_instance_id: number; region_id: number; hourly_price: number; monthly_price: number; currency: string; available: number; created_at: string; updated_at: string; } export type GpuInstanceInput = Omit; export type GpuPricingInput = Omit; ``` ### 3. Repositories #### `src/repositories/gpu-instances.ts` - GpuInstancesRepository Extends `BaseRepository` with specialized methods: **Methods**: - `findByProvider(providerId: number)` - Find all GPU instances for a provider - `findByGpuType(gpuType: string)` - Find instances by GPU type - `findByInstanceId(providerId: number, instanceId: string)` - Find specific instance - `upsertMany(providerId: number, instances: GpuInstanceInput[])` - Bulk upsert with conflict resolution - `search(criteria)` - Advanced search with filters for vCPU, memory, GPU count, GPU type, GPU memory - `getAvailableGpuTypes()` - Get distinct GPU types in database **Features**: - Follows BaseRepository pattern - Uses `createLogger('[GpuInstancesRepository]')` - Batch operations for efficiency - Comprehensive error handling with RepositoryError - Proper parameter binding for SQL injection prevention #### `src/repositories/gpu-pricing.ts` - GpuPricingRepository Extends `BaseRepository` for pricing operations: **Methods**: - `findByGpuInstance(gpuInstanceId: number)` - Get all pricing for GPU instance - `findByRegion(regionId: number)` - Get all GPU pricing in region - `findByGpuInstanceAndRegion(gpuInstanceId, regionId)` - Get specific pricing record - `upsertMany(pricingData: GpuPricingInput[])` - Bulk upsert pricing data - `searchByPriceRange(minHourly?, maxHourly?, minMonthly?, maxMonthly?)` - Search by price **Features**: - Follows BaseRepository pattern - Uses `createLogger('[GpuPricingRepository]')` - Batch operations with conflict resolution - Price range filtering ### 4. Repository Factory (`src/repositories/index.ts`) Extended RepositoryFactory with GPU repositories: ```typescript export class RepositoryFactory { private _gpuInstances?: GpuInstancesRepository; private _gpuPricing?: GpuPricingRepository; get gpuInstances(): GpuInstancesRepository { return this._gpuInstances ??= new GpuInstancesRepository(this.db); } get gpuPricing(): GpuPricingRepository { return this._gpuPricing ??= new GpuPricingRepository(this.db); } } ``` ### 5. Linode Connector (`src/connectors/linode.ts`) Added GPU normalization methods: **New Methods**: - `normalizeGpuInstance(raw: LinodeInstanceType, providerId: number): GpuInstanceInput` - Normalizes Linode GPU instance data for database storage - Extracts GPU-specific information - Converts units (MB to GB, GB to TB, Mbps to Gbps) - Stores pricing in metadata - `extractGpuType(raw: LinodeInstanceType): string` (private) - Intelligent GPU type extraction from instance label - Recognizes: RTX6000, A100, V100, generic RTX - Defaults to "NVIDIA GPU" for unknown types **Features**: - Consistent with existing normalization patterns - Proper unit conversions - GPU type detection from instance labels - Metadata preservation ## Design Decisions ### Why Separate GPU Tables? 1. **Performance**: GPU instances have different query patterns (GPU type, GPU count filters) 2. **Schema Clarity**: GPU-specific fields (gpu_memory_gb) don't belong in general instances 3. **Extensibility**: Easy to add GPU-specific features without affecting general instances 4. **Pricing Separation**: GPU pricing may have different dynamics (spot pricing, regional availability) ### Why Not Reuse Pricing Table? 1. **Foreign Key Clarity**: Separate gpu_instance_id vs instance_type_id prevents confusion 2. **Query Optimization**: Dedicated indexes for GPU pricing queries 3. **Future Features**: GPU pricing may need GPU-specific fields (spot pricing, tensor core hours) 4. **Data Integrity**: Clear separation prevents mixing GPU and regular instance pricing ### GPU Type Detection Strategy Uses label-based heuristics because: - Linode API doesn't expose specific GPU model in structured fields - Label parsing is reliable for current Linode naming conventions - Extensible: Easy to add new GPU models as they become available - Fallback: Defaults to "NVIDIA GPU" for unknown types ## Integration Points ### Usage in Sync Service To integrate with existing sync workflows: ```typescript // Fetch and separate GPU instances const allInstances = await linodeConnector.fetchInstanceTypes(); const gpuInstances = allInstances.filter(inst => inst.gpus > 0); const regularInstances = allInstances.filter(inst => inst.gpus === 0); // Normalize and store separately const normalizedGpu = gpuInstances.map(inst => linodeConnector.normalizeGpuInstance(inst, providerId) ); await repos.gpuInstances.upsertMany(providerId, normalizedGpu); ``` ### Querying GPU Instances ```typescript // Find all NVIDIA A100 instances const a100s = await repos.gpuInstances.findByGpuType('NVIDIA A100'); // Search with filters const results = await repos.gpuInstances.search({ providerId: 1, minGpuCount: 2, minMemoryMb: 32768, gpuType: 'NVIDIA RTX6000' }); // Get available GPU types const gpuTypes = await repos.gpuInstances.getAvailableGpuTypes(); ``` ## Testing Status ✅ **TypeScript Compilation**: Passes without errors ✅ **Type Safety**: All types properly defined and used ✅ **Pattern Consistency**: Follows existing repository and connector patterns ⏳ **Unit Tests**: Existing tests still pass (verification in progress) 📝 **New Tests Needed**: GPU-specific repository and connector tests ## Next Steps ### 1. Sync Service Integration Update `src/services/sync.ts` to: - Separate GPU instances during sync - Store GPU instances in gpu_instances table - Store GPU pricing in gpu_pricing table ### 2. API Endpoints (Optional) Add GPU-specific endpoints: - `GET /gpu-instances` - Query GPU instances - `GET /gpu-types` - List available GPU types - `GET /gpu-pricing` - Query GPU pricing ### 3. Testing Create test files: - `src/repositories/gpu-instances.test.ts` - `src/repositories/gpu-pricing.test.ts` - `src/connectors/linode-gpu.test.ts` ### 4. Database Migration Run schema update on production: ```bash npm run db:migrate:remote ``` ### 5. Documentation - Update API documentation with GPU endpoints - Add GPU query examples to README - Document GPU type naming conventions ## Files Created 1. `/Users/kaffa/cloud-server/src/repositories/gpu-instances.ts` (279 lines) 2. `/Users/kaffa/cloud-server/src/repositories/gpu-pricing.ts` (201 lines) ## Files Modified 1. `/Users/kaffa/cloud-server/schema.sql` - Added gpu_instances and gpu_pricing tables 2. `/Users/kaffa/cloud-server/src/types.ts` - Added GpuInstance and GpuPricing types 3. `/Users/kaffa/cloud-server/src/repositories/index.ts` - Added GPU repositories to factory 4. `/Users/kaffa/cloud-server/src/connectors/linode.ts` - Added GPU normalization methods ## Verification ```bash # Type check npx tsc --noEmit # ✅ Passes # Run tests npm test # ⏳ In progress # Check schema cat schema.sql | grep -A 20 "gpu_instances" # ✅ Tables defined ``` ## Notes - GPU memory (gpu_memory_gb) is set to null for Linode as API doesn't provide this - Can be populated manually or from external data sources if needed - Metadata field stores pricing and other provider-specific data as JSON - All repositories follow lazy singleton pattern via RepositoryFactory - Proper error handling with RepositoryError and ErrorCodes - Comprehensive logging with contextual information