google-cloud-spanner 3.55.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- google/cloud/spanner.py +47 -0
- google/cloud/spanner_admin_database_v1/__init__.py +146 -0
- google/cloud/spanner_admin_database_v1/gapic_metadata.json +418 -0
- google/cloud/spanner_admin_database_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_database_v1/py.typed +2 -0
- google/cloud/spanner_admin_database_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/__init__.py +22 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/async_client.py +4097 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/client.py +4602 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/pagers.py +989 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/base.py +820 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc.py +1303 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/grpc_asyncio.py +1688 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest.py +6512 -0
- google/cloud/spanner_admin_database_v1/services/database_admin/transports/rest_base.py +1650 -0
- google/cloud/spanner_admin_database_v1/types/__init__.py +144 -0
- google/cloud/spanner_admin_database_v1/types/backup.py +1106 -0
- google/cloud/spanner_admin_database_v1/types/backup_schedule.py +369 -0
- google/cloud/spanner_admin_database_v1/types/common.py +180 -0
- google/cloud/spanner_admin_database_v1/types/spanner_database_admin.py +1303 -0
- google/cloud/spanner_admin_instance_v1/__init__.py +110 -0
- google/cloud/spanner_admin_instance_v1/gapic_metadata.json +343 -0
- google/cloud/spanner_admin_instance_v1/gapic_version.py +16 -0
- google/cloud/spanner_admin_instance_v1/py.typed +2 -0
- google/cloud/spanner_admin_instance_v1/services/__init__.py +15 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/__init__.py +22 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/async_client.py +3466 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/client.py +3881 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/pagers.py +856 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/__init__.py +38 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/base.py +545 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc.py +1347 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/grpc_asyncio.py +1539 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest.py +4834 -0
- google/cloud/spanner_admin_instance_v1/services/instance_admin/transports/rest_base.py +1198 -0
- google/cloud/spanner_admin_instance_v1/types/__init__.py +104 -0
- google/cloud/spanner_admin_instance_v1/types/common.py +99 -0
- google/cloud/spanner_admin_instance_v1/types/spanner_instance_admin.py +2375 -0
- google/cloud/spanner_dbapi/__init__.py +93 -0
- google/cloud/spanner_dbapi/_helpers.py +113 -0
- google/cloud/spanner_dbapi/batch_dml_executor.py +135 -0
- google/cloud/spanner_dbapi/checksum.py +80 -0
- google/cloud/spanner_dbapi/client_side_statement_executor.py +140 -0
- google/cloud/spanner_dbapi/client_side_statement_parser.py +106 -0
- google/cloud/spanner_dbapi/connection.py +818 -0
- google/cloud/spanner_dbapi/cursor.py +609 -0
- google/cloud/spanner_dbapi/exceptions.py +172 -0
- google/cloud/spanner_dbapi/parse_utils.py +392 -0
- google/cloud/spanner_dbapi/parsed_statement.py +63 -0
- google/cloud/spanner_dbapi/parser.py +258 -0
- google/cloud/spanner_dbapi/partition_helper.py +41 -0
- google/cloud/spanner_dbapi/transaction_helper.py +294 -0
- google/cloud/spanner_dbapi/types.py +106 -0
- google/cloud/spanner_dbapi/utils.py +147 -0
- google/cloud/spanner_dbapi/version.py +20 -0
- google/cloud/spanner_v1/__init__.py +154 -0
- google/cloud/spanner_v1/_helpers.py +751 -0
- google/cloud/spanner_v1/_opentelemetry_tracing.py +165 -0
- google/cloud/spanner_v1/backup.py +397 -0
- google/cloud/spanner_v1/batch.py +433 -0
- google/cloud/spanner_v1/client.py +538 -0
- google/cloud/spanner_v1/data_types.py +350 -0
- google/cloud/spanner_v1/database.py +1968 -0
- google/cloud/spanner_v1/database_sessions_manager.py +249 -0
- google/cloud/spanner_v1/gapic_metadata.json +268 -0
- google/cloud/spanner_v1/gapic_version.py +16 -0
- google/cloud/spanner_v1/instance.py +735 -0
- google/cloud/spanner_v1/keyset.py +193 -0
- google/cloud/spanner_v1/merged_result_set.py +146 -0
- google/cloud/spanner_v1/metrics/constants.py +71 -0
- google/cloud/spanner_v1/metrics/metrics_capture.py +75 -0
- google/cloud/spanner_v1/metrics/metrics_exporter.py +384 -0
- google/cloud/spanner_v1/metrics/metrics_interceptor.py +156 -0
- google/cloud/spanner_v1/metrics/metrics_tracer.py +588 -0
- google/cloud/spanner_v1/metrics/metrics_tracer_factory.py +328 -0
- google/cloud/spanner_v1/metrics/spanner_metrics_tracer_factory.py +172 -0
- google/cloud/spanner_v1/param_types.py +110 -0
- google/cloud/spanner_v1/pool.py +813 -0
- google/cloud/spanner_v1/py.typed +2 -0
- google/cloud/spanner_v1/request_id_header.py +64 -0
- google/cloud/spanner_v1/services/__init__.py +15 -0
- google/cloud/spanner_v1/services/spanner/__init__.py +22 -0
- google/cloud/spanner_v1/services/spanner/async_client.py +2205 -0
- google/cloud/spanner_v1/services/spanner/client.py +2624 -0
- google/cloud/spanner_v1/services/spanner/pagers.py +196 -0
- google/cloud/spanner_v1/services/spanner/transports/__init__.py +38 -0
- google/cloud/spanner_v1/services/spanner/transports/base.py +520 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc.py +911 -0
- google/cloud/spanner_v1/services/spanner/transports/grpc_asyncio.py +1144 -0
- google/cloud/spanner_v1/services/spanner/transports/rest.py +3468 -0
- google/cloud/spanner_v1/services/spanner/transports/rest_base.py +981 -0
- google/cloud/spanner_v1/session.py +631 -0
- google/cloud/spanner_v1/session_options.py +133 -0
- google/cloud/spanner_v1/snapshot.py +1057 -0
- google/cloud/spanner_v1/streamed.py +402 -0
- google/cloud/spanner_v1/table.py +181 -0
- google/cloud/spanner_v1/testing/__init__.py +0 -0
- google/cloud/spanner_v1/testing/database_test.py +121 -0
- google/cloud/spanner_v1/testing/interceptors.py +118 -0
- google/cloud/spanner_v1/testing/mock_database_admin.py +38 -0
- google/cloud/spanner_v1/testing/mock_spanner.py +261 -0
- google/cloud/spanner_v1/testing/spanner_database_admin_pb2_grpc.py +1267 -0
- google/cloud/spanner_v1/testing/spanner_pb2_grpc.py +882 -0
- google/cloud/spanner_v1/transaction.py +747 -0
- google/cloud/spanner_v1/types/__init__.py +118 -0
- google/cloud/spanner_v1/types/commit_response.py +94 -0
- google/cloud/spanner_v1/types/keys.py +248 -0
- google/cloud/spanner_v1/types/mutation.py +201 -0
- google/cloud/spanner_v1/types/query_plan.py +220 -0
- google/cloud/spanner_v1/types/result_set.py +379 -0
- google/cloud/spanner_v1/types/spanner.py +1815 -0
- google/cloud/spanner_v1/types/transaction.py +818 -0
- google/cloud/spanner_v1/types/type.py +288 -0
- google_cloud_spanner-3.55.0.dist-info/LICENSE +202 -0
- google_cloud_spanner-3.55.0.dist-info/METADATA +318 -0
- google_cloud_spanner-3.55.0.dist-info/RECORD +119 -0
- google_cloud_spanner-3.55.0.dist-info/WHEEL +5 -0
- google_cloud_spanner-3.55.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
# Copyright 2016 Google LLC All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
"""Context manager for Cloud Spanner batched writes."""
|
|
16
|
+
import functools
|
|
17
|
+
|
|
18
|
+
from google.cloud.spanner_v1 import CommitRequest
|
|
19
|
+
from google.cloud.spanner_v1 import Mutation
|
|
20
|
+
from google.cloud.spanner_v1 import TransactionOptions
|
|
21
|
+
from google.cloud.spanner_v1 import BatchWriteRequest
|
|
22
|
+
|
|
23
|
+
from google.cloud.spanner_v1._helpers import _SessionWrapper
|
|
24
|
+
from google.cloud.spanner_v1._helpers import _make_list_value_pbs
|
|
25
|
+
from google.cloud.spanner_v1._helpers import (
|
|
26
|
+
_metadata_with_prefix,
|
|
27
|
+
_metadata_with_leader_aware_routing,
|
|
28
|
+
_merge_Transaction_Options,
|
|
29
|
+
AtomicCounter,
|
|
30
|
+
)
|
|
31
|
+
from google.cloud.spanner_v1._opentelemetry_tracing import trace_call
|
|
32
|
+
from google.cloud.spanner_v1 import RequestOptions
|
|
33
|
+
from google.cloud.spanner_v1._helpers import _retry
|
|
34
|
+
from google.cloud.spanner_v1._helpers import _retry_on_aborted_exception
|
|
35
|
+
from google.cloud.spanner_v1._helpers import _check_rst_stream_error
|
|
36
|
+
from google.api_core.exceptions import InternalServerError
|
|
37
|
+
from google.cloud.spanner_v1.metrics.metrics_capture import MetricsCapture
|
|
38
|
+
import time
|
|
39
|
+
|
|
40
|
+
DEFAULT_RETRY_TIMEOUT_SECS = 30
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _BatchBase(_SessionWrapper):
|
|
44
|
+
"""Accumulate mutations for transmission during :meth:`commit`.
|
|
45
|
+
|
|
46
|
+
:type session: :class:`~google.cloud.spanner_v1.session.Session`
|
|
47
|
+
:param session: the session used to perform the commit
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
transaction_tag = None
|
|
51
|
+
_read_only = False
|
|
52
|
+
|
|
53
|
+
def __init__(self, session):
|
|
54
|
+
super(_BatchBase, self).__init__(session)
|
|
55
|
+
self._mutations = []
|
|
56
|
+
|
|
57
|
+
def _check_state(self):
|
|
58
|
+
"""Helper for :meth:`commit` et al.
|
|
59
|
+
|
|
60
|
+
Subclasses must override
|
|
61
|
+
|
|
62
|
+
:raises: :exc:`ValueError` if the object's state is invalid for making
|
|
63
|
+
API requests.
|
|
64
|
+
"""
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
|
|
67
|
+
def insert(self, table, columns, values):
|
|
68
|
+
"""Insert one or more new table rows.
|
|
69
|
+
|
|
70
|
+
:type table: str
|
|
71
|
+
:param table: Name of the table to be modified.
|
|
72
|
+
|
|
73
|
+
:type columns: list of str
|
|
74
|
+
:param columns: Name of the table columns to be modified.
|
|
75
|
+
|
|
76
|
+
:type values: list of lists
|
|
77
|
+
:param values: Values to be modified.
|
|
78
|
+
"""
|
|
79
|
+
self._mutations.append(Mutation(insert=_make_write_pb(table, columns, values)))
|
|
80
|
+
# TODO: Decide if we should add a span event per mutation:
|
|
81
|
+
# https://github.com/googleapis/python-spanner/issues/1269
|
|
82
|
+
|
|
83
|
+
def update(self, table, columns, values):
|
|
84
|
+
"""Update one or more existing table rows.
|
|
85
|
+
|
|
86
|
+
:type table: str
|
|
87
|
+
:param table: Name of the table to be modified.
|
|
88
|
+
|
|
89
|
+
:type columns: list of str
|
|
90
|
+
:param columns: Name of the table columns to be modified.
|
|
91
|
+
|
|
92
|
+
:type values: list of lists
|
|
93
|
+
:param values: Values to be modified.
|
|
94
|
+
"""
|
|
95
|
+
self._mutations.append(Mutation(update=_make_write_pb(table, columns, values)))
|
|
96
|
+
# TODO: Decide if we should add a span event per mutation:
|
|
97
|
+
# https://github.com/googleapis/python-spanner/issues/1269
|
|
98
|
+
|
|
99
|
+
def insert_or_update(self, table, columns, values):
|
|
100
|
+
"""Insert/update one or more table rows.
|
|
101
|
+
|
|
102
|
+
:type table: str
|
|
103
|
+
:param table: Name of the table to be modified.
|
|
104
|
+
|
|
105
|
+
:type columns: list of str
|
|
106
|
+
:param columns: Name of the table columns to be modified.
|
|
107
|
+
|
|
108
|
+
:type values: list of lists
|
|
109
|
+
:param values: Values to be modified.
|
|
110
|
+
"""
|
|
111
|
+
self._mutations.append(
|
|
112
|
+
Mutation(insert_or_update=_make_write_pb(table, columns, values))
|
|
113
|
+
)
|
|
114
|
+
# TODO: Decide if we should add a span event per mutation:
|
|
115
|
+
# https://github.com/googleapis/python-spanner/issues/1269
|
|
116
|
+
|
|
117
|
+
def replace(self, table, columns, values):
|
|
118
|
+
"""Replace one or more table rows.
|
|
119
|
+
|
|
120
|
+
:type table: str
|
|
121
|
+
:param table: Name of the table to be modified.
|
|
122
|
+
|
|
123
|
+
:type columns: list of str
|
|
124
|
+
:param columns: Name of the table columns to be modified.
|
|
125
|
+
|
|
126
|
+
:type values: list of lists
|
|
127
|
+
:param values: Values to be modified.
|
|
128
|
+
"""
|
|
129
|
+
self._mutations.append(Mutation(replace=_make_write_pb(table, columns, values)))
|
|
130
|
+
# TODO: Decide if we should add a span event per mutation:
|
|
131
|
+
# https://github.com/googleapis/python-spanner/issues/1269
|
|
132
|
+
|
|
133
|
+
def delete(self, table, keyset):
|
|
134
|
+
"""Delete one or more table rows.
|
|
135
|
+
|
|
136
|
+
:type table: str
|
|
137
|
+
:param table: Name of the table to be modified.
|
|
138
|
+
|
|
139
|
+
:type keyset: :class:`~google.cloud.spanner_v1.keyset.Keyset`
|
|
140
|
+
:param keyset: Keys/ranges identifying rows to delete.
|
|
141
|
+
"""
|
|
142
|
+
delete = Mutation.Delete(table=table, key_set=keyset._to_pb())
|
|
143
|
+
self._mutations.append(Mutation(delete=delete))
|
|
144
|
+
# TODO: Decide if we should add a span event per mutation:
|
|
145
|
+
# https://github.com/googleapis/python-spanner/issues/1269
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class Batch(_BatchBase):
|
|
149
|
+
"""Accumulate mutations for transmission during :meth:`commit`."""
|
|
150
|
+
|
|
151
|
+
committed = None
|
|
152
|
+
commit_stats = None
|
|
153
|
+
"""Timestamp at which the batch was successfully committed."""
|
|
154
|
+
|
|
155
|
+
def _check_state(self):
|
|
156
|
+
"""Helper for :meth:`commit` et al.
|
|
157
|
+
|
|
158
|
+
Subclasses must override
|
|
159
|
+
|
|
160
|
+
:raises: :exc:`ValueError` if the object's state is invalid for making
|
|
161
|
+
API requests.
|
|
162
|
+
"""
|
|
163
|
+
if self.committed is not None:
|
|
164
|
+
raise ValueError("Batch already committed")
|
|
165
|
+
|
|
166
|
+
def commit(
|
|
167
|
+
self,
|
|
168
|
+
return_commit_stats=False,
|
|
169
|
+
request_options=None,
|
|
170
|
+
max_commit_delay=None,
|
|
171
|
+
exclude_txn_from_change_streams=False,
|
|
172
|
+
isolation_level=TransactionOptions.IsolationLevel.ISOLATION_LEVEL_UNSPECIFIED,
|
|
173
|
+
**kwargs,
|
|
174
|
+
):
|
|
175
|
+
"""Commit mutations to the database.
|
|
176
|
+
|
|
177
|
+
:type return_commit_stats: bool
|
|
178
|
+
:param return_commit_stats:
|
|
179
|
+
If true, the response will return commit stats which can be accessed though commit_stats.
|
|
180
|
+
|
|
181
|
+
:type request_options:
|
|
182
|
+
:class:`google.cloud.spanner_v1.types.RequestOptions`
|
|
183
|
+
:param request_options:
|
|
184
|
+
(Optional) Common options for this request.
|
|
185
|
+
If a dict is provided, it must be of the same form as the protobuf
|
|
186
|
+
message :class:`~google.cloud.spanner_v1.types.RequestOptions`.
|
|
187
|
+
|
|
188
|
+
:type max_commit_delay: :class:`datetime.timedelta`
|
|
189
|
+
:param max_commit_delay:
|
|
190
|
+
(Optional) The amount of latency this request is willing to incur
|
|
191
|
+
in order to improve throughput.
|
|
192
|
+
|
|
193
|
+
:type exclude_txn_from_change_streams: bool
|
|
194
|
+
:param exclude_txn_from_change_streams:
|
|
195
|
+
(Optional) If true, instructs the transaction to be excluded from being recorded in change streams
|
|
196
|
+
with the DDL option `allow_txn_exclusion=true`. This does not exclude the transaction from
|
|
197
|
+
being recorded in the change streams with the DDL option `allow_txn_exclusion` being false or
|
|
198
|
+
unset.
|
|
199
|
+
|
|
200
|
+
:type isolation_level:
|
|
201
|
+
:class:`google.cloud.spanner_v1.types.TransactionOptions.IsolationLevel`
|
|
202
|
+
:param isolation_level:
|
|
203
|
+
(Optional) Sets isolation level for the transaction.
|
|
204
|
+
|
|
205
|
+
:rtype: datetime
|
|
206
|
+
:returns: timestamp of the committed changes.
|
|
207
|
+
"""
|
|
208
|
+
self._check_state()
|
|
209
|
+
database = self._session._database
|
|
210
|
+
api = database.spanner_api
|
|
211
|
+
metadata = _metadata_with_prefix(database.name)
|
|
212
|
+
if database._route_to_leader_enabled:
|
|
213
|
+
metadata.append(
|
|
214
|
+
_metadata_with_leader_aware_routing(database._route_to_leader_enabled)
|
|
215
|
+
)
|
|
216
|
+
txn_options = TransactionOptions(
|
|
217
|
+
read_write=TransactionOptions.ReadWrite(),
|
|
218
|
+
exclude_txn_from_change_streams=exclude_txn_from_change_streams,
|
|
219
|
+
isolation_level=isolation_level,
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
txn_options = _merge_Transaction_Options(
|
|
223
|
+
database.default_transaction_options.default_read_write_transaction_options,
|
|
224
|
+
txn_options,
|
|
225
|
+
)
|
|
226
|
+
trace_attributes = {"num_mutations": len(self._mutations)}
|
|
227
|
+
|
|
228
|
+
if request_options is None:
|
|
229
|
+
request_options = RequestOptions()
|
|
230
|
+
elif type(request_options) is dict:
|
|
231
|
+
request_options = RequestOptions(request_options)
|
|
232
|
+
request_options.transaction_tag = self.transaction_tag
|
|
233
|
+
|
|
234
|
+
# Request tags are not supported for commit requests.
|
|
235
|
+
request_options.request_tag = None
|
|
236
|
+
|
|
237
|
+
request = CommitRequest(
|
|
238
|
+
session=self._session.name,
|
|
239
|
+
mutations=self._mutations,
|
|
240
|
+
single_use_transaction=txn_options,
|
|
241
|
+
return_commit_stats=return_commit_stats,
|
|
242
|
+
max_commit_delay=max_commit_delay,
|
|
243
|
+
request_options=request_options,
|
|
244
|
+
)
|
|
245
|
+
observability_options = getattr(database, "observability_options", None)
|
|
246
|
+
with trace_call(
|
|
247
|
+
f"CloudSpanner.{type(self).__name__}.commit",
|
|
248
|
+
self._session,
|
|
249
|
+
trace_attributes,
|
|
250
|
+
observability_options=observability_options,
|
|
251
|
+
metadata=metadata,
|
|
252
|
+
) as span, MetricsCapture():
|
|
253
|
+
|
|
254
|
+
def wrapped_method(*args, **kwargs):
|
|
255
|
+
method = functools.partial(
|
|
256
|
+
api.commit,
|
|
257
|
+
request=request,
|
|
258
|
+
metadata=database.metadata_with_request_id(
|
|
259
|
+
# This code is retried due to ABORTED, hence nth_request
|
|
260
|
+
# should be increased. attempt can only be increased if
|
|
261
|
+
# we encounter UNAVAILABLE or INTERNAL.
|
|
262
|
+
getattr(database, "_next_nth_request", 0),
|
|
263
|
+
1,
|
|
264
|
+
metadata,
|
|
265
|
+
span,
|
|
266
|
+
),
|
|
267
|
+
)
|
|
268
|
+
return method(*args, **kwargs)
|
|
269
|
+
|
|
270
|
+
deadline = time.time() + kwargs.get(
|
|
271
|
+
"timeout_secs", DEFAULT_RETRY_TIMEOUT_SECS
|
|
272
|
+
)
|
|
273
|
+
default_retry_delay = kwargs.get("default_retry_delay", None)
|
|
274
|
+
response = _retry_on_aborted_exception(
|
|
275
|
+
wrapped_method,
|
|
276
|
+
deadline=deadline,
|
|
277
|
+
default_retry_delay=default_retry_delay,
|
|
278
|
+
)
|
|
279
|
+
self.committed = response.commit_timestamp
|
|
280
|
+
self.commit_stats = response.commit_stats
|
|
281
|
+
return self.committed
|
|
282
|
+
|
|
283
|
+
def __enter__(self):
|
|
284
|
+
"""Begin ``with`` block."""
|
|
285
|
+
self._check_state()
|
|
286
|
+
|
|
287
|
+
return self
|
|
288
|
+
|
|
289
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
290
|
+
"""End ``with`` block."""
|
|
291
|
+
if exc_type is None:
|
|
292
|
+
self.commit()
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class MutationGroup(_BatchBase):
|
|
296
|
+
"""A container for mutations.
|
|
297
|
+
|
|
298
|
+
Clients should use :class:`~google.cloud.spanner_v1.MutationGroups` to
|
|
299
|
+
obtain instances instead of directly creating instances.
|
|
300
|
+
|
|
301
|
+
:type session: :class:`~google.cloud.spanner_v1.session.Session`
|
|
302
|
+
:param session: The session used to perform the commit.
|
|
303
|
+
|
|
304
|
+
:type mutations: list
|
|
305
|
+
:param mutations: The list into which mutations are to be accumulated.
|
|
306
|
+
"""
|
|
307
|
+
|
|
308
|
+
def __init__(self, session, mutations=[]):
|
|
309
|
+
super(MutationGroup, self).__init__(session)
|
|
310
|
+
self._mutations = mutations
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class MutationGroups(_SessionWrapper):
|
|
314
|
+
"""Accumulate mutation groups for transmission during :meth:`batch_write`.
|
|
315
|
+
|
|
316
|
+
:type session: :class:`~google.cloud.spanner_v1.session.Session`
|
|
317
|
+
:param session: the session used to perform the commit
|
|
318
|
+
"""
|
|
319
|
+
|
|
320
|
+
committed = None
|
|
321
|
+
|
|
322
|
+
def __init__(self, session):
|
|
323
|
+
super(MutationGroups, self).__init__(session)
|
|
324
|
+
self._mutation_groups = []
|
|
325
|
+
|
|
326
|
+
def _check_state(self):
|
|
327
|
+
"""Checks if the object's state is valid for making API requests.
|
|
328
|
+
|
|
329
|
+
:raises: :exc:`ValueError` if the object's state is invalid for making
|
|
330
|
+
API requests.
|
|
331
|
+
"""
|
|
332
|
+
if self.committed is not None:
|
|
333
|
+
raise ValueError("MutationGroups already committed")
|
|
334
|
+
|
|
335
|
+
def group(self):
|
|
336
|
+
"""Returns a new `MutationGroup` to which mutations can be added."""
|
|
337
|
+
mutation_group = BatchWriteRequest.MutationGroup()
|
|
338
|
+
self._mutation_groups.append(mutation_group)
|
|
339
|
+
return MutationGroup(self._session, mutation_group.mutations)
|
|
340
|
+
|
|
341
|
+
def batch_write(self, request_options=None, exclude_txn_from_change_streams=False):
|
|
342
|
+
"""Executes batch_write.
|
|
343
|
+
|
|
344
|
+
:type request_options:
|
|
345
|
+
:class:`google.cloud.spanner_v1.types.RequestOptions`
|
|
346
|
+
:param request_options:
|
|
347
|
+
(Optional) Common options for this request.
|
|
348
|
+
If a dict is provided, it must be of the same form as the protobuf
|
|
349
|
+
message :class:`~google.cloud.spanner_v1.types.RequestOptions`.
|
|
350
|
+
|
|
351
|
+
:type exclude_txn_from_change_streams: bool
|
|
352
|
+
:param exclude_txn_from_change_streams:
|
|
353
|
+
(Optional) If true, instructs the transaction to be excluded from being recorded in change streams
|
|
354
|
+
with the DDL option `allow_txn_exclusion=true`. This does not exclude the transaction from
|
|
355
|
+
being recorded in the change streams with the DDL option `allow_txn_exclusion` being false or
|
|
356
|
+
unset.
|
|
357
|
+
|
|
358
|
+
:rtype: :class:`Iterable[google.cloud.spanner_v1.types.BatchWriteResponse]`
|
|
359
|
+
:returns: a sequence of responses for each batch.
|
|
360
|
+
"""
|
|
361
|
+
self._check_state()
|
|
362
|
+
|
|
363
|
+
database = self._session._database
|
|
364
|
+
api = database.spanner_api
|
|
365
|
+
metadata = _metadata_with_prefix(database.name)
|
|
366
|
+
if database._route_to_leader_enabled:
|
|
367
|
+
metadata.append(
|
|
368
|
+
_metadata_with_leader_aware_routing(database._route_to_leader_enabled)
|
|
369
|
+
)
|
|
370
|
+
trace_attributes = {"num_mutation_groups": len(self._mutation_groups)}
|
|
371
|
+
if request_options is None:
|
|
372
|
+
request_options = RequestOptions()
|
|
373
|
+
elif type(request_options) is dict:
|
|
374
|
+
request_options = RequestOptions(request_options)
|
|
375
|
+
|
|
376
|
+
request = BatchWriteRequest(
|
|
377
|
+
session=self._session.name,
|
|
378
|
+
mutation_groups=self._mutation_groups,
|
|
379
|
+
request_options=request_options,
|
|
380
|
+
exclude_txn_from_change_streams=exclude_txn_from_change_streams,
|
|
381
|
+
)
|
|
382
|
+
observability_options = getattr(database, "observability_options", None)
|
|
383
|
+
with trace_call(
|
|
384
|
+
"CloudSpanner.batch_write",
|
|
385
|
+
self._session,
|
|
386
|
+
trace_attributes,
|
|
387
|
+
observability_options=observability_options,
|
|
388
|
+
metadata=metadata,
|
|
389
|
+
) as span, MetricsCapture():
|
|
390
|
+
attempt = AtomicCounter(0)
|
|
391
|
+
nth_request = getattr(database, "_next_nth_request", 0)
|
|
392
|
+
|
|
393
|
+
def wrapped_method(*args, **kwargs):
|
|
394
|
+
method = functools.partial(
|
|
395
|
+
api.batch_write,
|
|
396
|
+
request=request,
|
|
397
|
+
metadata=database.metadata_with_request_id(
|
|
398
|
+
nth_request,
|
|
399
|
+
attempt.increment(),
|
|
400
|
+
metadata,
|
|
401
|
+
span,
|
|
402
|
+
),
|
|
403
|
+
)
|
|
404
|
+
return method(*args, **kwargs)
|
|
405
|
+
|
|
406
|
+
response = _retry(
|
|
407
|
+
wrapped_method,
|
|
408
|
+
allowed_exceptions={
|
|
409
|
+
InternalServerError: _check_rst_stream_error,
|
|
410
|
+
},
|
|
411
|
+
)
|
|
412
|
+
self.committed = True
|
|
413
|
+
return response
|
|
414
|
+
|
|
415
|
+
|
|
416
|
+
def _make_write_pb(table, columns, values):
|
|
417
|
+
"""Helper for :meth:`Batch.insert` et al.
|
|
418
|
+
|
|
419
|
+
:type table: str
|
|
420
|
+
:param table: Name of the table to be modified.
|
|
421
|
+
|
|
422
|
+
:type columns: list of str
|
|
423
|
+
:param columns: Name of the table columns to be modified.
|
|
424
|
+
|
|
425
|
+
:type values: list of lists
|
|
426
|
+
:param values: Values to be modified.
|
|
427
|
+
|
|
428
|
+
:rtype: :class:`google.cloud.spanner_v1.types.Mutation.Write`
|
|
429
|
+
:returns: Write protobuf
|
|
430
|
+
"""
|
|
431
|
+
return Mutation.Write(
|
|
432
|
+
table=table, columns=columns, values=_make_list_value_pbs(values)
|
|
433
|
+
)
|