1 // Copyright 2017 Google Inc.
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 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H
17
18 #include "google/cloud/bigtable/async_row_reader.h"
19 #include "google/cloud/bigtable/completion_queue.h"
20 #include "google/cloud/bigtable/data_client.h"
21 #include "google/cloud/bigtable/filters.h"
22 #include "google/cloud/bigtable/idempotent_mutation_policy.h"
23 #include "google/cloud/bigtable/mutations.h"
24 #include "google/cloud/bigtable/read_modify_write_rule.h"
25 #include "google/cloud/bigtable/row_key_sample.h"
26 #include "google/cloud/bigtable/row_reader.h"
27 #include "google/cloud/bigtable/row_set.h"
28 #include "google/cloud/bigtable/rpc_backoff_policy.h"
29 #include "google/cloud/bigtable/rpc_retry_policy.h"
30 #include "google/cloud/bigtable/version.h"
31 #include "google/cloud/future.h"
32 #include "google/cloud/grpc_error_delegate.h"
33 #include "google/cloud/status.h"
34 #include "google/cloud/status_or.h"
35 #include "absl/meta/type_traits.h"
36
37 namespace google {
38 namespace cloud {
39 namespace bigtable {
40 inline namespace BIGTABLE_CLIENT_NS {
41 /// The branch taken by a Table::CheckAndMutateRow operation.
42 enum class MutationBranch {
43 /// The predicate provided to CheckAndMutateRow did not match and the
44 /// `false_mutations` (if any) were applied.
45 kPredicateNotMatched,
46 /// The predicate provided to CheckAndMutateRow matched and the
47 /// `true_mutations` (if any) were applied.
48 kPredicateMatched,
49 };
50
51 class MutationBatcher;
52
53 /**
54 * Return the full table name.
55 *
56 * The full table name is:
57 *
58 * `projects/<PROJECT_ID>/instances/<INSTANCE_ID>/tables/<table_id>`
59 *
60 * Where the project id and instance id come from the @p client parameter.
61 */
TableName(std::shared_ptr<DataClient> const & client,std::string const & table_id)62 inline std::string TableName(std::shared_ptr<DataClient> const& client,
63 std::string const& table_id) {
64 return InstanceName(client) + "/tables/" + table_id;
65 }
66
67 /**
68 * The main interface to interact with data in a Cloud Bigtable table.
69 *
70 * This class provides member functions to:
71 * - read specific rows: `Table::ReadRow()`
72 * - scan a ranges of rows: `Table::ReadRows()`
73 * - update or create a single row: `Table::Apply()`
74 * - update or modify multiple rows: `Table::BulkApply()`
75 * - update a row based on previous values: `Table::CheckAndMutateRow()`
76 * - to atomically append data and/or increment multiple values in a row:
77 * `Table::ReadModifyWriteRow()`
78 * - to sample the row keys: `Table::SampleRows()`.
79 *
80 * The class deals with the most common transient failures, and retries the
81 * underlying RPC calls subject to the policies configured by the application.
82 * These policies are documented in `Table::Table()`.
83 *
84 * @par Thread-safety
85 * Instances of this class created via copy-construction or copy-assignment
86 * share the underlying pool of connections. Access to these copies via multiple
87 * threads is guaranteed to work. Two threads operating on the same instance of
88 * this class is not guaranteed to work.
89 *
90 * @par Cost
91 * Creating a new object of type `Table` is comparable to creating a few objects
92 * of type `std::string` or a few objects of type `std::shared_ptr<int>`. The
93 * class represents a shallow handle to a remote object.
94 *
95 * @par Error Handling
96 * This class uses `StatusOr<T>` to report errors. When an operation fails to
97 * perform its work the returned `StatusOr<T>` contains the error details. If
98 * the `ok()` member function in the `StatusOr<T>` returns `true` then it
99 * contains the expected result. Operations that do not return a value simply
100 * return a `google::cloud::Status` indicating success or the details of the
101 * error Please consult the
102 * [`StatusOr<T>` documentation](#google::cloud::v1::StatusOr) for more details.
103 *
104 * @code
105 * namespace cbt = google::cloud::bigtable;
106 * cbt::Table = ...;
107 * google::cloud::StatusOr<std::pair<bool, cbt::Row>> row = table.ReadRow(...);
108 *
109 * if (!row) {
110 * std::cerr << "Error reading row\n";
111 * return;
112 * }
113 *
114 * // Use "row" as a smart pointer here, e.g.:
115 * if (!row->first) {
116 * std::cout << "Contacting the server was successful, but the row does not"
117 * << " exist\n";
118 * return;
119 * }
120 * std::cout << "The row has " << row->second.cells().size() << " cells\n";
121 * @endcode
122 *
123 * In addition, the @ref index "main page" contains examples using `StatusOr<T>`
124 * to handle errors.
125 *
126 * @par Retry, Backoff, and Idempotency Policies
127 * The library automatically retries requests that fail with transient errors,
128 * and uses [truncated exponential backoff][backoff-link] to backoff between
129 * retries. The default policies are to continue retrying for up to 10 minutes.
130 * On each transient failure the backoff period is doubled, starting with an
131 * initial backoff of 100 milliseconds. The backoff period growth is truncated
132 * at 60 seconds. The default idempotency policy is to only retry idempotent
133 * operations. Note that most operations that change state are **not**
134 * idempotent.
135 *
136 * The application can override these policies when constructing objects of this
137 * class. The documentation for the constructors show examples of this in
138 * action.
139 *
140 * [backoff-link]: https://cloud.google.com/storage/docs/exponential-backoff
141 *
142 * @see https://cloud.google.com/bigtable/ for an overview of Cloud Bigtable.
143 *
144 * @see https://cloud.google.com/bigtable/docs/overview for an overview of the
145 * Cloud Bigtable data model.
146 *
147 * @see https://cloud.google.com/bigtable/docs/instances-clusters-nodes for an
148 * introduction of the main APIs into Cloud Bigtable.
149 *
150 * @see https://cloud.google.com/bigtable/docs/reference/service-apis-overview
151 * for an overview of the underlying Cloud Bigtable API.
152 *
153 * @see #google::cloud::v1::StatusOr for a description of the error reporting
154 * class used by this library.
155 *
156 * @see `LimitedTimeRetryPolicy` and `LimitedErrorCountRetryPolicy` for
157 * alternative retry policies.
158 *
159 * @see `ExponentialBackoffPolicy` to configure different parameters for the
160 * exponential backoff policy.
161 *
162 * @see `SafeIdempotentMutationPolicy` and `AlwaysRetryMutationPolicy` for
163 * alternative idempotency policies.
164 */
165 class Table {
166 private:
167 // We need to eliminate some function overloads from resolution, and that
168 // requires a bit of infrastructure in the private section.
169
170 /// A meta function to check if @p P is a valid Policy type.
171 template <typename P>
172 struct ValidPolicy
173 : absl::disjunction<std::is_base_of<RPCBackoffPolicy, P>,
174 std::is_base_of<RPCRetryPolicy, P>,
175 std::is_base_of<IdempotentMutationPolicy, P>> {};
176
177 /// A meta function to check if all the @p Policies are valid policy types.
178 template <typename... Policies>
179 struct ValidPolicies : absl::conjunction<ValidPolicy<Policies>...> {};
180
181 public:
182 /**
183 * Constructor with default policies.
184 *
185 * @param client how to communicate with Cloud Bigtable, including
186 * credentials, the project id, and the instance id.
187 * @param table_id the table id within the instance defined by client. The
188 * full table name is `client->instance_name() + '/tables/' + table_id`.
189 */
Table(std::shared_ptr<DataClient> client,std::string const & table_id)190 Table(std::shared_ptr<DataClient> client, std::string const& table_id)
191 : Table(std::move(client), std::string{}, table_id) {}
192
193 /**
194 * Constructor with default policies.
195 *
196 * @param client how to communicate with Cloud Bigtable, including
197 * credentials, the project id, and the instance id.
198 * @param app_profile_id the app_profile_id needed for using the replication
199 * API.
200 * @param table_id the table id within the instance defined by client. The
201 * full table name is `client->instance_name() + '/tables/' + table_id`.
202 *
203 * @par Example
204 * @snippet bigtable_hello_app_profile.cc cbt namespace
205 *
206 * @par Example Using AppProfile
207 * @snippet bigtable_hello_app_profile.cc read with app profile
208 */
Table(std::shared_ptr<DataClient> client,std::string app_profile_id,std::string const & table_id)209 Table(std::shared_ptr<DataClient> client, std::string app_profile_id,
210 std::string const& table_id)
211 : client_(std::move(client)),
212 app_profile_id_(std::move(app_profile_id)),
213 table_name_(TableName(client_, table_id)),
214 table_id_(table_id),
215 rpc_retry_policy_prototype_(
216 bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)),
217 rpc_backoff_policy_prototype_(
218 bigtable::DefaultRPCBackoffPolicy(internal::kBigtableLimits)),
219 metadata_update_policy_(
220 MetadataUpdatePolicy(table_name_, MetadataParamTypes::TABLE_NAME)),
221 idempotent_mutation_policy_(
222 bigtable::DefaultIdempotentMutationPolicy()) {}
223
224 /**
225 * Constructor with explicit policies.
226 *
227 * The policies are passed by value, because this makes it easy for
228 * applications to create them.
229 *
230 * @par Example
231 * @code
232 * using namespace std::chrono_literals; // assuming C++14.
233 * auto client = bigtable::CreateDefaultClient(...); // details ommitted
234 * bigtable::Table table(client, "my-table",
235 * // Allow up to 20 minutes to retry operations
236 * bigtable::LimitedTimeRetryPolicy(20min),
237 * // Start with 50 milliseconds backoff, grow
238 * // exponentially to 5 minutes.
239 * bigtable::ExponentialBackoffPolicy(50ms, 5min),
240 * // Only retry idempotent mutations.
241 * bigtable::SafeIdempotentMutationPolicy());
242 * @endcode
243 *
244 * @param client how to communicate with Cloud Bigtable, including
245 * credentials, the project id, and the instance id.
246 * @param table_id the table id within the instance defined by client. The
247 * full table name is `client->instance_name() + "/tables/" + table_id`.
248 * @param policies the set of policy overrides for this object.
249 * @tparam Policies the types of the policies to override, the types must
250 * derive from one of the following types:
251 *
252 * - `IdempotentMutationPolicy` which mutations are retried. Use
253 * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
254 * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
255 * caveats in the class definition to understand the downsides of the
256 * latter. You can also create your own policies that decide which
257 * mutations to retry.
258 * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
259 * `ExponentialBackoffPolicy` is implemented. You can also create your
260 * own policies that backoff using a different algorithm.
261 * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
262 * `LimitedErrorCountRetryPolicy` to limit the number of failures
263 * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
264 * request. You can also create your own policies that combine time and
265 * error counts.
266 *
267 * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
268 * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
269 * LimitedTimeRetryPolicy.
270 *
271 * @par Idempotency Policy Example
272 * @snippet data_snippets.cc apply relaxed idempotency
273 *
274 * @par Modified Retry Policy Example
275 * @snippet data_snippets.cc apply custom retry
276 */
277 template <
278 typename... Policies,
279 typename std::enable_if<ValidPolicies<Policies...>::value, int>::type = 0>
280 // NOLINTNEXTLINE(performance-unnecessary-value-param) TODO(#4112)
Table(std::shared_ptr<DataClient> client,std::string const & table_id,Policies &&...policies)281 Table(std::shared_ptr<DataClient> client, std::string const& table_id,
282 Policies&&... policies)
283 : Table(std::move(client), table_id) {
284 ChangePolicies(std::forward<Policies>(policies)...);
285 }
286
287 /**
288 * Constructor with explicit policies.
289 *
290 * The policies are passed by value, because this makes it easy for
291 * applications to create them.
292 *
293 * @par Example
294 * @code
295 * using namespace std::chrono_literals; // assuming C++14.
296 * auto client = bigtable::CreateDefaultClient(...); // details ommitted
297 * bigtable::Table table(client, "app_id", "my-table",
298 * // Allow up to 20 minutes to retry operations
299 * bigtable::LimitedTimeRetryPolicy(20min),
300 * // Start with 50 milliseconds backoff, grow
301 * // exponentially to 5 minutes.
302 * bigtable::ExponentialBackoffPolicy(50ms, 5min),
303 * // Only retry idempotent mutations.
304 * bigtable::SafeIdempotentMutationPolicy());
305 * @endcode
306 *
307 * @param client how to communicate with Cloud Bigtable, including
308 * credentials, the project id, and the instance id.
309 * @param app_profile_id the app_profile_id needed for using the replication
310 * API.
311 * @param table_id the table id within the instance defined by client. The
312 * full table name is `client->instance_name() + "/tables/" + table_id`.
313 * @param policies the set of policy overrides for this object.
314 * @tparam Policies the types of the policies to override, the types must
315 * derive from one of the following types:
316 * - `IdempotentMutationPolicy` which mutations are retried. Use
317 * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
318 * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
319 * caveats in the class definition to understand the downsides of the
320 * latter. You can also create your own policies that decide which
321 * mutations to retry.
322 * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
323 * `ExponentialBackoffPolicy` is implemented. You can also create your
324 * own policies that backoff using a different algorithm.
325 * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
326 * `LimitedErrorCountRetryPolicy` to limit the number of failures
327 * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
328 * request. You can also create your own policies that combine time and
329 * error counts.
330 *
331 * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
332 * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
333 * LimitedTimeRetryPolicy.
334 *
335 * @par Idempotency Policy Example
336 * @snippet data_snippets.cc apply relaxed idempotency
337 *
338 * @par Modified Retry Policy Example
339 * @snippet data_snippets.cc apply custom retry
340 */
341 template <
342 typename... Policies,
343 typename std::enable_if<ValidPolicies<Policies...>::value, int>::type = 0>
344 // NOLINTNEXTLINE(performance-unnecessary-value-param) TODO(#4112)
Table(std::shared_ptr<DataClient> client,std::string app_profile_id,std::string const & table_id,Policies &&...policies)345 Table(std::shared_ptr<DataClient> client, std::string app_profile_id,
346 std::string const& table_id, Policies&&... policies)
347 : Table(std::move(client), std::move(app_profile_id), table_id) {
348 ChangePolicies(std::forward<Policies>(policies)...);
349 }
350
table_name()351 std::string const& table_name() const { return table_name_; }
app_profile_id()352 std::string const& app_profile_id() const { return app_profile_id_; }
project_id()353 std::string const& project_id() const { return client_->project_id(); }
instance_id()354 std::string const& instance_id() const { return client_->instance_id(); }
table_id()355 std::string const& table_id() const { return table_id_; }
356
357 /**
358 * Attempts to apply the mutation to a row.
359 *
360 * @param mut the mutation. Note that this function takes ownership (and
361 * then discards) the data in the mutation. In general, a
362 * `SingleRowMutation` can be used to modify and/or delete multiple cells,
363 * across different columns and column families.
364 *
365 * @return status of the operation.
366 *
367 * @par Idempotency
368 * This operation is idempotent if the provided mutations are idempotent. Note
369 * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
370 * **not** an idempotent operation.
371 *
372 * @par Example
373 * @snippet data_snippets.cc apply
374 */
375 Status Apply(SingleRowMutation mut);
376
377 /**
378 * Makes asynchronous attempts to apply the mutation to a row.
379 *
380 * @warning This is an early version of the asynchronous APIs for Cloud
381 * Bigtable. These APIs might be changed in backward-incompatible ways. It
382 * is not subject to any SLA or deprecation policy.
383 *
384 * @param mut the mutation. Note that this function takes ownership
385 * (and then discards) the data in the mutation. In general, a
386 * `SingleRowMutation` can be used to modify and/or delete
387 * multiple cells, across different columns and column families.
388 * @param cq the completion queue that will execute the asynchronous
389 * calls, the application must ensure that one or more threads are
390 * blocked on `cq.Run()`.
391 *
392 * @par Idempotency
393 * This operation is idempotent if the provided mutations are idempotent. Note
394 * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
395 * **not** an idempotent operation.
396 *
397 * @par Example
398 * @snippet data_async_snippets.cc async-apply
399 */
400
401 future<Status> AsyncApply(SingleRowMutation mut, CompletionQueue& cq);
402
403 /**
404 * Attempts to apply mutations to multiple rows.
405 *
406 * @param mut the mutations, note that this function takes
407 * ownership (and then discards) the data in the mutation. In general, a
408 * `BulkMutation` can modify multiple rows, and the modifications for each
409 * row can change (or create) multiple cells, across different columns and
410 * column families.
411 *
412 * @par Idempotency
413 * This operation is idempotent if the provided mutations are idempotent. Note
414 * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
415 * **not** an idempotent operation.
416 *
417 * @par Example
418 * @snippet data_snippets.cc bulk apply
419 */
420 std::vector<FailedMutation> BulkApply(BulkMutation mut);
421
422 /**
423 * Makes asynchronous attempts to apply mutations to multiple rows.
424 *
425 * @warning This is an early version of the asynchronous APIs for Cloud
426 * Bigtable. These APIs might be changed in backward-incompatible ways. It
427 * is not subject to any SLA or deprecation policy.
428 *
429 * @param mut the mutations, note that this function takes
430 * ownership (and then discards) the data in the mutation. In general, a
431 * `BulkMutation` can modify multiple rows, and the modifications for each
432 * row can change (or create) multiple cells, across different columns and
433 * column families.
434 * @param cq the completion queue that will execute the asynchronous calls,
435 * the application must ensure that one or more threads are blocked on
436 * `cq.Run()`.
437 *
438 * @par Idempotency
439 * This operation is idempotent if the provided mutations are idempotent. Note
440 * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
441 * **not** an idempotent operation.
442 *
443 * @par Example
444 * @snippet data_async_snippets.cc bulk async-bulk-apply
445 */
446 future<std::vector<FailedMutation>> AsyncBulkApply(BulkMutation mut,
447 CompletionQueue& cq);
448
449 /**
450 * Reads a set of rows from the table.
451 *
452 * @param row_set the rows to read from.
453 * @param filter is applied on the server-side to data in the rows.
454 *
455 * @par Idempotency
456 * This is a read-only operation and therefore it is always idempotent.
457 *
458 * @par Example
459 * @snippet read_snippets.cc read rows
460 */
461 RowReader ReadRows(RowSet row_set, Filter filter);
462
463 /**
464 * Reads a limited set of rows from the table.
465 *
466 * @param row_set the rows to read from.
467 * @param rows_limit the maximum number of rows to read. Cannot be a negative
468 * number or zero. Use `ReadRows(RowSet, Filter)` to read all matching
469 * rows.
470 * @param filter is applied on the server-side to data in the rows.
471 *
472 * @par Idempotency
473 * This is a read-only operation and therefore it is always idempotent.
474 *
475 * @par Example
476 * @snippet read_snippets.cc read rows with limit
477 */
478 RowReader ReadRows(RowSet row_set, std::int64_t rows_limit, Filter filter);
479
480 /**
481 * Read and return a single row from the table.
482 *
483 * @param row_key the row to read.
484 * @param filter a filter expression, can be used to select a subset of the
485 * column families and columns in the row.
486 * @returns a tuple, the first element is a boolean, with value `false` if the
487 * row does not exist. If the first element is `true` the second element
488 * has the contents of the Row. Note that the contents may be empty
489 * if the filter expression removes all column families and columns.
490 *
491 * @par Idempotency
492 * This is a read-only operation and therefore it is always idempotent.
493 *
494 * @par Example
495 * @snippet read_snippets.cc read row
496 */
497 StatusOr<std::pair<bool, Row>> ReadRow(std::string row_key, Filter filter);
498
499 /**
500 * Atomic test-and-set for a row using filter expressions.
501 *
502 * Atomically check the value of a row using a filter expression. If the
503 * expression passes (meaning at least one element is returned by it), one
504 * set of mutations is applied. If the filter does not pass, a different set
505 * of mutations is applied. The changes are atomically applied in the server.
506 *
507 * @param row_key the row to modify.
508 * @param filter the filter expression.
509 * @param true_mutations the mutations for the "filter passed" case.
510 * @param false_mutations the mutations for the "filter did not pass" case.
511 * @returns true if the filter passed.
512 *
513 * @par Idempotency
514 * This operation is always treated as non-idempotent.
515 *
516 * @par Check for Value Example
517 * @snippet data_snippets.cc check and mutate
518 *
519 * @par Check for Cell Presence Example
520 * @snippet data_snippets.cc check and mutate not present
521 */
522 StatusOr<MutationBranch> CheckAndMutateRow(
523 std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
524 std::vector<Mutation> false_mutations);
525
526 /**
527 * Make an asynchronous request to conditionally mutate a row.
528 *
529 * @warning This is an early version of the asynchronous APIs for Cloud
530 * Bigtable. These APIs might be changed in backward-incompatible ways. It
531 * is not subject to any SLA or deprecation policy.
532 *
533 * @param row_key the row key on which the conditional mutation will be
534 * performed
535 * @param filter the condition, depending on which the mutation will be
536 * performed
537 * @param true_mutations the mutations which will be performed if @p filter is
538 * true
539 * @param false_mutations the mutations which will be performed if @p filter
540 * is false
541 * @param cq the completion queue that will execute the asynchronous calls,
542 * the application must ensure that one or more threads are blocked on
543 * `cq.Run()`.
544 *
545 * @par Idempotency
546 * This operation is always treated as non-idempotent.
547 *
548 * @par Example
549 * @snippet data_async_snippets.cc async check and mutate
550 */
551 future<StatusOr<MutationBranch>> AsyncCheckAndMutateRow(
552 std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
553 std::vector<Mutation> false_mutations, CompletionQueue& cq);
554
555 /**
556 * Sample of the row keys in the table, including approximate data sizes.
557 *
558 * @returns Note that the sample may only include one element for small
559 * tables. In addition, the sample may include row keys that do not exist
560 * on the table, and may include the empty row key to indicate
561 * "end of table".
562 *
563 * @par Idempotency
564 * This operation is always treated as non-idempotent.
565 *
566 * @par Examples
567 * @snippet data_snippets.cc sample row keys
568 */
569 StatusOr<std::vector<bigtable::RowKeySample>> SampleRows();
570
571 /**
572 * Atomically read and modify the row in the server, returning the
573 * resulting row
574 *
575 * @tparam Args this is zero or more ReadModifyWriteRules to apply on a row
576 * @param row_key the row to read
577 * @param rule to modify the row. Two types of rules are applied here
578 * AppendValue which will read the existing value and append the
579 * text provided to the value.
580 * IncrementAmount which will read the existing uint64 big-endian-int
581 * and add the value provided.
582 * Both rules accept the family and column identifier to modify.
583 * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
584 * @returns The new contents of all modified cells.
585 *
586 * @par Idempotency
587 * This operation is always treated as non-idempotent.
588 *
589 * @par Example
590 * @snippet data_snippets.cc read modify write
591 */
592 template <typename... Args>
ReadModifyWriteRow(std::string row_key,bigtable::ReadModifyWriteRule rule,Args &&...rules)593 StatusOr<Row> ReadModifyWriteRow(std::string row_key,
594 bigtable::ReadModifyWriteRule rule,
595 Args&&... rules) {
596 grpc::Status status;
597
598 ::google::bigtable::v2::ReadModifyWriteRowRequest request;
599 request.set_row_key(std::move(row_key));
600
601 // Generate a better compile time error message than the default one
602 // if the types do not match
603 static_assert(
604 absl::conjunction<
605 std::is_convertible<Args, bigtable::ReadModifyWriteRule>...>::value,
606 "The arguments passed to ReadModifyWriteRow(row_key,...) must be "
607 "convertible to bigtable::ReadModifyWriteRule");
608
609 *request.add_rules() = std::move(rule).as_proto();
610 AddRules(request, std::forward<Args>(rules)...);
611 return ReadModifyWriteRowImpl(std::move(request));
612 }
613
614 /**
615 * Make an asynchronous request to atomically read and modify a row.
616 *
617 * @warning This is an early version of the asynchronous APIs for Cloud
618 * Bigtable. These APIs might be changed in backward-incompatible ways. It
619 * is not subject to any SLA or deprecation policy.
620 *
621 * @param row_key the row key on which modification will be performed
622 * @param cq the completion queue that will execute the asynchronous calls,
623 * the application must ensure that one or more threads are blocked on
624 * `cq.Run()`.
625 *
626 * @param rule to modify the row. Two types of rules are applied here
627 * AppendValue which will read the existing value and append the
628 * text provided to the value.
629 * IncrementAmount which will read the existing uint64 big-endian-int
630 * and add the value provided.
631 * Both rules accept the family and column identifier to modify.
632 * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
633 * @returns A future, that becomes satisfied when the operation completes,
634 * at that point the future has the contents of all modified cells.
635 *
636 * @par Idempotency
637 * This operation is always treated as non-idempotent.
638 *
639 * @par Example
640 * @snippet data_async_snippets.cc async read modify write
641 */
642 template <typename... Args>
AsyncReadModifyWriteRow(std::string row_key,CompletionQueue & cq,bigtable::ReadModifyWriteRule rule,Args &&...rules)643 future<StatusOr<Row>> AsyncReadModifyWriteRow(
644 std::string row_key, CompletionQueue& cq,
645 bigtable::ReadModifyWriteRule rule, Args&&... rules) {
646 ::google::bigtable::v2::ReadModifyWriteRowRequest request;
647 request.set_row_key(std::move(row_key));
648 *request.add_rules() = std::move(rule).as_proto();
649 AddRules(request, std::forward<Args>(rules)...);
650
651 return AsyncReadModifyWriteRowImpl(cq, std::move(request));
652 }
653
654 /**
655 * Asynchronously reads a set of rows from the table.
656 *
657 * @warning This is an early version of the asynchronous APIs for Cloud
658 * Bigtable. These APIs might be changed in backward-incompatible ways. It
659 * is not subject to any SLA or deprecation policy.
660 *
661 * @param cq the completion queue that will execute the asynchronous calls,
662 * the application must ensure that one or more threads are blocked on
663 * `cq.Run()`.
664 * @param on_row the callback to be invoked on each successfully read row; it
665 * should be invocable with `Row` and return a future<bool>; the returned
666 * `future<bool>` should be satisfied with `true` when the user is ready
667 * to receive the next callback and with `false` when the user doesn't
668 * want any more rows; if `on_row` throws, the results are undefined
669 * @param on_finish the callback to be invoked when the stream is closed; it
670 * should be invocable with `Status` and not return anything; it will
671 * always be called as the last callback; if `on_finish` throws, the
672 * results are undefined
673 * @param row_set the rows to read from.
674 * @param filter is applied on the server-side to data in the rows.
675 *
676 * @tparam RowFunctor the type of the @p on_row callback.
677 * @tparam FinishFunctor the type of the @p on_finish callback.
678 *
679 * @par Example
680 * @snippet data_async_snippets.cc async read rows
681 */
682 template <typename RowFunctor, typename FinishFunctor>
AsyncReadRows(CompletionQueue & cq,RowFunctor on_row,FinishFunctor on_finish,RowSet row_set,Filter filter)683 void AsyncReadRows(CompletionQueue& cq, RowFunctor on_row,
684 FinishFunctor on_finish, RowSet row_set, Filter filter) {
685 AsyncRowReader<RowFunctor, FinishFunctor>::Create(
686 cq, client_, app_profile_id_, table_name_, std::move(on_row),
687 std::move(on_finish), std::move(row_set),
688 AsyncRowReader<RowFunctor, FinishFunctor>::NO_ROWS_LIMIT,
689 std::move(filter), clone_rpc_retry_policy(), clone_rpc_backoff_policy(),
690 metadata_update_policy_,
691 absl::make_unique<bigtable::internal::ReadRowsParserFactory>());
692 }
693
694 /**
695 * Asynchronously reads a set of rows from the table.
696 *
697 * @warning This is an early version of the asynchronous APIs for Cloud
698 * Bigtable. These APIs might be changed in backward-incompatible ways. It
699 * is not subject to any SLA or deprecation policy.
700 *
701 * @param cq the completion queue that will execute the asynchronous calls,
702 * the application must ensure that one or more threads are blocked on
703 * `cq.Run()`.
704 * @param on_row the callback to be invoked on each successfully read row; it
705 * should be invocable with `Row` and return a future<bool>; the returned
706 * `future<bool>` should be satisfied with `true` when the user is ready
707 * to receive the next callback and with `false` when the user doesn't
708 * want any more rows; if `on_row` throws, the results are undefined
709 * @param on_finish the callback to be invoked when the stream is closed; it
710 * should be invocable with `Status` and not return anything; it will
711 * always be called as the last callback; if `on_finish` throws, the
712 * results are undefined
713 * @param row_set the rows to read from.
714 * @param rows_limit the maximum number of rows to read. Cannot be a negative
715 * number or zero. Use `AsyncReadRows(CompletionQueue, RowSet, Filter)` to
716 * read all matching rows.
717 * @param filter is applied on the server-side to data in the rows.
718 *
719 * @tparam RowFunctor the type of the @p on_row callback.
720 * @tparam FinishFunctor the type of the @p on_finish callback.
721 *
722 * @par Example
723 * @snippet data_async_snippets.cc async read rows with limit
724 */
725 template <typename RowFunctor, typename FinishFunctor>
AsyncReadRows(CompletionQueue & cq,RowFunctor on_row,FinishFunctor on_finish,RowSet row_set,std::int64_t rows_limit,Filter filter)726 void AsyncReadRows(CompletionQueue& cq, RowFunctor on_row,
727 FinishFunctor on_finish, RowSet row_set,
728 std::int64_t rows_limit, Filter filter) {
729 AsyncRowReader<RowFunctor, FinishFunctor>::Create(
730 cq, client_, app_profile_id_, table_name_, std::move(on_row),
731 std::move(on_finish), std::move(row_set), rows_limit, std::move(filter),
732 clone_rpc_retry_policy(), clone_rpc_backoff_policy(),
733 metadata_update_policy_,
734 absl::make_unique<bigtable::internal::ReadRowsParserFactory>());
735 }
736
737 /**
738 * Asynchronously read and return a single row from the table.
739 *
740 * @warning This is an early version of the asynchronous APIs for Cloud
741 * Bigtable. These APIs might be changed in backward-incompatible ways. It
742 * is not subject to any SLA or deprecation policy.
743 *
744 * @param cq the completion queue that will execute the asynchronous calls,
745 * the application must ensure that one or more threads are blocked on
746 * `cq.Run()`.
747 * @param row_key the row to read.
748 * @param filter a filter expression, can be used to select a subset of the
749 * column families and columns in the row.
750 * @returns a future satisfied when the operation completes, failes
751 * permanently or keeps failing transiently, but the retry policy has been
752 * exhausted. The future will return a tuple. The first element is a
753 * boolean, with value `false` if the row does not exist. If the first
754 * element is `true` the second element has the contents of the Row. Note
755 * that the contents may be empty if the filter expression removes all
756 * column families and columns.
757 *
758 * @par Idempotency
759 * This is a read-only operation and therefore it is always idempotent.
760 *
761 * @par Example
762 * @snippet data_async_snippets.cc async read row
763 */
764 future<StatusOr<std::pair<bool, Row>>> AsyncReadRow(CompletionQueue& cq,
765 std::string row_key,
766 Filter filter);
767
768 private:
769 /**
770 * Send request ReadModifyWriteRowRequest to modify the row and get it back
771 */
772 StatusOr<Row> ReadModifyWriteRowImpl(
773 ::google::bigtable::v2::ReadModifyWriteRowRequest request);
774
775 future<StatusOr<Row>> AsyncReadModifyWriteRowImpl(
776 CompletionQueue& cq,
777 ::google::bigtable::v2::ReadModifyWriteRowRequest request);
778
AddRules(google::bigtable::v2::ReadModifyWriteRowRequest &)779 void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest&) {
780 // no-op for empty list
781 }
782
783 template <typename... Args>
AddRules(google::bigtable::v2::ReadModifyWriteRowRequest & request,bigtable::ReadModifyWriteRule rule,Args &&...args)784 void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest& request,
785 bigtable::ReadModifyWriteRule rule, Args&&... args) {
786 *request.add_rules() = std::move(rule).as_proto();
787 AddRules(request, std::forward<Args>(args)...);
788 }
789
clone_rpc_retry_policy()790 std::unique_ptr<RPCRetryPolicy> clone_rpc_retry_policy() {
791 return rpc_retry_policy_prototype_->clone();
792 }
793
clone_rpc_backoff_policy()794 std::unique_ptr<RPCBackoffPolicy> clone_rpc_backoff_policy() {
795 return rpc_backoff_policy_prototype_->clone();
796 }
797
clone_metadata_update_policy()798 MetadataUpdatePolicy clone_metadata_update_policy() {
799 return metadata_update_policy_;
800 }
801
clone_idempotent_mutation_policy()802 std::unique_ptr<IdempotentMutationPolicy> clone_idempotent_mutation_policy() {
803 return idempotent_mutation_policy_->clone();
804 }
805
806 //@{
807 /// @name Helper functions to implement constructors with changed policies.
ChangePolicy(RPCRetryPolicy const & policy)808 void ChangePolicy(RPCRetryPolicy const& policy) {
809 rpc_retry_policy_prototype_ = policy.clone();
810 }
811
ChangePolicy(RPCBackoffPolicy const & policy)812 void ChangePolicy(RPCBackoffPolicy const& policy) {
813 rpc_backoff_policy_prototype_ = policy.clone();
814 }
815
ChangePolicy(IdempotentMutationPolicy const & policy)816 void ChangePolicy(IdempotentMutationPolicy const& policy) {
817 idempotent_mutation_policy_ = policy.clone();
818 }
819
820 template <typename Policy, typename... Policies>
ChangePolicies(Policy && policy,Policies &&...policies)821 void ChangePolicies(Policy&& policy, Policies&&... policies) {
822 ChangePolicy(policy);
823 ChangePolicies(std::forward<Policies>(policies)...);
824 }
ChangePolicies()825 void ChangePolicies() {}
826 //@}
827
828 friend class MutationBatcher;
829 std::shared_ptr<DataClient> client_;
830 std::string app_profile_id_;
831 std::string table_name_;
832 std::string table_id_;
833 std::shared_ptr<RPCRetryPolicy const> rpc_retry_policy_prototype_;
834 std::shared_ptr<RPCBackoffPolicy const> rpc_backoff_policy_prototype_;
835 MetadataUpdatePolicy metadata_update_policy_;
836 std::shared_ptr<IdempotentMutationPolicy> idempotent_mutation_policy_;
837 };
838
839 } // namespace BIGTABLE_CLIENT_NS
840 } // namespace bigtable
841 } // namespace cloud
842 } // namespace google
843
844 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H
845