diff --git a/google/cloud/bigtable_v2/__init__.py b/google/cloud/bigtable_v2/__init__.py index 5f2893c50..6a880dfa4 100644 --- a/google/cloud/bigtable_v2/__init__.py +++ b/google/cloud/bigtable_v2/__init__.py @@ -43,10 +43,16 @@ from .types.data import RowSet from .types.data import TimestampRange from .types.data import ValueRange +from .types.request_stats import AllReadStats +from .types.request_stats import ReadEfficiencyStats +from .types.request_stats import ReadIteratorStats +from .types.request_stats import RequestLatencyStats +from .types.request_stats import RequestStats from .types.response_params import ResponseParams __all__ = ( "BigtableAsyncClient", + "AllReadStats", "BigtableClient", "Cell", "CheckAndMutateRowRequest", @@ -61,11 +67,15 @@ "Mutation", "PingAndWarmRequest", "PingAndWarmResponse", + "ReadEfficiencyStats", + "ReadIteratorStats", "ReadModifyWriteRowRequest", "ReadModifyWriteRowResponse", "ReadModifyWriteRule", "ReadRowsRequest", "ReadRowsResponse", + "RequestLatencyStats", + "RequestStats", "ResponseParams", "Row", "RowFilter", diff --git a/google/cloud/bigtable_v2/services/bigtable/async_client.py b/google/cloud/bigtable_v2/services/bigtable/async_client.py index c5f673a74..a5becca8d 100644 --- a/google/cloud/bigtable_v2/services/bigtable/async_client.py +++ b/google/cloud/bigtable_v2/services/bigtable/async_client.py @@ -43,6 +43,7 @@ from google.cloud.bigtable_v2.types import bigtable from google.cloud.bigtable_v2.types import data +from google.cloud.bigtable_v2.types import request_stats from .transports.base import BigtableTransport, DEFAULT_CLIENT_INFO from .transports.grpc_asyncio import BigtableGrpcAsyncIOTransport from .client import BigtableClient @@ -238,10 +239,8 @@ def read_rows( on the ``request`` instance; if ``request`` is provided, this should not be set. app_profile_id (:class:`str`): - This value specifies routing for - replication. If not specified, the - "default" application profile will be - used. + This value specifies routing for replication. This API + only accepts the empty value of app_profile_id. This corresponds to the ``app_profile_id`` field on the ``request`` instance; if ``request`` is provided, this diff --git a/google/cloud/bigtable_v2/services/bigtable/client.py b/google/cloud/bigtable_v2/services/bigtable/client.py index 30dd2934f..df2341dbc 100644 --- a/google/cloud/bigtable_v2/services/bigtable/client.py +++ b/google/cloud/bigtable_v2/services/bigtable/client.py @@ -36,6 +36,7 @@ from google.cloud.bigtable_v2.types import bigtable from google.cloud.bigtable_v2.types import data +from google.cloud.bigtable_v2.types import request_stats from .transports.base import BigtableTransport, DEFAULT_CLIENT_INFO from .transports.grpc import BigtableGrpcTransport from .transports.grpc_asyncio import BigtableGrpcAsyncIOTransport @@ -474,10 +475,8 @@ def read_rows( on the ``request`` instance; if ``request`` is provided, this should not be set. app_profile_id (str): - This value specifies routing for - replication. If not specified, the - "default" application profile will be - used. + This value specifies routing for replication. This API + only accepts the empty value of app_profile_id. This corresponds to the ``app_profile_id`` field on the ``request`` instance; if ``request`` is provided, this diff --git a/google/cloud/bigtable_v2/types/__init__.py b/google/cloud/bigtable_v2/types/__init__.py index ec6fbafd4..17bb66ae6 100644 --- a/google/cloud/bigtable_v2/types/__init__.py +++ b/google/cloud/bigtable_v2/types/__init__.py @@ -43,6 +43,13 @@ TimestampRange, ValueRange, ) +from .request_stats import ( + AllReadStats, + ReadEfficiencyStats, + ReadIteratorStats, + RequestLatencyStats, + RequestStats, +) from .response_params import ( ResponseParams, ) @@ -74,5 +81,10 @@ "RowSet", "TimestampRange", "ValueRange", + "AllReadStats", + "ReadEfficiencyStats", + "ReadIteratorStats", + "RequestLatencyStats", + "RequestStats", "ResponseParams", ) diff --git a/google/cloud/bigtable_v2/types/bigtable.py b/google/cloud/bigtable_v2/types/bigtable.py index 72785c264..3082fe732 100644 --- a/google/cloud/bigtable_v2/types/bigtable.py +++ b/google/cloud/bigtable_v2/types/bigtable.py @@ -16,6 +16,7 @@ import proto # type: ignore from google.cloud.bigtable_v2.types import data +from google.cloud.bigtable_v2.types import request_stats as gb_request_stats from google.protobuf import wrappers_pb2 # type: ignore from google.rpc import status_pb2 # type: ignore @@ -50,9 +51,8 @@ class ReadRowsRequest(proto.Message): Values are of the form ``projects//instances//tables/``. app_profile_id (str): - This value specifies routing for replication. - If not specified, the "default" application - profile will be used. + This value specifies routing for replication. This API only + accepts the empty value of app_profile_id. rows (google.cloud.bigtable_v2.types.RowSet): The row keys and/or ranges to read sequentially. If not specified, reads from all @@ -65,8 +65,21 @@ class ReadRowsRequest(proto.Message): The read will stop after committing to N rows' worth of results. The default (zero) is to return all results. + request_stats_view (google.cloud.bigtable_v2.types.ReadRowsRequest.RequestStatsView): + The view into RequestStats, as described + above. """ + class RequestStatsView(proto.Enum): + r"""The desired view into RequestStats that should be returned in + the response. + See also: RequestStats message. + """ + REQUEST_STATS_VIEW_UNSPECIFIED = 0 + REQUEST_STATS_NONE = 1 + REQUEST_STATS_EFFICIENCY = 2 + REQUEST_STATS_FULL = 3 + table_name = proto.Field( proto.STRING, number=1, @@ -89,6 +102,11 @@ class ReadRowsRequest(proto.Message): proto.INT64, number=4, ) + request_stats_view = proto.Field( + proto.ENUM, + number=6, + enum=RequestStatsView, + ) class ReadRowsResponse(proto.Message): @@ -109,6 +127,28 @@ class ReadRowsResponse(proto.Message): that was filtered out since the last committed row key, allowing the client to skip that work on a retry. + request_stats (google.cloud.bigtable_v2.types.RequestStats): + If requested, provide enhanced query performance statistics. + The semantics dictate: + + - request_stats is empty on every (streamed) response, + except + - request_stats has non-empty information after all chunks + have been streamed, where the ReadRowsResponse message + only contains request_stats. + + - For example, if a read request would have returned an + empty response instead a single ReadRowsResponse is + streamed with empty chunks and request_stats filled. + + Visually, response messages will stream as follows: ... -> + {chunks: [...]} -> {chunks: [], request_stats: {...}} + \_\ **/ \_**\ \__________/ Primary response Trailer of + RequestStats info + + Or if the read did not return any values: {chunks: [], + request_stats: {...}} \________________________________/ + Trailer of RequestStats info """ class CellChunk(proto.Message): @@ -232,6 +272,11 @@ class CellChunk(proto.Message): proto.BYTES, number=2, ) + request_stats = proto.Field( + proto.MESSAGE, + number=3, + message=gb_request_stats.RequestStats, + ) class SampleRowKeysRequest(proto.Message): @@ -370,8 +415,8 @@ class Entry(proto.Message): Required. Changes to be atomically applied to the specified row. Mutations are applied in order, meaning that earlier mutations can be - masked by later ones. - You must specify at least one mutation. + masked by later ones. You must specify at least + one mutation. """ row_key = proto.Field( diff --git a/google/cloud/bigtable_v2/types/request_stats.py b/google/cloud/bigtable_v2/types/request_stats.py new file mode 100644 index 000000000..d6f30c1c2 --- /dev/null +++ b/google/cloud/bigtable_v2/types/request_stats.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import proto # type: ignore + +from google.protobuf import duration_pb2 # type: ignore + + +__protobuf__ = proto.module( + package="google.bigtable.v2", + manifest={ + "ReadIteratorStats", + "RequestLatencyStats", + "ReadEfficiencyStats", + "AllReadStats", + "RequestStats", + }, +) + + +class ReadIteratorStats(proto.Message): + r"""ReadIteratorStats captures information about the iteration of + rows or cells over the course of a read, e.g. how many results + were scanned in a read operation versus the results returned. + + Attributes: + rows_seen_count (int): + The rows seen (scanned) as part of the + request. This includes the count of rows + returned, as captured below. + rows_returned_count (int): + The rows returned as part of the request. + cells_seen_count (int): + The cells seen (scanned) as part of the + request. This includes the count of cells + returned, as captured below. + cells_returned_count (int): + The cells returned as part of the request. + deletes_seen_count (int): + The deletes seen as part of the request. + """ + + rows_seen_count = proto.Field( + proto.INT64, + number=1, + ) + rows_returned_count = proto.Field( + proto.INT64, + number=2, + ) + cells_seen_count = proto.Field( + proto.INT64, + number=3, + ) + cells_returned_count = proto.Field( + proto.INT64, + number=4, + ) + deletes_seen_count = proto.Field( + proto.INT64, + number=5, + ) + + +class RequestLatencyStats(proto.Message): + r"""RequestLatencyStats provides a measurement of the latency of + the request as it interacts with different systems over its + lifetime, e.g. how long the request took to execute within a + frontend server. + + Attributes: + frontend_server_latency (google.protobuf.duration_pb2.Duration): + The latency measured by the frontend server + handling this request, from when the request was + received, to when this value is sent back in the + response. For more context on the component that + is measuring this latency, see: + https://cloud.google.com/bigtable/docs/overview + Note: This value may be slightly shorter than + the value reported into aggregate latency + metrics in Monitoring for this request + (https://cloud.google.com/bigtable/docs/monitoring-instance) + as this value needs to be sent in the response + before the latency measurement including that + transmission is finalized. + """ + + frontend_server_latency = proto.Field( + proto.MESSAGE, + number=1, + message=duration_pb2.Duration, + ) + + +class ReadEfficiencyStats(proto.Message): + r"""ReadEfficiencyStats captures information about the efficiency + of a read. + + Attributes: + read_iterator_stats (google.cloud.bigtable_v2.types.ReadIteratorStats): + Iteration stats describe how efficient the + read is, e.g. comparing rows seen vs. rows + returned or cells seen vs cells returned can + provide an indication of read efficiency (the + higher the ratio of seen to retuned the better). + request_latency_stats (google.cloud.bigtable_v2.types.RequestLatencyStats): + Request latency stats describe the time taken + to complete a request, from the server side. + """ + + read_iterator_stats = proto.Field( + proto.MESSAGE, + number=1, + message="ReadIteratorStats", + ) + request_latency_stats = proto.Field( + proto.MESSAGE, + number=2, + message="RequestLatencyStats", + ) + + +class AllReadStats(proto.Message): + r"""AllReadStats captures all known information about a read. + + Attributes: + read_iterator_stats (google.cloud.bigtable_v2.types.ReadIteratorStats): + Iteration stats describe how efficient the + read is, e.g. comparing rows seen vs. rows + returned or cells seen vs cells returned can + provide an indication of read efficiency (the + higher the ratio of seen to retuned the better). + request_latency_stats (google.cloud.bigtable_v2.types.RequestLatencyStats): + Request latency stats describe the time taken + to complete a request, from the server side. + """ + + read_iterator_stats = proto.Field( + proto.MESSAGE, + number=1, + message="ReadIteratorStats", + ) + request_latency_stats = proto.Field( + proto.MESSAGE, + number=2, + message="RequestLatencyStats", + ) + + +class RequestStats(proto.Message): + r"""RequestStats is the container for additional information pertaining + to a single request, helpful for evaluating the performance of the + sent request. Currently, there are the following supported methods: + + - google.bigtable.v2.ReadRows + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + read_efficiency_stats (google.cloud.bigtable_v2.types.ReadEfficiencyStats): + Available with the + ReadRowsRequest.RequestStatsView.REQUEST_STATS_EFFICIENCY + view, see package google.bigtable.v2. + + This field is a member of `oneof`_ ``stats``. + all_read_stats (google.cloud.bigtable_v2.types.AllReadStats): + Available with the + ReadRowsRequest.RequestStatsView.REQUEST_STATS_FULL view, + see package google.bigtable.v2. + + This field is a member of `oneof`_ ``stats``. + """ + + read_efficiency_stats = proto.Field( + proto.MESSAGE, + number=1, + oneof="stats", + message="ReadEfficiencyStats", + ) + all_read_stats = proto.Field( + proto.MESSAGE, + number=2, + oneof="stats", + message="AllReadStats", + ) + + +__all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/scripts/fixup_bigtable_v2_keywords.py b/scripts/fixup_bigtable_v2_keywords.py index 7459d0806..4424228fd 100644 --- a/scripts/fixup_bigtable_v2_keywords.py +++ b/scripts/fixup_bigtable_v2_keywords.py @@ -44,7 +44,7 @@ class bigtableCallTransformer(cst.CSTTransformer): 'mutate_rows': ('table_name', 'entries', 'app_profile_id', ), 'ping_and_warm': ('name', 'app_profile_id', ), 'read_modify_write_row': ('table_name', 'row_key', 'rules', 'app_profile_id', ), - 'read_rows': ('table_name', 'app_profile_id', 'rows', 'filter', 'rows_limit', ), + 'read_rows': ('table_name', 'app_profile_id', 'rows', 'filter', 'rows_limit', 'request_stats_view', ), 'sample_row_keys': ('table_name', 'app_profile_id', ), } diff --git a/tests/unit/gapic/bigtable_v2/test_bigtable.py b/tests/unit/gapic/bigtable_v2/test_bigtable.py index f3207869b..38f1bbd80 100644 --- a/tests/unit/gapic/bigtable_v2/test_bigtable.py +++ b/tests/unit/gapic/bigtable_v2/test_bigtable.py @@ -42,6 +42,7 @@ from google.cloud.bigtable_v2.services.bigtable import transports from google.cloud.bigtable_v2.types import bigtable from google.cloud.bigtable_v2.types import data +from google.cloud.bigtable_v2.types import request_stats from google.oauth2 import service_account import google.auth