From 9220458cbfe3d45026cf965f80e6c9897a301950 Mon Sep 17 00:00:00 2001 From: Sergey Prika Date: Tue, 6 May 2025 13:53:20 +0300 Subject: [PATCH 1/3] Add no lock parameter for Postgres --- database/postgres/postgres.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/database/postgres/postgres.go b/database/postgres/postgres.go index 5e4519115..cfeb7306e 100644 --- a/database/postgres/postgres.go +++ b/database/postgres/postgres.go @@ -52,6 +52,7 @@ type Config struct { migrationsTableName string StatementTimeout time.Duration MultiStatementMaxSize int + NoLock bool } type Postgres struct { @@ -201,6 +202,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, @@ -208,6 +217,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 { @@ -233,6 +243,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 @@ -250,6 +263,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 From 1ca430cd53332bdc6cd4b0a93ab91f9967ad094e Mon Sep 17 00:00:00 2001 From: Sergey Prika Date: Tue, 6 May 2025 13:54:03 +0300 Subject: [PATCH 2/3] Add test for no lock paramter for Postgres --- database/postgres/postgres_test.go | 51 ++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/database/postgres/postgres_test.go b/database/postgres/postgres_test.go index 0eea47e94..b4e7d8ab6 100644 --- a/database/postgres/postgres_test.go +++ b/database/postgres/postgres_test.go @@ -668,6 +668,57 @@ func testPostgresLock(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 testWithInstanceConcurrent(t *testing.T) { dktesting.ParallelTest(t, specs, func(t *testing.T, c dktest.ContainerInfo) { ip, port, err := c.FirstPort() From 5d3e16c8fcf389457a32a5096e58132435850fb8 Mon Sep 17 00:00:00 2001 From: Sergey Prika Date: Tue, 6 May 2025 13:57:40 +0300 Subject: [PATCH 3/3] Add README description for x-no-lock parameter for Postgres --- database/postgres/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/database/postgres/README.md b/database/postgres/README.md index bc823f4e1..47fa534ed 100644 --- a/database/postgres/README.md +++ b/database/postgres/README.md @@ -9,6 +9,7 @@ | `x-statement-timeout` | `StatementTimeout` | Abort any statement that takes more than the specified number of milliseconds | | `x-multi-statement` | `MultiStatementEnabled` | Enable multi-statement execution (default: false) | | `x-multi-statement-max-size` | `MultiStatementMaxSize` | Maximum size of single statement in bytes (default: 10MB) | +| `x-no-lock` | `NoLock` | Prevent acquiring advisory lock (default: false) | | `dbname` | `DatabaseName` | The name of the database to connect to | | `search_path` | | This variable specifies the order in which schemas are searched when an object is referenced by a simple name with no schema specified. | | `user` | | The user to sign in as |