Skip to content

Commit 8922f64

Browse files
author
dbking
committed
Before the successful renaming, a session accessed the ghost table, which had already unlocked the original table.
There is a very small probability that other sessions dml operations on the original table will occur, and this dml operation will appear in the original table after renaming, resulting in data loss.
1 parent 4502796 commit 8922f64

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

go/logic/applier.go

+42-1
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ func (this *Applier) RevertAtomicCutOverWaitTimeout() {
10991099
}
11001100

11011101
// AtomicCutOverMagicLock
1102-
func (this *Applier) AtomicCutOverMagicLock(sessionIdChan chan int64, tableLocked chan<- error, okToUnlockTable <-chan bool, tableUnlocked chan<- error) error {
1102+
func (this *Applier) AtomicCutOverMagicLock(sessionIdChan chan int64, tableLocked chan<- error, okToUnlockTable <-chan bool, tableUnlocked chan<- error, renameLockSessionId *int64) error {
11031103
tx, err := this.db.Begin()
11041104
if err != nil {
11051105
tableLocked <- err
@@ -1190,6 +1190,23 @@ func (this *Applier) AtomicCutOverMagicLock(sessionIdChan chan int64, tableLocke
11901190
// We DO NOT return here because we must `UNLOCK TABLES`!
11911191
}
11921192

1193+
this.migrationContext.Log.Infof("Session renameLockSessionId is %+v", *renameLockSessionId)
1194+
// checking the lock holded by rename session
1195+
if *renameLockSessionId > 0 {
1196+
for i := 0; i <= 50; i++ {
1197+
err := this.ExpectMetadataLock(*renameLockSessionId)
1198+
if err == nil {
1199+
this.migrationContext.Log.Infof("Rename session is pending lock on the origin table !")
1200+
break
1201+
} else {
1202+
if i == 50 {
1203+
return err
1204+
}
1205+
time.Sleep(10 * time.Millisecond)
1206+
}
1207+
}
1208+
}
1209+
11931210
// Tables still locked
11941211
this.migrationContext.Log.Infof("Releasing lock from %s.%s, %s.%s",
11951212
sql.EscapeName(this.migrationContext.DatabaseName),
@@ -1409,3 +1426,27 @@ func (this *Applier) Teardown() {
14091426
this.singletonDB.Close()
14101427
atomic.StoreInt64(&this.finishedMigrating, 1)
14111428
}
1429+
1430+
func (this *Applier) ExpectMetadataLock(sessionId int64) error {
1431+
found := false
1432+
query := `
1433+
select /* gh-ost */ m.owner_thread_id
1434+
from performance_schema.metadata_locks m join performance_schema.threads t
1435+
on m.owner_thread_id=t.thread_id
1436+
where m.object_type = 'TABLE' and m.object_schema = ? and m.object_name = ?
1437+
and m.lock_type = 'EXCLUSIVE' and m.lock_status = 'PENDING'
1438+
and t.processlist_id = ?
1439+
`
1440+
err := sqlutils.QueryRowsMap(this.db, query, func(m sqlutils.RowMap) error {
1441+
found = true
1442+
return nil
1443+
}, this.migrationContext.DatabaseName, this.migrationContext.OriginalTableName, sessionId)
1444+
if err != nil {
1445+
return err
1446+
}
1447+
if !found {
1448+
err = fmt.Errorf("cannot find PENDING metadata lock on original table: `%s`.`%s`", this.migrationContext.DatabaseName, this.migrationContext.OriginalTableName)
1449+
return this.migrationContext.Log.Errore(err)
1450+
}
1451+
return nil
1452+
}

go/logic/migrator.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -669,8 +669,9 @@ func (this *Migrator) atomicCutOver() (err error) {
669669
lockOriginalSessionIdChan := make(chan int64, 2)
670670
tableLocked := make(chan error, 2)
671671
tableUnlocked := make(chan error, 2)
672+
var renameLockSessionId int64
672673
go func() {
673-
if err := this.applier.AtomicCutOverMagicLock(lockOriginalSessionIdChan, tableLocked, okToUnlockTable, tableUnlocked); err != nil {
674+
if err := this.applier.AtomicCutOverMagicLock(lockOriginalSessionIdChan, tableLocked, okToUnlockTable, tableUnlocked, &renameLockSessionId); err != nil {
674675
this.migrationContext.Log.Errore(err)
675676
}
676677
}()
@@ -735,6 +736,7 @@ func (this *Migrator) atomicCutOver() (err error) {
735736
// Now that we've found the RENAME blocking, AND the locking connection still alive,
736737
// we know it is safe to proceed to release the lock
737738

739+
renameLockSessionId = renameSessionId
738740
okToUnlockTable <- true
739741
// BAM! magic table dropped, original table lock is released
740742
// -> RENAME released -> queries on original are unblocked.

0 commit comments

Comments
 (0)