Fix #4716: Add synchronization to autoCompleteSuggestions.sort() (#4737)

* Add test for #4716: sort() should be safe for concurrent calls

* Fix #4716: Add mutex protection to autoCompleteSuggestions.sort()

Adds sync.RWMutex to prevent data race during concurrent sort() calls.
Changes sort() from value receiver to pointer receiver to support locking.

The mutex ensures thread-safe access when multiple goroutines call sort()
simultaneously during autocomplete initialization.
This commit is contained in:
Nathan Wallace
2025-11-16 13:59:43 -05:00
committed by GitHub
parent 57712dc4df
commit 114ac22dea
2 changed files with 72 additions and 2 deletions

View File

@@ -1,8 +1,10 @@
package interactive
import (
"github.com/c-bata/go-prompt"
"sort"
"sync"
"github.com/c-bata/go-prompt"
)
const (
@@ -15,6 +17,7 @@ const (
)
type autoCompleteSuggestions struct {
mu sync.RWMutex
schemas []prompt.Suggest
unqualifiedTables []prompt.Suggest
unqualifiedQueries []prompt.Suggest
@@ -72,7 +75,10 @@ func (s *autoCompleteSuggestions) setQueriesForMod(modName string, queries []pro
s.queriesByMod[modName] = queries
}
func (s autoCompleteSuggestions) sort() {
func (s *autoCompleteSuggestions) sort() {
s.mu.Lock()
defer s.mu.Unlock()
sortSuggestions := func(s []prompt.Suggest) {
sort.Slice(s, func(i, j int) bool {
return s[i].Text < s[j].Text

View File

@@ -0,0 +1,64 @@
package interactive
import (
"sync"
"testing"
"github.com/c-bata/go-prompt"
)
// TestAutoCompleteSuggestions_ConcurrentSort tests that sort() can be called
// concurrently without triggering data races.
// This test reproduces the race condition reported in issue #4716.
func TestAutoCompleteSuggestions_ConcurrentSort(t *testing.T) {
// Create a populated autoCompleteSuggestions instance
suggestions := newAutocompleteSuggestions()
// Populate with test data
suggestions.schemas = []prompt.Suggest{
{Text: "public"},
{Text: "aws"},
{Text: "github"},
}
suggestions.unqualifiedTables = []prompt.Suggest{
{Text: "table1"},
{Text: "table2"},
{Text: "table3"},
}
suggestions.unqualifiedQueries = []prompt.Suggest{
{Text: "query1"},
{Text: "query2"},
{Text: "query3"},
}
suggestions.tablesBySchema["public"] = []prompt.Suggest{
{Text: "users"},
{Text: "accounts"},
}
suggestions.queriesByMod["aws"] = []prompt.Suggest{
{Text: "aws_query1"},
{Text: "aws_query2"},
}
// Call sort() concurrently from multiple goroutines
// This should trigger a race condition if the sort() method is not thread-safe
var wg sync.WaitGroup
numGoroutines := 10
for i := 0; i < numGoroutines; i++ {
wg.Add(1)
go func() {
defer wg.Done()
suggestions.sort()
}()
}
// Wait for all goroutines to complete
wg.Wait()
// If we get here without panicking or race detector errors, the test passes
// Note: This test will fail when run with -race flag if sort() is not thread-safe
}