Skip to content

Commit 90691fa

Browse files
planetscale-actions-botGuptaManan100
authored andcommitted
[latest-17.0](vitessio#3891): CherryPick(vitessio#14716): Fix RegisterNotifier to use a copy of the tables to prevent data races (vitessio#3900)
* backport of 3891 * feat: fix build issues Signed-off-by: Manan Gupta <[email protected]> --------- Signed-off-by: Manan Gupta <[email protected]> Co-authored-by: Manan Gupta <[email protected]>
1 parent 2960a36 commit 90691fa

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

go/vt/vttablet/tabletserver/schema/engine.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,8 @@ func (se *Engine) RegisterNotifier(name string, f notifier, runNotifier bool) {
708708
created = append(created, table)
709709
}
710710
if runNotifier {
711-
f(se.tables, created, nil, nil)
711+
s := maps.Clone(se.tables)
712+
f(s, created, nil, nil)
712713
}
713714
}
714715

@@ -736,10 +737,7 @@ func (se *Engine) broadcast(created, altered, dropped []*Table) {
736737

737738
se.notifierMu.Lock()
738739
defer se.notifierMu.Unlock()
739-
s := make(map[string]*Table, len(se.tables))
740-
for k, v := range se.tables {
741-
s[k] = v
742-
}
740+
s := maps.Clone(se.tables)
743741
for _, f := range se.notifiers {
744742
f(s, created, altered, dropped)
745743
}
@@ -757,10 +755,7 @@ func (se *Engine) GetTable(tableName sqlparser.IdentifierCS) *Table {
757755
func (se *Engine) GetSchema() map[string]*Table {
758756
se.mu.Lock()
759757
defer se.mu.Unlock()
760-
tables := make(map[string]*Table, len(se.tables))
761-
for k, v := range se.tables {
762-
tables[k] = v
763-
}
758+
tables := maps.Clone(se.tables)
764759
return tables
765760
}
766761

go/vt/vttablet/tabletserver/schema/engine_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,29 @@ func AddFakeInnoDBReadRowsResult(db *fakesqldb.DB, value int) *fakesqldb.Expecte
745745
))
746746
}
747747

748+
// TestRegisterNotifier tests the functionality of RegisterNotifier
749+
// It also makes sure that writing to the tables map in the schema engine doesn't change the tables received by the notifiers.
750+
func TestRegisterNotifier(t *testing.T) {
751+
// Create a new engine for testing
752+
se := NewEngineForTests()
753+
se.notifiers = map[string]notifier{}
754+
se.tables = map[string]*Table{
755+
"t1": nil,
756+
"t2": nil,
757+
"t3": nil,
758+
}
759+
760+
var tablesReceived map[string]*Table
761+
// Register a notifier and make it run immediately.
762+
se.RegisterNotifier("TestRegisterNotifier", func(full map[string]*Table, created, altered, dropped []*Table) {
763+
tablesReceived = full
764+
}, true)
765+
766+
// Change the se.tables and make sure it doesn't affect the tables received by the notifier.
767+
se.tables["t4"] = nil
768+
require.Len(t, tablesReceived, 3)
769+
}
770+
748771
// TestEngineMysqlTime tests the functionality of Engine.mysqlTime function
749772
func TestEngineMysqlTime(t *testing.T) {
750773
tests := []struct {

0 commit comments

Comments
 (0)