package gameking import ( "errors" "net/http" "strings" "chatapp3-golang/internal/model" "gorm.io/gorm" "gorm.io/gorm/clause" ) // ensureActivityEnableSafetyTx 把“索引已在线”和“GC 没在删除”纳入首次启用事务。 // 它与 GC 删除事务锁同一控制行,因此两个并发请求不会同时各自通过旧状态检查。 func ensureActivityEnableSafetyTx(tx *gorm.DB) error { if err := requireBackfillIndexOnDB(tx); err != nil { return err } var run model.TaskCenterArchiveGCRun if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("id = ?", uint8(1)).First(&run).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return NewAppError(http.StatusServiceUnavailable, "archive_gc_migration_required", "migration 060 archive GC safety state is required before enabling game king") } return NewAppError(http.StatusServiceUnavailable, "archive_gc_state_check_failed", "cannot verify archive GC state before enabling game king") } if strings.EqualFold(run.Status, "RUNNING") { return NewAppError(http.StatusConflict, "archive_gc_running", "pause task center archive GC before enabling game king") } return nil } func requireBackfillIndexOnDB(db *gorm.DB) error { var columns []backfillIndexColumn if err := db.Raw(` SELECT COLUMN_NAME, SEQ_IN_INDEX, SUB_PART, INDEX_TYPE, IS_VISIBLE FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'task_center_event_archive_outbox' AND INDEX_NAME = ? ORDER BY SEQ_IN_INDEX ASC`, taskCenterGameKingBackfillIndex).Scan(&columns).Error; err != nil { return NewAppError(http.StatusServiceUnavailable, "backfill_index_check_failed", "cannot verify the required task center backfill index") } required := [...]string{"sys_origin", "event_type", "occurred_at", "id"} if len(columns) == len(required) { valid := true for index, requiredName := range required { column := columns[index] if column.SeqInIndex != index+1 || !strings.EqualFold(column.ColumnName, requiredName) || column.SubPart != nil || !strings.EqualFold(column.IndexType, "BTREE") || !strings.EqualFold(column.IsVisible, "YES") { valid = false break } } if valid { return nil } } return NewAppError( http.StatusServiceUnavailable, "backfill_index_required", "migration 058 backfill index (sys_origin,event_type,occurred_at,id) must be online before enabling or backfill", ) }