-
Notifications
You must be signed in to change notification settings - Fork 1.5k
used uber atomic bool instead standard in lock/unlock db #580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
9814da9
55902af
1e867eb
1598b1e
93b3798
c1da4a8
312d98d
0b282a5
c4fd509
946b672
71bfde6
8120a9a
93fac42
11e2c9d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ import ( | |
"crypto/x509" | ||
"database/sql" | ||
"fmt" | ||
"go.uber.org/atomic" | ||
"io" | ||
"io/ioutil" | ||
nurl "net/url" | ||
|
@@ -49,7 +50,7 @@ type Mysql struct { | |
// just do everything over a single conn anyway. | ||
conn *sql.Conn | ||
db *sql.DB | ||
isLocked bool | ||
isLocked atomic.Bool | ||
|
||
config *Config | ||
} | ||
|
@@ -251,61 +252,62 @@ func (m *Mysql) Close() error { | |
} | ||
|
||
func (m *Mysql) Lock() error { | ||
if m.isLocked { | ||
if !m.isLocked.CAS(false, true) { | ||
return database.ErrLocked | ||
} | ||
|
||
if m.config.NoLock { | ||
m.isLocked = true | ||
return nil | ||
} | ||
|
||
aid, err := database.GenerateAdvisoryLockId( | ||
fmt.Sprintf("%s:%s", m.config.DatabaseName, m.config.MigrationsTable)) | ||
if err != nil { | ||
m.isLocked.Store(false) | ||
return err | ||
} | ||
|
||
query := "SELECT GET_LOCK(?, 10)" | ||
var success bool | ||
if err := m.conn.QueryRowContext(context.Background(), query, aid).Scan(&success); err != nil { | ||
m.isLocked.Store(false) | ||
return &database.Error{OrigErr: err, Err: "try lock failed", Query: []byte(query)} | ||
} | ||
|
||
if success { | ||
m.isLocked = true | ||
return nil | ||
if !success { | ||
m.isLocked.Store(false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Actually, let's add our own CAS wrapper to automatically restore the lock state on error (in func casRestoreOnErr(lock *atomic.Bool, o, n bool, f func() error) error {
if !lock.CAS(o, n) {
return ErrLocked
}
if err := f(); err != nil {
// Automatically unlock
lock.Store(o)
return err
}
return nil
} Also, can you add tests for this wrapper? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you. Of course I will do it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, review pls |
||
return database.ErrLocked | ||
} | ||
|
||
return database.ErrLocked | ||
return nil | ||
} | ||
|
||
func (m *Mysql) Unlock() error { | ||
if !m.isLocked { | ||
return nil | ||
if !m.isLocked.CAS(true, false) { | ||
return database.ErrNotLocked | ||
} | ||
|
||
if m.config.NoLock { | ||
m.isLocked = false | ||
return nil | ||
} | ||
|
||
aid, err := database.GenerateAdvisoryLockId( | ||
fmt.Sprintf("%s:%s", m.config.DatabaseName, m.config.MigrationsTable)) | ||
if err != nil { | ||
m.isLocked.Store(true) | ||
return err | ||
} | ||
|
||
query := `SELECT RELEASE_LOCK(?)` | ||
if _, err := m.conn.ExecContext(context.Background(), query, aid); err != nil { | ||
m.isLocked.Store(true) | ||
return &database.Error{OrigErr: err, Query: []byte(query)} | ||
} | ||
|
||
// NOTE: RELEASE_LOCK could return NULL or (or 0 if the code is changed), | ||
// in which case isLocked should be true until the timeout expires -- synchronizing | ||
// these states is likely not worth trying to do; reconsider the necessity of isLocked. | ||
|
||
m.isLocked = false | ||
return nil | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, this is my bug))