* Fix "cannot start a transaction within a transaction" issue [why] If db.BeginTx(ctx, nil) context is cancelled too fast, "BEGIN" statement can be completed inside DB, but we still try to cancel it with sqlite3_interrupt. In such case we get context.Cancelled or context.DeadlineExceeded from exec(), but operation really completed. Connection returned into pool, and returns "cannot start a transaction within a transaction" error for next db.BeginTx() call. [how] Handle status code returned from cancelled operation. [testing] Added unit-test which reproduces issue. * Reduce TestQueryRowContextCancelParallel concurrency [why] Tests times out in travis-ci when run with -race option.
This commit is contained in:
committed by
GitHub
parent
6a8b30186d
commit
862b95943f
@@ -136,6 +136,44 @@ func TestShortTimeout(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecContextCancel(t *testing.T) {
|
||||
srcTempFilename := TempFilename(t)
|
||||
defer os.Remove(srcTempFilename)
|
||||
|
||||
db, err := sql.Open("sqlite3", srcTempFilename)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
|
||||
ts := time.Now()
|
||||
initDatabase(t, db, 1000)
|
||||
spent := time.Since(ts)
|
||||
if spent < 100*time.Millisecond {
|
||||
t.Skip("test will be too racy, as ExecContext below will be too fast.")
|
||||
}
|
||||
|
||||
// expected to be extremely slow query
|
||||
q := `
|
||||
INSERT INTO test_table (key1, key_id, key2, key3, key4, key5, key6, data)
|
||||
SELECT t1.key1 || t2.key1, t1.key_id || t2.key_id, t1.key2 || t2.key2, t1.key3 || t2.key3, t1.key4 || t2.key4, t1.key5 || t2.key5, t1.key6 || t2.key6, t1.data || t2.data
|
||||
FROM test_table t1 LEFT OUTER JOIN test_table t2`
|
||||
// expect query above take ~ same time as setup above
|
||||
ctx, cancel := context.WithTimeout(context.Background(), spent/2)
|
||||
defer cancel()
|
||||
ts = time.Now()
|
||||
r, err := db.ExecContext(ctx, q)
|
||||
// racy check
|
||||
if r != nil {
|
||||
n, err := r.RowsAffected()
|
||||
t.Log(n, err, time.Since(ts))
|
||||
}
|
||||
if err != context.DeadlineExceeded {
|
||||
t.Fatal(err, ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryRowContextCancel(t *testing.T) {
|
||||
srcTempFilename := TempFilename(t)
|
||||
defer os.Remove(srcTempFilename)
|
||||
@@ -191,7 +229,7 @@ func TestQueryRowContextCancelParallel(t *testing.T) {
|
||||
testCtx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
Reference in New Issue
Block a user