diff --git a/bigtable/bttest/inmem.go b/bigtable/bttest/inmem.go index 3503f43078d3..a155d6b6f07f 100644 --- a/bigtable/bttest/inmem.go +++ b/bigtable/bttest/inmem.go @@ -33,6 +33,7 @@ package bttest // import "cloud.google.com/go/bigtable/bttest" import ( "bytes" "context" + "encoding/base64" "encoding/binary" "fmt" "log" @@ -45,6 +46,9 @@ import ( "sync" "time" + "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/proto" + longrunning "cloud.google.com/go/longrunning/autogen/longrunningpb" emptypb "github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/wrappers" @@ -423,7 +427,31 @@ func (s *server) DeleteSnapshot(context.Context, *btapb.DeleteSnapshotRequest) ( return nil, status.Errorf(codes.Unimplemented, "the emulator does not currently support snapshots") } +func featureFlagsFromContext(context context.Context) *btpb.FeatureFlags { + ff := &btpb.FeatureFlags{} + + var md, ok = metadata.FromIncomingContext(context) + if !ok { + return ff + } + + features := md.Get("bigtable-features") + if len(features) == 0 { + return ff + } + + dec, err := base64.URLEncoding.DecodeString(features[0]) + if err != nil { + return ff + } + + _ = proto.Unmarshal(dec, ff) + return ff +} + func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRowsServer) error { + featureFlags := featureFlagsFromContext(stream.Context()) + start := time.Now() s.mu.Lock() tbl, ok := s.tables[req.TableName] @@ -500,6 +528,10 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo } } if req.Reversed { + if !featureFlags.ReverseScans { + return status.Errorf(codes.Unimplemented, "Client doesn't support reverse scans yet") + } + sort.Sort(sort.Reverse(byRowKey(rows))) } else { sort.Sort(byRowKey(rows)) @@ -517,7 +549,7 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo break } - if err := streamRow(stream, r, req.Filter, iterStats); err != nil { + if err := streamRow(stream, r, req.Filter, iterStats, featureFlags); err != nil { return err } } @@ -543,7 +575,7 @@ func (s *server) ReadRows(req *btpb.ReadRowsRequest, stream btpb.Bigtable_ReadRo // streamRow filters the given row and sends it via the given stream. // Returns true if at least one cell matched the filter and was streamed, false otherwise. -func streamRow(stream btpb.Bigtable_ReadRowsServer, r *row, f *btpb.RowFilter, s *btpb.ReadIterationStats) error { +func streamRow(stream btpb.Bigtable_ReadRowsServer, r *row, f *btpb.RowFilter, s *btpb.ReadIterationStats, ff *btpb.FeatureFlags) error { r.mu.Lock() nr := r.copy() r.mu.Unlock() @@ -562,6 +594,14 @@ func streamRow(stream btpb.Bigtable_ReadRowsServer, r *row, f *btpb.RowFilter, s return err } if !match { + // if the client requested it, send last_scanned_row responses for rows that didn't match a filter + if ff.LastScannedRowResponses { + rrr := &btpb.ReadRowsResponse{ + LastScannedRowKey: []byte(r.key), + } + return stream.Send(rrr) + } + return nil } diff --git a/bigtable/bttest/inmem_test.go b/bigtable/bttest/inmem_test.go index 3c93cf8e48fa..0e348e740df2 100644 --- a/bigtable/bttest/inmem_test.go +++ b/bigtable/bttest/inmem_test.go @@ -27,6 +27,9 @@ import ( "testing" "time" + "google.golang.org/grpc/metadata" + + "cloud.google.com/go/bigtable/internal/option" "cloud.google.com/go/internal/testutil" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/wrappers" @@ -597,6 +600,7 @@ func TestDropRowRange(t *testing.T) { type MockReadRowsServer struct { responses []*btpb.ReadRowsResponse + ctx context.Context grpc.ServerStream } @@ -605,6 +609,13 @@ func (s *MockReadRowsServer) Send(resp *btpb.ReadRowsResponse) error { return nil } +func (s *MockReadRowsServer) Context() context.Context { + if s.ctx == nil { + return context.Background() + } + return s.ctx +} + func TestCheckTimestampMaxValue(t *testing.T) { // Test that max Timestamp value can be passed in TimestampMicros without error // and that max Timestamp is the largest valid value in Millis. @@ -706,6 +717,64 @@ func TestReadRows(t *testing.T) { } } +func TestReadRowsLastScannedRow(t *testing.T) { + ctx := context.Background() + s := &server{ + tables: make(map[string]*table), + } + newTbl := btapb.Table{ + ColumnFamilies: map[string]*btapb.ColumnFamily{ + "cf0": {GcRule: &btapb.GcRule{Rule: &btapb.GcRule_MaxNumVersions{MaxNumVersions: 1}}}, + }, + } + tblInfo, err := s.CreateTable(ctx, &btapb.CreateTableRequest{Parent: "cluster", TableId: "t", Table: &newTbl}) + if err != nil { + t.Fatalf("Creating table: %v", err) + } + mreq := &btpb.MutateRowRequest{ + TableName: tblInfo.Name, + RowKey: []byte("row"), + Mutations: []*btpb.Mutation{{ + Mutation: &btpb.Mutation_SetCell_{SetCell: &btpb.Mutation_SetCell{ + FamilyName: "cf0", + ColumnQualifier: []byte("col"), + TimestampMicros: 1000, + Value: []byte{}, + }}, + }}, + } + if _, err := s.MutateRow(ctx, mreq); err != nil { + t.Fatalf("Populating table: %v", err) + } + + for _, rowset := range []*btpb.RowSet{ + {RowKeys: [][]byte{[]byte("row")}}, + {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")}}}}, + {RowRanges: []*btpb.RowRange{{StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("r")}}}}, + {RowRanges: []*btpb.RowRange{{ + StartKey: &btpb.RowRange_StartKeyClosed{StartKeyClosed: []byte("")}, + EndKey: &btpb.RowRange_EndKeyOpen{EndKeyOpen: []byte("s")}, + }}}, + } { + featureFlags := option.WithFeatureFlags() + ctx := metadata.NewIncomingContext(context.Background(), featureFlags) + + mock := &MockReadRowsServer{ctx: ctx} + filter := &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{BlockAllFilter: true}} + req := &btpb.ReadRowsRequest{TableName: tblInfo.Name, Rows: rowset, Filter: filter} + if err = s.ReadRows(req, mock); err != nil { + t.Fatalf("ReadRows error: %v", err) + } + if got, want := len(mock.responses), 1; got != want { + t.Errorf("%+v: response count: got %d, want %d", rowset, got, want) + } + expect := &btpb.ReadRowsResponse{LastScannedRowKey: []byte("row")} + if !proto.Equal(mock.responses[0], expect) { + t.Errorf("%+v: response: got %+v, want %+v", rowset, mock.responses[0], expect) + } + } +} + func TestReadRowsError(t *testing.T) { ctx := context.Background() s := &server{ @@ -1093,7 +1162,8 @@ func TestReadRowsReversed(t *testing.T) { } } - rrss := new(MockReadRowsServer) + serverCtx := metadata.NewIncomingContext(context.Background(), option.WithFeatureFlags()) + rrss := &MockReadRowsServer{ctx: serverCtx} rreq := &btpb.ReadRowsRequest{TableName: tbl.Name, Reversed: true} if err := srv.ReadRows(rreq, rrss); err != nil { t.Fatalf("Failed to read rows: %v", err) diff --git a/bigtable/bttest/validation_test.go b/bigtable/bttest/validation_test.go index da5953f83cfd..233521d7a763 100644 --- a/bigtable/bttest/validation_test.go +++ b/bigtable/bttest/validation_test.go @@ -164,7 +164,8 @@ func TestValidateReadRowsRequestSendsRPCError(t *testing.T) { }, } - err := srv.ReadRows(badReq, nil) + stream := &MockReadRowsServer{} + err := srv.ReadRows(badReq, stream) if err == nil { t.Errorf("#%d: unexpectedly returned nil error", i) continue diff --git a/bigtable/go.mod b/bigtable/go.mod index 49d5d84545cc..7d81a9c62117 100644 --- a/bigtable/go.mod +++ b/bigtable/go.mod @@ -3,31 +3,31 @@ module cloud.google.com/go/bigtable go 1.19 require ( - cloud.google.com/go v0.110.2 - cloud.google.com/go/iam v1.1.0 - cloud.google.com/go/longrunning v0.5.0 + cloud.google.com/go v0.110.4 + cloud.google.com/go/iam v1.1.1 + cloud.google.com/go/longrunning v0.5.1 github.com/golang/protobuf v1.5.3 github.com/google/btree v1.1.2 github.com/google/go-cmp v0.5.9 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-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 + google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e + google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 + google.golang.org/grpc v1.56.2 + google.golang.org/protobuf v1.31.0 rsc.io/binaryregexp v0.2.0 ) require ( - cloud.google.com/go/compute v1.19.3 // indirect + cloud.google.com/go/compute v1.20.1 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect - github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 // indirect - github.com/envoyproxy/go-control-plane v0.11.0 // indirect - github.com/envoyproxy/protoc-gen-validate v0.10.0 // indirect + github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect + github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f // indirect + github.com/envoyproxy/protoc-gen-validate v0.10.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/s2a-go v0.1.4 // indirect github.com/google/uuid v1.3.0 // indirect @@ -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-20230629202037-9506855d4529 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 // indirect ) diff --git a/bigtable/go.sum b/bigtable/go.sum index 1f42ff511826..2d824bbff459 100644 --- a/bigtable/go.sum +++ b/bigtable/go.sum @@ -1,15 +1,15 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA= -cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw= -cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds= -cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= +cloud.google.com/go v0.110.4 h1:1JYyxKMN9hd5dR2MYTPWkGUgcoxVVhg0LKNKEo0qvmk= +cloud.google.com/go v0.110.4/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI= +cloud.google.com/go/compute v1.20.1 h1:6aKEtlUiwEpJzM001l0yFkpXmUVXaN8W+fbkb2AZNbg= +cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/iam v1.1.0 h1:67gSqaPukx7O8WLLHMa0PNs3EBGd2eE4d+psbO/CO94= -cloud.google.com/go/iam v1.1.0/go.mod h1:nxdHjaKfCr7fNYx/HJMM8LgiMugmveWlkatear5gVyk= -cloud.google.com/go/longrunning v0.5.0 h1:DK8BH0+hS+DIvc9a2TPnteUievsTCH4ORMAASSb7JcQ= -cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc= +cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= +cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU= +cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI= +cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -27,8 +27,8 @@ github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XP github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195 h1:58f1tJ1ra+zFINPlwLWvQsR9CzAKt2e+EWV2yX9oXQ4= -github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -36,11 +36,11 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/go-control-plane v0.11.0 h1:jtLewhRR2vMRNnq2ZZUoCjUlgut+Y0+sDDWPOfwOi1o= -github.com/envoyproxy/go-control-plane v0.11.0/go.mod h1:VnHyVMpzcLvCFt9yUz1UnCwHLhwx1WguiVDV7pTG/tI= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f h1:7T++XKzy4xg7PKy+bM+Sa9/oe1OC88yz2hXQUISoXfA= +github.com/envoyproxy/go-control-plane v0.11.1-0.20230524094728-9239064ad72f/go.mod h1:sfYdkwUW4BA3PbKjySwjJy+O4Pu0h62rlqCMHNk+K+Q= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v0.10.0 h1:oIfnZFdC0YhpNNEX+SuIqko4cqqVZeN9IGTrhZje83Y= -github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= +github.com/envoyproxy/protoc-gen-validate v0.10.1 h1:c0g45+xCJhdgFGw7a5QAfdS4byAbud7miNWJ1WwEVf8= +github.com/envoyproxy/protoc-gen-validate v0.10.1/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -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-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/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg= +google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU= +google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o= 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= @@ -195,8 +195,8 @@ google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTp google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= -google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag= -google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= +google.golang.org/grpc v1.56.2 h1:fVRFRnXvU+x6C4IlHZewvJOVHoOv1TUuQyoRsYnB4bI= +google.golang.org/grpc v1.56.2/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -208,8 +208,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/bigtable/internal/option/option.go b/bigtable/internal/option/option.go index dde511f32f45..84ad6d1053eb 100644 --- a/bigtable/internal/option/option.go +++ b/bigtable/internal/option/option.go @@ -19,9 +19,13 @@ package option import ( "context" + "encoding/base64" "fmt" "os" + btpb "google.golang.org/genproto/googleapis/bigtable/v2" + "google.golang.org/protobuf/proto" + "cloud.google.com/go/internal/version" gax "github.com/googleapis/gax-go/v2" "google.golang.org/api/option" @@ -59,6 +63,25 @@ func withGoogleClientInfo() metadata.MD { return metadata.Pairs("x-goog-api-client", gax.XGoogHeader(kv...)) } +func makeFeatureFlags() string { + ff := btpb.FeatureFlags{ReverseScans: true, LastScannedRowResponses: true} + b, err := proto.Marshal(&ff) + if err != nil { + return "" + } + + return base64.URLEncoding.EncodeToString(b) +} + +var featureFlags = makeFeatureFlags() + +// WithFeatureFlags set the feature flags the client supports in the +// `bigtable-features` header sent on each request. Intended for +// use by Google-written clients. +func WithFeatureFlags() metadata.MD { + return metadata.Pairs("bigtable-features", featureFlags) +} + // streamInterceptor intercepts the creation of ClientStream within the bigtable // client to inject Google client information into the context metadata for // streaming RPCs.