Google Cloud Bigtable C++ Client  2.0.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 // https://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/completion_queue.h"
19 #include "google/cloud/bigtable/data_client.h"
20 #include "google/cloud/bigtable/data_connection.h"
21 #include "google/cloud/bigtable/filters.h"
22 #include "google/cloud/bigtable/idempotent_mutation_policy.h"
23 #include "google/cloud/bigtable/internal/defaults.h"
24 #include "google/cloud/bigtable/internal/legacy_async_row_reader.h"
25 #include "google/cloud/bigtable/mutation_branch.h"
26 #include "google/cloud/bigtable/mutations.h"
27 #include "google/cloud/bigtable/options.h"
28 #include "google/cloud/bigtable/read_modify_write_rule.h"
29 #include "google/cloud/bigtable/resource_names.h"
30 #include "google/cloud/bigtable/row_key_sample.h"
31 #include "google/cloud/bigtable/row_reader.h"
32 #include "google/cloud/bigtable/row_set.h"
33 #include "google/cloud/bigtable/rpc_backoff_policy.h"
34 #include "google/cloud/bigtable/rpc_retry_policy.h"
35 #include "google/cloud/bigtable/table_resource.h"
36 #include "google/cloud/bigtable/version.h"
37 #include "google/cloud/future.h"
38 #include "google/cloud/grpc_error_delegate.h"
39 #include "google/cloud/options.h"
40 #include "google/cloud/status.h"
41 #include "google/cloud/status_or.h"
42 #include "absl/meta/type_traits.h"
43 #include <string>
44 #include <vector>
45 
46 namespace google {
47 namespace cloud {
48 namespace bigtable {
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> 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 concurrently on the same
88  * instance of 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 [`StatusOr<T>`
102  * documentation](#google::cloud::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::StatusOr for a description of the error reporting class
154  * 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  * Constructs a `Table` object.
184  *
185  * @param conn the connection to the Cloud Bigtable service. See
186  * `MakeDataConnection()` for how to create a connection. To mock the
187  * behavior of `Table` in your tests, use a
188  * `bigtable_mocks::MockDataConnection`.
189  * @param tr identifies the table resource by its project, instance, and table
190  * ids.
191  * @param options Configuration options for the table. Use
192  * `AppProfileIdOption` to supply an app profile for the `Table`
193  * operations. Or configure retry / backoff / idempotency policies with
194  * the options enumerated in `DataPolicyOptionList`.
195  *
196  * @par Example Using AppProfile
197  * @snippet bigtable_hello_app_profile.cc read with app profile
198  *
199  * @par Idempotency Policy Example
200  * @snippet data_snippets.cc apply relaxed idempotency
201  *
202  * @par Modified Retry Policy Example
203  * @snippet data_snippets.cc apply custom retry
204  */
205  explicit Table(std::shared_ptr<bigtable::DataConnection> conn,
206  TableResource tr, Options options = {})
207  : table_(std::move(tr)),
208  table_name_(table_.FullName()),
209  connection_(std::move(conn)),
210  options_(google::cloud::internal::MergeOptions(
211  std::move(options),
212  internal::DefaultDataOptions(connection_->options()))),
213  metadata_update_policy_(bigtable_internal::MakeMetadataUpdatePolicy(
214  table_name_, app_profile_id())) {}
215 
216  /**
217  * Constructor with default policies.
218  *
219  * @param client how to communicate with Cloud Bigtable, including
220  * credentials, the project id, and the instance id.
221  * @param table_id the table id within the instance defined by client. The
222  * full table name is `client->instance_name() + '/tables/' + table_id`.
223  */
224  Table(std::shared_ptr<DataClient> client, std::string const& table_id)
225  : Table(std::move(client), std::string{}, table_id) {}
226 
227  /**
228  * Constructor with default policies.
229  *
230  * @param client how to communicate with Cloud Bigtable, including
231  * credentials, the project id, and the instance id.
232  * @param app_profile_id the app_profile_id needed for using the replication
233  * API.
234  * @param table_id the table id within the instance defined by client. The
235  * full table name is `client->instance_name() + '/tables/' + table_id`.
236  */
237  Table(std::shared_ptr<DataClient> client, std::string app_profile_id,
238  std::string const& table_id)
239  : client_(std::move(client)),
240  table_(client_->project_id(), client_->instance_id(), table_id),
241  table_name_(table_.FullName()),
242  rpc_retry_policy_prototype_(
243  bigtable::DefaultRPCRetryPolicy(internal::kBigtableLimits)),
244  rpc_backoff_policy_prototype_(
245  bigtable::DefaultRPCBackoffPolicy(internal::kBigtableLimits)),
246  idempotent_mutation_policy_(
248  background_threads_(client_->BackgroundThreadsFactory()()),
249  options_(Options{}.set<AppProfileIdOption>(std::move(app_profile_id))),
250  metadata_update_policy_(bigtable_internal::MakeMetadataUpdatePolicy(
251  table_name_, this->app_profile_id())) {}
252 
253  /**
254  * Constructor with explicit policies.
255  *
256  * The policies are passed by value, because this makes it easy for
257  * applications to create them.
258  *
259  * @par Example
260  * @code
261  * using namespace std::chrono_literals; // assuming C++14.
262  * auto client = bigtable::MakeClient(...); // details omitted
263  * bigtable::Table table(client, "my-table",
264  * // Allow up to 20 minutes to retry operations
265  * bigtable::LimitedTimeRetryPolicy(20min),
266  * // Start with 50 milliseconds backoff, grow
267  * // exponentially to 5 minutes.
268  * bigtable::ExponentialBackoffPolicy(50ms, 5min),
269  * // Only retry idempotent mutations.
270  * bigtable::SafeIdempotentMutationPolicy());
271  * @endcode
272  *
273  * @param client how to communicate with Cloud Bigtable, including
274  * credentials, the project id, and the instance id.
275  * @param table_id the table id within the instance defined by client. The
276  * full table name is `client->instance_name() + "/tables/" + table_id`.
277  * @param policies the set of policy overrides for this object.
278  * @tparam Policies the types of the policies to override, the types must
279  * derive from one of the following types:
280  *
281  * - `IdempotentMutationPolicy` which mutations are retried. Use
282  * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
283  * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
284  * caveats in the class definition to understand the downsides of the
285  * latter. You can also create your own policies that decide which
286  * mutations to retry.
287  * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
288  * `ExponentialBackoffPolicy` is implemented. You can also create your
289  * own policies that backoff using a different algorithm.
290  * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
291  * `LimitedErrorCountRetryPolicy` to limit the number of failures
292  * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
293  * request. You can also create your own policies that combine time and
294  * error counts.
295  *
296  * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
297  * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
298  * LimitedTimeRetryPolicy.
299  */
300  template <
301  typename... Policies,
302  typename std::enable_if<ValidPolicies<Policies...>::value, int>::type = 0>
303  Table(std::shared_ptr<DataClient> client, std::string const& table_id,
304  Policies&&... policies)
305  : Table(std::move(client), table_id) {
306  ChangePolicies(std::forward<Policies>(policies)...);
307  }
308 
309  /**
310  * Constructor with explicit policies.
311  *
312  * The policies are passed by value, because this makes it easy for
313  * applications to create them.
314  *
315  * @par Example
316  * @code
317  * using namespace std::chrono_literals; // assuming C++14.
318  * auto client = bigtable::MakeClient(...); // details omitted
319  * bigtable::Table table(client, "app_id", "my-table",
320  * // Allow up to 20 minutes to retry operations
321  * bigtable::LimitedTimeRetryPolicy(20min),
322  * // Start with 50 milliseconds backoff, grow
323  * // exponentially to 5 minutes.
324  * bigtable::ExponentialBackoffPolicy(50ms, 5min),
325  * // Only retry idempotent mutations.
326  * bigtable::SafeIdempotentMutationPolicy());
327  * @endcode
328  *
329  * @param client how to communicate with Cloud Bigtable, including
330  * credentials, the project id, and the instance id.
331  * @param app_profile_id the app_profile_id needed for using the replication
332  * API.
333  * @param table_id the table id within the instance defined by client. The
334  * full table name is `client->instance_name() + "/tables/" + table_id`.
335  * @param policies the set of policy overrides for this object.
336  * @tparam Policies the types of the policies to override, the types must
337  * derive from one of the following types:
338  * - `IdempotentMutationPolicy` which mutations are retried. Use
339  * `SafeIdempotentMutationPolicy` to only retry idempotent operations,
340  * use `AlwaysRetryMutationPolicy` to retry all operations. Read the
341  * caveats in the class definition to understand the downsides of the
342  * latter. You can also create your own policies that decide which
343  * mutations to retry.
344  * - `RPCBackoffPolicy` how to backoff from a failed RPC. Currently only
345  * `ExponentialBackoffPolicy` is implemented. You can also create your
346  * own policies that backoff using a different algorithm.
347  * - `RPCRetryPolicy` for how long to retry failed RPCs. Use
348  * `LimitedErrorCountRetryPolicy` to limit the number of failures
349  * allowed. Use `LimitedTimeRetryPolicy` to bound the time for any
350  * request. You can also create your own policies that combine time and
351  * error counts.
352  *
353  * @see SafeIdempotentMutationPolicy, AlwaysRetryMutationPolicy,
354  * ExponentialBackoffPolicy, LimitedErrorCountRetryPolicy,
355  * LimitedTimeRetryPolicy.
356  */
357  template <
358  typename... Policies,
359  typename std::enable_if<ValidPolicies<Policies...>::value, int>::type = 0>
360  Table(std::shared_ptr<DataClient> client, std::string app_profile_id,
361  std::string const& table_id, Policies&&... policies)
362  : Table(std::move(client), std::move(app_profile_id), table_id) {
363  ChangePolicies(std::forward<Policies>(policies)...);
364  }
365 
366  std::string const& table_name() const { return table_name_; }
367  std::string const& app_profile_id() const {
368  return options_.get<AppProfileIdOption>();
369  }
370  std::string const& project_id() const {
371  return table_.instance().project_id();
372  }
373  std::string const& instance_id() const {
374  return table_.instance().instance_id();
375  }
376  std::string const& table_id() const { return table_.table_id(); }
377 
378  /**
379  * Returns a Table that reuses the connection and configuration of this
380  * Table, but with a different resource name.
381  *
382  * @note The app profile id is copied from this Table.
383  */
384  Table WithNewTarget(std::string project_id, std::string instance_id,
385  std::string table_id) const {
386  auto table = *this;
387  table.table_ = TableResource(std::move(project_id), std::move(instance_id),
388  std::move(table_id));
389  table.table_name_ = table.table_.FullName();
390  table.metadata_update_policy_ = bigtable_internal::MakeMetadataUpdatePolicy(
391  table.table_name_, table.app_profile_id());
392  return table;
393  }
394 
395  /**
396  * Returns a Table that reuses the connection and configuration of this
397  * Table, but with a different resource name.
398  */
399  Table WithNewTarget(std::string project_id, std::string instance_id,
400  std::string app_profile_id, std::string table_id) const {
401  auto table = *this;
402  table.table_ = TableResource(std::move(project_id), std::move(instance_id),
403  std::move(table_id));
404  table.table_name_ = table.table_.FullName();
405  table.options_.set<AppProfileIdOption>(std::move(app_profile_id));
406  table.metadata_update_policy_ = bigtable_internal::MakeMetadataUpdatePolicy(
407  table.table_name_, table.app_profile_id());
408  return table;
409  }
410 
411  /**
412  * Attempts to apply the mutation to a row.
413  *
414  * @param mut the mutation. Note that this function takes ownership (and
415  * then discards) the data in the mutation. In general, a
416  * `SingleRowMutation` can be used to modify and/or delete multiple cells,
417  * across different columns and column families.
418  *
419  * @return status of the operation.
420  *
421  * @par Idempotency
422  * This operation is idempotent if the provided mutations are idempotent. Note
423  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
424  * **not** an idempotent operation.
425  *
426  * @par Thread-safety
427  * Two threads concurrently calling this member function on the same instance
428  * of this class are **not** guaranteed to work.
429  *
430  * @par Example
431  * @snippet data_snippets.cc apply
432  */
434 
435  /**
436  * Makes asynchronous attempts to apply the mutation to a row.
437  *
438  * @warning This is an early version of the asynchronous APIs for Cloud
439  * Bigtable. These APIs might be changed in backward-incompatible ways. It
440  * is not subject to any SLA or deprecation policy.
441  *
442  * @param mut the mutation. Note that this function takes ownership
443  * (and then discards) the data in the mutation. In general, a
444  * `SingleRowMutation` can be used to modify and/or delete
445  * multiple cells, across different columns and column families.
446  *
447  * @par Idempotency
448  * This operation is idempotent if the provided mutations are idempotent. Note
449  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
450  * **not** an idempotent operation.
451  *
452  * @par Example
453  * @snippet data_async_snippets.cc async-apply
454  */
456 
457  /**
458  * Attempts to apply mutations to multiple rows.
459  *
460  * These mutations are applied in bulk, in a single `MutateRowsRequest` RPC.
461  * Failures are handled on a per mutation basis. If the result of a mutation
462  * is a permanent (non-retryable) error, or if a non-idempotent mutation fails
463  * for any reason, the mutation will not be retried. Only idempotent mutations
464  * that encounter transient (retryable) errors can be retried. These mutations
465  * are collected and retried in bulk. This function will continue to retry any
466  * remaining errors until this class's retry policy is exhausted.
467  *
468  * It is possible that some mutations may not be attempted at all. These
469  * mutations are considered failing and will be returned.
470  *
471  * @note The retry policy is only impacted by the result of the gRPC stream.
472  * Let's say you have a `LimitedErrorCountRetryPolicy` of 2. If an
473  * idempotent mutation fails with a retryable error and the stream itself
474  * succeeds, it may be retried more than 2 times. Only when the stream
475  * fails twice will we give up and consider the mutation to be failed.
476  *
477  * @note This function takes ownership (and then discards) the data in the
478  * mutation. In general, a `BulkMutation` can modify multiple rows, and
479  * the modifications for each row can change (or create) multiple cells,
480  * across different columns and column families.
481  *
482  * @param mut the mutations
483  * @returns a list of failed mutations
484  *
485  * @par Idempotency
486  * This operation is idempotent if the provided mutations are idempotent. Note
487  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
488  * **not** an idempotent operation.
489  *
490  * @par Thread-safety
491  * Two threads concurrently calling this member function on the same instance
492  * of this class are **not** guaranteed to work. Consider copying the object
493  * and using different copies in each thread.
494  *
495  * @par Example
496  * @snippet data_snippets.cc bulk apply
497  */
499 
500  /**
501  * Makes asynchronous attempts to apply mutations to multiple rows.
502  *
503  * These mutations are applied in bulk, in a single `MutateRowsRequest` RPC.
504  * Failures are handled on a per mutation basis. If the result of a mutation
505  * is a permanent (non-retryable) error, or if a non-idempotent mutation fails
506  * for any reason, the mutation will not be retried. Only idempotent mutations
507  * that encounter transient (retryable) errors can be retried. These mutations
508  * are collected and retried in bulk. This function will continue to retry any
509  * remaining errors until this class's retry policy is exhausted.
510  *
511  * It is possible that some mutations may not be attempted at all. These
512  * mutations are considered failing and will be returned.
513  *
514  * @note The retry policy is only impacted by the result of the gRPC stream.
515  * Let's say you have a `LimitedErrorCountRetryPolicy` of 2. If an
516  * idempotent mutation fails with a retryable error and the stream itself
517  * succeeds, it may be retried more than 2 times. Only when the stream
518  * fails twice will we give up and consider the mutation to be failed.
519  *
520  * @note This function takes ownership (and then discards) the data in the
521  * mutation. In general, a `BulkMutation` can modify multiple rows, and
522  * the modifications for each row can change (or create) multiple cells,
523  * across different columns and column families.
524  *
525  * @param mut the mutations
526  * @returns a future to be filled with a list of failed mutations, when the
527  * operation is complete.
528  *
529  * @par Idempotency
530  * This operation is idempotent if the provided mutations are idempotent. Note
531  * that `google::cloud::bigtable::SetCell()` without an explicit timestamp is
532  * **not** an idempotent operation.
533  *
534  * @par Thread-safety
535  * Two threads concurrently calling this member function on the same instance
536  * of this class are **not** guaranteed to work. Consider copying the object
537  * and using different copies in each thread.
538  *
539  * @par Example
540  * @snippet data_async_snippets.cc bulk async-bulk-apply
541  */
543 
544  /**
545  * Reads a set of rows from the table.
546  *
547  * @param row_set the rows to read from.
548  * @param filter is applied on the server-side to data in the rows.
549  *
550  * @par Idempotency
551  * This is a read-only operation and therefore it is always idempotent.
552  *
553  * @par Thread-safety
554  * Two threads concurrently calling this member function on the same instance
555  * of this class are **not** guaranteed to work. Consider copying the object
556  * and using different copies in each thread. The values returned by
557  * different calls are independent with respect to thread-safety, please see
558  * the `RowReader` documentation for more details.
559  *
560  * @par Example
561  * @snippet read_snippets.cc read rows
562  */
563  RowReader ReadRows(RowSet row_set, Filter filter);
564 
565  /**
566  * Reads a limited set of rows from the table.
567  *
568  * @param row_set the rows to read from.
569  * @param rows_limit the maximum number of rows to read. Cannot be a negative
570  * number or zero. Use `ReadRows(RowSet, Filter)` to read all matching
571  * rows.
572  * @param filter is applied on the server-side to data in the rows.
573  *
574  * @par Idempotency
575  * This is a read-only operation and therefore it is always idempotent.
576  *
577  * @par Thread-safety
578  * Two threads concurrently calling this member function on the same instance
579  * of this class are **not** guaranteed to work. Consider copying the object
580  * and using different copies in each thread. The values returned by
581  * different calls are independent with respect to thread-safety, please see
582  * the `RowReader` documentation for more details.
583  *
584  * @par Example
585  * @snippet read_snippets.cc read rows with limit
586  */
587  RowReader ReadRows(RowSet row_set, std::int64_t rows_limit, Filter filter);
588 
589  /**
590  * Read and return a single row from the table.
591  *
592  * @param row_key the row to read.
593  * @param filter a filter expression, can be used to select a subset of the
594  * column families and columns in the row.
595  * @returns a tuple, the first element is a boolean, with value `false` if the
596  * row does not exist. If the first element is `true` the second element
597  * has the contents of the Row. Note that the contents may be empty
598  * if the filter expression removes all column families and columns.
599  *
600  * @par Idempotency
601  * This is a read-only operation and therefore it is always idempotent.
602  *
603  * @par Thread-safety
604  * Two threads concurrently calling this member function on the same instance
605  * of this class are **not** guaranteed to work. Consider copying the object
606  * and using different copies in each thread.
607  *
608  * @par Example
609  * @snippet read_snippets.cc read row
610  */
611  StatusOr<std::pair<bool, Row>> ReadRow(std::string row_key, Filter filter);
612 
613  /**
614  * Atomic test-and-set for a row using filter expressions.
615  *
616  * Atomically check the value of a row using a filter expression. If the
617  * expression passes (meaning at least one element is returned by it), one
618  * set of mutations is applied. If the filter does not pass, a different set
619  * of mutations is applied. The changes are atomically applied in the server.
620  *
621  * @param row_key the row to modify.
622  * @param filter the filter expression.
623  * @param true_mutations the mutations for the "filter passed" case.
624  * @param false_mutations the mutations for the "filter did not pass" case.
625  * @returns true if the filter passed.
626  *
627  * @par Idempotency
628  * This operation is always treated as non-idempotent.
629  *
630  * @par Thread-safety
631  * Two threads concurrently calling this member function on the same instance
632  * of this class are **not** guaranteed to work. Consider copying the object
633  * and using different copies in each thread.
634  *
635  * @par Check for Value Example
636  * @snippet data_snippets.cc check and mutate
637  *
638  * @par Check for Cell Presence Example
639  * @snippet data_snippets.cc check and mutate not present
640  */
642  std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
643  std::vector<Mutation> false_mutations);
644 
645  /**
646  * Make an asynchronous request to conditionally mutate a row.
647  *
648  * @warning This is an early version of the asynchronous APIs for Cloud
649  * Bigtable. These APIs might be changed in backward-incompatible ways. It
650  * is not subject to any SLA or deprecation policy.
651  *
652  * @param row_key the row key on which the conditional mutation will be
653  * performed
654  * @param filter the condition, depending on which the mutation will be
655  * performed
656  * @param true_mutations the mutations which will be performed if @p filter is
657  * true
658  * @param false_mutations the mutations which will be performed if @p filter
659  * is false
660  *
661  * @par Idempotency
662  * This operation is always treated as non-idempotent.
663  *
664  * @par Thread-safety
665  * Two threads concurrently calling this member function on the same instance
666  * of this class are **not** guaranteed to work. Consider copying the object
667  * and using different copies in each thread.
668  *
669  * @par Example
670  * @snippet data_async_snippets.cc async check and mutate
671  */
673  std::string row_key, Filter filter, std::vector<Mutation> true_mutations,
674  std::vector<Mutation> false_mutations);
675 
676  /**
677  * Sample of the row keys in the table, including approximate data sizes.
678  *
679  * @note The sample may only include one element for small tables. In
680  * addition, the sample may include row keys that do not exist on the
681  * table, and may include the empty row key to indicate "end of table".
682  *
683  * @par Idempotency
684  * This operation is always treated as idempotent.
685  *
686  * @par Thread-safety
687  * Two threads concurrently calling this member function on the same instance
688  * of this class are **not** guaranteed to work. Consider copying the object
689  * and using different copies in each thread.
690  *
691  * @par Examples
692  * @snippet data_snippets.cc sample row keys
693  */
694  StatusOr<std::vector<bigtable::RowKeySample>> SampleRows();
695 
696  /**
697  * Asynchronously obtains a sample of the row keys in the table, including
698  * approximate data sizes.
699  *
700  * @returns a future, that becomes satisfied when the operation completes.
701  *
702  * @note The sample may only include one element for small tables. In
703  * addition, the sample may include row keys that do not exist on the
704  * table, and may include the empty row key to indicate "end of table".
705  *
706  * @par Idempotency
707  * This operation is always treated as idempotent.
708  *
709  * @par Thread-safety
710  * Two threads concurrently calling this member function on the same instance
711  * of this class are **not** guaranteed to work. Consider copying the object
712  * and using different copies in each thread.
713  *
714  * @par Examples
715  * @snippet data_async_snippets.cc async sample row keys
716  */
717  future<StatusOr<std::vector<bigtable::RowKeySample>>> AsyncSampleRows();
718 
719  /**
720  * Atomically read and modify the row in the server, returning the
721  * resulting row
722  *
723  * @tparam Args this is zero or more ReadModifyWriteRules to apply on a row
724  * @param row_key the row to read
725  * @param rule to modify the row. Two types of rules are applied here
726  * AppendValue which will read the existing value and append the
727  * text provided to the value.
728  * IncrementAmount which will read the existing uint64 big-endian-int
729  * and add the value provided.
730  * Both rules accept the family and column identifier to modify.
731  * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
732  * @returns the new contents of all modified cells.
733  *
734  * @par Idempotency
735  * This operation is always treated as non-idempotent.
736  *
737  * @par Thread-safety
738  * Two threads concurrently calling this member function on the same instance
739  * of this class are **not** guaranteed to work. Consider copying the object
740  * and using different copies in each thread.
741  *
742  * @par Example
743  * @snippet data_snippets.cc read modify write
744  */
745  template <typename... Args>
746  StatusOr<Row> ReadModifyWriteRow(std::string row_key,
748  Args&&... rules) {
749  ::google::bigtable::v2::ReadModifyWriteRowRequest request;
750  request.set_row_key(std::move(row_key));
751 
752  // Generate a better compile time error message than the default one
753  // if the types do not match
754  static_assert(
755  absl::conjunction<
756  std::is_convertible<Args, bigtable::ReadModifyWriteRule>...>::value,
757  "The arguments passed to ReadModifyWriteRow(row_key,...) must be "
758  "convertible to bigtable::ReadModifyWriteRule");
759 
760  *request.add_rules() = std::move(rule).as_proto();
761  AddRules(request, std::forward<Args>(rules)...);
762  return ReadModifyWriteRowImpl(std::move(request));
763  }
764 
765  /**
766  * Make an asynchronous request to atomically read and modify a row.
767  *
768  * @warning This is an early version of the asynchronous APIs for Cloud
769  * Bigtable. These APIs might be changed in backward-incompatible ways. It
770  * is not subject to any SLA or deprecation policy.
771  *
772  * @param row_key the row key on which modification will be performed
773  *
774  * @param rule to modify the row. Two types of rules are applied here
775  * AppendValue which will read the existing value and append the
776  * text provided to the value.
777  * IncrementAmount which will read the existing uint64 big-endian-int
778  * and add the value provided.
779  * Both rules accept the family and column identifier to modify.
780  * @param rules is the zero or more ReadModifyWriteRules to apply on a row.
781  * @returns a future, that becomes satisfied when the operation completes,
782  * at that point the future has the contents of all modified cells.
783  *
784  * @par Idempotency
785  * This operation is always treated as non-idempotent.
786  *
787  * @par Thread-safety
788  * Two threads concurrently calling this member function on the same instance
789  * of this class are **not** guaranteed to work.
790  *
791  * @par Example
792  * @snippet data_async_snippets.cc async read modify write
793  */
794  template <typename... Args>
796  std::string row_key, bigtable::ReadModifyWriteRule rule,
797  Args&&... rules) {
798  ::google::bigtable::v2::ReadModifyWriteRowRequest request;
799  request.set_row_key(std::move(row_key));
800 
801  // Generate a better compile time error message than the default one
802  // if the types do not match
803  static_assert(
804  absl::conjunction<
805  std::is_convertible<Args, bigtable::ReadModifyWriteRule>...>::value,
806  "The arguments passed to AsyncReadModifyWriteRow(row_key,...) must be "
807  "convertible to bigtable::ReadModifyWriteRule");
808 
809  *request.add_rules() = std::move(rule).as_proto();
810  AddRules(request, std::forward<Args>(rules)...);
811  return AsyncReadModifyWriteRowImpl(std::move(request));
812  }
813 
814  /**
815  * Asynchronously reads a set of rows from the table.
816  *
817  * @warning This is an early version of the asynchronous APIs for Cloud
818  * Bigtable. These APIs might be changed in backward-incompatible ways. It
819  * is not subject to any SLA or deprecation policy.
820  *
821  * @param on_row the callback to be invoked on each successfully read row; it
822  * should be invocable with `Row` and return a future<bool>; the returned
823  * `future<bool>` should be satisfied with `true` when the user is ready
824  * to receive the next callback and with `false` when the user doesn't
825  * want any more rows; if `on_row` throws, the results are undefined
826  * @param on_finish the callback to be invoked when the stream is closed; it
827  * should be invocable with `Status` and not return anything; it will
828  * always be called as the last callback; if `on_finish` throws, the
829  * results are undefined
830  * @param row_set the rows to read from.
831  * @param filter is applied on the server-side to data in the rows.
832  *
833  * @tparam RowFunctor the type of the @p on_row callback.
834  * @tparam FinishFunctor the type of the @p on_finish callback.
835  *
836  * @par Thread-safety
837  * Two threads concurrently calling this member function on the same instance
838  * of this class are **not** guaranteed to work. Consider copying the object
839  * and using different copies in each thread.
840  *
841  * @par Example
842  * @snippet data_async_snippets.cc async read rows
843  */
844  template <typename RowFunctor, typename FinishFunctor>
845  void AsyncReadRows(RowFunctor on_row, FinishFunctor on_finish, RowSet row_set,
846  Filter filter) {
847  AsyncReadRows(std::move(on_row), std::move(on_finish), std::move(row_set),
848  RowReader::NO_ROWS_LIMIT, std::move(filter));
849  }
850 
851  /**
852  * Asynchronously reads a set of rows from the table.
853  *
854  * @warning This is an early version of the asynchronous APIs for Cloud
855  * Bigtable. These APIs might be changed in backward-incompatible ways. It
856  * is not subject to any SLA or deprecation policy.
857  *
858  * @param on_row the callback to be invoked on each successfully read row; it
859  * should be invocable with `Row` and return a future<bool>; the returned
860  * `future<bool>` should be satisfied with `true` when the user is ready
861  * to receive the next callback and with `false` when the user doesn't
862  * want any more rows; if `on_row` throws, the results are undefined
863  * @param on_finish the callback to be invoked when the stream is closed; it
864  * should be invocable with `Status` and not return anything; it will
865  * always be called as the last callback; if `on_finish` throws, the
866  * results are undefined
867  * @param row_set the rows to read from.
868  * @param rows_limit the maximum number of rows to read. Cannot be a negative
869  * number or zero. Use `AsyncReadRows(RowSet, Filter)` to
870  * read all matching rows.
871  * @param filter is applied on the server-side to data in the rows.
872  *
873  * @tparam RowFunctor the type of the @p on_row callback.
874  * @tparam FinishFunctor the type of the @p on_finish callback.
875  *
876  * @par Thread-safety
877  * Two threads concurrently calling this member function on the same instance
878  * of this class are **not** guaranteed to work. Consider copying the object
879  * and using different copies in each thread. The callbacks passed to this
880  * function may be executed on any thread running the provided completion
881  * queue.
882  *
883  * @par Example
884  * @snippet data_async_snippets.cc async read rows with limit
885  */
886  template <typename RowFunctor, typename FinishFunctor>
887  void AsyncReadRows(RowFunctor on_row, FinishFunctor on_finish,
888  // NOLINTNEXTLINE(performance-unnecessary-value-param)
889  RowSet row_set, std::int64_t rows_limit, Filter filter) {
890  static_assert(
891  google::cloud::internal::is_invocable<RowFunctor, bigtable::Row>::value,
892  "RowFunctor must be invocable with Row.");
893  static_assert(
894  google::cloud::internal::is_invocable<FinishFunctor, Status>::value,
895  "FinishFunctor must be invocable with Status.");
896  static_assert(
897  std::is_same<
898  google::cloud::internal::invoke_result_t<RowFunctor, bigtable::Row>,
899  future<bool>>::value,
900  "RowFunctor should return a future<bool>.");
901 
902  auto on_row_ptr = std::make_shared<RowFunctor>(std::move(on_row));
903  // NOLINTNEXTLINE(performance-unnecessary-value-param)
904  auto on_row_fn = [on_row_ptr](Row row) {
905  return (*on_row_ptr)(std::move(row));
906  };
907 
908  auto on_finish_ptr = std::make_shared<FinishFunctor>(std::move(on_finish));
909  // NOLINTNEXTLINE(performance-unnecessary-value-param)
910  auto on_finish_fn = [on_finish_ptr](Status status) {
911  return (*on_finish_ptr)(std::move(status));
912  };
913 
914  if (connection_) {
915  google::cloud::internal::OptionsSpan span(options_);
916  connection_->AsyncReadRows(table_name_, std::move(on_row_fn),
917  std::move(on_finish_fn), std::move(row_set),
918  rows_limit, std::move(filter));
919  return;
920  }
921 
922  bigtable_internal::LegacyAsyncRowReader::Create(
923  background_threads_->cq(), client_, app_profile_id(), table_name_,
924  std::move(on_row_fn), std::move(on_finish_fn), std::move(row_set),
925  rows_limit, std::move(filter), clone_rpc_retry_policy(),
926  clone_rpc_backoff_policy(), metadata_update_policy_,
927  absl::make_unique<bigtable::internal::ReadRowsParserFactory>());
928  }
929 
930  /**
931  * Asynchronously read and return a single row from the table.
932  *
933  * @warning This is an early version of the asynchronous APIs for Cloud
934  * Bigtable. These APIs might be changed in backward-incompatible ways. It
935  * is not subject to any SLA or deprecation policy.
936  *
937  * @param row_key the row to read.
938  * @param filter a filter expression, can be used to select a subset of the
939  * column families and columns in the row.
940  * @returns a future satisfied when the operation completes, fails
941  * permanently or keeps failing transiently, but the retry policy has been
942  * exhausted. The future will return a tuple. The first element is a
943  * boolean, with value `false` if the row does not exist. If the first
944  * element is `true` the second element has the contents of the Row. Note
945  * that the contents may be empty if the filter expression removes all
946  * column families and columns.
947  *
948  * @par Idempotency
949  * This is a read-only operation and therefore it is always idempotent.
950  *
951  * @par Thread-safety
952  * Two threads concurrently calling this member function on the same instance
953  * of this class are **not** guaranteed to work. Consider copying the object
954  * and using different copies in each thread.
955  *
956  * @par Example
957  * @snippet data_async_snippets.cc async read row
958  */
959  future<StatusOr<std::pair<bool, Row>>> AsyncReadRow(std::string row_key,
960  Filter filter);
961 
962  private:
963  /**
964  * Send request ReadModifyWriteRowRequest to modify the row and get it back
965  */
966  StatusOr<Row> ReadModifyWriteRowImpl(
967  ::google::bigtable::v2::ReadModifyWriteRowRequest request);
968 
969  future<StatusOr<Row>> AsyncReadModifyWriteRowImpl(
970  ::google::bigtable::v2::ReadModifyWriteRowRequest request);
971 
972  void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest&) {
973  // no-op for empty list
974  }
975 
976  template <typename... Args>
977  void AddRules(google::bigtable::v2::ReadModifyWriteRowRequest& request,
978  bigtable::ReadModifyWriteRule rule, Args&&... args) {
979  *request.add_rules() = std::move(rule).as_proto();
980  AddRules(request, std::forward<Args>(args)...);
981  }
982 
983  std::unique_ptr<RPCRetryPolicy> clone_rpc_retry_policy() {
984  return rpc_retry_policy_prototype_->clone();
985  }
986 
987  std::unique_ptr<RPCBackoffPolicy> clone_rpc_backoff_policy() {
988  return rpc_backoff_policy_prototype_->clone();
989  }
990 
991  MetadataUpdatePolicy clone_metadata_update_policy() {
992  return metadata_update_policy_;
993  }
994 
995  std::unique_ptr<IdempotentMutationPolicy> clone_idempotent_mutation_policy() {
996  return idempotent_mutation_policy_->clone();
997  }
998 
999  //@{
1000  /// @name Helper functions to implement constructors with changed policies.
1001  void ChangePolicy(RPCRetryPolicy const& policy) {
1002  rpc_retry_policy_prototype_ = policy.clone();
1003  }
1004 
1005  void ChangePolicy(RPCBackoffPolicy const& policy) {
1006  rpc_backoff_policy_prototype_ = policy.clone();
1007  }
1008 
1009  void ChangePolicy(IdempotentMutationPolicy const& policy) {
1010  idempotent_mutation_policy_ = policy.clone();
1011  }
1012 
1013  template <typename Policy, typename... Policies>
1014  void ChangePolicies(Policy&& policy, Policies&&... policies) {
1015  ChangePolicy(policy);
1016  ChangePolicies(std::forward<Policies>(policies)...);
1017  }
1018  void ChangePolicies() {}
1019  //@}
1020 
1021  friend class MutationBatcher;
1022  std::shared_ptr<DataClient> client_;
1023  TableResource table_;
1024  std::string table_name_;
1025  std::shared_ptr<RPCRetryPolicy const> rpc_retry_policy_prototype_;
1026  std::shared_ptr<RPCBackoffPolicy const> rpc_backoff_policy_prototype_;
1027  std::shared_ptr<IdempotentMutationPolicy> idempotent_mutation_policy_;
1028  std::shared_ptr<BackgroundThreads> background_threads_;
1029  std::shared_ptr<DataConnection> connection_;
1030  Options options_;
1031  MetadataUpdatePolicy metadata_update_policy_;
1032 };
1033 
1035 } // namespace bigtable
1036 } // namespace cloud
1037 } // namespace google
1038 
1039 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_TABLE_H