Skip to content

Commit 4997b64

Browse files
committed
emulator: SetCell: Fix the handling of 0 and negative timestamps.
If < -1, return an error and fail the entire mutation chain. If -1, substitute the current system timestamp. If 0, store as is. Passing unit checking the above also added.
1 parent c33e39f commit 4997b64

3 files changed

Lines changed: 63 additions & 18 deletions

File tree

google/cloud/bigtable/emulator/column_family.cc

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@ namespace emulator {
2424

2525
absl::optional<std::string> ColumnRow::SetCell(
2626
std::chrono::milliseconds timestamp, std::string const& value) {
27-
if (timestamp <= std::chrono::milliseconds::zero()) {
28-
timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
29-
std::chrono::system_clock::now().time_since_epoch());
30-
}
31-
3227
absl::optional<std::string> ret = absl::nullopt;
3328
auto cell_it = cells_.find(timestamp);
3429
if (!(cell_it == cells_.end())) {

google/cloud/bigtable/emulator/rollback_test.cc

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,16 @@ Status HasRow(std::shared_ptr<google::cloud::bigtable::emulator::Table>& table,
263263
// Test that SetCell does the right thing when it receives a zero or
264264
// negative timestamp, and that the cell created can be correctly
265265
// deleted if rollback occurs.
266+
//
267+
// In particular:
268+
//
269+
// Supplied with a timestamp of -1, it should store the current system time as
270+
// timestamp.
271+
//
272+
// Supplied with a timestamp of 0, it should store it as is.
273+
//
274+
// Supplied with a timestamp < -1, it should return an error and fail the entire
275+
// mutation chain.
266276
TEST(TransactonRollback, ZeroOrNegativeTimestampHandling) {
267277
::google::bigtable::admin::v2::Table schema;
268278
::google::bigtable::admin::v2::ColumnFamily column_family;
@@ -294,16 +304,11 @@ TEST(TransactonRollback, ZeroOrNegativeTimestampHandling) {
294304
auto column = status_or.value();
295305
ASSERT_EQ(1, column.size());
296306
for (auto const& cell : column) {
297-
ASSERT_GT(cell.first.count(), 0);
307+
ASSERT_EQ(cell.first.count(), 0);
298308
ASSERT_EQ(data, cell.second);
299309
}
300310

301-
// Test that a SetCell mutation with timestamp set to 0 can be
302-
// correctly rolled back. In the following, the first mutation
303-
// (timestamp 0) should succeed and the next one should fail. The
304-
// condition after that should be that the first one (timestamp 0)
305-
// should be rolled back so that a row with row_key_2 key should not
306-
// exist when the MutateRow request returns.
311+
// Test that a mutation with timestamp 0 can be rolled back.
307312
v.clear();
308313
v = {{column_family_name, column_qualifier, 0, data},
309314
{"non_existent_column_family_name_causes_tx_rollbaclk", column_qualifier,
@@ -312,6 +317,48 @@ TEST(TransactonRollback, ZeroOrNegativeTimestampHandling) {
312317
status = SetCells(table, table_name, row_key_2, v);
313318
ASSERT_NE(true, status.ok());
314319
ASSERT_FALSE(HasRow(table, column_family_name, row_key_2).ok());
320+
321+
// Test that a mutation with timestamp 0 succeeds and stores 0 as
322+
// the timestamp.
323+
v.clear();
324+
v = {
325+
{column_family_name, column_qualifier, 0, data},
326+
};
327+
auto const* const row_key_3 = "2";
328+
status = SetCells(table, table_name, row_key_3, v);
329+
ASSERT_STATUS_OK(status);
330+
ASSERT_STATUS_OK(HasCell(table, v[0].column_family_name, row_key_3,
331+
v[0].column_qualifier, 0, v[0].data));
332+
333+
// Test that a mutation with timestamp < -1 fails
334+
v.clear();
335+
v = {
336+
{column_family_name, column_qualifier, -2, data},
337+
};
338+
auto const* const row_key_4 = "3";
339+
status = SetCells(table, table_name, row_key_4, v);
340+
ASSERT_FALSE(status.ok());
341+
342+
// Test that a mutation with timestamp -1 suceeds and stores the
343+
// system time.
344+
v.clear();
345+
v = {
346+
{column_family_name, column_qualifier, -1, data},
347+
};
348+
auto const* const row_key_5 = "4";
349+
auto system_time_ms_before = std::chrono::duration_cast<std::chrono::milliseconds>(
350+
std::chrono::system_clock::now().time_since_epoch());
351+
status = SetCells(table, table_name, row_key_5, v);
352+
ASSERT_STATUS_OK(status);
353+
auto column_or = GetColumn(
354+
table, v[0].column_family_name, row_key_5, v[0].column_qualifier);
355+
ASSERT_STATUS_OK(column_or.status());
356+
auto col = column_or.value();
357+
ASSERT_EQ(col.size(), 1);
358+
auto cell_it = col.begin();
359+
ASSERT_NE(cell_it, col.end());
360+
ASSERT_EQ(cell_it->second, v[0].data);
361+
ASSERT_GE(cell_it->first, system_time_ms_before);
315362
}
316363

317364
// Does the SetCell mutation work to set a cell to a specific value?

google/cloud/bigtable/emulator/table.cc

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,13 +245,16 @@ Status Table::DoMutationsWithPossibleRollback(
245245
absl::optional<std::chrono::milliseconds> timestamp_override =
246246
absl::nullopt;
247247

248-
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
249-
std::chrono::microseconds(set_cell.timestamp_micros()));
248+
if (set_cell.timestamp_micros() < -1) {
249+
return InvalidArgumentError(
250+
"Timestamp micros cannot be < -1.",
251+
GCP_ERROR_INFO().WithMetadata("mutation", mutation.DebugString()));
252+
}
250253

251-
if (timestamp <= std::chrono::milliseconds::zero()) {
252-
timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
253-
std::chrono::system_clock::now().time_since_epoch());
254-
timestamp_override.emplace(std::move(timestamp));
254+
if (set_cell.timestamp_micros() == -1) {
255+
timestamp_override.emplace(
256+
std::chrono::duration_cast<std::chrono::milliseconds>(
257+
std::chrono::system_clock::now().time_since_epoch()));
255258
}
256259

257260
auto status = row_transaction.SetCell(set_cell, timestamp_override);

0 commit comments

Comments
 (0)