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

Commit 3eae4aa

Browse files
committed
fixed lint and mypy
1 parent 996acf2 commit 3eae4aa

11 files changed

Lines changed: 236 additions & 145 deletions

File tree

google/cloud/bigtable/data/_async/_mutate_rows.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ async def _run_attempt(self):
169169
retry after the attempt is complete
170170
GoogleAPICallError: if the gapic rpc fails
171171
"""
172-
# register attempt start
172+
# register attempt start
173173
self._operation_metric.start_attempt()
174174
request_entries = [self.mutations[idx].proto for idx in self.remaining_indices]
175175
# track mutations in this request that have not been finalized yet

google/cloud/bigtable/data/_async/_read_rows.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,11 @@
3434
from google.cloud.bigtable.data._helpers import TrackedBackoffGenerator
3535

3636
from google.api_core import retry as retries
37-
from google.api_core.retry import exponential_sleep_generator
3837

3938
from google.cloud.bigtable.data._cross_sync import CrossSync
4039

4140
if TYPE_CHECKING:
41+
from google.cloud.bigtable.data._metrics import ActiveAttemptMetric
4242
from google.cloud.bigtable.data._metrics import ActiveOperationMetric
4343

4444
if CrossSync.is_async:
@@ -139,7 +139,7 @@ def _read_rows_attempt(self) -> CrossSync.Iterable[Row]:
139139
Yields:
140140
Row: The next row in the stream
141141
"""
142-
self._operation_metric.start_attempt()
142+
attempt_metric = self._operation_metric.start_attempt()
143143
# revise request keys and ranges between attempts
144144
if self._last_yielded_row_key is not None:
145145
# if this is a retry, try to trim down the request to avoid ones we've already processed
@@ -150,20 +150,20 @@ def _read_rows_attempt(self) -> CrossSync.Iterable[Row]:
150150
)
151151
except _RowSetComplete:
152152
# if we've already seen all the rows, we're done
153-
return self.merge_rows(None, self._operation_metric)
153+
return self.merge_rows(None, attempt_metric)
154154
# revise the limit based on number of rows already yielded
155155
if self._remaining_count is not None:
156156
self.request.rows_limit = self._remaining_count
157157
if self._remaining_count == 0:
158-
return self.merge_rows(None, self._operation_metric)
158+
return self.merge_rows(None, attempt_metric)
159159
# create and return a new row merger
160160
gapic_stream = self.target.client._gapic_client.read_rows(
161161
self.request,
162162
timeout=next(self.attempt_timeout_gen),
163163
retry=None,
164164
)
165165
chunked_stream = self.chunk_stream(gapic_stream)
166-
return self.merge_rows(chunked_stream, self._operation_metric)
166+
return self.merge_rows(chunked_stream, attempt_metric)
167167

168168
@CrossSync.convert()
169169
async def chunk_stream(
@@ -223,7 +223,7 @@ async def chunk_stream(
223223
)
224224
async def merge_rows(
225225
chunks: CrossSync.Iterable[ReadRowsResponsePB.CellChunk] | None,
226-
operation_metric: ActiveOperationMetric,
226+
attempt_metric: ActiveAttemptMetric,
227227
) -> CrossSync.Iterable[Row]:
228228
"""
229229
Merge chunks into rows
@@ -322,13 +322,13 @@ async def merge_rows(
322322
if is_first_row:
323323
# record first row latency in metrics
324324
is_first_row = False
325-
operation_metric.attempt_first_response()
326-
block_time = time.monotonic()
325+
attempt_metric.attempt_first_response()
326+
block_time = time.monotonic_ns()
327327
yield Row(row_key, cells)
328328
# most metric operations use setters, but this one updates
329329
# the value directly to avoid extra overhead
330-
operation_metric.active_attempt.application_blocking_time_ms += ( # type: ignore
331-
time.monotonic() - block_time
330+
attempt_metric.active_attempt.application_blocking_time_ns += ( # type: ignore
331+
time.monotonic_ns() - block_time
332332
) * 1000
333333
break
334334
c = await it.__anext__()

google/cloud/bigtable/data/_async/client.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@
125125
if TYPE_CHECKING:
126126
from google.cloud.bigtable.data._helpers import RowKeySamples
127127
from google.cloud.bigtable.data._helpers import ShardedQuery
128-
from google.cloud.bigtable.data._metrics import ActiveOperationMetric
129128

130129
if CrossSync.is_async:
131130
from google.cloud.bigtable.data._async.mutations_batcher import (
@@ -1021,7 +1020,7 @@ async def read_rows_stream(
10211020
)
10221021
retryable_excs = _get_retryable_errors(retryable_errors, self)
10231022

1024-
with self._metrics.create_operation(
1023+
async with self._metrics.create_operation(
10251024
OperationType.READ_ROWS, streaming=True
10261025
) as operation_metric:
10271026
row_merger = CrossSync._ReadRowsOperation(
@@ -1130,7 +1129,7 @@ async def read_row(
11301129
)
11311130
retryable_excs = _get_retryable_errors(retryable_errors, self)
11321131

1133-
with self._metrics.create_operation(
1132+
async with self._metrics.create_operation(
11341133
OperationType.READ_ROWS, streaming=False
11351134
) as operation_metric:
11361135
row_merger = CrossSync._ReadRowsOperation(

google/cloud/bigtable/data/_async/mutations_batcher.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,21 @@ async def add_to_flow(self, mutations: RowMutationEntry | list[RowMutationEntry]
182182
yield mutations[start_idx:end_idx]
183183

184184
async def add_to_flow_with_metrics(
185-
self, mutations: RowMutationEntry | list[RowMutationEntry], metrics_controller: BigtableClientSideMetricsController
185+
self,
186+
mutations: RowMutationEntry | list[RowMutationEntry],
187+
metrics_controller: BigtableClientSideMetricsController,
186188
):
187189
inner_generator = self.add_to_flow(mutations)
188190
while True:
189191
# start a new metric
190192
metric = metrics_controller.create_operation(OperationType.BULK_MUTATE_ROWS)
191-
flow_start_time = time.monotonic()
193+
flow_start_time = time.monotonic_ns()
192194
try:
193195
value = await inner_generator.__anext__()
194196
except StopAsyncIteration:
195197
metric.cancel()
196198
return
197-
metric.flow_throttling_time = time.monotonic() - flow_start_time
199+
metric.flow_throttling_time_ns = time.monotonic_ns() - flow_start_time
198200
yield value, metric
199201

200202

@@ -373,9 +375,14 @@ async def _flush_internal(self, new_entries: list[RowMutationEntry]):
373375
"""
374376
# flush new entries
375377
in_process_requests: list[CrossSync.Future[list[FailedMutationEntryError]]] = []
376-
async for batch, metric in self._flow_control.add_to_flow_with_metrics(new_entries, self._target._metrics):
378+
async for batch, metric in self._flow_control.add_to_flow_with_metrics(
379+
new_entries, self._target._metrics
380+
):
377381
batch_task = CrossSync.create_task(
378-
self._execute_mutate_rows, batch, metric, sync_executor=self._sync_rpc_executor
382+
self._execute_mutate_rows,
383+
batch,
384+
metric,
385+
sync_executor=self._sync_rpc_executor,
379386
)
380387
in_process_requests.append(batch_task)
381388
# wait for all inflight requests to complete

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414
from __future__ import annotations
1515

16-
from typing import Callable, Tuple, cast, TYPE_CHECKING
16+
from typing import Tuple, cast, TYPE_CHECKING
1717

1818
import time
1919
import re
@@ -184,7 +184,7 @@ def start(self) -> None:
184184
return self._handle_error(INVALID_STATE_ERROR.format("start", self.state))
185185
self.start_time_ns = time.monotonic_ns()
186186

187-
def start_attempt(self) -> None:
187+
def start_attempt(self) -> ActiveAttemptMetric:
188188
"""
189189
Called to initiate a new attempt for the operation.
190190
@@ -210,6 +210,7 @@ def start_attempt(self) -> None:
210210
backoff_ns = 0
211211

212212
self.active_attempt = ActiveAttemptMetric(backoff_before_attempt_ns=backoff_ns)
213+
return self.active_attempt
213214

214215
def add_response_metadata(self, metadata: dict[str, bytes | str]) -> None:
215216
"""
@@ -428,4 +429,4 @@ async def __aexit__(self, exc_type, exc_val, exc_tb):
428429
if exc_val is None:
429430
self.end_with_success()
430431
else:
431-
self.end_with_status(exc_val)
432+
self.end_with_status(exc_val)

google/cloud/bigtable/data/_metrics/handlers/_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,4 @@ def on_operation_cancelled(self, op: ActiveOperationMetric) -> None:
3535
def on_attempt_complete(
3636
self, attempt: CompletedAttemptMetric, op: ActiveOperationMetric
3737
) -> None:
38-
pass
38+
pass

google/cloud/bigtable/data/_metrics/handlers/_stdout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ def print(self):
4545
print(
4646
f"{ops_type}: count: {count}, avg latency: {avg_latency:.2f} ms, avg attempts: {avg_attempts:.1f}"
4747
)
48-
print()
48+
print()

google/cloud/bigtable/data/_sync_autogen/_mutate_rows.py

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
import google.cloud.bigtable.data.exceptions as bt_exceptions
2424
from google.cloud.bigtable.data._helpers import _attempt_timeout_generator
2525
from google.cloud.bigtable.data._helpers import _retry_exception_factory
26+
from google.cloud.bigtable.data._helpers import TrackedBackoffGenerator
2627
from google.cloud.bigtable.data.mutations import _MUTATE_ROWS_REQUEST_MUTATION_LIMIT
2728
from google.cloud.bigtable.data.mutations import _EntryWithProto
2829
from google.cloud.bigtable.data._cross_sync import CrossSync
2930

3031
if TYPE_CHECKING:
3132
from google.cloud.bigtable.data.mutations import RowMutationEntry
33+
from google.cloud.bigtable.data._metrics import ActiveOperationMetric
3234
from google.cloud.bigtable_v2.services.bigtable.client import (
3335
BigtableClient as GapicClientType,
3436
)
@@ -54,6 +56,8 @@ class _MutateRowsOperation:
5456
operation_timeout: the timeout to use for the entire operation, in seconds.
5557
attempt_timeout: the timeout to use for each mutate_rows attempt, in seconds.
5658
If not specified, the request will run until operation_timeout is reached.
59+
metric: the metric object representing the active operation
60+
retryable_exceptions: a list of exceptions that should be retried
5761
"""
5862

5963
def __init__(
@@ -63,6 +67,7 @@ def __init__(
6367
mutation_entries: list["RowMutationEntry"],
6468
operation_timeout: float,
6569
attempt_timeout: float | None,
70+
metric: ActiveOperationMetric,
6671
retryable_exceptions: Sequence[type[Exception]] = (),
6772
):
6873
total_mutations = sum((len(entry.mutations) for entry in mutation_entries))
@@ -75,7 +80,7 @@ def __init__(
7580
self.is_retryable = retries.if_exception_type(
7681
*retryable_exceptions, bt_exceptions._MutateRowsIncomplete
7782
)
78-
sleep_generator = retries.exponential_sleep_generator(0.01, 2, 60)
83+
sleep_generator = TrackedBackoffGenerator(0.01, 2, 60)
7984
self._operation = lambda: CrossSync._Sync_Impl.retry_target(
8085
self._run_attempt,
8186
self.is_retryable,
@@ -89,37 +94,40 @@ def __init__(
8994
self.mutations = [_EntryWithProto(m, m._to_pb()) for m in mutation_entries]
9095
self.remaining_indices = list(range(len(self.mutations)))
9196
self.errors: dict[int, list[Exception]] = {}
97+
metric.backoff_generator = sleep_generator
98+
self._operation_metric = metric
9299

93100
def start(self):
94101
"""Start the operation, and run until completion
95102
96103
Raises:
97104
MutationsExceptionGroup: if any mutations failed"""
98-
try:
99-
self._operation()
100-
except Exception as exc:
101-
incomplete_indices = self.remaining_indices.copy()
102-
for idx in incomplete_indices:
103-
self._handle_entry_error(idx, exc)
104-
finally:
105-
all_errors: list[Exception] = []
106-
for idx, exc_list in self.errors.items():
107-
if len(exc_list) == 0:
108-
raise core_exceptions.ClientError(
109-
f"Mutation {idx} failed with no associated errors"
105+
with self._operation_metric:
106+
try:
107+
self._operation()
108+
except Exception as exc:
109+
incomplete_indices = self.remaining_indices.copy()
110+
for idx in incomplete_indices:
111+
self._handle_entry_error(idx, exc)
112+
finally:
113+
all_errors: list[Exception] = []
114+
for idx, exc_list in self.errors.items():
115+
if len(exc_list) == 0:
116+
raise core_exceptions.ClientError(
117+
f"Mutation {idx} failed with no associated errors"
118+
)
119+
elif len(exc_list) == 1:
120+
cause_exc = exc_list[0]
121+
else:
122+
cause_exc = bt_exceptions.RetryExceptionGroup(exc_list)
123+
entry = self.mutations[idx].entry
124+
all_errors.append(
125+
bt_exceptions.FailedMutationEntryError(idx, entry, cause_exc)
126+
)
127+
if all_errors:
128+
raise bt_exceptions.MutationsExceptionGroup(
129+
all_errors, len(self.mutations)
110130
)
111-
elif len(exc_list) == 1:
112-
cause_exc = exc_list[0]
113-
else:
114-
cause_exc = bt_exceptions.RetryExceptionGroup(exc_list)
115-
entry = self.mutations[idx].entry
116-
all_errors.append(
117-
bt_exceptions.FailedMutationEntryError(idx, entry, cause_exc)
118-
)
119-
if all_errors:
120-
raise bt_exceptions.MutationsExceptionGroup(
121-
all_errors, len(self.mutations)
122-
)
123131

124132
def _run_attempt(self):
125133
"""Run a single attempt of the mutate_rows rpc.
@@ -128,6 +136,7 @@ def _run_attempt(self):
128136
_MutateRowsIncomplete: if there are failed mutations eligible for
129137
retry after the attempt is complete
130138
GoogleAPICallError: if the gapic rpc fails"""
139+
self._operation_metric.start_attempt()
131140
request_entries = [self.mutations[idx].proto for idx in self.remaining_indices]
132141
active_request_indices = {
133142
req_idx: orig_idx

0 commit comments

Comments
 (0)