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

Commit b7f1f90

Browse files
gkevinzhengmutianf
andauthored
feat: Reworked the wait_for_consistency call (#1144)
* feat: Reworked the wait_for_consistency call * linting * Update google/cloud/bigtable/admin_v2/overlay/services/bigtable_table_admin/client.py Co-authored-by: Mattie Fu <mattiefu@google.com> * Improved documentation * linting again * linting --------- Co-authored-by: Mattie Fu <mattiefu@google.com>
1 parent 3d714e2 commit b7f1f90

7 files changed

Lines changed: 315 additions & 271 deletions

File tree

google/cloud/bigtable/admin_v2/overlay/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
from .types import (
3333
RestoreTableOperation,
34-
CheckConsistencyPollingFuture,
3534
)
3635

3736
from .services.bigtable_table_admin import (
@@ -40,6 +39,5 @@
4039

4140
__all__ = (
4241
"RestoreTableOperation",
43-
"CheckConsistencyPollingFuture",
4442
"BigtableTableAdminClient",
4543
)

google/cloud/bigtable/admin_v2/overlay/services/bigtable_table_admin/client.py

Lines changed: 82 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@
5050
from google.cloud.bigtable.admin_v2.services.bigtable_table_admin.transports.base import (
5151
BigtableTableAdminTransport,
5252
)
53-
from google.cloud.bigtable.admin_v2.overlay.types import consistency, restore_table
53+
from google.cloud.bigtable.admin_v2.overlay.types import (
54+
consistency,
55+
restore_table,
56+
wait_for_consistency_request,
57+
)
5458

5559
from google.cloud.bigtable.gapic_version import __version__ as bigtable_version
5660

@@ -227,20 +231,19 @@ def sample_restore_table():
227231
def wait_for_consistency(
228232
self,
229233
request: Optional[
230-
Union[bigtable_table_admin.CheckConsistencyRequest, dict]
234+
Union[wait_for_consistency_request.WaitForConsistencyRequest, dict]
231235
] = None,
232236
*,
233237
name: Optional[str] = None,
234-
consistency_token: Optional[str] = None,
235238
retry: OptionalRetry = gapic_v1.method.DEFAULT,
236239
timeout: Union[float, object] = gapic_v1.method.DEFAULT,
237240
metadata: Sequence[Tuple[str, Union[str, bytes]]] = (),
238-
) -> consistency.CheckConsistencyPollingFuture:
239-
r"""Creates a polling future that periodically checks replication
240-
consistency based on a consistency token, that is, if replication
241-
has caught up based on the conditions specified in the token and
242-
the check request. The future will stop checking once the underlying
243-
:meth:`check_consistency` request involving that token returns True.
241+
) -> bool:
242+
r"""Blocks until the mutations for the specified Table that have been
243+
made before the call have been replicated or reads using an app profile with `DataBoostIsolationReadOnly`
244+
can see all writes committed before the token was created. This is done by generating
245+
a consistency token for the Table, then polling :meth:`check_consistency`
246+
for the specified table until the call returns True.
244247
245248
.. code-block:: python
246249
@@ -257,41 +260,29 @@ def sample_wait_for_consistency():
257260
client = admin_v2.BigtableTableAdminClient()
258261
259262
# Initialize request argument(s)
260-
request = admin_v2.CheckConsistencyRequest(
263+
request = admin_v2.WaitForConsistencyRequest(
261264
name="name_value",
262-
consistency_token="consistency_token_value",
263265
)
264266
265267
# Make the request
266-
future = client.wait_for_consistency(request=request)
267-
268-
# Wait for the table to become consistent
269268
print("Waiting for operation to complete...")
270269
271-
response = future.result()
270+
response = client.wait_for_replication(request=request)
272271
273272
# Handle the response
274273
print(response)
275274
276275
Args:
277-
request (Union[google.cloud.bigtable.admin_v2.types.CheckConsistencyRequest, dict]):
278-
The request object. Request message for
279-
[google.bigtable.admin.v2.BigtableTableAdmin.CheckConsistency][google.bigtable.admin.v2.BigtableTableAdmin.CheckConsistency]
276+
request (Union[google.cloud.bigtable.admin_v2.overlay.types.WaitForConsistencyRequest, dict]):
277+
The request object.
280278
name (str):
281279
Required. The unique name of the Table for which to
282-
check replication consistency. Values are of the form
280+
create a consistency token. Values are of the form
283281
``projects/{project}/instances/{instance}/tables/{table}``.
284282
285283
This corresponds to the ``name`` field
286284
on the ``request`` instance; if ``request`` is provided, this
287285
should not be set.
288-
consistency_token (str):
289-
Required. The token created using
290-
GenerateConsistencyToken for the Table.
291-
292-
This corresponds to the ``consistency_token`` field
293-
on the ``request`` instance; if ``request`` is provided, this
294-
should not be set.
295286
retry (google.api_core.retry.Retry): Designation of what errors, if any,
296287
should be retried.
297288
timeout (float): The timeout for this request.
@@ -301,120 +292,82 @@ def sample_wait_for_consistency():
301292
be of type `bytes`.
302293
303294
Returns:
304-
google.cloud.bigtable.admin_v2.overlay.types.CheckConsistencyPollingFuture:
305-
An object representing a polling future.
295+
bool:
296+
If the `standard_read_remote_writes` mode is specified in the request object, returns
297+
`True` after the mutations of the specified table have been fully replicated. If the
298+
`data_boost_read_local_writes` mode is specified in the request object, returns `True`
299+
after reads using an app profile with `DataBoostIsolationReadOnly` can see all writes
300+
committed before the token was created.
306301
307-
The result type for the operation will be `bool`, and will return True when the
308-
consistency check involving the given consistency token returns True.
302+
Raises:
303+
google.api_core.GoogleAPICallError: If the operation errors or if
304+
the timeout is reached before the operation completes.
309305
"""
310-
api_call = functools.partial(
311-
self.check_consistency,
312-
request,
313-
name=name,
314-
consistency_token=consistency_token,
315-
timeout=timeout,
316-
metadata=metadata,
306+
# Create or coerce a protobuf request object.
307+
# - Quick check: If we got a request object, we should *not* have
308+
# gotten any keyword arguments that map to the request.
309+
flattened_params = [name]
310+
has_flattened_params = (
311+
len([param for param in flattened_params if param is not None]) > 0
312+
)
313+
if request is not None and has_flattened_params:
314+
raise ValueError(
315+
"If the `request` argument is set, then none of "
316+
"the individual field arguments should be set."
317+
)
318+
319+
# - Use the request object if provided (there's no risk of modifying the input as
320+
# there are no flattened fields), or create one.
321+
if not isinstance(
322+
request, wait_for_consistency_request.WaitForConsistencyRequest
323+
):
324+
request = wait_for_consistency_request.WaitForConsistencyRequest(request)
325+
# If we have keyword arguments corresponding to fields on the
326+
# request, apply these.
327+
if name is not None:
328+
request.name = name
329+
330+
# Generate the consistency token.
331+
generate_consistency_token_request = (
332+
bigtable_table_admin.GenerateConsistencyTokenRequest(
333+
name=request.name,
334+
)
317335
)
318-
return consistency.CheckConsistencyPollingFuture(api_call, default_retry=retry)
319-
320-
def wait_for_replication(
321-
self,
322-
request: Optional[
323-
Union[bigtable_table_admin.GenerateConsistencyTokenRequest, dict]
324-
] = None,
325-
*,
326-
name: Optional[str] = None,
327-
retry: OptionalRetry = gapic_v1.method.DEFAULT,
328-
timeout: Union[float, object] = gapic_v1.method.DEFAULT,
329-
metadata: Sequence[Tuple[str, Union[str, bytes]]] = (),
330-
) -> consistency.CheckConsistencyPollingFuture:
331-
r"""Generates a consistency token for a Table, which will then
332-
be used to create a polling future for checking the replication
333-
consistency based on that token. The future will stop checking
334-
once the underlying :meth:`check_consistency` request involving
335-
that token returns True.
336-
337-
.. code-block:: python
338-
339-
# This snippet should be regarded as a code template only.
340-
# It will require modifications to work:
341-
# - It may require correct/in-range values for request initialization.
342-
# - It may require specifying regional endpoints when creating the service
343-
# client as shown in:
344-
# https://googleapis.dev/python/google-api-core/latest/client_options.html
345-
from google.cloud.bigtable import admin_v2
346-
347-
def sample_wait_for_replication():
348-
# Create a client
349-
client = admin_v2.BigtableTableAdminClient()
350-
351-
# Initialize request argument(s)
352-
request = admin_v2.GenerateConsistencyTokenRequest(
353-
name="name_value",
354-
)
355-
356-
# Make the request
357-
future = client.wait_for_replication(request=request)
358-
359-
# Wait for the table to become consistent
360-
print("Waiting for operation to complete...")
361-
362-
response = future.result()
363-
364-
# Handle the response
365-
print(response)
366-
367-
Args:
368-
request (Union[google.cloud.bigtable.admin_v2.types.GenerateConsistencyTokenRequest, dict]):
369-
The request object. Request message for
370-
[google.bigtable.admin.v2.BigtableTableAdmin.GenerateConsistencyToken][google.bigtable.admin.v2.BigtableTableAdmin.GenerateConsistencyToken]
371-
name (str):
372-
Required. The unique name of the Table for which to
373-
create a consistency token. Values are of the form
374-
``projects/{project}/instances/{instance}/tables/{table}``.
375-
376-
This corresponds to the ``name`` field
377-
on the ``request`` instance; if ``request`` is provided, this
378-
should not be set.
379-
retry (google.api_core.retry.Retry): Designation of what errors, if any,
380-
should be retried.
381-
timeout (float): The timeout for this request.
382-
metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be
383-
sent along with the request as metadata. Normally, each value must be of type `str`,
384-
but for metadata keys ending with the suffix `-bin`, the corresponding values must
385-
be of type `bytes`.
386-
387-
Returns:
388-
google.cloud.bigtable.admin_v2.overlay.types.CheckConsistencyPollingFuture:
389-
An object representing a polling future.
390336

391-
The result type for the operation will be `bool`, and will return True when the
392-
consistency check involving the given consistency token returns True.
393-
"""
394337
generate_consistency_response = self.generate_consistency_token(
395-
request,
396-
name=name,
338+
generate_consistency_token_request,
397339
retry=retry,
398340
timeout=timeout,
399341
metadata=metadata,
400342
)
401343

402344
# Create the CheckConsistencyRequest object.
403-
check_consistency_request = bigtable_table_admin.CheckConsistencyRequest()
404-
405-
# If the generate_consistency_token request is valid, there's a name in the request object
406-
# or the name parameter.
407-
if isinstance(request, dict):
408-
check_consistency_request.name = request["name"]
409-
elif isinstance(request, bigtable_table_admin.GenerateConsistencyTokenRequest):
410-
check_consistency_request.name = request.name
411-
else:
412-
check_consistency_request.name = name
413-
414-
check_consistency_request.consistency_token = (
415-
generate_consistency_response.consistency_token
345+
check_consistency_request = bigtable_table_admin.CheckConsistencyRequest(
346+
name=request.name,
347+
consistency_token=generate_consistency_response.consistency_token,
348+
)
349+
350+
# Since the default values of StandardReadRemoteWrites and DataBoostReadLocalWrites evaluate to
351+
# False in proto plus, we cannot do a simple "if request.standard_read_remote_writes" to check
352+
# whether or not that field is defined in the original request object.
353+
mode_oneof_field = request._pb.WhichOneof("mode")
354+
if mode_oneof_field:
355+
setattr(
356+
check_consistency_request,
357+
mode_oneof_field,
358+
getattr(request, mode_oneof_field),
359+
)
360+
361+
check_consistency_call = functools.partial(
362+
self.check_consistency,
363+
check_consistency_request,
364+
retry=retry,
365+
timeout=timeout,
366+
metadata=metadata,
416367
)
417368

418-
return self.wait_for_consistency(
419-
check_consistency_request, retry=retry, timeout=timeout, metadata=metadata
369+
# Block and wait until the polling harness returns True.
370+
check_consistency_future = consistency._CheckConsistencyPollingFuture(
371+
check_consistency_call
420372
)
373+
return check_consistency_future.result()

google/cloud/bigtable/admin_v2/overlay/types/__init__.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from .consistency import (
16-
CheckConsistencyPollingFuture,
17-
)
18-
1915
from .restore_table import (
2016
RestoreTableOperation,
2117
)
2218

19+
from .wait_for_consistency_request import (
20+
WaitForConsistencyRequest,
21+
)
22+
2323
__all__ = (
24-
"CheckConsistencyPollingFuture",
2524
"RestoreTableOperation",
25+
"WaitForConsistencyRequest",
2626
)

google/cloud/bigtable/admin_v2/overlay/types/consistency.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
OptionalRetry = Union[retries.Retry, object, None] # type: ignore
2626

2727

28-
class CheckConsistencyPollingFuture(polling.PollingFuture):
28+
class _CheckConsistencyPollingFuture(polling.PollingFuture):
2929
"""A Future that polls an underlying `check_consistency` operation until it returns True.
3030
3131
**This class should not be instantiated by users** and should only be instantiated by the admin
@@ -41,13 +41,8 @@ class CheckConsistencyPollingFuture(polling.PollingFuture):
4141
google.cloud.bigtable.admin_v2.types.CheckConsistencyResponse]):
4242
A :meth:`check_consistency
4343
<google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.BigtableTableAdminClient.check_consistency>`
44-
call from the admin client. The call should fix every user parameter except for retry,
44+
call from the admin client. The call should fix every user parameter,
4545
which will be done via :meth:`functools.partial`.
46-
default_retry(Optional[google.api_core.retry.Retry]): The `retry` parameter passed in to either
47-
:meth:`wait_for_consistency
48-
<google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.BigtableTableAdminClient.wait_for_consistency>`
49-
or :meth:`wait_for_replication
50-
<google.cloud.bigtable.admin_v2.overlay.services.bigtable_table_admin.BigtableTableAdminClient.wait_for_replication>`
5146
polling (google.api_core.retry.Retry): The configuration used for polling.
5247
This parameter controls how often :meth:`done` is polled. If the
5348
``timeout`` argument is specified in the :meth:`result
@@ -60,17 +55,15 @@ def __init__(
6055
check_consistency_call: Callable[
6156
[OptionalRetry], bigtable_table_admin.CheckConsistencyResponse
6257
],
63-
default_retry: OptionalRetry = gapic_v1.method.DEFAULT,
6458
polling: retries.Retry = polling.DEFAULT_POLLING,
6559
**kwargs
6660
):
67-
super(CheckConsistencyPollingFuture, self).__init__(polling=polling, **kwargs)
61+
super(_CheckConsistencyPollingFuture, self).__init__(polling=polling, **kwargs)
6862

6963
# Done is called with two different scenarios, retry is specified or not specified.
7064
# API_call will be a functools partial with everything except retry specified because of
7165
# that.
7266
self._check_consistency_call = check_consistency_call
73-
self._default_retry = default_retry
7467

7568
def done(self, retry: OptionalRetry = None):
7669
"""Polls the underlying `check_consistency` call to see if the future is complete.
@@ -92,10 +85,8 @@ def done(self, retry: OptionalRetry = None):
9285
if self._result_set:
9386
return True
9487

95-
retry = retry or self._default_retry
96-
9788
try:
98-
check_consistency_response = self._check_consistency_call(retry=retry)
89+
check_consistency_response = self._check_consistency_call()
9990
if check_consistency_response.consistent:
10091
self.set_result(True)
10192

0 commit comments

Comments
 (0)