codeintel: Write to the lsif_commits table in a deterministic order
Created by: efritz
Reduce deadlock probability by always writing tuples in a deterministic order. This should (hopefully) make it impossible for two threads to be blocked on writing the same tuples.
This was tested with the following script. A deadlock occurred immediately on the first attempt without this change, and went a few dozen rounds without error afterwards:
func TestDeadlockPrevention(t *testing.T) {
if testing.Short() {
t.Skip()
}
dbtesting.SetupGlobalTestDB(t)
db := testDB()
commits := map[string][]string{}
for i := 0; i < 10000; i++ {
commits[makeCommit(i)] = []string{makeCommit(i + 1), makeCommit(i + 2)}
}
i := 0
f := func() {
errs := make(chan error)
tx1, err1 := db.Transact(context.Background())
if err1 != nil {
t.Fatal(err1)
}
tx2, err2 := db.Transact(context.Background())
if err2 != nil {
t.Fatal(err2)
}
go func() {
errs <- tx1.UpdateCommits(context.Background(), i, commits)
errs <- tx1.Done(nil)
}()
go func() {
errs <- tx2.UpdateCommits(context.Background(), i, commits)
errs <- tx2.Done(nil)
}()
for i := 0; i < 4; i++ {
if err := <-errs; err != nil {
t.Fatal(err)
}
}
close(errs)
}
for {
f()
i++
}
}