Google Cloud Bigtable C++ Client  1.32.1
A C++ Client Library for Google Cloud Bigtable
mutations.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_MUTATIONS_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_MUTATIONS_H
17 
18 #include "google/cloud/bigtable/cell.h"
19 #include "google/cloud/bigtable/row_key.h"
20 #include "google/cloud/bigtable/version.h"
21 #include "google/cloud/grpc_error_delegate.h"
22 #include "google/cloud/internal/big_endian.h"
23 #include "google/cloud/status.h"
24 #include "google/cloud/status_or.h"
25 #include "absl/meta/type_traits.h"
26 #include <google/bigtable/v2/bigtable.pb.h>
27 #include <google/bigtable/v2/data.pb.h>
28 #include <grpcpp/grpcpp.h>
29 #include <chrono>
30 #include <string>
31 #include <type_traits>
32 #include <vector>
33 
34 namespace google {
35 namespace cloud {
36 namespace bigtable {
37 inline namespace BIGTABLE_CLIENT_NS {
38 /**
39  * Represent a single change to a specific row in a Table.
40  *
41  * Mutations come in different forms, they can set a specific cell,
42  * delete a specific cell or delete multiple cells in a row.
43  */
44 struct Mutation {
45  google::bigtable::v2::Mutation op;
46 };
47 
48 /**
49  * A magic value where the server sets the timestamp.
50  *
51  * Notice that using this value in a SetCell() mutation makes it non-idempotent,
52  * and by default the client will not retry such mutations.
53  */
54 constexpr std::int64_t ServerSetTimestamp() { return -1; }
55 
56 /// Create a mutation to set a cell value.
57 template <typename ColumnType, typename ValueType>
58 Mutation SetCell(std::string family, ColumnType&& column,
59  std::chrono::milliseconds timestamp, ValueType&& value) {
60  Mutation m;
61  auto& set_cell = *m.op.mutable_set_cell();
62  set_cell.set_family_name(std::move(family));
63  set_cell.set_column_qualifier(std::forward<ColumnType>(column));
64  set_cell.set_timestamp_micros(
65  std::chrono::duration_cast<std::chrono::microseconds>(timestamp).count());
66  set_cell.set_value(std::forward<ValueType>(value));
67  return m;
68 }
69 
70 /// Create a mutation to store a 64-bit big endian integer value.
71 template <typename ColumnType>
72 Mutation SetCell(std::string family, ColumnType&& column,
73  std::chrono::milliseconds timestamp, std::int64_t value) {
74  Mutation m;
75  auto& set_cell = *m.op.mutable_set_cell();
76  set_cell.set_family_name(std::move(family));
77  set_cell.set_column_qualifier(std::forward<ColumnType>(column));
78  set_cell.set_timestamp_micros(
79  std::chrono::duration_cast<std::chrono::microseconds>(timestamp).count());
80  set_cell.set_value(google::cloud::internal::EncodeBigEndian(value));
81  return m;
82 }
83 
84 /**
85  * Create a mutation to set a cell value where the server sets the time.
86  *
87  * These mutations are not idempotent and not retried by default.
88  */
89 template <typename ColumnType, typename ValueType>
90 Mutation SetCell(std::string family, ColumnType&& column, ValueType&& value) {
91  Mutation m;
92  auto& set_cell = *m.op.mutable_set_cell();
93  set_cell.set_family_name(std::move(family));
94  set_cell.set_column_qualifier(std::forward<ColumnType>(column));
95  set_cell.set_timestamp_micros(ServerSetTimestamp());
96  set_cell.set_value(std::forward<ValueType>(value));
97  return m;
98 }
99 
100 /**
101  * Create a mutation to store a 64-bit big endian integer value.
102  *
103  * @note This mutation is not idempotent, the default policies do not retry
104  * transient failures for this mutation.
105  */
106 template <typename ColumnType>
107 Mutation SetCell(std::string family, ColumnType&& column, std::int64_t value) {
108  Mutation m;
109  auto& set_cell = *m.op.mutable_set_cell();
110  set_cell.set_family_name(std::move(family));
111  set_cell.set_column_qualifier(std::forward<ColumnType>(column));
112  set_cell.set_timestamp_micros(ServerSetTimestamp());
113  set_cell.set_value(google::cloud::internal::EncodeBigEndian(value));
114  return m;
115 }
116 
117 /**
118  * Create a mutation to set a cell value based on a `bigtable::Cell`.
119  *
120  * These mutations are not idempotent and not retried by default.
121  */
122 Mutation SetCell(Cell cell);
123 
124 //@{
125 /**
126  * @name Create mutations to delete a range of cells from a column.
127  *
128  * The following functions create a mutation that deletes all the
129  * cells in the given column family and, column within the given
130  * timestamp in the range.
131  *
132  * The function accepts any instantiation of `std::chrono::duration<>` for the
133  * @p timestamp_begin and @p timestamp_end parameters. For example:
134  *
135  * @code
136  * using namespace std::chrono_literals; // C++14
137  * bigtable::DeleteFromColumn("fam", "col", 0us, 10us)
138  * @endcode
139  *
140  * The ending timestamp is exclusive, while the beginning timestamp is
141  * inclusive. That is, the interval is [@p timestamp_begin, @p timestamp_end).
142  * The value 0 is special and treated as "unbounded" for both the begin and
143  * end endpoints of the time range. The Cloud Bigtable server rejects
144  * invalid and empty ranges, i.e., any range where the endpoint is smaller or
145  * equal than to the initial endpoint unless either endpoint is 0.
146  *
147  * @tparam Rep1 a placeholder to match the Rep tparam for @p timestamp_begin
148  * type. The semantics of this template parameter are documented in
149  * std::chrono::duration<>` (in brief, the underlying arithmetic type
150  * used to store the number of ticks), for our purposes it is simply a
151  * formal parameter.
152  *
153  * @tparam Rep2 similar formal parameter for the type of @p timestamp_end.
154  *
155  * @tparam Period1 a placeholder to match the Period tparam for
156  * @p timestamp_begin type. The semantics of this template parameter are
157  * documented in `std::chrono::duration<>` (in brief, the length of the tick
158  * in seconds,vexpressed as a `std::ratio<>`), for our purposes it is simply
159  * a formal parameter.
160  *
161  * @tparam Period2 similar formal parameter for the type of @p timestamp_end.
162  *
163  * @tparam ColumnType the type of the column qualifier. It should satisfy
164  * std::is_constructible<ColumnQualifierType, ColumnType>.
165  */
166 template <typename Rep1, typename Period1, typename Rep2, typename Period2,
167  typename ColumnType>
168 Mutation DeleteFromColumn(std::string family, ColumnType&& column,
169  std::chrono::duration<Rep1, Period1> timestamp_begin,
170  std::chrono::duration<Rep2, Period2> timestamp_end) {
171  Mutation m;
172  auto& d = *m.op.mutable_delete_from_column();
173  d.set_family_name(std::move(family));
174  d.set_column_qualifier(std::forward<ColumnType>(column));
175  d.mutable_time_range()->set_start_timestamp_micros(
176  std::chrono::duration_cast<std::chrono::microseconds>(timestamp_begin)
177  .count());
178  d.mutable_time_range()->set_end_timestamp_micros(
179  std::chrono::duration_cast<std::chrono::microseconds>(timestamp_end)
180  .count());
181  return m;
182 }
183 
184 //@{
185 /**
186  * @name The following functions create a mutation that deletes all the
187  * cells in the given column family and column, starting from and
188  * including, @a timestamp_begin.
189  *
190  * The function accepts any instantiation of `std::chrono::duration<>` for the
191  * @p timestamp_begin For example:
192  *
193  * @code
194  * using namespace std::chrono_literals; // C++14
195  * bigtable::DeleteFromColumn("fam", "col", 10us)
196  * @endcode
197  *
198  * @tparam Rep1 a placeholder to match the Rep tparam for @p timestamp_begin
199  * type. The semantics of this template parameter are documented in
200  * `std::chrono::duration<>` (in brief, the underlying arithmetic type
201  * used to store the number of ticks), for our purposes it is simply a
202  * formal parameter.
203  *
204  * @tparam Period1 a placeholder to match the Period tparam for @p
205  * timestamp_begin type. The semantics of this template parameter
206  * are documented in `std::chrono::duration<>` (in brief, the length
207  * of the tick in seconds, expressed as a `std::ratio<>`), for our
208  * purposes it is simply a formal parameter.
209  *
210  * @tparam ColumnType the type of the column qualifier. It should satisfy
211  * std::is_constructible<ColumnQualifierType, ColumnType>.
212  */
213 template <typename Rep1, typename Period1, typename ColumnType>
215  std::string family, ColumnType&& column,
216  std::chrono::duration<Rep1, Period1> timestamp_begin) {
217  Mutation m;
218  auto& d = *m.op.mutable_delete_from_column();
219  d.set_family_name(std::move(family));
220  d.set_column_qualifier(std::forward<ColumnType>(column));
221  d.mutable_time_range()->set_start_timestamp_micros(
222  std::chrono::duration_cast<std::chrono::microseconds>(timestamp_begin)
223  .count());
224  return m;
225 }
226 
227 //@{
228 /**
229  * @name The following functions create a mutation that deletes all the
230  * cells in the given column family and column, Delete up to @a timestamp_end,
231  * but excluding, @a timestamp_end.
232  *
233  * The function accepts any instantiation of `std::chrono::duration<>` for the
234  * @p timestamp_end For example:
235  *
236  * @code
237  * using namespace std::chrono_literals; // C++14
238  * bigtable::DeleteFromColumn("fam", "col", 10us)
239  * @endcode
240  *
241  * @tparam Rep2 a placeholder to match the Rep tparam for @p timestamp_end type.
242  * The semantics of this template parameter are documented in
243  * `std::chrono::duration<>` (in brief, the underlying arithmetic type
244  * used to store the number of ticks), for our purposes it is simply a
245  * formal parameter.
246  *
247  * @tparam Period2 a placeholder to match the Period tparam for @p timestamp_end
248  * type. The semantics of this template parameter are documented in
249  * `std::chrono::duration<>` (in brief, the length of the tick in seconds,
250  * expressed as a `std::ratio<>`), for our purposes it is simply a formal
251  * parameter.
252  *
253  * @tparam ColumnType the type of the column qualifier. It should satisfy
254  * std::is_constructible<ColumnQualifierType, ColumnType>.
255  */
256 template <typename Rep2, typename Period2, typename ColumnType>
258  std::string family, ColumnType&& column,
259  std::chrono::duration<Rep2, Period2> timestamp_end) {
260  Mutation m;
261  auto& d = *m.op.mutable_delete_from_column();
262  d.set_family_name(std::move(family));
263  d.set_column_qualifier(std::forward<ColumnType>(column));
264  d.mutable_time_range()->set_end_timestamp_micros(
265  std::chrono::duration_cast<std::chrono::microseconds>(timestamp_end)
266  .count());
267  return m;
268 }
269 
270 /// Delete all the values for the column.
271 template <typename ColumnType>
272 Mutation DeleteFromColumn(std::string family, ColumnType&& column) {
273  Mutation m;
274  auto& d = *m.op.mutable_delete_from_column();
275  d.set_family_name(std::move(family));
276  d.set_column_qualifier(std::forward<ColumnType>(column));
277  return m;
278 }
279 //@}
280 
281 /// Create a mutation to delete all the cells in a column family.
282 Mutation DeleteFromFamily(std::string family);
283 
284 /// Create a mutation to delete all the cells in a row.
286 
287 /**
288  * Represent a single row mutation.
289  *
290  * Bigtable can perform multiple changes to a single row atomically.
291  * This class represents 0 or more changes to apply to a single row.
292  * The changes may include setting cells (which implicitly insert the
293  * values), deleting values, etc.
294  */
296  public:
297  /// Create an empty mutation.
298  template <
299  typename RowKey,
300  typename std::enable_if<std::is_constructible<RowKeyType, RowKey>::value,
301  int>::type = 0>
302  // NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
303  explicit SingleRowMutation(RowKey&& row_key) {
304  request_.set_row_key(RowKeyType(std::forward<RowKey>(row_key)));
305  }
306 
307  /// Create a row mutation from a initializer list.
308  template <typename RowKey>
309  SingleRowMutation(RowKey&& row_key, std::initializer_list<Mutation> list) {
310  request_.set_row_key(std::forward<RowKey>(row_key));
311  for (auto&& i : list) {
312  *request_.add_mutations() = i.op;
313  }
314  }
315 
316  /// Create a single-row multiple-cell mutation from a variadic list.
317  template <
318  typename RowKey, typename... M,
319  typename std::enable_if<std::is_constructible<RowKeyType, RowKey>::value,
320  int>::type = 0>
321  explicit SingleRowMutation(RowKey&& row_key, M&&... m) {
322  static_assert(
323  absl::conjunction<std::is_convertible<M, Mutation>...>::value,
324  "The arguments passed to SingleRowMutation(std::string, ...) must be "
325  "convertible to Mutation");
326  request_.set_row_key(std::forward<RowKey>(row_key));
327  emplace_many(std::forward<M>(m)...);
328  }
329 
330  /// Create a row mutation from gRPC proto
332  ::google::bigtable::v2::MutateRowsRequest::Entry entry) {
333  using std::swap;
334  swap(*request_.mutable_row_key(), *entry.mutable_row_key());
335  swap(*request_.mutable_mutations(), *entry.mutable_mutations());
336  }
337 
338  /// Create a row mutation from gRPC proto
339  explicit SingleRowMutation(::google::bigtable::v2::MutateRowRequest request)
340  : request_(std::move(request)) {}
341 
342  // Add a mutation at the end.
344  *request_.add_mutations() = std::move(mut.op);
345  return *this;
346  }
347 
348  // Get the row key.
349  RowKeyType const& row_key() const { return request_.row_key(); }
350 
351  friend class Table;
352 
357 
358  /// Move the contents into a bigtable::v2::MutateRowsRequest::Entry.
359  void MoveTo(google::bigtable::v2::MutateRowsRequest::Entry* entry) {
360  entry->set_row_key(std::move(*request_.mutable_row_key()));
361  *entry->mutable_mutations() = std::move(*request_.mutable_mutations());
362  }
363 
364  /// Transfer the contents to @p request.
365  void MoveTo(google::bigtable::v2::MutateRowRequest& request) {
366  request.set_row_key(std::move(*request_.mutable_row_key()));
367  *request.mutable_mutations() = std::move(*request_.mutable_mutations());
368  }
369 
370  /// Remove the contents of the mutation.
371  void Clear() { request_.Clear(); }
372 
373  private:
374  /// Add multiple mutations to single row
375  template <typename... M>
376  void emplace_many(Mutation first, M&&... tail) {
377  emplace_back(std::move(first));
378  emplace_many(std::forward<M>(tail)...);
379  }
380 
381  void emplace_many(Mutation m) { emplace_back(std::move(m)); }
382 
383  ::google::bigtable::v2::MutateRowRequest request_;
384 };
385 
386 /**
387  * A SingleRowMutation that failed.
388  *
389  * A multi-row mutation returns the list of operations that failed,
390  * this class encapsulates both the failure and the original
391  * mutation. The application can then choose to resend the mutation,
392  * or log it, or save it for processing via some other means.
393  */
395  public:
396  FailedMutation(google::cloud::Status status, int index)
397  : status_(std::move(status)), original_index_(index) {}
398 
399  FailedMutation(google::rpc::Status const& status, int index)
400  : status_(MakeStatusFromRpcError(status)), original_index_(index) {}
401 
404  FailedMutation(FailedMutation const&) = default;
406 
407  //@{
408  /// @name accessors
409  google::cloud::Status const& status() const { return status_; }
410  int original_index() const { return original_index_; }
411  //@}
412 
413  friend class BulkMutation;
414 
415  private:
416  google::cloud::Status status_;
417  int original_index_;
418 };
419 
420 /**
421  * Report unrecoverable errors in a partially completed mutation.
422  */
423 class PermanentMutationFailure : public std::runtime_error {
424  public:
425  PermanentMutationFailure(char const* msg,
426  std::vector<FailedMutation> failures)
427  : std::runtime_error(msg), failures_(std::move(failures)) {}
428 
429  PermanentMutationFailure(char const* msg, grpc::Status status,
430  std::vector<FailedMutation> failures)
431  : std::runtime_error(msg),
432  failures_(std::move(failures)),
433  status_(std::move(status)) {}
434 
435  /**
436  * The details of each mutation failure.
437  *
438  * Because BulkApply() and Apply() take ownership of the data in the mutations
439  * the failures are returned with their full contents, in case the application
440  * wants to take further action with them. Any successful mutations are
441  * discarded.
442  *
443  * Any mutations that fail with an unknown state are included with a
444  * `grpc::StatusCode::OK`.
445  */
446  std::vector<FailedMutation> const& failures() const { return failures_; }
447 
448  /**
449  * The `grpc::Status` of the request.
450  *
451  * Notice that it can return `grpc::Status::OK` when there are partial
452  * failures in a `BulkApply()` operation.
453  */
454  grpc::Status const& status() const { return status_; }
455 
456  private:
457  std::vector<FailedMutation> failures_;
458  grpc::Status status_;
459 };
460 
461 /**
462  * Represent a set of mutations across multiple rows.
463  *
464  * Cloud Bigtable can batch multiple mutations in a single request.
465  * The mutations are not atomic, but it is more efficient to send them
466  * in a batch than to make multiple smaller requests.
467  */
469  public:
470  /// Create an empty set of mutations.
471  BulkMutation() = default;
472 
473  /// Create a multi-row mutation from a range of SingleRowMutations.
474  template <typename Iterator>
475  BulkMutation(Iterator begin, Iterator end) {
476  static_assert(
477  std::is_convertible<decltype(*begin), SingleRowMutation>::value,
478  "The iterator value type must be convertible to SingleRowMutation");
479  for (auto i = begin; i != end; ++i) {
480  push_back(*i);
481  }
482  }
483 
484  /// Create a multi-row mutation from a initializer list.
485  BulkMutation(std::initializer_list<SingleRowMutation> list)
486  : BulkMutation(list.begin(), list.end()) {}
487 
488  /// Create a multi-row mutation from a SingleRowMutation
490  emplace_back(std::move(mutation));
491  }
492 
493  /// Create a multi-row mutation from two SingleRowMutation
495  emplace_back(std::move(m1));
496  emplace_back(std::move(m2));
497  }
498 
499  /// Create a multi-row mutation from a variadic list.
500  template <typename... M,
501  typename std::enable_if<absl::conjunction<std::is_convertible<
502  M, SingleRowMutation>...>::value,
503  int>::type = 0>
504  // NOLINTNEXTLINE(google-explicit-constructor)
505  BulkMutation(M&&... m) : BulkMutation() {
506  emplace_many(std::forward<M>(m)...);
507  }
508 
509  // Add a mutation to the batch.
511  mut.MoveTo(request_.add_entries());
512  return *this;
513  }
514 
515  // Add a failed mutation to the batch.
517  fm.status_ = google::cloud::Status();
518  return *this;
519  }
520 
521  // Add a mutation to the batch.
523  mut.MoveTo(request_.add_entries());
524  return *this;
525  }
526 
527  /// Move the contents into a bigtable::v2::MutateRowsRequest
528  void MoveTo(google::bigtable::v2::MutateRowsRequest* request) {
529  request_.Swap(request);
530  request_ = {};
531  }
532 
533  /// Return true if there are no mutations in this set.
534  bool empty() const { return request_.entries().empty(); }
535 
536  /// Return the number of mutations in this set.
537  std::size_t size() const { return request_.entries().size(); }
538 
539  /// Return the estimated size in bytes of all the mutations in this set.
540  std::size_t estimated_size_in_bytes() const {
541  return request_.ByteSizeLong();
542  }
543 
544  private:
545  template <typename... M>
546  void emplace_many(SingleRowMutation first, M&&... tail) {
547  emplace_back(std::move(first));
548  emplace_many(std::forward<M>(tail)...);
549  }
550 
551  void emplace_many(SingleRowMutation m) { emplace_back(std::move(m)); }
552 
553  google::bigtable::v2::MutateRowsRequest request_;
554 };
555 
556 } // namespace BIGTABLE_CLIENT_NS
557 } // namespace bigtable
558 } // namespace cloud
559 } // namespace google
560 
561 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_MUTATIONS_H