burncloud_database_models/
migrations.rs

1// SQL 迁移脚本 - 创建 BurnCloud 模型管理数据库表结构
2
3/// PostgreSQL 迁移脚本
4pub const POSTGRES_MIGRATIONS: &[&str] = &[
5    // 001_initial_schema.sql
6    r#"
7-- 创建模型表
8CREATE TABLE IF NOT EXISTS models (
9    id UUID PRIMARY KEY,
10    name VARCHAR(255) NOT NULL UNIQUE,
11    display_name VARCHAR(255) NOT NULL,
12    description TEXT,
13    version VARCHAR(100) NOT NULL,
14    model_type VARCHAR(50) NOT NULL,
15    size_category VARCHAR(50) NOT NULL,
16    file_size BIGINT NOT NULL,
17    provider VARCHAR(255) NOT NULL,
18    license VARCHAR(255),
19    tags JSONB NOT NULL DEFAULT '[]',
20    languages JSONB NOT NULL DEFAULT '[]',
21    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
22    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
23    file_path VARCHAR(500),
24    checksum VARCHAR(255),
25    download_url TEXT,
26    config JSONB NOT NULL DEFAULT '{}',
27    rating REAL,
28    download_count BIGINT NOT NULL DEFAULT 0,
29    is_official BOOLEAN NOT NULL DEFAULT false
30);
31
32-- 创建已安装模型表
33CREATE TABLE IF NOT EXISTS installed_models (
34    id UUID PRIMARY KEY,
35    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
36    install_path VARCHAR(500) NOT NULL,
37    installed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
38    status VARCHAR(50) NOT NULL,
39    port INTEGER,
40    process_id INTEGER,
41    last_used TIMESTAMPTZ,
42    usage_count BIGINT NOT NULL DEFAULT 0,
43    UNIQUE(model_id)
44);
45
46-- 创建可用模型表
47CREATE TABLE IF NOT EXISTS available_models (
48    id UUID PRIMARY KEY,
49    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
50    is_installed BOOLEAN NOT NULL DEFAULT false,
51    published_at TIMESTAMPTZ NOT NULL,
52    last_updated TIMESTAMPTZ NOT NULL,
53    system_requirements JSONB NOT NULL,
54    UNIQUE(model_id)
55);
56
57-- 创建运行时配置表
58CREATE TABLE IF NOT EXISTS runtime_configs (
59    id UUID PRIMARY KEY,
60    name VARCHAR(255) NOT NULL,
61    max_context_length INTEGER,
62    temperature REAL,
63    top_p REAL,
64    top_k INTEGER,
65    max_tokens INTEGER,
66    stop_sequences JSONB NOT NULL DEFAULT '[]',
67    batch_size INTEGER,
68    max_concurrent_requests INTEGER,
69    gpu_device_ids JSONB NOT NULL DEFAULT '[]',
70    memory_limit_mb BIGINT,
71    enable_streaming BOOLEAN NOT NULL DEFAULT true,
72    custom_params JSONB NOT NULL DEFAULT '{}',
73    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
74    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
75);
76
77-- 创建模型运行时表
78CREATE TABLE IF NOT EXISTS model_runtimes (
79    id UUID PRIMARY KEY,
80    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
81    runtime_config_id UUID NOT NULL REFERENCES runtime_configs(id) ON DELETE CASCADE,
82    name VARCHAR(255) NOT NULL,
83    port INTEGER NOT NULL,
84    process_id INTEGER,
85    started_at TIMESTAMPTZ,
86    stopped_at TIMESTAMPTZ,
87    status VARCHAR(50) NOT NULL,
88    health_endpoint VARCHAR(255) NOT NULL,
89    api_endpoint VARCHAR(255) NOT NULL,
90    log_file VARCHAR(500),
91    environment JSONB NOT NULL DEFAULT '{}',
92    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
93    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
94    UNIQUE(model_id, port)
95);
96
97-- 创建运行时指标表
98CREATE TABLE IF NOT EXISTS runtime_metrics (
99    id UUID PRIMARY KEY,
100    runtime_id UUID NOT NULL REFERENCES model_runtimes(id) ON DELETE CASCADE,
101    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
102    cpu_usage_percent REAL NOT NULL,
103    memory_usage_mb BIGINT NOT NULL,
104    gpu_usage_percent REAL,
105    gpu_memory_usage_mb BIGINT,
106    active_connections INTEGER NOT NULL,
107    total_requests BIGINT NOT NULL,
108    successful_requests BIGINT NOT NULL,
109    failed_requests BIGINT NOT NULL,
110    avg_response_time_ms REAL NOT NULL,
111    throughput_rps REAL NOT NULL,
112    queue_length INTEGER NOT NULL
113);
114
115-- 创建运行时事件表
116CREATE TABLE IF NOT EXISTS runtime_events (
117    id UUID PRIMARY KEY,
118    runtime_id UUID NOT NULL REFERENCES model_runtimes(id) ON DELETE CASCADE,
119    event_type VARCHAR(50) NOT NULL,
120    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
121    message TEXT NOT NULL,
122    details JSONB,
123    severity VARCHAR(20) NOT NULL
124);
125
126-- 创建索引
127CREATE INDEX IF NOT EXISTS idx_models_name ON models(name);
128CREATE INDEX IF NOT EXISTS idx_models_provider ON models(provider);
129CREATE INDEX IF NOT EXISTS idx_models_model_type ON models(model_type);
130CREATE INDEX IF NOT EXISTS idx_models_created_at ON models(created_at);
131CREATE INDEX IF NOT EXISTS idx_installed_models_model_id ON installed_models(model_id);
132CREATE INDEX IF NOT EXISTS idx_installed_models_status ON installed_models(status);
133CREATE INDEX IF NOT EXISTS idx_available_models_model_id ON available_models(model_id);
134CREATE INDEX IF NOT EXISTS idx_runtime_metrics_runtime_id ON runtime_metrics(runtime_id);
135CREATE INDEX IF NOT EXISTS idx_runtime_metrics_timestamp ON runtime_metrics(timestamp);
136CREATE INDEX IF NOT EXISTS idx_runtime_events_runtime_id ON runtime_events(runtime_id);
137CREATE INDEX IF NOT EXISTS idx_runtime_events_timestamp ON runtime_events(timestamp);
138"#,
139
140    // 002_repositories.sql
141    r#"
142-- 创建模型仓库表
143CREATE TABLE IF NOT EXISTS model_repositories (
144    id UUID PRIMARY KEY,
145    name VARCHAR(255) NOT NULL UNIQUE,
146    url TEXT NOT NULL,
147    repo_type VARCHAR(50) NOT NULL,
148    enabled BOOLEAN NOT NULL DEFAULT true,
149    auth_config JSONB,
150    last_sync TIMESTAMPTZ,
151    sync_status VARCHAR(50) NOT NULL DEFAULT 'never',
152    description TEXT,
153    tags JSONB NOT NULL DEFAULT '[]',
154    priority INTEGER NOT NULL DEFAULT 100,
155    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
156    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
157);
158
159-- 创建仓库索引表
160CREATE TABLE IF NOT EXISTS repository_indexes (
161    id UUID PRIMARY KEY,
162    repository_id UUID NOT NULL REFERENCES model_repositories(id) ON DELETE CASCADE,
163    version VARCHAR(100) NOT NULL,
164    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
165    checksum VARCHAR(255),
166    metadata JSONB NOT NULL DEFAULT '{}',
167    UNIQUE(repository_id)
168);
169
170-- 创建仓库模型表
171CREATE TABLE IF NOT EXISTS repository_models (
172    id UUID PRIMARY KEY,
173    repository_id UUID NOT NULL REFERENCES model_repositories(id) ON DELETE CASCADE,
174    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
175    repo_model_id VARCHAR(255) NOT NULL,
176    repo_path VARCHAR(500) NOT NULL,
177    download_urls JSONB NOT NULL DEFAULT '[]',
178    files JSONB NOT NULL DEFAULT '[]',
179    dependencies JSONB NOT NULL DEFAULT '[]',
180    installation_notes TEXT,
181    usage_examples JSONB NOT NULL DEFAULT '[]',
182    license_text TEXT,
183    model_card TEXT,
184    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
185    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
186    UNIQUE(repository_id, repo_model_id)
187);
188
189-- 创建同步结果表
190CREATE TABLE IF NOT EXISTS sync_results (
191    id UUID PRIMARY KEY,
192    repository_id UUID NOT NULL REFERENCES model_repositories(id) ON DELETE CASCADE,
193    started_at TIMESTAMPTZ NOT NULL,
194    completed_at TIMESTAMPTZ,
195    status VARCHAR(50) NOT NULL,
196    models_added INTEGER NOT NULL DEFAULT 0,
197    models_updated INTEGER NOT NULL DEFAULT 0,
198    models_removed INTEGER NOT NULL DEFAULT 0,
199    error_message TEXT,
200    log_entries JSONB NOT NULL DEFAULT '[]'
201);
202
203-- 创建索引
204CREATE INDEX IF NOT EXISTS idx_repository_models_repository_id ON repository_models(repository_id);
205CREATE INDEX IF NOT EXISTS idx_repository_models_model_id ON repository_models(model_id);
206CREATE INDEX IF NOT EXISTS idx_sync_results_repository_id ON sync_results(repository_id);
207CREATE INDEX IF NOT EXISTS idx_sync_results_started_at ON sync_results(started_at);
208"#,
209
210    // 003_monitoring.sql
211    r#"
212-- 创建全局配置表
213CREATE TABLE IF NOT EXISTS global_configs (
214    id UUID PRIMARY KEY,
215    version VARCHAR(100) NOT NULL,
216    config_data JSONB NOT NULL,
217    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
218    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
219);
220
221-- 创建系统指标表
222CREATE TABLE IF NOT EXISTS system_metrics (
223    id UUID PRIMARY KEY,
224    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
225    cpu_usage_percent REAL NOT NULL,
226    cpu_cores INTEGER NOT NULL,
227    memory_total_bytes BIGINT NOT NULL,
228    memory_used_bytes BIGINT NOT NULL,
229    memory_usage_percent REAL NOT NULL,
230    disk_total_bytes BIGINT NOT NULL,
231    disk_used_bytes BIGINT NOT NULL,
232    disk_usage_percent REAL NOT NULL,
233    network_rx_bytes_per_sec BIGINT NOT NULL,
234    network_tx_bytes_per_sec BIGINT NOT NULL,
235    gpu_usage_percent REAL,
236    gpu_memory_usage_mb BIGINT,
237    load_1m REAL NOT NULL,
238    load_5m REAL NOT NULL,
239    load_15m REAL NOT NULL
240);
241
242-- 创建应用指标表
243CREATE TABLE IF NOT EXISTS application_metrics (
244    id UUID PRIMARY KEY,
245    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
246    uptime_seconds BIGINT NOT NULL,
247    total_requests BIGINT NOT NULL,
248    successful_requests BIGINT NOT NULL,
249    failed_requests BIGINT NOT NULL,
250    active_connections INTEGER NOT NULL,
251    avg_response_time_ms REAL NOT NULL,
252    p95_response_time_ms REAL NOT NULL,
253    p99_response_time_ms REAL NOT NULL,
254    current_qps REAL NOT NULL,
255    peak_qps REAL NOT NULL,
256    error_rate_percent REAL NOT NULL,
257    health_status VARCHAR(20) NOT NULL
258);
259
260-- 创建模型指标表
261CREATE TABLE IF NOT EXISTS model_metrics (
262    id UUID PRIMARY KEY,
263    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
264    runtime_id UUID REFERENCES model_runtimes(id) ON DELETE SET NULL,
265    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
266    status VARCHAR(50) NOT NULL,
267    total_requests BIGINT NOT NULL,
268    successful_requests BIGINT NOT NULL,
269    failed_requests BIGINT NOT NULL,
270    avg_inference_time_ms REAL NOT NULL,
271    tokens_per_second REAL NOT NULL,
272    memory_usage_bytes BIGINT NOT NULL,
273    gpu_memory_usage_bytes BIGINT,
274    cpu_usage_percent REAL NOT NULL,
275    gpu_usage_percent REAL,
276    queue_length INTEGER NOT NULL,
277    last_request_time TIMESTAMPTZ
278);
279
280-- 创建告警事件表
281CREATE TABLE IF NOT EXISTS alert_events (
282    id UUID PRIMARY KEY,
283    alert_type VARCHAR(100) NOT NULL,
284    severity VARCHAR(20) NOT NULL,
285    title VARCHAR(255) NOT NULL,
286    description TEXT NOT NULL,
287    triggered_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
288    resolved_at TIMESTAMPTZ,
289    status VARCHAR(20) NOT NULL DEFAULT 'triggered',
290    resource_type VARCHAR(100) NOT NULL,
291    resource_id VARCHAR(255) NOT NULL,
292    resource_name VARCHAR(255) NOT NULL,
293    value REAL NOT NULL,
294    threshold REAL NOT NULL,
295    labels JSONB NOT NULL DEFAULT '{}',
296    metadata JSONB NOT NULL DEFAULT '{}'
297);
298
299-- 创建索引
300CREATE INDEX IF NOT EXISTS idx_system_metrics_timestamp ON system_metrics(timestamp);
301CREATE INDEX IF NOT EXISTS idx_application_metrics_timestamp ON application_metrics(timestamp);
302CREATE INDEX IF NOT EXISTS idx_model_metrics_model_id ON model_metrics(model_id);
303CREATE INDEX IF NOT EXISTS idx_model_metrics_timestamp ON model_metrics(timestamp);
304CREATE INDEX IF NOT EXISTS idx_alert_events_triggered_at ON alert_events(triggered_at);
305CREATE INDEX IF NOT EXISTS idx_alert_events_status ON alert_events(status);
306CREATE INDEX IF NOT EXISTS idx_alert_events_severity ON alert_events(severity);
307"#,
308
309    // 004_tasks_and_sessions.sql
310    r#"
311-- 创建用户会话表
312CREATE TABLE IF NOT EXISTS user_sessions (
313    id UUID PRIMARY KEY,
314    user_id VARCHAR(255) NOT NULL,
315    session_token VARCHAR(255) NOT NULL UNIQUE,
316    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
317    expires_at TIMESTAMPTZ NOT NULL,
318    last_accessed TIMESTAMPTZ NOT NULL DEFAULT NOW(),
319    ip_address INET NOT NULL,
320    user_agent TEXT,
321    is_active BOOLEAN NOT NULL DEFAULT true
322);
323
324-- 创建API使用统计表
325CREATE TABLE IF NOT EXISTS api_usage (
326    id UUID PRIMARY KEY,
327    api_key_id UUID,
328    endpoint VARCHAR(255) NOT NULL,
329    method VARCHAR(10) NOT NULL,
330    timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
331    response_time_ms INTEGER NOT NULL,
332    status_code INTEGER NOT NULL,
333    request_size_bytes BIGINT NOT NULL,
334    response_size_bytes BIGINT NOT NULL,
335    ip_address INET NOT NULL,
336    user_agent TEXT
337);
338
339-- 创建任务队列表
340CREATE TABLE IF NOT EXISTS tasks (
341    id UUID PRIMARY KEY,
342    task_type VARCHAR(100) NOT NULL,
343    payload JSONB NOT NULL,
344    status VARCHAR(20) NOT NULL DEFAULT 'pending',
345    priority INTEGER NOT NULL DEFAULT 0,
346    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
347    started_at TIMESTAMPTZ,
348    completed_at TIMESTAMPTZ,
349    error_message TEXT,
350    retry_count INTEGER NOT NULL DEFAULT 0,
351    max_retries INTEGER NOT NULL DEFAULT 3,
352    scheduled_at TIMESTAMPTZ
353);
354
355-- 创建下载任务表
356CREATE TABLE IF NOT EXISTS download_tasks (
357    id UUID PRIMARY KEY,
358    model_id UUID NOT NULL REFERENCES models(id) ON DELETE CASCADE,
359    url TEXT NOT NULL,
360    file_path VARCHAR(500) NOT NULL,
361    total_size BIGINT NOT NULL,
362    downloaded_size BIGINT NOT NULL DEFAULT 0,
363    status VARCHAR(20) NOT NULL DEFAULT 'pending',
364    progress_percent REAL NOT NULL DEFAULT 0,
365    download_speed_bps BIGINT NOT NULL DEFAULT 0,
366    estimated_time_remaining INTEGER,
367    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
368    started_at TIMESTAMPTZ,
369    completed_at TIMESTAMPTZ,
370    error_message TEXT
371);
372
373-- 创建索引
374CREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON user_sessions(user_id);
375CREATE INDEX IF NOT EXISTS idx_user_sessions_session_token ON user_sessions(session_token);
376CREATE INDEX IF NOT EXISTS idx_user_sessions_expires_at ON user_sessions(expires_at);
377CREATE INDEX IF NOT EXISTS idx_api_usage_timestamp ON api_usage(timestamp);
378CREATE INDEX IF NOT EXISTS idx_api_usage_endpoint ON api_usage(endpoint);
379CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
380CREATE INDEX IF NOT EXISTS idx_tasks_task_type ON tasks(task_type);
381CREATE INDEX IF NOT EXISTS idx_tasks_created_at ON tasks(created_at);
382CREATE INDEX IF NOT EXISTS idx_download_tasks_model_id ON download_tasks(model_id);
383CREATE INDEX IF NOT EXISTS idx_download_tasks_status ON download_tasks(status);
384"#,
385
386    // 005_triggers_and_functions.sql
387    r#"
388-- 创建自动更新 updated_at 字段的函数
389CREATE OR REPLACE FUNCTION update_updated_at_column()
390RETURNS TRIGGER AS $$
391BEGIN
392    NEW.updated_at = NOW();
393    RETURN NEW;
394END;
395$$ LANGUAGE plpgsql;
396
397-- 为需要的表创建触发器
398CREATE TRIGGER update_models_updated_at BEFORE UPDATE ON models
399    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
400
401CREATE TRIGGER update_runtime_configs_updated_at BEFORE UPDATE ON runtime_configs
402    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
403
404CREATE TRIGGER update_model_runtimes_updated_at BEFORE UPDATE ON model_runtimes
405    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
406
407CREATE TRIGGER update_model_repositories_updated_at BEFORE UPDATE ON model_repositories
408    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
409
410CREATE TRIGGER update_repository_models_updated_at BEFORE UPDATE ON repository_models
411    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
412
413CREATE TRIGGER update_global_configs_updated_at BEFORE UPDATE ON global_configs
414    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
415
416-- 创建清理过期数据的函数
417CREATE OR REPLACE FUNCTION cleanup_old_metrics()
418RETURNS void AS $$
419BEGIN
420    -- 清理30天前的系统指标
421    DELETE FROM system_metrics WHERE timestamp < NOW() - INTERVAL '30 days';
422
423    -- 清理30天前的应用指标
424    DELETE FROM application_metrics WHERE timestamp < NOW() - INTERVAL '30 days';
425
426    -- 清理7天前的运行时指标
427    DELETE FROM runtime_metrics WHERE timestamp < NOW() - INTERVAL '7 days';
428
429    -- 清理90天前的API使用记录
430    DELETE FROM api_usage WHERE timestamp < NOW() - INTERVAL '90 days';
431
432    -- 清理过期的用户会话
433    DELETE FROM user_sessions WHERE expires_at < NOW();
434END;
435$$ LANGUAGE plpgsql;
436
437-- 创建计算模型统计信息的函数
438CREATE OR REPLACE FUNCTION get_model_stats(model_uuid UUID)
439RETURNS JSON AS $$
440DECLARE
441    result JSON;
442BEGIN
443    SELECT json_build_object(
444        'total_requests', COALESCE(SUM(total_requests), 0),
445        'successful_requests', COALESCE(SUM(successful_requests), 0),
446        'failed_requests', COALESCE(SUM(failed_requests), 0),
447        'avg_inference_time_ms', COALESCE(AVG(avg_inference_time_ms), 0),
448        'avg_tokens_per_second', COALESCE(AVG(tokens_per_second), 0),
449        'last_activity', MAX(timestamp)
450    ) INTO result
451    FROM model_metrics
452    WHERE model_id = model_uuid
453    AND timestamp >= NOW() - INTERVAL '24 hours';
454
455    RETURN result;
456END;
457$$ LANGUAGE plpgsql;
458"#,
459];
460
461/// SQLite 迁移脚本
462pub const SQLITE_MIGRATIONS: &[&str] = &[
463    // 001_initial_schema.sql
464    r#"
465-- 创建模型表
466CREATE TABLE IF NOT EXISTS models (
467    id TEXT PRIMARY KEY,
468    name TEXT NOT NULL UNIQUE,
469    display_name TEXT NOT NULL,
470    description TEXT,
471    version TEXT NOT NULL,
472    model_type TEXT NOT NULL,
473    size_category TEXT NOT NULL,
474    file_size INTEGER NOT NULL,
475    provider TEXT NOT NULL,
476    license TEXT,
477    tags TEXT NOT NULL DEFAULT '[]',
478    languages TEXT NOT NULL DEFAULT '[]',
479    created_at TEXT NOT NULL DEFAULT (datetime('now')),
480    updated_at TEXT NOT NULL DEFAULT (datetime('now')),
481    file_path TEXT,
482    checksum TEXT,
483    download_url TEXT,
484    config TEXT NOT NULL DEFAULT '{}',
485    rating REAL,
486    download_count INTEGER NOT NULL DEFAULT 0,
487    is_official INTEGER NOT NULL DEFAULT 0
488);
489
490-- 创建已安装模型表
491CREATE TABLE IF NOT EXISTS installed_models (
492    id TEXT PRIMARY KEY,
493    model_id TEXT NOT NULL,
494    install_path TEXT NOT NULL,
495    installed_at TEXT NOT NULL DEFAULT (datetime('now')),
496    status TEXT NOT NULL,
497    port INTEGER,
498    process_id INTEGER,
499    last_used TEXT,
500    usage_count INTEGER NOT NULL DEFAULT 0,
501    FOREIGN KEY (model_id) REFERENCES models(id) ON DELETE CASCADE,
502    UNIQUE(model_id)
503);
504
505-- 创建可用模型表
506CREATE TABLE IF NOT EXISTS available_models (
507    id TEXT PRIMARY KEY,
508    model_id TEXT NOT NULL,
509    is_installed INTEGER NOT NULL DEFAULT 0,
510    published_at TEXT NOT NULL,
511    last_updated TEXT NOT NULL,
512    system_requirements TEXT NOT NULL,
513    FOREIGN KEY (model_id) REFERENCES models(id) ON DELETE CASCADE,
514    UNIQUE(model_id)
515);
516
517-- 创建运行时配置表
518CREATE TABLE IF NOT EXISTS runtime_configs (
519    id TEXT PRIMARY KEY,
520    name TEXT NOT NULL,
521    max_context_length INTEGER,
522    temperature REAL,
523    top_p REAL,
524    top_k INTEGER,
525    max_tokens INTEGER,
526    stop_sequences TEXT NOT NULL DEFAULT '[]',
527    batch_size INTEGER,
528    max_concurrent_requests INTEGER,
529    gpu_device_ids TEXT NOT NULL DEFAULT '[]',
530    memory_limit_mb INTEGER,
531    enable_streaming INTEGER NOT NULL DEFAULT 1,
532    custom_params TEXT NOT NULL DEFAULT '{}',
533    created_at TEXT NOT NULL DEFAULT (datetime('now')),
534    updated_at TEXT NOT NULL DEFAULT (datetime('now'))
535);
536
537-- 创建模型运行时表
538CREATE TABLE IF NOT EXISTS model_runtimes (
539    id TEXT PRIMARY KEY,
540    model_id TEXT NOT NULL,
541    runtime_config_id TEXT NOT NULL,
542    name TEXT NOT NULL,
543    port INTEGER NOT NULL,
544    process_id INTEGER,
545    started_at TEXT,
546    stopped_at TEXT,
547    status TEXT NOT NULL,
548    health_endpoint TEXT NOT NULL,
549    api_endpoint TEXT NOT NULL,
550    log_file TEXT,
551    environment TEXT NOT NULL DEFAULT '{}',
552    created_at TEXT NOT NULL DEFAULT (datetime('now')),
553    updated_at TEXT NOT NULL DEFAULT (datetime('now')),
554    FOREIGN KEY (model_id) REFERENCES models(id) ON DELETE CASCADE,
555    FOREIGN KEY (runtime_config_id) REFERENCES runtime_configs(id) ON DELETE CASCADE,
556    UNIQUE(model_id, port)
557);
558
559-- 创建运行时指标表
560CREATE TABLE IF NOT EXISTS runtime_metrics (
561    id TEXT PRIMARY KEY,
562    runtime_id TEXT NOT NULL,
563    timestamp TEXT NOT NULL DEFAULT (datetime('now')),
564    cpu_usage_percent REAL NOT NULL,
565    memory_usage_mb INTEGER NOT NULL,
566    gpu_usage_percent REAL,
567    gpu_memory_usage_mb INTEGER,
568    active_connections INTEGER NOT NULL,
569    total_requests INTEGER NOT NULL,
570    successful_requests INTEGER NOT NULL,
571    failed_requests INTEGER NOT NULL,
572    avg_response_time_ms REAL NOT NULL,
573    throughput_rps REAL NOT NULL,
574    queue_length INTEGER NOT NULL,
575    FOREIGN KEY (runtime_id) REFERENCES model_runtimes(id) ON DELETE CASCADE
576);
577
578-- 创建运行时事件表
579CREATE TABLE IF NOT EXISTS runtime_events (
580    id TEXT PRIMARY KEY,
581    runtime_id TEXT NOT NULL,
582    event_type TEXT NOT NULL,
583    timestamp TEXT NOT NULL DEFAULT (datetime('now')),
584    message TEXT NOT NULL,
585    details TEXT,
586    severity TEXT NOT NULL,
587    FOREIGN KEY (runtime_id) REFERENCES model_runtimes(id) ON DELETE CASCADE
588);
589
590-- 创建索引
591CREATE INDEX IF NOT EXISTS idx_models_name ON models(name);
592CREATE INDEX IF NOT EXISTS idx_models_provider ON models(provider);
593CREATE INDEX IF NOT EXISTS idx_models_model_type ON models(model_type);
594CREATE INDEX IF NOT EXISTS idx_models_created_at ON models(created_at);
595CREATE INDEX IF NOT EXISTS idx_installed_models_model_id ON installed_models(model_id);
596CREATE INDEX IF NOT EXISTS idx_installed_models_status ON installed_models(status);
597CREATE INDEX IF NOT EXISTS idx_available_models_model_id ON available_models(model_id);
598CREATE INDEX IF NOT EXISTS idx_runtime_metrics_runtime_id ON runtime_metrics(runtime_id);
599CREATE INDEX IF NOT EXISTS idx_runtime_metrics_timestamp ON runtime_metrics(timestamp);
600CREATE INDEX IF NOT EXISTS idx_runtime_events_runtime_id ON runtime_events(runtime_id);
601CREATE INDEX IF NOT EXISTS idx_runtime_events_timestamp ON runtime_events(timestamp);
602"#,
603
604    // 其他 SQLite 迁移脚本可以根据需要添加...
605];
606
607/// MySQL 迁移脚本
608pub const MYSQL_MIGRATIONS: &[&str] = &[
609    // MySQL 迁移脚本可以根据需要添加...
610];
611
612use sqlx::{Database, Pool};
613use async_trait::async_trait;
614
615#[async_trait]
616pub trait MigrationRunner<DB: Database> {
617    async fn run_migrations(pool: &Pool<DB>) -> Result<(), sqlx::Error>;
618    async fn get_migration_version(pool: &Pool<DB>) -> Result<i32, sqlx::Error>;
619}
620
621#[cfg(feature = "postgres")]
622pub struct PostgresMigrationRunner;
623
624#[cfg(feature = "postgres")]
625#[async_trait]
626impl MigrationRunner<sqlx::Postgres> for PostgresMigrationRunner {
627    async fn run_migrations(pool: &Pool<sqlx::Postgres>) -> Result<(), sqlx::Error> {
628        // 创建迁移历史表
629        sqlx::query(r#"
630            CREATE TABLE IF NOT EXISTS _migration_history (
631                id SERIAL PRIMARY KEY,
632                version INTEGER NOT NULL UNIQUE,
633                name VARCHAR(255) NOT NULL,
634                applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
635            )
636        "#)
637        .execute(pool)
638        .await?;
639
640        // 获取当前版本
641        let current_version = Self::get_migration_version(pool).await.unwrap_or(0);
642
643        // 运行所有高于当前版本的迁移
644        for (index, migration) in POSTGRES_MIGRATIONS.iter().enumerate() {
645            let version = (index + 1) as i32;
646            if version > current_version {
647                // 执行迁移
648                sqlx::query(migration).execute(pool).await?;
649
650                // 记录迁移历史
651                sqlx::query(r#"
652                    INSERT INTO _migration_history (version, name)
653                    VALUES ($1, $2)
654                "#)
655                .bind(version)
656                .bind(format!("migration_{:03}", version))
657                .execute(pool)
658                .await?;
659
660                println!("Applied migration version {}", version);
661            }
662        }
663
664        Ok(())
665    }
666
667    async fn get_migration_version(pool: &Pool<sqlx::Postgres>) -> Result<i32, sqlx::Error> {
668        let row: Option<(i32,)> = sqlx::query_as(
669            "SELECT MAX(version) FROM _migration_history"
670        )
671        .fetch_optional(pool)
672        .await?;
673
674        Ok(row.map(|(v,)| v).unwrap_or(0))
675    }
676}
677
678#[cfg(feature = "sqlite")]
679pub struct SqliteMigrationRunner;
680
681#[cfg(feature = "sqlite")]
682#[async_trait]
683impl MigrationRunner<sqlx::Sqlite> for SqliteMigrationRunner {
684    async fn run_migrations(pool: &Pool<sqlx::Sqlite>) -> Result<(), sqlx::Error> {
685        // 创建迁移历史表
686        sqlx::query(r#"
687            CREATE TABLE IF NOT EXISTS _migration_history (
688                id INTEGER PRIMARY KEY AUTOINCREMENT,
689                version INTEGER NOT NULL UNIQUE,
690                name TEXT NOT NULL,
691                applied_at TEXT NOT NULL DEFAULT (datetime('now'))
692            )
693        "#)
694        .execute(pool)
695        .await?;
696
697        // 获取当前版本
698        let current_version = Self::get_migration_version(pool).await.unwrap_or(0);
699
700        // 运行所有高于当前版本的迁移
701        for (index, migration) in SQLITE_MIGRATIONS.iter().enumerate() {
702            let version = (index + 1) as i32;
703            if version > current_version {
704                // 执行迁移
705                sqlx::query(migration).execute(pool).await?;
706
707                // 记录迁移历史
708                sqlx::query(r#"
709                    INSERT INTO _migration_history (version, name)
710                    VALUES (?1, ?2)
711                "#)
712                .bind(version)
713                .bind(format!("migration_{:03}", version))
714                .execute(pool)
715                .await?;
716
717                println!("Applied migration version {}", version);
718            }
719        }
720
721        Ok(())
722    }
723
724    async fn get_migration_version(pool: &Pool<sqlx::Sqlite>) -> Result<i32, sqlx::Error> {
725        let row: Option<(Option<i32>,)> = sqlx::query_as(
726            "SELECT MAX(version) FROM _migration_history"
727        )
728        .fetch_optional(pool)
729        .await?;
730
731        Ok(row.and_then(|(v,)| v).unwrap_or(0))
732    }
733}