Skip to content

Commit e61aaf1

Browse files
committed
fixing local lock optimization implementation
1 parent 9814da9 commit e61aaf1

File tree

3 files changed

+22
-25
lines changed

3 files changed

+22
-25
lines changed

database/pgx/pgx.go

+7-10
Original file line numberDiff line numberDiff line change
@@ -221,44 +221,41 @@ func (p *Postgres) Close() error {
221221

222222
// https://www.postgresql.org/docs/9.6/static/explicit-locking.html#ADVISORY-LOCKS
223223
func (p *Postgres) Lock() error {
224-
if p.isLocked.Load() {
224+
if !p.isLocked.CAS(false, true) {
225225
return database.ErrLocked
226226
}
227227

228228
aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName)
229229
if err != nil {
230+
p.isLocked.Store(false)
230231
return err
231232
}
232233

233234
// This will wait indefinitely until the lock can be acquired.
234235
query := `SELECT pg_advisory_lock($1)`
235236
if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil {
237+
p.isLocked.Store(false)
236238
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)}
237239
}
238-
239-
if !p.isLocked.CAS(false, true) {
240-
return database.ErrLocked
241-
}
242240
return nil
243241
}
244242

245243
func (p *Postgres) Unlock() error {
246-
if !p.isLocked.Load() {
247-
return nil
244+
if !p.isLocked.CAS(true, false) {
245+
return database.ErrNotLocked
248246
}
249247

250248
aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName)
251249
if err != nil {
250+
p.isLocked.Store(true)
252251
return err
253252
}
254253

255254
query := `SELECT pg_advisory_unlock($1)`
256255
if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil {
256+
p.isLocked.Store(true)
257257
return &database.Error{OrigErr: err, Query: []byte(query)}
258258
}
259-
if !p.isLocked.CAS(true, false) {
260-
return database.ErrNotLocked
261-
}
262259
return nil
263260
}
264261

database/postgres/postgres.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -215,39 +215,40 @@ func (p *Postgres) Close() error {
215215

216216
// https://www.postgresql.org/docs/9.6/static/explicit-locking.html#ADVISORY-LOCKS
217217
func (p *Postgres) Lock() error {
218-
if p.isLocked.Load() {
218+
if !p.isLocked.CAS(false, true) {
219219
return database.ErrLocked
220220
}
221221

222222
aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName)
223223
if err != nil {
224+
p.isLocked.Store(false)
224225
return err
225226
}
226227

227228
// This will wait indefinitely until the lock can be acquired.
228229
query := `SELECT pg_advisory_lock($1)`
229230
if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil {
231+
p.isLocked.Store(false)
230232
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)}
231233
}
232234

233-
if !p.isLocked.CAS(false, true) {
234-
return database.ErrLocked
235-
}
236235
return nil
237236
}
238237

239238
func (p *Postgres) Unlock() error {
240-
if !p.isLocked.Load() {
241-
return nil
239+
if !p.isLocked.CAS(true, false) {
240+
return database.ErrLocked
242241
}
243242

244243
aid, err := database.GenerateAdvisoryLockId(p.config.DatabaseName, p.config.migrationsSchemaName, p.config.migrationsTableName)
245244
if err != nil {
245+
p.isLocked.Store(true)
246246
return err
247247
}
248248

249249
query := `SELECT pg_advisory_unlock($1)`
250250
if _, err := p.conn.ExecContext(context.Background(), query, aid); err != nil {
251+
p.isLocked.Store(true)
251252
return &database.Error{OrigErr: err, Query: []byte(query)}
252253
}
253254
if !p.isLocked.CAS(true, false) {

database/sqlserver/sqlserver.go

+8-9
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ func (ss *SQLServer) Close() error {
155155

156156
// Lock creates an advisory local on the database to prevent multiple migrations from running at the same time.
157157
func (ss *SQLServer) Lock() error {
158-
if ss.isLocked.Load() {
158+
if !ss.isLocked.CAS(false, true) {
159159
return database.ErrLocked
160160
}
161161

@@ -171,36 +171,35 @@ func (ss *SQLServer) Lock() error {
171171

172172
var status mssql.ReturnStatus
173173
if _, err = ss.conn.ExecContext(context.Background(), query, aid, &status); err == nil && status > -1 {
174-
if !ss.isLocked.CAS(false, true) {
175-
return database.ErrLocked
176-
}
177174
return nil
178175
} else if err != nil {
176+
ss.isLocked.Store(false)
179177
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)}
180178
} else {
179+
ss.isLocked.Store(false)
181180
return &database.Error{Err: fmt.Sprintf("try lock failed with error %v: %v", status, lockErrorMap[status]), Query: []byte(query)}
182181
}
183182
}
184183

185184
// Unlock froms the migration lock from the database
186185
func (ss *SQLServer) Unlock() error {
187-
if !ss.isLocked.Load() {
188-
return nil
186+
if !ss.isLocked.CAS(true, false) {
187+
return database.ErrNotLocked
189188
}
190189

191190
aid, err := database.GenerateAdvisoryLockId(ss.config.DatabaseName, ss.config.SchemaName)
192191
if err != nil {
192+
ss.isLocked.Store(true)
193193
return err
194194
}
195195

196196
// MS Docs: sp_releaseapplock: https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-releaseapplock-transact-sql?view=sql-server-2017
197197
query := `EXEC sp_releaseapplock @Resource = @p1, @LockOwner = 'Session'`
198198
if _, err := ss.conn.ExecContext(context.Background(), query, aid); err != nil {
199+
ss.isLocked.Store(true)
199200
return &database.Error{OrigErr: err, Query: []byte(query)}
200201
}
201-
if !ss.isLocked.CAS(true, false) {
202-
return database.ErrNotLocked
203-
}
202+
204203
return nil
205204
}
206205

0 commit comments

Comments
 (0)