Skip to content
This repository was archived by the owner on Apr 1, 2026. It is now read-only.

Commit 3ffc7c0

Browse files
committed
use ResponseParams proto to parse blob
1 parent f6831bb commit 3ffc7c0

2 files changed

Lines changed: 48 additions & 24 deletions

File tree

google/cloud/bigtable/data/_metrics/data_model.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
from grpc import StatusCode
2929

3030
import google.cloud.bigtable.data.exceptions as bt_exceptions
31+
from google.cloud.bigtable_v2.types.response_params import ResponseParams
32+
from google.protobuf.message import DecodeError
3133

3234
if TYPE_CHECKING:
3335
from google.cloud.bigtable.data._metrics.handlers._base import MetricsHandler
@@ -229,12 +231,16 @@ def add_response_metadata(self, metadata: dict[str, bytes | str]) -> None:
229231
INVALID_STATE_ERROR.format("add_response_metadata", self.state)
230232
)
231233
if self.cluster_id is None or self.zone is None:
232-
# BIGTABLE_METADATA_KEY should give a binary string with cluster_id and zone
234+
# BIGTABLE_METADATA_KEY should give a binary-encoded ResponseParams proto
233235
blob = cast(bytes, metadata.get(BIGTABLE_METADATA_KEY))
234236
if blob:
235237
parse_result = self._parse_response_metadata_blob(blob)
236238
if parse_result is not None:
237-
self.zone, self.cluster_id = parse_result
239+
cluster, zone = parse_result
240+
if cluster:
241+
self.cluster_id = cluster
242+
if zone:
243+
self.zone = zone
238244
else:
239245
self._handle_error(
240246
f"Failed to decode {BIGTABLE_METADATA_KEY} metadata: {blob!r}"
@@ -251,24 +257,19 @@ def add_response_metadata(self, metadata: dict[str, bytes | str]) -> None:
251257
@lru_cache(maxsize=32)
252258
def _parse_response_metadata_blob(blob: bytes) -> Tuple[str, str] | None:
253259
"""
254-
Parse the response metadata blob and return a dictionary of key-value pairs.
260+
Parse the response metadata blob and return a tuple of cluster and zone.
255261
256262
Function is cached to avoid parsing the same blob multiple times.
257263
258264
Args:
259265
- blob: the metadata blob as extracted from the grpc call
260266
Returns:
261-
- a tuple of zone and cluster_id, or None if parsing failed
267+
- a tuple of cluster_id and zone, or None if parsing failed
262268
"""
263269
try:
264-
decoded = "".join(
265-
c if c.isprintable() else " " for c in blob.decode("utf-8")
266-
)
267-
split_data = decoded.split()
268-
zone = split_data[0]
269-
cluster_id = split_data[1]
270-
return zone, cluster_id
271-
except (AttributeError, IndexError):
270+
proto = ResponseParams.pb().FromString(blob)
271+
return proto.cluster_id, proto.zone_id
272+
except (DecodeError, TypeError):
272273
# failed to parse metadata
273274
return None
274275

tests/unit/data/_metrics/test_data_model.py

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from google.cloud.bigtable.data._metrics.data_model import OperationState as State
2121
from google.cloud.bigtable.data._metrics.data_model import TimeTuple
22+
from google.cloud.bigtable_v2.types import ResponseParams
2223

2324

2425
class TestActiveOperationMetric:
@@ -247,27 +248,47 @@ def mock_generator():
247248
assert metric.active_attempt.backoff_before_attempt == i
248249

249250
@pytest.mark.parametrize(
250-
"start_cluster,start_zone,metadata_field,end_cluster,end_zone",
251+
"start_cluster,start_zone,metadata_proto,end_cluster,end_zone",
251252
[
252253
(None, None, None, None, None),
253254
("orig_cluster", "orig_zone", None, "orig_cluster", "orig_zone"),
254-
(None, None, b"zone cluster", "cluster", "zone"),
255+
(None, None, ResponseParams(), None, None),
256+
(
257+
"orig_cluster",
258+
"orig_zone",
259+
ResponseParams(),
260+
"orig_cluster",
261+
"orig_zone",
262+
),
255263
(
256264
None,
257265
None,
258-
b"\n\rtest-cluster\x12\x0cus-central1-b",
259-
"us-central1-b",
266+
ResponseParams(cluster_id="test-cluster", zone_id="us-central1-b"),
260267
"test-cluster",
268+
"us-central1-b",
269+
),
270+
(
271+
None,
272+
"filled",
273+
ResponseParams(cluster_id="cluster", zone_id="zone"),
274+
"cluster",
275+
"zone",
276+
),
277+
(None, "filled", ResponseParams(cluster_id="cluster"), "cluster", "filled"),
278+
(None, "filled", ResponseParams(zone_id="zone"), None, "zone"),
279+
(
280+
"filled",
281+
None,
282+
ResponseParams(cluster_id="cluster", zone_id="zone"),
283+
"cluster",
284+
"zone",
261285
),
262-
("orig_cluster", "orig_zone", b"new_new", "orig_cluster", "orig_zone"),
263-
(None, None, b"", None, None),
264-
(None, None, b"zone cluster future", "cluster", "zone"),
265-
(None, "filled", b"zone cluster", "cluster", "zone"),
266-
("filled", None, b"zone cluster", "cluster", "zone"),
286+
("filled", None, ResponseParams(cluster_id="cluster"), "cluster", None),
287+
("filled", None, ResponseParams(zone_id="zone"), "filled", "zone"),
267288
],
268289
)
269290
def test_add_response_metadata_cbt_header(
270-
self, start_cluster, start_zone, metadata_field, end_cluster, end_zone
291+
self, start_cluster, start_zone, metadata_proto, end_cluster, end_zone
271292
):
272293
"""
273294
calling add_response_metadata should update fields based on grpc response metadata
@@ -283,8 +304,10 @@ def test_add_response_metadata_cbt_header(
283304
metric.active_attempt = mock.Mock()
284305
metric.active_attempt.gfe_latency = None
285306
metadata = grpc.aio.Metadata()
286-
if metadata_field:
287-
metadata["x-goog-ext-425905942-bin"] = metadata_field
307+
if metadata_proto is not None:
308+
metadata["x-goog-ext-425905942-bin"] = ResponseParams.serialize(
309+
metadata_proto
310+
)
288311
metric.add_response_metadata(metadata)
289312
assert metric.cluster_id == end_cluster
290313
assert metric.zone == end_zone

0 commit comments

Comments
 (0)