diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index aa547962e..3815c983c 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,4 +13,4 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:e09366bdf0fd9c8976592988390b24d53583dd9f002d476934da43725adbb978 + digest: sha256:7a40313731a7cb1454eef6b33d3446ebb121836738dc3ab3d2d3ded5268c35b6 diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index 385f2d4d6..d15994bac 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -325,31 +325,30 @@ platformdirs==2.5.2 \ --hash=sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788 \ --hash=sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19 # via virtualenv -protobuf==3.20.1 \ - --hash=sha256:06059eb6953ff01e56a25cd02cca1a9649a75a7e65397b5b9b4e929ed71d10cf \ - --hash=sha256:097c5d8a9808302fb0da7e20edf0b8d4703274d140fd25c5edabddcde43e081f \ - --hash=sha256:284f86a6207c897542d7e956eb243a36bb8f9564c1742b253462386e96c6b78f \ - --hash=sha256:32ca378605b41fd180dfe4e14d3226386d8d1b002ab31c969c366549e66a2bb7 \ - --hash=sha256:3cc797c9d15d7689ed507b165cd05913acb992d78b379f6014e013f9ecb20996 \ - --hash=sha256:62f1b5c4cd6c5402b4e2d63804ba49a327e0c386c99b1675c8a0fefda23b2067 \ - --hash=sha256:69ccfdf3657ba59569c64295b7d51325f91af586f8d5793b734260dfe2e94e2c \ - --hash=sha256:6f50601512a3d23625d8a85b1638d914a0970f17920ff39cec63aaef80a93fb7 \ - --hash=sha256:7403941f6d0992d40161aa8bb23e12575637008a5a02283a930addc0508982f9 \ - --hash=sha256:755f3aee41354ae395e104d62119cb223339a8f3276a0cd009ffabfcdd46bb0c \ - --hash=sha256:77053d28427a29987ca9caf7b72ccafee011257561259faba8dd308fda9a8739 \ - --hash=sha256:7e371f10abe57cee5021797126c93479f59fccc9693dafd6bd5633ab67808a91 \ - --hash=sha256:9016d01c91e8e625141d24ec1b20fed584703e527d28512aa8c8707f105a683c \ - --hash=sha256:9be73ad47579abc26c12024239d3540e6b765182a91dbc88e23658ab71767153 \ - --hash=sha256:adc31566d027f45efe3f44eeb5b1f329da43891634d61c75a5944e9be6dd42c9 \ - --hash=sha256:adfc6cf69c7f8c50fd24c793964eef18f0ac321315439d94945820612849c388 \ - --hash=sha256:af0ebadc74e281a517141daad9d0f2c5d93ab78e9d455113719a45a49da9db4e \ - --hash=sha256:cb29edb9eab15742d791e1025dd7b6a8f6fcb53802ad2f6e3adcb102051063ab \ - --hash=sha256:cd68be2559e2a3b84f517fb029ee611546f7812b1fdd0aa2ecc9bc6ec0e4fdde \ - --hash=sha256:cdee09140e1cd184ba9324ec1df410e7147242b94b5f8b0c64fc89e38a8ba531 \ - --hash=sha256:db977c4ca738dd9ce508557d4fce0f5aebd105e158c725beec86feb1f6bc20d8 \ - --hash=sha256:dd5789b2948ca702c17027c84c2accb552fc30f4622a98ab5c51fcfe8c50d3e7 \ - --hash=sha256:e250a42f15bf9d5b09fe1b293bdba2801cd520a9f5ea2d7fb7536d4441811d20 \ - --hash=sha256:ff8d8fa42675249bb456f5db06c00de6c2f4c27a065955917b28c4f15978b9c3 +protobuf==3.20.2 \ + --hash=sha256:03d76b7bd42ac4a6e109742a4edf81ffe26ffd87c5993126d894fe48a120396a \ + --hash=sha256:09e25909c4297d71d97612f04f41cea8fa8510096864f2835ad2f3b3df5a5559 \ + --hash=sha256:18e34a10ae10d458b027d7638a599c964b030c1739ebd035a1dfc0e22baa3bfe \ + --hash=sha256:291fb4307094bf5ccc29f424b42268640e00d5240bf0d9b86bf3079f7576474d \ + --hash=sha256:2c0b040d0b5d5d207936ca2d02f00f765906622c07d3fa19c23a16a8ca71873f \ + --hash=sha256:384164994727f274cc34b8abd41a9e7e0562801361ee77437099ff6dfedd024b \ + --hash=sha256:3cb608e5a0eb61b8e00fe641d9f0282cd0eedb603be372f91f163cbfbca0ded0 \ + --hash=sha256:5d9402bf27d11e37801d1743eada54372f986a372ec9679673bfcc5c60441151 \ + --hash=sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750 \ + --hash=sha256:7a5037af4e76c975b88c3becdf53922b5ffa3f2cddf657574a4920a3b33b80f3 \ + --hash=sha256:8228e56a865c27163d5d1d1771d94b98194aa6917bcfb6ce139cbfa8e3c27334 \ + --hash=sha256:84a1544252a933ef07bb0b5ef13afe7c36232a774affa673fc3636f7cee1db6c \ + --hash=sha256:84fe5953b18a383fd4495d375fe16e1e55e0a3afe7b4f7b4d01a3a0649fcda9d \ + --hash=sha256:9c673c8bfdf52f903081816b9e0e612186684f4eb4c17eeb729133022d6032e3 \ + --hash=sha256:9f876a69ca55aed879b43c295a328970306e8e80a263ec91cf6e9189243c613b \ + --hash=sha256:a9e5ae5a8e8985c67e8944c23035a0dff2c26b0f5070b2f55b217a1c33bbe8b1 \ + --hash=sha256:b4fdb29c5a7406e3f7ef176b2a7079baa68b5b854f364c21abe327bbeec01cdb \ + --hash=sha256:c184485e0dfba4dfd451c3bd348c2e685d6523543a0f91b9fd4ae90eb09e8422 \ + --hash=sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019 \ + --hash=sha256:e39cf61bb8582bda88cdfebc0db163b774e7e03364bbf9ce1ead13863e81e359 \ + --hash=sha256:e8fbc522303e09036c752a0afcc5c0603e917222d8bedc02813fd73b4b4ed804 \ + --hash=sha256:f34464ab1207114e73bba0794d1257c150a2b89b7a9faf504e00af7c9fd58978 \ + --hash=sha256:f52dabc96ca99ebd2169dadbe018824ebda08a795c7684a0b7d203a290f3adb0 # via # gcp-docuploader # gcp-releasetool diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ed69b363..c2e894ae8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ [1]: https://pypi.org/project/google-cloud-bigtable/#history +## [2.13.0](https://github.com/googleapis/python-bigtable/compare/v2.12.0...v2.13.0) (2022-09-29) + + +### Features + +* Publish the RequestStats proto ([#676](https://github.com/googleapis/python-bigtable/issues/676)) ([199949b](https://github.com/googleapis/python-bigtable/commit/199949b2a930706654680b91a93f2a903bf112bf)) + + +### Bug Fixes + +* **deps:** Require protobuf >= 3.20.2 ([#679](https://github.com/googleapis/python-bigtable/issues/679)) ([030ef38](https://github.com/googleapis/python-bigtable/commit/030ef3868c442a8a21c4b4d6217b99cab09a1be7)) + ## [2.12.0](https://github.com/googleapis/python-bigtable/compare/v2.11.3...v2.12.0) (2022-09-19) 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/setup.py b/setup.py index 72fc4fd30..adcfa5417 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ name = "google-cloud-bigtable" description = "Google Cloud Bigtable API client library" -version = "2.12.0" +version = "2.13.0" # Should be one of: # 'Development Status :: 3 - Alpha' # 'Development Status :: 4 - Beta' @@ -33,7 +33,7 @@ "google-cloud-core >= 1.4.1, <3.0.0dev", "grpc-google-iam-v1 >= 0.12.4, <1.0.0dev", "proto-plus >= 1.22.0, <2.0.0dev", - "protobuf >= 3.19.0, <5.0.0dev", + "protobuf >= 3.20.2, <5.0.0dev", ] extras = {"libcst": "libcst >= 0.2.5"} diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt index f9281ed96..8dacb7c6c 100644 --- a/testing/constraints-3.7.txt +++ b/testing/constraints-3.7.txt @@ -10,5 +10,5 @@ google-cloud-core==1.4.1 grpc-google-iam-v1==0.12.4 proto-plus==1.22.0 libcst==0.2.5 -protobuf==3.19.0 +protobuf==3.20.2 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