From 529973649c44c9943b8c1b04ae7b24b0883f54db Mon Sep 17 00:00:00 2001 From: John Nielsen Date: Tue, 23 Apr 2024 14:53:50 -0600 Subject: [PATCH 1/2] PG remote backend: use a unique creation lock for each database schema --- internal/backend/remote-state/pg/client.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/backend/remote-state/pg/client.go b/internal/backend/remote-state/pg/client.go index 2ce79cc4ba6b..1ef3181ff18b 100644 --- a/internal/backend/remote-state/pg/client.go +++ b/internal/backend/remote-state/pg/client.go @@ -88,15 +88,16 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) { return nil } - // Try to acquire locks for the existing row `id` and the creation lock `-1`. - query := `SELECT %s.id, pg_try_advisory_lock(%s.id), pg_try_advisory_lock(-1) FROM %s.%s WHERE %s.name = $1` - row := c.Client.QueryRow(fmt.Sprintf(query, statesTableName, statesTableName, c.SchemaName, statesTableName, statesTableName), c.Name) + // Try to acquire locks for the existing row `id` and the creation lock. + creation_lock := c.SchemaName + "_create" + query := `SELECT %s.id, pg_try_advisory_lock(%s.id), pg_try_advisory_lock(%s) FROM %s.%s WHERE %s.name = $1` + row := c.Client.QueryRow(fmt.Sprintf(query, statesTableName, statesTableName, creation_lock, c.SchemaName, statesTableName, statesTableName), c.Name) var pgLockId, didLock, didLockForCreate []byte err = row.Scan(&pgLockId, &didLock, &didLockForCreate) switch { case err == sql.ErrNoRows: // No rows means we're creating the workspace. Take the creation lock. - innerRow := c.Client.QueryRow(`SELECT pg_try_advisory_lock(-1)`) + innerRow := c.Client.QueryRow(fmt.Sprintf(`SELECT pg_try_advisory_lock(%s)`, creation_lock)) var innerDidLock []byte err := innerRow.Scan(&innerDidLock) if err != nil { @@ -105,12 +106,12 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) { if string(innerDidLock) == "false" { return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Already locked for workspace creation: %s", c.Name)} } - info.Path = "-1" + info.Path = creation_lock case err != nil: return "", &statemgr.LockError{Info: info, Err: err} case string(didLock) == "false": // Existing workspace is already locked. Release the attempted creation lock. - lockUnlock("-1") + lockUnlock(creation_lock) return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Workspace is already locked: %s", c.Name)} case string(didLockForCreate) == "false": // Someone has the creation lock already. Release the existing workspace because it might not be safe to touch. @@ -118,7 +119,7 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) { return "", &statemgr.LockError{Info: info, Err: fmt.Errorf("Cannot lock workspace; already locked for workspace creation: %s", c.Name)} default: // Existing workspace is now locked. Release the attempted creation lock. - lockUnlock("-1") + lockUnlock(creation_lock) info.Path = string(pgLockId) } c.info = info From d4ca8381a3675fb8ac47d0b2807f5268668588b2 Mon Sep 17 00:00:00 2001 From: John Nielsen Date: Tue, 23 Apr 2024 18:49:10 -0600 Subject: [PATCH 2/2] Fix missed fmt.Sprintf, whitespace agreement --- internal/backend/remote-state/pg/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/backend/remote-state/pg/client.go b/internal/backend/remote-state/pg/client.go index 1ef3181ff18b..c16f3677cec4 100644 --- a/internal/backend/remote-state/pg/client.go +++ b/internal/backend/remote-state/pg/client.go @@ -89,7 +89,7 @@ func (c *RemoteClient) Lock(info *statemgr.LockInfo) (string, error) { } // Try to acquire locks for the existing row `id` and the creation lock. - creation_lock := c.SchemaName + "_create" + creation_lock := fmt.Sprintf("%s_create", c.SchemaName) query := `SELECT %s.id, pg_try_advisory_lock(%s.id), pg_try_advisory_lock(%s) FROM %s.%s WHERE %s.name = $1` row := c.Client.QueryRow(fmt.Sprintf(query, statesTableName, statesTableName, creation_lock, c.SchemaName, statesTableName, statesTableName), c.Name) var pgLockId, didLock, didLockForCreate []byte