diff --git a/Makefile b/Makefile index 8e8690a0a..36e85e454 100644 --- a/Makefile +++ b/Makefile @@ -429,6 +429,12 @@ start-local: docker-compose -f docker-compose.local.yml up -d stop-local: docker-compose -f docker-compose.local.yml stop +start-mysql: + docker-compose -f docker-compose.mysql.yml up -d mysql +stop-mysql: + docker-compose -f docker-compose.mysql.yml stop mysql +logs-mysql: + docker-compose -f docker-compose.mysql.yml logs -f mysql docker-local: docker-local-bookworm docker-local-all: docker-local-bookworm docker-local-bullseye docker-local-buster docker-local-jammy docker-local-bookworm: diff --git a/docker-compose.mariadb.yml b/docker-compose.mariadb.yml index c330b8d14..0c4ef78c9 100644 --- a/docker-compose.mariadb.yml +++ b/docker-compose.mariadb.yml @@ -101,21 +101,6 @@ services: MYSQL_PASSWORD: "photoprism" MYSQL_ROOT_PASSWORD: "photoprism" - ## MySQL 8 Database Server - ## Docs: https://dev.mysql.com/doc/refman/8.0/en/ - mysql: - image: mysql:8 - command: mysqld --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 - expose: - - "4001" # database port (internal) - volumes: - - "./scripts/sql/mariadb-init.sql:/docker-entrypoint-initdb.d/init.sql" - environment: - MYSQL_DATABASE: "photoprism" - MYSQL_USER: "photoprism" - MYSQL_PASSWORD: "photoprism" - MYSQL_ROOT_PASSWORD: "photoprism" - ## Join shared "photoprism-develop" network networks: default: diff --git a/docker-compose.mysql.yml b/docker-compose.mysql.yml new file mode 100644 index 000000000..c813919af --- /dev/null +++ b/docker-compose.mysql.yml @@ -0,0 +1,22 @@ +version: '3.5' + +# MySQL versions for testing compatibility +services: + ## MySQL 8 Database Server + ## Docs: https://dev.mysql.com/doc/refman/8.0/en/ + mysql: + image: mysql:8 + command: mysqld --port=4001 --innodb-buffer-pool-size=256M --transaction-isolation=READ-COMMITTED --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --max-connections=512 --innodb-rollback-on-timeout=OFF --innodb-lock-wait-timeout=120 + expose: + - "4001" # database port (internal) + environment: + MYSQL_DATABASE: "photoprism" + MYSQL_USER: "photoprism" + MYSQL_PASSWORD: "photoprism" + MYSQL_ROOT_PASSWORD: "photoprism" + +## Join shared "photoprism-develop" network +networks: + default: + name: photoprism-develop + external: true diff --git a/internal/config/config_db.go b/internal/config/config_db.go index 219e7258b..fcf6bbfad 100644 --- a/internal/config/config_db.go +++ b/internal/config/config_db.go @@ -10,14 +10,14 @@ import ( "strings" "time" - "github.com/photoprism/photoprism/pkg/clean" - "github.com/jinzhu/gorm" _ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/sqlite" "github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/mutex" + "github.com/photoprism/photoprism/pkg/clean" + "github.com/photoprism/photoprism/pkg/txt" ) // SQL Databases. @@ -307,9 +307,11 @@ func (c *Config) InitTestDb() { // connectDb establishes a database connection. func (c *Config) connectDb() error { + // Make sure this is not running twice. mutex.Db.Lock() defer mutex.Db.Unlock() + // Get database driver and data source name. dbDriver := c.DatabaseDriver() dbDsn := c.DatabaseDsn() @@ -321,6 +323,7 @@ func (c *Config) connectDb() error { return errors.New("config: database DSN not specified") } + // Open database connection. db, err := gorm.Open(dbDriver, dbDsn) if err != nil || db == nil { for i := 1; i <= 12; i++ { @@ -338,12 +341,33 @@ func (c *Config) connectDb() error { } } + // Configure database logging. db.LogMode(false) db.SetLogger(log) + // Set database connection parameters. db.DB().SetMaxOpenConns(c.DatabaseConns()) db.DB().SetMaxIdleConns(c.DatabaseConnsIdle()) - db.DB().SetConnMaxLifetime(10 * time.Minute) + db.DB().SetConnMaxLifetime(time.Hour) + + // Check database server version. + switch dbDriver { + case MySQL: + type Res struct { + Value string `gorm:"column:Value;"` + } + var res Res + if err = db.Raw("SHOW VARIABLES LIKE 'innodb_version'").Scan(&res).Error; err != nil { + return err + } else if v := strings.Split(res.Value, "."); len(v) < 3 { + log.Warnf("config: unknown database server version") + } else if major := txt.UInt(v[0]); major < 10 { + err = fmt.Errorf("config: MySQL %s is not supported, please upgrade to MariaDB 10.5.12 or later (https://docs.photoprism.app/getting-started/#databases)", res.Value) + return err + } else if txt.UInt(v[1]) <= 5 && txt.UInt(v[2]) <= 12 { + log.Errorf("config: MariaDB %s is not supported, please upgrade to MariaDB 10.5.12 or later (https://docs.photoprism.app/getting-started/#databases)", res.Value) + } + } c.db = db