Google Cloud Bigtable C++ Client  1.1.0
A C++ Client Library for Google Cloud Bigtable
table.h
Go to the documentation of this file.
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_utils/grpc_error_delegate.h"
33 #include "google/cloud/internal/disjunction.h"
34 #include "google/cloud/status.h"
35 #include "google/cloud/status_or.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  */
62 inline std::string TableName(std::shared_ptr<DataClient> client,
63  std::string const& table_id) {
64  return InstanceName(std::move(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::v0::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::v0::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 valid_policy : google::cloud::internal::disjunction<
173  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 valid_policies : internal::conjunction<valid_policy<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  */
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  */
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_(
216  bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)),
217  rpc_backoff_policy_(
218  bigtable::DefaultRPCBackoffPolicy(internal::kBigtableLimits)),
219  metadata_update_policy_(table_name(), MetadataParamTypes::TABLE_NAME),
220  idempotent_mutation_policy_(
221  bigtable::DefaultIdempotentMutationPolicy()) {}
222 
223  /**
224  * Constructor with explicit policies.
225  *
226  * The policies are passed by value, because this makes it easy for
227  * applications to create them.
228  *
229  * @par Example
230  * @code
231  * using namespace std::chrono_literals; // assuming C++14.
232  * auto client = bigtable::CreateDefaultClient(...); // details ommitted
233  * bigtable::Table table(client, "my-table",
234  * // Allow up to 20 minutes to retry operations
235  * bigtable::LimitedTimeRetryPolicy(20min),
236  * // Start with 50 milliseconds backoff, grow
237  * // exponentially to 5 minutes.
238  * bigtable::ExponentialBackoffPolicy(50ms, 5min),
239  * // Only retry idempotent mutations.
240  * bigtable::SafeIdempotentMutationPolicy());
241  * @endcode
242  *
243  * @param client how to communicate with Cloud Bigtable, including
244  * credentials, the project id, and the instance id.
245  * @param table_id the table id within the instance defined by client. The
246  * full table name is `client->instance_name() + "/tables/" + table_id`.
247  * @param policies the set of policy overrides for this object.
248  * @tparam Policies the types of the policies to override, the types must
249  * derive from one of the following types:
250  *
251  * - `IdempotentMutationPolicy` which mutations are retried. Use
252  * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
253  * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
254  * caveats in the class definition to understand the downsides of the
255  * latter. You can also create your own policies that decide which
256  * mutations to retry.
257  * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
258  * `ExponentialBackoffPolicy` is implemented. You can also create your
259  * own policies that backoff using a different algorithm.
260  * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
261  * `LimitedErrorCountRetryPolicy` to limit the number of failures
262  * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
263  * request. You can also create your own policies that combine time and
264  * error counts.
265  *
266  * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
267  * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
268  * LimitedTimeRetryPolicy.
269  *
270  * @par Idempotency Policy Example
271  * @snippet data_snippets.cc apply relaxed idempotency
272  *
273  * @par Modified Retry Policy Example
274  * @snippet data_snippets.cc apply custom retry
275  */
276  template <typename... Policies,
277  typename std::enable_if<valid_policies<Policies...>::value,
278  int>::type = 0>
279  Table(std::shared_ptr<DataClient> client, std::string const& table_id,
280  Policies&&... policies)
281  : Table(std::move(client), table_id) {
282  ChangePolicies(std::forward<Policies>(policies)...);
283  }
284 
285  /**
286  * Constructor with explicit policies.
287  *
288  * The policies are passed by value, because this makes it easy for
289  * applications to create them.
290  *
291  * @par Example
292  * @code
293  * using namespace std::chrono_literals; // assuming C++14.
294  * auto client = bigtable::CreateDefaultClient(...); // details ommitted
295  * bigtable::Table table(client, "app_id", "my-table",
296  * // Allow up to 20 minutes to retry operations
297  * bigtable::LimitedTimeRetryPolicy(20min),
298  * // Start with 50 milliseconds backoff, grow
299  * // exponentially to 5 minutes.
300  * bigtable::ExponentialBackoffPolicy(50ms, 5min),
301  * // Only retry idempotent mutations.
302  * bigtable::SafeIdempotentMutationPolicy());
303  * @endcode
304  *
305  * @param client how to communicate with Cloud Bigtable, including
306  * credentials, the project id, and the instance id.
307  * @param app_profile_id the app_profile_id needed for using the replication
308  * API.
309  * @param table_id the table id within the instance defined by client. The
310  * full table name is `client->instance_name() + "/tables/" + table_id`.
311  * @param policies the set of policy overrides for this object.
312  * @tparam Policies the types of the policies to override, the types must
313  * derive from one of the following types:
314  * - `IdempotentMutationPolicy` which mutations are retried. Use
315  * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
316  * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
317  * caveats in the class definition to understand the downsides of the
318  * latter. You can also create your own policies that decide which
319  * mutations to retry.
320  * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
321  * `ExponentialBackoffPolicy` is implemented. You can also create your
322  * own policies that backoff using a different algorithm.
323  * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
324  * `LimitedErrorCountRetryPolicy` to limit the number of failures
325  * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
326  * request. You can also create your own policies that combine time and
327  * error counts.
328  *
329  * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
330  * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
331  * LimitedTimeRetryPolicy.
332  *
333  * @par Idempotency Policy Example
334  * @snippet data_snippets.cc apply relaxed idempotency
335  *
336  * @par Modified Retry Policy Example
337  * @snippet data_snippets.cc apply custom retry
338  */
339  template <typename... Policies,
340  typename std::enable_if<valid_policies<Policies...>::value,
341  int>::type = 0>
342  Table(std::shared_ptr<DataClient> client, std::string app_profile_id,
343  std::string const& table_id, Policies&&... policies)
344  : Table(std::move(client), std::move(app_profile_id), table_id) {
345  ChangePolicies(std::forward<Policies>(policies)...);
346  }
347 
348  std::string const& table_name() const { return table_name_; }
349  std::string const& app_profile_id() const { return app_profile_id_; }
350  std::string const& project_id() const { return client_->project_id(); }
351  std::string const& instance_id() const { return client_->instance_id(); }
352  std::string const& table_id() const { return table_id_; }
353 
354  /**
355  * Attempts to apply the mutation to a row.
356  *
357  * @param mut the mutation. Note that this function takes ownership (and
358  * then discards) the data in the mutation. In general, a
359  * `SingleRowMutation` can be used to modify and/or delete multiple cells,
360  * across different columns and column families.
361  *
362  * @return status of the operation.
363  *
364  * @par Idempotency
365  * This operation is idempotent if the provided mutations are idempotent. Note
366  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
367  * **not** an idempotent operation.
368  *
369  * @par Example
370  * @snippet data_snippets.cc apply
371  */
372  Status Apply(SingleRowMutation mut);
373 
374  /**
375  * Makes asynchronous attempts to apply the mutation to a row.
376  *
377  * @warning This is an early version of the asynchronous APIs for Cloud
378  * Bigtable. These APIs might be changed in backward-incompatible ways. It
379  * is not subject to any SLA or deprecation policy.
380  *
381  * @param mut the mutation. Note that this function takes ownership
382  * (and then discards) the data in the mutation. In general, a
383  * `SingleRowMutation` can be used to modify and/or delete
384  * multiple cells, across different columns and column families.
385  * @param cq the completion queue that will execute the asynchronous
386  * calls, the application must ensure that one or more threads are
387  * blocked on `cq.Run()`.
388  *
389  * @par Idempotency
390  * This operation is idempotent if the provided mutations are idempotent. Note
391  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
392  * **not** an idempotent operation.
393  *
394  * @par Example
395  * @snippet data_async_snippets.cc async-apply
396  */
397 
398  future<Status> AsyncApply(SingleRowMutation mut, CompletionQueue& cq);
399 
400  /**
401  * Attempts to apply mutations to multiple rows.
402  *
403  * @param mut the mutations, note that this function takes
404  * ownership (and then discards) the data in the mutation. In general, a
405  * `BulkMutation` can modify multiple rows, and the modifications for each
406  * row can change (or create) multiple cells, across different columns and
407  * column families.
408  *
409  * @par Idempotency
410  * This operation is idempotent if the provided mutations are idempotent. Note
411  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
412  * **not** an idempotent operation.
413  *
414  * @par Example
415  * @snippet data_snippets.cc bulk apply
416  */
417  std::vector<FailedMutation> BulkApply(BulkMutation mut);
418 
419  /**
420  * Makes asynchronous attempts to apply mutations to multiple rows.
421  *
422  * @warning This is an early version of the asynchronous APIs for Cloud
423  * Bigtable. These APIs might be changed in backward-incompatible ways. It
424  * is not subject to any SLA or deprecation policy.
425  *
426  * @param mut the mutations, note that this function takes
427  * ownership (and then discards) the data in the mutation. In general, a
428  * `BulkMutation` can modify multiple rows, and the modifications for each
429  * row can change (or create) multiple cells, across different columns and
430  * column families.
431  * @param cq the completion queue that will execute the asynchronous calls,
432  * the application must ensure that one or more threads are blocked on
433  * `cq.Run()`.
434  *
435  * @par Idempotency
436  * This operation is idempotent if the provided mutations are idempotent. Note
437  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
438  * **not** an idempotent operation.
439  *
440  * @par Example
441  * @snippet data_async_snippets.cc bulk async-bulk-apply
442  */
443  future<std::vector<FailedMutation>> AsyncBulkApply(BulkMutation mut,
444  CompletionQueue& cq);
445 
446  /**
447  * Reads a set of rows from the table.
448  *
449  * @param row_set the rows to read from.
450  * @param filter is applied on the server-side to data in the rows.
451  *
452  * @par Idempotency
453  * This is a read-only operation and therefore it is always idempotent.
454  *
455  * @par Example
456  * @snippet data_snippets.cc read rows
457  */
458  RowReader ReadRows(RowSet row_set, Filter filter);
459 
460  /**
461  * Reads a limited set of rows from the table.
462  *
463  * @param row_set the rows to read from.
464  * @param rows_limit the maximum number of rows to read. Cannot be a negative
465  * number or zero. Use `ReadRows(RowSet, Filter)` to read all matching
466  * rows.
467  * @param filter is applied on the server-side to data in the rows.
468  *
469  * @par Idempotency
470  * This is a read-only operation and therefore it is always idempotent.
471  *
472  * @par Example
473  * @snippet data_snippets.cc read rows with limit
474  */
475  RowReader ReadRows(RowSet row_set, std::int64_t rows_limit, Filter filter);
476 
477  /**
478  * Read and return a single row from the table.
479  *
480  * @param row_key the row to read.
481  * @param filter a filter expression, can be used to select a subset of the
482  * column families and columns in the row.
483  * @returns a tuple, the first element is a boolean, with value `false` if the
484  * row does not exist. If the first element is `true` the second element
485  * has the contents of the Row. Note that the contents may be empty
486  * if the filter expression removes all column families and columns.
487  *
488  * @par Idempotency
489  * This is a read-only operation and therefore it is always idempotent.
490  *
491  * @par Example
492  * @snippet data_snippets.cc read row
493  */
494  StatusOr<std::pair<bool, Row>> ReadRow(std::string row_key, Filter filter);
495 
496  /**
497  * Atomic test-and-set for a row using filter expressions.
498  *
499  * Atomically check the value of a row using a filter expression. If the
500  * expression passes (meaning at least one element is returned by it), one
501  * set of mutations is applied. If the filter does not pass, a different set
502  * of mutations is applied. The changes are atomically applied in the server.
503  *
504  * @param row_key the row to modify.
505  * @param filter the filter expression.
506  * @param true_mutations the mutations for the "filter passed" case.
507  * @param false_mutations the mutations for the "filter did not pass" case.
508  * @returns true if the filter passed.
509  *
510  * @par Idempotency
511  * This operation is always treated as non-idempotent.
512  *
513  * @par Check for Value Example
514  * @snippet data_snippets.cc check and mutate
515  *
516  * @par Check for Cell Presence Example
517  * @snippet data_snippets.cc check and mutate not present
518  */
519  StatusOr<MutationBranch> CheckAndMutateRow(
520  std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
521  std::vector<Mutation> false_mutations);
522 
523  /**
524  * Make an asynchronous request to conditionally mutate a row.
525  *
526  * @warning This is an early version of the asynchronous APIs for Cloud
527  * Bigtable. These APIs might be changed in backward-incompatible ways. It
528  * is not subject to any SLA or deprecation policy.
529  *
530  * @param row_key the row key on which the conditional mutation will be
531  * performed
532  * @param filter the condition, depending on which the mutation will be
533  * performed
534  * @param true_mutations the mutations which will be performed if @p filter is
535  * true
536  * @param false_mutations the mutations which will be performed if @p filter
537  * is false
538  * @param cq the completion queue that will execute the asynchronous calls,
539  * the application must ensure that one or more threads are blocked on
540  * `cq.Run()`.
541  *
542  * @par Idempotency
543  * This operation is always treated as non-idempotent.
544  *
545  * @par Example
546  * @snippet data_async_snippets.cc async check and mutate
547  */
548  future<StatusOr<MutationBranch>> AsyncCheckAndMutateRow(
549  std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
550  std::vector<Mutation> false_mutations, CompletionQueue& cq);
551 
552  /**
553  * Sample of the row keys in the table, including approximate data sizes.
554  *
555  * @returns Note that the sample may only include one element for small
556  * tables. In addition, the sample may include row keys that do not exist
557  * on the table, and may include the empty row key to indicate
558  * "end of table".
559  *
560  * @par Idempotency
561  * This operation is always treated as non-idempotent.
562  *
563  * @par Examples
564  * @snippet data_snippets.cc sample row keys
565  */
566  StatusOr<std::vector<bigtable::RowKeySample>> SampleRows();
567 
568  /**
569  * Atomically read and modify the row in the server, returning the
570  * resulting row
571  *
572  * @tparam Args this is zero or more ReadModifyWriteRules to apply on a row
573  * @param row_key the row to read
574  * @param rule to modify the row. Two types of rules are applied here
575  * AppendValue which will read the existing value and append the
576  * text provided to the value.
577  * IncrementAmount which will read the existing uint64 big-endian-int
578  * and add the value provided.
579  * Both rules accept the family and column identifier to modify.
580  * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
581  * @returns The new contents of all modified cells.
582  *
583  * @par Idempotency
584  * This operation is always treated as non-idempotent.
585  *
586  * @par Example
587  * @snippet data_snippets.cc read modify write
588  */
589  template <typename... Args>
590  StatusOr<Row> ReadModifyWriteRow(std::string row_key,
591  bigtable::ReadModifyWriteRule rule,
592  Args&&... rules) {
593  grpc::Status status;
594 
595  ::google::bigtable::v2::ReadModifyWriteRowRequest request;
596  request.set_row_key(std::move(row_key));
597 
598  // Generate a better compile time error message than the default one
599  // if the types do not match
600  static_assert(
601  bigtable::internal::conjunction<
602  std::is_convertible<Args, bigtable::ReadModifyWriteRule>...>::value,
603  "The arguments passed to ReadModifyWriteRow(row_key,...) must be "
604  "convertible to bigtable::ReadModifyWriteRule");
605 
606  *request.add_rules() = std::move(rule).as_proto();
607  AddRules(request, std::forward<Args>(rules)...);
608  return ReadModifyWriteRowImpl(std::move(request));
609  }
610 
611  /**
612  * Make an asynchronous request to atomically read and modify a row.
613  *
614  * @warning This is an early version of the asynchronous APIs for Cloud
615  * Bigtable. These APIs might be changed in backward-incompatible ways. It
616  * is not subject to any SLA or deprecation policy.
617  *
618  * @param row_key the row key on which modification will be performed
619  * @param cq the completion queue that will execute the asynchronous calls,
620  * the application must ensure that one or more threads are blocked on
621  * `cq.Run()`.
622  *
623  * @param rule to modify the row. Two types of rules are applied here
624  * AppendValue which will read the existing value and append the
625  * text provided to the value.
626  * IncrementAmount which will read the existing uint64 big-endian-int
627  * and add the value provided.
628  * Both rules accept the family and column identifier to modify.
629  * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
630  * @returns A future, that becomes satisfied when the operation completes,
631  * at that point the future has the contents of all modified cells.
632  *
633  * @par Idempotency
634  * This operation is always treated as non-idempotent.
635  *
636  * @par Example
637  * @snippet data_async_snippets.cc async read modify write
638  */
639  template <typename... Args>
640  future<StatusOr<Row>> AsyncReadModifyWriteRow(
641  std::string row_key, CompletionQueue& cq,
642  bigtable::ReadModifyWriteRule rule, Args&&... rules) {
643  ::google::bigtable::v2::ReadModifyWriteRowRequest request;
644  request.set_row_key(std::move(row_key));
645  *request.add_rules() = std::move(rule).as_proto();
646  AddRules(request, std::forward<Args>(rules)...);
647 
648  return AsyncReadModifyWriteRowImpl(cq, std::move(request));
649  }
650 
651  /**
652  * Asynchronously reads a set of rows from the table.
653  *
654  * @warning This is an early version of the asynchronous APIs for Cloud
655  * Bigtable. These APIs might be changed in backward-incompatible ways. It
656  * is not subject to any SLA or deprecation policy.
657  *
658  * @param cq the completion queue that will execute the asynchronous calls,
659  * the application must ensure that one or more threads are blocked on
660  * `cq.Run()`.
661  * @param on_row the callback to be invoked on each successfully read row; it
662  * should be invocable with `Row` and return a future<bool>; the returned
663  * `future<bool>` should be satisfied with `true` when the user is ready
664  * to receive the next callback and with `false` when the user doesn't
665  * want any more rows; if `on_row` throws, the results are undefined
666  * @param on_finish the callback to be invoked when the stream is closed; it
667  * should be invocable with `Status` and not return anything; it will
668  * always be called as the last callback; if `on_finish` throws, the
669  * results are undefined
670  * @param row_set the rows to read from.
671  * @param filter is applied on the server-side to data in the rows.
672  *
673  * @tparam RowFunctor the type of the @p on_row callback.
674  * @tparam FinishFunctor the type of the @p on_finish callback.
675  *
676  * @par Example
677  * @snippet data_async_snippets.cc async read rows
678  */
679  template <typename RowFunctor, typename FinishFunctor>
680  void AsyncReadRows(CompletionQueue& cq, RowFunctor on_row,
681  FinishFunctor on_finish, RowSet row_set, Filter filter) {
682  AsyncRowReader<RowFunctor, FinishFunctor>::Create(
683  cq, client_, app_profile_id_, table_name_, std::move(on_row),
684  std::move(on_finish), std::move(row_set),
685  AsyncRowReader<RowFunctor, FinishFunctor>::NO_ROWS_LIMIT,
686  std::move(filter), clone_rpc_retry_policy(), clone_rpc_backoff_policy(),
687  metadata_update_policy_,
688  google::cloud::internal::make_unique<
689  bigtable::internal::ReadRowsParserFactory>());
690  }
691 
692  /**
693  * Asynchronously reads a set of rows from the table.
694  *
695  * @warning This is an early version of the asynchronous APIs for Cloud
696  * Bigtable. These APIs might be changed in backward-incompatible ways. It
697  * is not subject to any SLA or deprecation policy.
698  *
699  * @param cq the completion queue that will execute the asynchronous calls,
700  * the application must ensure that one or more threads are blocked on
701  * `cq.Run()`.
702  * @param on_row the callback to be invoked on each successfully read row; it
703  * should be invocable with `Row` and return a future<bool>; the returned
704  * `future<bool>` should be satisfied with `true` when the user is ready
705  * to receive the next callback and with `false` when the user doesn't
706  * want any more rows; if `on_row` throws, the results are undefined
707  * @param on_finish the callback to be invoked when the stream is closed; it
708  * should be invocable with `Status` and not return anything; it will
709  * always be called as the last callback; if `on_finish` throws, the
710  * results are undefined
711  * @param row_set the rows to read from.
712  * @param rows_limit the maximum number of rows to read. Cannot be a negative
713  * number or zero. Use `AsyncReadRows(CompletionQueue, RowSet, Filter)` to
714  * read all matching rows.
715  * @param filter is applied on the server-side to data in the rows.
716  *
717  * @tparam RowFunctor the type of the @p on_row callback.
718  * @tparam FinishFunctor the type of the @p on_finish callback.
719  *
720  * @par Example
721  * @snippet data_async_snippets.cc async read rows with limit
722  */
723  template <typename RowFunctor, typename FinishFunctor>
724  void AsyncReadRows(CompletionQueue& cq, RowFunctor on_row,
725  FinishFunctor on_finish, RowSet row_set,
726  std::int64_t rows_limit, Filter filter) {
727  AsyncRowReader<RowFunctor, FinishFunctor>::Create(
728  cq, client_, app_profile_id_, table_name_, std::move(on_row),
729  std::move(on_finish), std::move(row_set), rows_limit, std::move(filter),
730  clone_rpc_retry_policy(), clone_rpc_backoff_policy(),
731  metadata_update_policy_,
732  google::cloud::internal::make_unique<
733  bigtable::internal::ReadRowsParserFactory>());
734  }
735 
736  /**
737  * Asynchronously read and return a single row from the table.
738  *
739  * @warning This is an early version of the asynchronous APIs for Cloud
740  * Bigtable. These APIs might be changed in backward-incompatible ways. It
741  * is not subject to any SLA or deprecation policy.
742  *
743  * @param cq the completion queue that will execute the asynchronous calls,
744  * the application must ensure that one or more threads are blocked on
745  * `cq.Run()`.
746  * @param row_key the row to read.
747  * @param filter a filter expression, can be used to select a subset of the
748  * column families and columns in the row.
749  * @returns a future satisfied when the operation completes, failes
750  * permanently or keeps failing transiently, but the retry policy has been
751  * exhausted. The future will return a tuple. The first element is a
752  * boolean, with value `false` if the row does not exist. If the first
753  * element is `true` the second element has the contents of the Row. Note
754  * that the contents may be empty if the filter expression removes all
755  * column families and columns.
756  *
757  * @par Idempotency
758  * This is a read-only operation and therefore it is always idempotent.
759  *
760  * @par Example
761  * @snippet data_async_snippets.cc async read row
762  */
763  future<StatusOr<std::pair<bool, Row>>> AsyncReadRow(CompletionQueue& cq,
764  std::string row_key,
765  Filter filter);
766 
767  private:
768  /**
769  * Send request ReadModifyWriteRowRequest to modify the row and get it back
770  */
771  StatusOr<Row> ReadModifyWriteRowImpl(
772  ::google::bigtable::v2::ReadModifyWriteRowRequest request);
773 
774  future<StatusOr<Row>> AsyncReadModifyWriteRowImpl(
775  CompletionQueue& cq,
776  ::google::bigtable::v2::ReadModifyWriteRowRequest request);
777 
778  void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest&) {
779  // no-op for empty list
780  }
781 
782  template <typename... Args>
783  void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest& request,
784  bigtable::ReadModifyWriteRule rule, Args&&... args) {
785  *request.add_rules() = std::move(rule).as_proto();
786  AddRules(request, std::forward<Args>(args)...);
787  }
788 
789  std::unique_ptr<RPCRetryPolicy> clone_rpc_retry_policy() {
790  return rpc_retry_policy_->clone();
791  }
792 
793  std::unique_ptr<RPCBackoffPolicy> clone_rpc_backoff_policy() {
794  return rpc_backoff_policy_->clone();
795  }
796 
797  MetadataUpdatePolicy clone_metadata_update_policy() {
798  return metadata_update_policy_;
799  }
800 
801  std::unique_ptr<IdempotentMutationPolicy> clone_idempotent_mutation_policy() {
802  return idempotent_mutation_policy_->clone();
803  }
804 
805  //@{
806  /// @name Helper functions to implement constructors with changed policies.
807  void ChangePolicy(RPCRetryPolicy& policy) {
808  rpc_retry_policy_ = policy.clone();
809  }
810 
811  void ChangePolicy(RPCBackoffPolicy& policy) {
812  rpc_backoff_policy_ = policy.clone();
813  }
814 
815  void ChangePolicy(IdempotentMutationPolicy& policy) {
816  idempotent_mutation_policy_ = policy.clone();
817  }
818 
819  template <typename Policy, typename... Policies>
820  void ChangePolicies(Policy&& policy, Policies&&... policies) {
821  ChangePolicy(policy);
822  ChangePolicies(std::forward<Policies>(policies)...);
823  }
824  void ChangePolicies() {}
825  //@}
826 
827  friend class MutationBatcher;
828  std::shared_ptr<DataClient> client_;
829  std::string app_profile_id_;
830  std::string table_name_;
831  std::string table_id_;
832  std::shared_ptr<RPCRetryPolicy> rpc_retry_policy_;
833  std::shared_ptr<RPCBackoffPolicy> rpc_backoff_policy_;
834  MetadataUpdatePolicy metadata_update_policy_;
835  std::shared_ptr<IdempotentMutationPolicy> idempotent_mutation_policy_;
836 };
837 
838 } // namespace BIGTABLE_CLIENT_NS
839 } // namespace bigtable
840 } // namespace cloud
841 } // namespace google
842 
843 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H_
#define BIGTABLE_CLIENT_NS
Definition: version.h:22