Skip to content

Data race between mysqlConn watcher and okHandler during context cancellation #1559

Closed
@bobvawter

Description

@bobvawter

Issue description

I have one goroutine running database transactions in a loop and another goroutine cancels the context being used. This leads to the data race shown below.

Example code

Execute with go test -v -race . -test.count 1000 -test.failfast -test.run 'TestRace'

func TestRace(t *testing.T) {
	r := require.New(t)

	driver := mysql.MySQLDriver{}
	connector, err := driver.OpenConnector("root:SoupOrSecret@/mysql")
	r.NoError(err)
	db := sql.OpenDB(connector)

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	triggerCancel := make(chan struct{})
	done := make(chan struct{})

	go func() {
		defer close(done)

		didTrigger := false
		for ctx.Err() == nil {
			tx, err := db.BeginTx(ctx, nil)
			if errors.Is(err, context.Canceled) {
				return
			}
			r.NoError(err)

			var one int
			err = tx.QueryRowContext(ctx, "SELECT 1").Scan(&one)
			if errors.Is(err, context.Canceled) {
				return
			}
			r.NoError(err)

			_ = tx.Rollback()
			if !didTrigger {
				didTrigger = true
				close(triggerCancel)
			}
		}
	}()

	<-triggerCancel
	time.Sleep(10 * time.Millisecond)
	cancel()
	<-done
}

Error log

WARNING: DATA RACE
Write at 0x00c000392458 by goroutine 28578:
  github.com/go-sql-driver/mysql.(*mysqlConn).clearResult()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/packets.go:630 +0x1c4
  github.com/go-sql-driver/mysql.(*mysqlConn).cleanup()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:156 +0x1a4
  github.com/go-sql-driver/mysql.(*mysqlConn).cancel()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:441 +0x84
  github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:628 +0x234

Previous read at 0x00c000392458 by goroutine 30352:
  github.com/go-sql-driver/mysql.(*okHandler).handleOkPacket()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/packets.go:650 +0xfd
  github.com/go-sql-driver/mysql.(*okHandler).readResultSetHeaderPacket()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/packets.go:536 +0x36f
  github.com/go-sql-driver/mysql.(*mysqlConn).exec()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:336 +0x18d
  github.com/go-sql-driver/mysql.(*mysqlConn).begin()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:121 +0x8a
  github.com/go-sql-driver/mysql.(*mysqlConn).BeginTx()
      /home/runner/go/pkg/mod/github.com/go-sql-driver/[email protected]/connection.go:498 +0x156
  database/sql.ctxDriverBegin()
      /opt/hostedtoolcache/go/1.20.14/x64/src/database/sql/ctxutil.go:104 +0x105
  database/sql.(*DB).beginDC.func1()
      /opt/hostedtoolcache/go/1.20.14/x64/src/database/sql/sql.go:1868 +0x156
  database/sql.withLock()
      /opt/hostedtoolcache/go/1.20.14/x64/src/database/sql/sql.go:3405 +0xa2
  database/sql.(*DB).beginDC()
      /opt/hostedtoolcache/go/1.20.14/x64/src/database/sql/sql.go:1864 +0x113
  database/sql.(*DB).begin()
      /opt/hostedtoolcache/go/1.20.14/x64/src/database/sql/sql.go:1857 +0x104
  database/sql.(*DB).BeginTx.func1()

Configuration

Driver version (or git SHA): 1.8.0

Go version: 1.20.7 & 1.22.1

Server version: mysql-v8 & mariadb-v10

Server OS: Ubuntu 22.04 (an ubuntu-latest GitHub actions runner)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions