|
15 | 15 | #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_EMULATOR_COLUMN_FAMILY_H |
16 | 16 | #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_EMULATOR_COLUMN_FAMILY_H |
17 | 17 |
|
| 18 | +#include "google/cloud/bigtable/cell.h" |
18 | 19 | #include "google/cloud/bigtable/emulator/cell_view.h" |
19 | 20 | #include "google/cloud/bigtable/emulator/filter.h" |
20 | 21 | #include "google/cloud/bigtable/emulator/filtered_map.h" |
21 | 22 | #include "google/cloud/bigtable/emulator/range_set.h" |
22 | 23 | #include "google/cloud/bigtable/read_modify_write_rule.h" |
23 | 24 | #include "google/cloud/internal/big_endian.h" |
24 | 25 | #include "google/cloud/internal/make_status.h" |
| 26 | +#include "google/cloud/status_or.h" |
25 | 27 | #include "absl/types/optional.h" |
26 | 28 | #include <google/bigtable/admin/v2/table.pb.h> |
27 | 29 | #include <google/bigtable/v2/data.pb.h> |
| 30 | +#include <google/bigtable/v2/types.pb.h> |
| 31 | +#include <absl/strings/str_format.h> |
28 | 32 | #include <chrono> |
| 33 | +#include <cstdint> |
29 | 34 | #include <map> |
30 | 35 | #include <memory> |
31 | 36 | #include <optional> |
@@ -88,6 +93,12 @@ class ColumnRow { |
88 | 93 | */ |
89 | 94 | absl::optional<std::string> SetCell(std::chrono::milliseconds timestamp, |
90 | 95 | std::string const& value); |
| 96 | + |
| 97 | + StatusOr<absl::optional<std::string>> UpdateCell( |
| 98 | + std::chrono::milliseconds timestamp, std::string& value, |
| 99 | + std::function<StatusOr<std::string>(std::string const&, |
| 100 | + std::string&&)> const& update_fn); |
| 101 | + |
91 | 102 | /** |
92 | 103 | * Delete cells falling into a given timestamp range. |
93 | 104 | * |
@@ -173,6 +184,13 @@ class ColumnFamilyRow { |
173 | 184 | absl::optional<std::string> SetCell(std::string const& column_qualifier, |
174 | 185 | std::chrono::milliseconds timestamp, |
175 | 186 | std::string const& value); |
| 187 | + |
| 188 | + StatusOr<absl::optional<std::string>> UpdateCell( |
| 189 | + std::string const& column_qualifier, std::chrono::milliseconds timestamp, |
| 190 | + std::string& value, |
| 191 | + std::function<StatusOr<std::string>(std::string const&, |
| 192 | + std::string&&)> const& update_fn); |
| 193 | + |
176 | 194 | /** |
177 | 195 | * Delete cells falling into a given timestamp range in one column. |
178 | 196 | * |
@@ -237,6 +255,13 @@ class ColumnFamilyRow { |
237 | 255 | class ColumnFamily { |
238 | 256 | public: |
239 | 257 | ColumnFamily() = default; |
| 258 | + // ConstructAggregateColumnFamily can be used to return an aggregate |
| 259 | + // ColumnFamily that can support AddToCell or MergeToCell and |
| 260 | + // similar aggregate complex types. To construct an ordinary |
| 261 | + // ColumnFamily, use the default constructor ColumnFamily(). |
| 262 | + static StatusOr<std::shared_ptr<ColumnFamily>> ConstructAggregateColumnFamily( |
| 263 | + google::bigtable::admin::v2::Type value_type); |
| 264 | + |
240 | 265 | // Disable copying. |
241 | 266 | ColumnFamily(ColumnFamily const&) = delete; |
242 | 267 | ColumnFamily& operator=(ColumnFamily const&) = delete; |
@@ -274,6 +299,21 @@ class ColumnFamily { |
274 | 299 | std::string const& column_qualifier, |
275 | 300 | std::chrono::milliseconds timestamp, |
276 | 301 | std::string const& value); |
| 302 | + |
| 303 | + /** |
| 304 | + * UpdateCell is like SetCell except that, when a cell exists with |
| 305 | + * the same timestamp, an update function (that depends on the column |
| 306 | + * family type) is called to derive a new value from the new and |
| 307 | + * existing value, and that is the value that is written. |
| 308 | + * |
| 309 | + * Simple (non-aggregate) column families have a default update |
| 310 | + * function that just returns the new value. |
| 311 | + * |
| 312 | + */ |
| 313 | + StatusOr<absl::optional<std::string>> UpdateCell( |
| 314 | + std::string const& row_key, std::string const& column_qualifier, |
| 315 | + std::chrono::milliseconds timestamp, std::string& value); |
| 316 | + |
277 | 317 | /** |
278 | 318 | * Delete the whole row from this column family. |
279 | 319 | * |
@@ -351,9 +391,81 @@ class ColumnFamily { |
351 | 391 | } |
352 | 392 |
|
353 | 393 | void clear() { rows_.clear(); } |
| 394 | + absl::optional<google::bigtable::admin::v2::Type> GetValueType() { |
| 395 | + return value_type_; |
| 396 | + }; |
354 | 397 |
|
355 | 398 | private: |
356 | 399 | std::map<std::string, ColumnFamilyRow> rows_; |
| 400 | + |
| 401 | + // Support for aggregate and other complex types. |
| 402 | + absl::optional<google::bigtable::admin::v2::Type> value_type_ = absl::nullopt; |
| 403 | + |
| 404 | + static StatusOr<std::string> DefaultUpdateCell( |
| 405 | + std::string const& /*existing_value*/, std::string&& new_value) { |
| 406 | + return new_value; |
| 407 | + }; |
| 408 | + |
| 409 | + static StatusOr<std::string> SumUpdateCellBEInt64( |
| 410 | + std::string const& existing_value, std::string&& new_value) { |
| 411 | + auto existing_value_int = |
| 412 | + google::cloud::internal::DecodeBigEndian<std::int64_t>(existing_value); |
| 413 | + if (!existing_value_int) { |
| 414 | + return existing_value_int.status(); |
| 415 | + } |
| 416 | + |
| 417 | + auto new_value_int = |
| 418 | + google::cloud::internal::DecodeBigEndian<std::int64_t>(new_value); |
| 419 | + if (!new_value_int) { |
| 420 | + return new_value_int.status(); |
| 421 | + } |
| 422 | + |
| 423 | + return google::cloud::internal::EncodeBigEndian(existing_value_int.value() + |
| 424 | + new_value_int.value()); |
| 425 | + }; |
| 426 | + |
| 427 | + static StatusOr<std::string> MaxUpdateCellBEInt64( |
| 428 | + std::string const& existing_value, std::string&& new_value) { |
| 429 | + auto existing_int = |
| 430 | + google::cloud::internal::DecodeBigEndian<std::int64_t>(existing_value); |
| 431 | + if (!existing_int) { |
| 432 | + return existing_int.status(); |
| 433 | + } |
| 434 | + auto new_int = google::cloud::internal::DecodeBigEndian<std::int64_t>( |
| 435 | + std::move(new_value)); |
| 436 | + if (!new_int) { |
| 437 | + return new_int.status(); |
| 438 | + } |
| 439 | + |
| 440 | + if (existing_int.value() > new_int.value()) { |
| 441 | + return existing_value; |
| 442 | + } |
| 443 | + |
| 444 | + return new_value; |
| 445 | + }; |
| 446 | + |
| 447 | + static StatusOr<std::string> MinUpdateCellBEInt64( |
| 448 | + std::string const& existing_value, std::string&& new_value) { |
| 449 | + auto existing_int = |
| 450 | + google::cloud::internal::DecodeBigEndian<std::int64_t>(existing_value); |
| 451 | + if (!existing_int) { |
| 452 | + return existing_int.status(); |
| 453 | + } |
| 454 | + auto new_int = google::cloud::internal::DecodeBigEndian<std::int64_t>( |
| 455 | + std::move(new_value)); |
| 456 | + if (!new_int) { |
| 457 | + return new_int.status(); |
| 458 | + } |
| 459 | + |
| 460 | + if (existing_int.value() < new_int.value()) { |
| 461 | + return existing_value; |
| 462 | + } |
| 463 | + |
| 464 | + return new_value; |
| 465 | + }; |
| 466 | + |
| 467 | + std::function<StatusOr<std::string>(std::string const&, std::string&&)> |
| 468 | + update_cell_ = DefaultUpdateCell; |
357 | 469 | }; |
358 | 470 |
|
359 | 471 | /** |
|
0 commit comments