From 9081e7c0ce73be0f7df1b4dbc06c17fba967ec26 Mon Sep 17 00:00:00 2001 From: Ray-Barker <56350191+Ray-Barker@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:02:25 +0000 Subject: [PATCH 1/2] Add no lock parameter for Postgres --- database/postgres/postgres.go | 17 ++++++++++ database/postgres/postgres_test.go | 51 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 9e6d6277f..cbac49e33 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -53,6 +53,7 @@ type Config struct { migrationsTableName string StatementTimeout time.Duration MultiStatementMaxSize int + NoLock bool } type Postgres struct { @@ -202,6 +203,14 @@ func (p *Postgres) Open(url string) (database.Driver, error) { } } + noLock := false + if s := purl.Query().Get("x-no-lock"); len(s) > 0 { + noLock, err = strconv.ParseBool(s) + if err != nil { + return nil, fmt.Errorf("Unable to parse option no-lock: %w", err) + } + } + px, err := WithInstance(db, &Config{ DatabaseName: purl.Path, MigrationsTable: migrationsTable, @@ -209,6 +218,7 @@ func (p *Postgres) Open(url string) (database.Driver, error) { StatementTimeout: time.Duration(statementTimeout) * time.Millisecond, MultiStatementEnabled: multiStatementEnabled, MultiStatementMaxSize: multiStatementMaxSize, + NoLock: noLock, }) if err != nil { @@ -234,6 +244,9 @@ func (p *Postgres) Close() error { // https://www.postgresql.org/docs/9.6/static/explicit-locking.html#ADVISORY-LOCKS func (p *Postgres) Lock() error { return database.CasRestoreOnErr(&p.isLocked, false, true, database.ErrLocked, func() error { + if p.config.NoLock { + return nil + } aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName) if err != nil { return err @@ -251,6 +264,9 @@ func (p *Postgres) Lock() error { func (p *Postgres) Unlock() error { return database.CasRestoreOnErr(&p.isLocked, true, false, database.ErrNotLocked, func() error { + if p.config.NoLock { + return nil + } aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName) if err != nil { return err @@ -453,6 +469,7 @@ func (p *Postgres) Drop() (err error) { // Note that this function locks the database, which deviates from the usual // convention of "caller locks" in the Postgres type. func (p *Postgres) ensureVersionTable() (err error) { + if err = p.Lock(); err != nil { return err } diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 65395cc7e..8a37f26b8 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -642,6 +642,57 @@ func TestPostgres_Lock(t *testing.T) { }) } +func TestNoLockParamValidation(t *testing.T) { + ip := "127.0.0.1" + port := 5432 + addr := fmt.Sprintf("postgres://root:root@%v:%v/public", ip, port) + p := &Postgres{} + _, err := p.Open(addr + "?x-no-lock=not-a-bool") + if !errors.Is(err, strconv.ErrSyntax) { + t.Fatal("Expected syntax error when passing a non-bool as x-no-lock parameter") + } +} + +func TestNoLockWorks(t *testing.T) { + dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { + ip, port, err := c.FirstPort() + if err != nil { + t.Fatal(err) + } + + addr := pgConnectionString(ip, port) + p := &Postgres{} + d, err := p.Open(addr) + if err != nil { + t.Fatal(err) + } + + lock := d.(*Postgres) + + p = &Postgres{} + d, err = p.Open(addr + "&x-no-lock=true") + if err != nil { + t.Fatal(err) + } + + noLock := d.(*Postgres) + + // Should be possible to take real lock and no-lock at the same time + if err = lock.Lock(); err != nil { + t.Fatal(err) + } + if err = noLock.Lock(); err != nil { + t.Fatal(err) + } + if err = lock.Unlock(); err != nil { + t.Fatal(err) + } + if err = noLock.Unlock(); err != nil { + t.Fatal(err) + } + }) +} + func TestWithInstance_Concurrent(t *testing.T) { dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { ip, port, err := c.FirstPort() From 22e4ef690563aeae1a6d49d0384454f1bff58dce Mon Sep 17 00:00:00 2001 From: Ray-Barker <56350191+Ray-Barker@users.noreply.github.com> Date: Fri, 19 Jan 2024 16:14:20 +0000 Subject: [PATCH 2/2] Fix lint error --- database/postgres/postgres.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index cbac49e33..ffdbcb1ac 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -53,7 +53,7 @@ type Config struct { migrationsTableName string StatementTimeout time.Duration MultiStatementMaxSize int - NoLock bool + NoLock bool } type Postgres struct {