diff --git a/pkg/indexstorage/indexstorage.go b/pkg/indexstorage/indexstorage.go index fc1422149..53f38c3d1 100644 --- a/pkg/indexstorage/indexstorage.go +++ b/pkg/indexstorage/indexstorage.go @@ -35,7 +35,11 @@ func NewIndexStorage(providerType string) (IndexStorage, error) { case redis.ProviderType: return redis.NewProvider(viper.GetString("redis_server.address"), viper.GetString("redis_server.port"), viper.GetString("redis_server.password")) case mysql.ProviderType: - return mysql.NewProvider(viper.GetString("search_index.mysql.dsn")) + return mysql.NewProvider(viper.GetString("search_index.mysql.dsn"), + mysql.WithConnMaxIdleTime(viper.GetDuration("search_index.mysql.conn_max_idletime")), + mysql.WithConnMaxLifetime(viper.GetDuration("search_index.mysql.conn_max_lifetime")), + mysql.WithMaxIdleConns(viper.GetInt("search_index.mysql.max_idle_connections")), + mysql.WithMaxOpenConns(viper.GetInt("search_index.mysql.max_open_connections"))) default: return nil, fmt.Errorf("invalid index storage provider type: %v", providerType) } diff --git a/pkg/indexstorage/mysql/mysql.go b/pkg/indexstorage/mysql/mysql.go index 05b0d27f5..812aaf11e 100644 --- a/pkg/indexstorage/mysql/mysql.go +++ b/pkg/indexstorage/mysql/mysql.go @@ -21,7 +21,6 @@ import ( "github.com/jmoiron/sqlx" "github.com/sigstore/rekor/pkg/log" - "github.com/spf13/viper" // this imports the mysql driver for go _ "github.com/go-sql-driver/mysql" @@ -46,7 +45,7 @@ type IndexStorageProvider struct { db *sqlx.DB } -func NewProvider(dsn string) (*IndexStorageProvider, error) { +func NewProvider(dsn string, opts ...Options) (*IndexStorageProvider, error) { var err error provider := &IndexStorageProvider{} provider.db, err = sqlx.Open(ProviderType, dsn) @@ -57,10 +56,12 @@ func NewProvider(dsn string) (*IndexStorageProvider, error) { return nil, err } - provider.db.SetConnMaxIdleTime(viper.GetDuration("search_index.mysql.conn_max_idletime")) - provider.db.SetConnMaxLifetime(viper.GetDuration("search_index.mysql.conn_max_lifetime")) - provider.db.SetMaxOpenConns(viper.GetInt("search_index.mysql.max_open_connections")) - provider.db.SetMaxIdleConns(viper.GetInt("search_index.mysql.max_idle_connections")) + for _, o := range opts { + o.applyConnMaxIdleTime(provider.db) + o.applyConnMaxLifetime(provider.db) + o.applyMaxIdleConns(provider.db) + o.applyMaxOpenConns(provider.db) + } if _, err := provider.db.Exec(createTableStmt); err != nil { return nil, fmt.Errorf("create table if not exists failed: %w", err) diff --git a/pkg/indexstorage/mysql/options.go b/pkg/indexstorage/mysql/options.go new file mode 100644 index 000000000..7e307cf9b --- /dev/null +++ b/pkg/indexstorage/mysql/options.go @@ -0,0 +1,116 @@ +// Copyright 2023 The Sigstore Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package mysql + +import ( + "time" + + "github.com/jmoiron/sqlx" +) + +// Options configures connections to the MySQL index storage system +type Options interface { + applyConnMaxIdleTime(*sqlx.DB) + applyConnMaxLifetime(*sqlx.DB) + applyMaxIdleConns(*sqlx.DB) + applyMaxOpenConns(*sqlx.DB) +} + +// NoOpOptionImpl implements the MySQLOption interfaces as no-ops. +type noOpOptionImpl struct{} + +// applyConnMaxIdleTime is a no-op required to fully implement the requisite interfaces +func (noOpOptionImpl) applyConnMaxIdleTime(_ *sqlx.DB) {} + +// ApplyConnMaxLifetime is a no-op required to fully implement the requisite interfaces +func (noOpOptionImpl) applyConnMaxLifetime(_ *sqlx.DB) {} + +// ApplyMaxOpenConns is a no-op required to fully implement the requisite interfaces +func (noOpOptionImpl) applyMaxOpenConns(_ *sqlx.DB) {} + +// ApplyMaxIdleConns is a no-op required to fully implement the requisite interfaces +func (noOpOptionImpl) applyMaxIdleConns(_ *sqlx.DB) {} + +// RequestConnMaxIdleTime implements the functional option pattern for specifying the maximum connection idle time +type RequestConnMaxIdleTime struct { + noOpOptionImpl + idleTime time.Duration +} + +// applyConnMaxIdleTime sets the maximum connection idle time +func (r RequestConnMaxIdleTime) applyConnMaxIdleTime(db *sqlx.DB) { + if db != nil { + db.SetConnMaxIdleTime(r.idleTime) + } +} + +// WithConnMaxIdleTime specifies the maximum connection idle time +func WithConnMaxIdleTime(idleTime time.Duration) RequestConnMaxIdleTime { + return RequestConnMaxIdleTime{idleTime: idleTime} +} + +// RequestConnMaxLifetime implements the functional option pattern for specifying the maximum connection lifetime +type RequestConnMaxLifetime struct { + noOpOptionImpl + lifetime time.Duration +} + +// ApplyConnMaxLifetime sets the maximum connection lifetime +func (r RequestConnMaxLifetime) applyConnMaxLifetime(db *sqlx.DB) { + if db != nil { + db.SetConnMaxLifetime(r.lifetime) + } +} + +// WithConnMaxLifetime specifies the maximum connection lifetime +func WithConnMaxLifetime(lifetime time.Duration) RequestConnMaxLifetime { + return RequestConnMaxLifetime{lifetime: lifetime} +} + +// RequestMaxIdleConns implements the functional option pattern for specifying the maximum number of idle connections +type RequestMaxIdleConns struct { + noOpOptionImpl + idleConns int +} + +// ApplyMaxIdleConns sets the maximum number of idle connections +func (r RequestMaxIdleConns) applyMaxIdleConns(db *sqlx.DB) { + if db != nil { + db.SetMaxIdleConns(r.idleConns) + } +} + +// WithMaxIdleConns specifies the maximum number of idle connections +func WithMaxIdleConns(idleConns int) RequestMaxIdleConns { + return RequestMaxIdleConns{idleConns: idleConns} +} + +// RequestMaxOpenConns implements the functional option pattern for specifying the maximum number of open connections +type RequestMaxOpenConns struct { + noOpOptionImpl + openConns int +} + +// applyMaxOpenConns sets the maximum number of open connections +func (r RequestMaxOpenConns) applyMaxOpenConns(db *sqlx.DB) { + if db != nil { + db.SetMaxOpenConns(r.openConns) + } +} + +// WithMaxOpenConns specifies the maximum number of open connections +func WithMaxOpenConns(openConns int) RequestMaxOpenConns { + return RequestMaxOpenConns{openConns: openConns} +}