diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index acb6fb325f14..3503f43078d3 100644 --- a/bigtable/bttest/inmem.go +++ b/bigtable/bttest/inmem.go @@ -499,7 +499,11 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo rows = append(rows, r) } } - sort.Sort(byRowKey(rows)) + if req.Reversed { + sort.Sort(sort.Reverse(byRowKey(rows))) + } else { + sort.Sort(byRowKey(rows)) + } limit := int(req.RowsLimit) if limit == 0 { diff --git a/bigtable/bttest/inmem_test.go b/bigtable/bttest/inmem_test.go index 3a57585c7e8c..3c93cf8e48fa 100644 --- a/bigtable/bttest/inmem_test.go +++ b/bigtable/bttest/inmem_test.go @@ -1053,6 +1053,84 @@ func TestReadRowsWithlabelTransformer(t *testing.T) { } } +func TestReadRowsReversed(t *testing.T) { + ctx := context.Background() + srv := &server{ + tables: make(map[string]*table), + } + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tbl, err := srv.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + entries := []struct { + row string + value []byte + }{ + {"row1", []byte("a")}, + {"row2", []byte("b")}, + } + + for _, entry := range entries { + req := &btpb.MutateRowRequest{ + TableName: tbl.Name, + RowKey: []byte(entry.row), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf", + ColumnQualifier: []byte("cq"), + TimestampMicros: 1000, + Value: entry.value, + }}, + }}, + } + if _, err := srv.MutateRow(ctx, req); err != nil { + t.Fatalf("Failed to insert entry %v into server: %v", entry, err) + } + } + + rrss := new(MockReadRowsServer) + rreq := &btpb.ReadRowsRequest{TableName: tbl.Name, Reversed: true} + if err := srv.ReadRows(rreq, rrss); err != nil { + t.Fatalf("Failed to read rows: %v", err) + } + + var gotChunks []*btpb.ReadRowsResponse_CellChunk + for _, res := range rrss.responses { + gotChunks = append(gotChunks, res.Chunks...) + } + + wantChunks := []*btpb.ReadRowsResponse_CellChunk{ + { + RowKey: []byte("row2"), + FamilyName: &wrappers.StringValue{Value: "cf"}, + Qualifier: &wrappers.BytesValue{Value: []byte("cq")}, + TimestampMicros: 1000, + Value: []byte("b"), + RowStatus: &btpb.ReadRowsResponse_CellChunk_CommitRow{ + CommitRow: true, + }, + }, + { + RowKey: []byte("row1"), + FamilyName: &wrappers.StringValue{Value: "cf"}, + Qualifier: &wrappers.BytesValue{Value: []byte("cq")}, + TimestampMicros: 1000, + Value: []byte("a"), + RowStatus: &btpb.ReadRowsResponse_CellChunk_CommitRow{ + CommitRow: true, + }, + }, + } + if diff := cmp.Diff(gotChunks, wantChunks, cmp.Comparer(proto.Equal)); diff != "" { + t.Fatalf("Response chunks mismatch: got: + want -\n%s", diff) + } +} + func TestCheckAndMutateRowWithoutPredicate(t *testing.T) { s := &server{ tables: make(map[string]*table), diff --git a/bigtable/go.mod b/bigtable/go.mod index ae57f260c49d..49d5d84545cc 100644 --- a/bigtable/go.mod +++ b/bigtable/go.mod @@ -12,8 +12,8 @@ require ( github.com/googleapis/cloud-bigtable-clients-test v0.0.0-20230505150253-16eeee810d3a github.com/googleapis/gax-go/v2 v2.11.0 google.golang.org/api v0.126.0 - google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc - google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc + google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 + google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 google.golang.org/grpc v1.55.0 google.golang.org/protobuf v1.30.0 rsc.io/binaryregexp v0.2.0 @@ -40,5 +40,5 @@ require ( golang.org/x/text v0.9.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 // indirect ) diff --git a/bigtable/go.sum b/bigtable/go.sum index b582208b8357..1f42ff511826 100644 --- a/bigtable/go.sum +++ b/bigtable/go.sum @@ -181,12 +181,12 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao= -google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529 h1:9JucMWR7sPvCxUFd6UsOUNmA5kCcWOfORaT3tpAsKQs= +google.golang.org/genproto v0.0.0-20230629202037-9506855d4529/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529 h1:s5YSX+ZH5b5vS9rnpGymvIyMpLRJizowqDlOuyjXnTk= +google.golang.org/genproto/googleapis/api v0.0.0-20230629202037-9506855d4529/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529 h1:DEH99RbiLZhMxrpEJCZ0A+wdTe0EOgou/poSLx9vWf4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230629202037-9506855d4529/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=