table: fix data race in select builder usage

When table is used with SelectBuilder it triggers data race on Where()
condition usage.

This change copies underlining slices on table creation to allow safe
concurrent usage of the table.
This commit is contained in:
Aleksandar Jankovic
2020-02-25 12:35:44 +01:00
committed by Michal Jan Matczuk
parent c36e6c5e66
commit ab2a96d9f3
2 changed files with 60 additions and 1 deletions

View File

@@ -45,7 +45,8 @@ func New(m Metadata) *Table { // nolint: gocritic
for _, k := range m.SortKey {
t.primaryKeyCmp = append(t.primaryKeyCmp, qb.Eq(k))
}
t.partKeyCmp = t.primaryKeyCmp[:len(t.metadata.PartKey)]
t.partKeyCmp = make([]qb.Cmp, len(m.PartKey))
copy(t.partKeyCmp, t.primaryKeyCmp[:len(t.metadata.PartKey)])
// prepare get stmt
t.get.stmt, t.get.names = qb.Select(m.Name).Where(t.primaryKeyCmp...).ToCql()

View File

@@ -5,9 +5,11 @@
package table
import (
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/scylladb/gocqlx/qb"
)
func TestTableGet(t *testing.T) {
@@ -219,3 +221,59 @@ func TestTableDelete(t *testing.T) {
}
}
}
func TestTableConcurrentUsage(t *testing.T) {
table := []struct {
Name string
M Metadata
C []string
N []string
S string
}{
{
Name: "Full select",
M: Metadata{
Name: "table",
Columns: []string{"a", "b", "c", "d"},
PartKey: []string{"a"},
SortKey: []string{"b"},
},
N: []string{"a", "b"},
S: "SELECT * FROM table WHERE a=? AND b=? ",
},
{
Name: "Sub select",
M: Metadata{
Name: "table",
Columns: []string{"a", "b", "c", "d"},
PartKey: []string{"a"},
SortKey: []string{"b"},
},
C: []string{"d"},
N: []string{"a", "b"},
S: "SELECT d FROM table WHERE a=? AND b=? ",
},
}
parallelCount := 3
// run SelectBuilder on the data set in parallel
for _, test := range table {
var wg sync.WaitGroup
testTable := New(test.M)
wg.Add(parallelCount)
for i := 0; i < parallelCount; i++ {
go func() {
defer wg.Done()
stmt, names := testTable.SelectBuilder(test.C...).
Where(qb.Eq("b")).ToCql()
if diff := cmp.Diff(test.S, stmt); diff != "" {
t.Error(diff)
}
if diff := cmp.Diff(test.N, names); diff != "" {
t.Error(diff, names)
}
}()
}
wg.Wait()
}
}