Skip to content

Commit 5711fb1

Browse files
authored
fix(bttest): fix race condition in SampleRowKeys (#4207)
Fixes mutex locking/unlocking and adds a test for concurrent operations.
1 parent fdf29be commit 5711fb1

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

bigtable/bttest/inmem.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,14 @@ func (s *server) ModifyColumnFamilies(ctx context.Context, req *btapb.ModifyColu
252252

253253
func (s *server) DropRowRange(ctx context.Context, req *btapb.DropRowRangeRequest) (*emptypb.Empty, error) {
254254
s.mu.Lock()
255-
defer s.mu.Unlock()
256255
tbl, ok := s.tables[req.Name]
256+
s.mu.Unlock()
257257
if !ok {
258258
return nil, status.Errorf(codes.NotFound, "table %q not found", req.Name)
259259
}
260260

261+
tbl.mu.Lock()
262+
defer tbl.mu.Unlock()
261263
if req.GetDeleteAllDataFromTable() {
262264
tbl.rows = btree.New(btreeDegree)
263265
} else {

bigtable/bttest/inmem_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,76 @@ func TestSampleRowKeys(t *testing.T) {
273273
}
274274
}
275275

276+
func TestTableRowsConcurrent(t *testing.T) {
277+
s := &server{
278+
tables: make(map[string]*table),
279+
}
280+
ctx := context.Background()
281+
newTbl := btapb.Table{
282+
ColumnFamilies: map[string]*btapb.ColumnFamily{
283+
"cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}},
284+
},
285+
}
286+
tbl, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl})
287+
if err != nil {
288+
t.Fatalf("Creating table: %v", err)
289+
}
290+
291+
// Populate the table
292+
populate := func() {
293+
rowCount := 100
294+
for i := 0; i < rowCount; i++ {
295+
req := &btpb.MutateRowRequest{
296+
TableName: tbl.Name,
297+
RowKey: []byte("row-" + strconv.Itoa(i)),
298+
Mutations: []*btpb.Mutation{{
299+
Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{
300+
FamilyName: "cf",
301+
ColumnQualifier: []byte("col"),
302+
TimestampMicros: 1000,
303+
Value: []byte("value"),
304+
}},
305+
}},
306+
}
307+
if _, err := s.MutateRow(ctx, req); err != nil {
308+
t.Fatalf("Populating table: %v", err)
309+
}
310+
}
311+
}
312+
313+
attempts := 500
314+
finished := make(chan bool)
315+
go func() {
316+
populate()
317+
mock := &MockSampleRowKeysServer{}
318+
for i := 0; i < attempts; i++ {
319+
if err := s.SampleRowKeys(&btpb.SampleRowKeysRequest{TableName: tbl.Name}, mock); err != nil {
320+
t.Errorf("SampleRowKeys error: %v", err)
321+
}
322+
}
323+
finished <- true
324+
}()
325+
go func() {
326+
for i := 0; i < attempts; i++ {
327+
req := &btapb.DropRowRangeRequest{
328+
Name: tbl.Name,
329+
Target: &btapb.DropRowRangeRequest_DeleteAllDataFromTable{DeleteAllDataFromTable: true},
330+
}
331+
if _, err = s.DropRowRange(ctx, req); err != nil {
332+
t.Fatalf("Dropping all rows: %v", err)
333+
}
334+
}
335+
finished <- true
336+
}()
337+
for i := 0; i < 2; i++ {
338+
select {
339+
case <-finished:
340+
case <-time.After(2 * time.Second):
341+
t.Fatalf("Timeout waiting for task %d\n", i)
342+
}
343+
}
344+
}
345+
276346
func TestDropRowRange(t *testing.T) {
277347
s := &server{
278348
tables: make(map[string]*table),

0 commit comments

Comments
 (0)