Skip to content

Commit 57aaf8d

Browse files
authored
feat(bigtable): enable microsecond timestamps in client (#14057)
- Enable microsecond timestamp flag in stub settings - Plumb timestamp origin to Mutation setCell - Skip emulator in mutation-based integration tests to prevent failures
1 parent dc3a286 commit 57aaf8d

12 files changed

Lines changed: 79 additions & 13 deletions

File tree

java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/models/Mutation.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.bigtable.v2.Mutation.DeleteFromRow;
2424
import com.google.bigtable.v2.Mutation.MergeToCell;
2525
import com.google.bigtable.v2.Mutation.SetCell;
26+
import com.google.bigtable.v2.Mutation.TimestampOrigin;
2627
import com.google.cloud.bigtable.data.v2.models.Range.TimestampRange;
2728
import com.google.common.base.Preconditions;
2829
import com.google.common.collect.ImmutableList;
@@ -32,6 +33,7 @@
3233
import java.io.ObjectInputStream;
3334
import java.io.ObjectOutputStream;
3435
import java.io.Serializable;
36+
import java.time.Instant;
3537
import java.util.List;
3638
import javax.annotation.Nonnull;
3739

@@ -154,9 +156,10 @@ public Mutation setCell(
154156
@Override
155157
public Mutation setCell(
156158
@Nonnull String familyName, @Nonnull ByteString qualifier, @Nonnull ByteString value) {
157-
long timestamp = System.currentTimeMillis() * 1_000;
159+
Instant now = Instant.now();
160+
long timestamp = now.getEpochSecond() * 1_000_000L + now.getNano() / 1_000;
158161

159-
return setCell(familyName, qualifier, timestamp, value);
162+
return setCell(familyName, qualifier, timestamp, value, TimestampOrigin.CLIENT_AUTO_GENERATED);
160163
}
161164

162165
@Override
@@ -165,6 +168,15 @@ public Mutation setCell(
165168
@Nonnull ByteString qualifier,
166169
long timestamp,
167170
@Nonnull ByteString value) {
171+
return setCell(familyName, qualifier, timestamp, value, TimestampOrigin.USER_SPECIFIED);
172+
}
173+
174+
private Mutation setCell(
175+
@Nonnull String familyName,
176+
@Nonnull ByteString qualifier,
177+
long timestamp,
178+
@Nonnull ByteString value,
179+
@Nonnull TimestampOrigin timestampOrigin) {
168180
Validations.validateFamily(familyName);
169181
Preconditions.checkNotNull(qualifier, "qualifier can't be null.");
170182
Preconditions.checkNotNull(value, "value can't be null.");
@@ -182,6 +194,7 @@ public Mutation setCell(
182194
.setTimestampMicros(timestamp)
183195
.setValue(value)
184196
.build())
197+
.setTimestampOrigin(timestampOrigin)
185198
.build());
186199

187200
return this;

java-bigtable/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/data/v2/stub/EnhancedBigtableStubSettings.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,8 @@ private Builder() {
660660
.setDirectAccessRequested(isDirectPathRequested)
661661
.setTrafficDirectorEnabled(isDirectPathRequested)
662662
.setPeerInfo(true)
663-
.setSessionsCompatible(true);
663+
.setSessionsCompatible(true)
664+
.setMicrosecondTimestamp(true);
664665
}
665666

666667
private Builder(EnhancedBigtableStubSettings settings) {
@@ -1008,6 +1009,7 @@ public EnhancedBigtableStubSettings build() {
10081009

10091010
featureFlags.setRoutingCookie(true);
10101011
featureFlags.setRetryInfo(true);
1012+
featureFlags.setMicrosecondTimestamp(true);
10111013
// client_Side_metrics_enabled feature flag is only set when a user is running with a
10121014
// DefaultMetricsProvider. This may cause false negatives when a user registered the
10131015
// metrics on their CustomOpenTelemetryMetricsProvider.

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/BulkMutateIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ public class BulkMutateIT {
5353

5454
@Test(timeout = 60 * 1000)
5555
public void test() throws IOException, InterruptedException {
56+
assume()
57+
.withMessage("Emulator does not support microsecond timestamp granularity")
58+
.that(testEnvRule.env())
59+
.isNotInstanceOf(EmulatorEnv.class);
60+
5661
BigtableDataSettings settings = testEnvRule.env().getDataClientSettings();
5762
String rowPrefix = UUID.randomUUID().toString();
5863
// Set target latency really low so it'll trigger adjusting thresholds

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/CheckAndMutateIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ public class CheckAndMutateIT {
4949

5050
@Test
5151
public void test() throws Exception {
52+
assume()
53+
.withMessage("Emulator does not support microsecond timestamp granularity")
54+
.that(testEnvRule.env())
55+
.isNotInstanceOf(EmulatorEnv.class);
56+
5257
TableId tableId = testEnvRule.env().getTableId();
5358
String familyId = testEnvRule.env().getFamilyId();
5459
String rowKey = UUID.randomUUID().toString();

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/MutateRowIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ public class MutateRowIT {
4444

4545
@Test
4646
public void test() throws Exception {
47+
assume()
48+
.withMessage("Emulator does not support microsecond timestamp granularity")
49+
.that(testEnvRule.env())
50+
.isNotInstanceOf(EmulatorEnv.class);
51+
4752
String rowKey = UUID.randomUUID().toString();
4853
String familyId = testEnvRule.env().getFamilyId();
4954

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/ReadIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ public void setUp() {
9292

9393
@Test
9494
public void isRowExists() throws Exception {
95+
assume()
96+
.withMessage("Emulator does not support microsecond timestamp granularity")
97+
.that(testEnvRule.env())
98+
.isNotInstanceOf(EmulatorEnv.class);
99+
95100
String rowKey = prefix + "-test-row-key";
96101
TableId tableId = testEnvRule.env().getTableId();
97102
testEnvRule

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/it/SampleRowsIT.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public class SampleRowsIT {
5050

5151
@Test
5252
public void test() throws InterruptedException, ExecutionException, TimeoutException {
53+
assume()
54+
.withMessage("Emulator does not support microsecond timestamp granularity")
55+
.that(testEnvRule.env())
56+
.isNotInstanceOf(EmulatorEnv.class);
57+
5358
BigtableDataClient client = testEnvRule.env().getDataClient();
5459
String rowPrefix = UUID.randomUUID().toString();
5560

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/BulkMutationTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public void test() throws ParseException {
7373
+ " timestamp_micros: 1000"
7474
+ " value: 'fake-value1'"
7575
+ " }"
76+
+ " timestamp_origin: USER_SPECIFIED"
7677
+ " }"
7778
+ " mutations {"
7879
+ " set_cell {"
@@ -81,6 +82,7 @@ public void test() throws ParseException {
8182
+ " timestamp_micros: 2000"
8283
+ " value: 'fake-value2'"
8384
+ " }"
85+
+ " timestamp_origin: USER_SPECIFIED"
8486
+ " }"
8587
+ "}"
8688
+ "entries {"
@@ -92,6 +94,7 @@ public void test() throws ParseException {
9294
+ " timestamp_micros: 3000"
9395
+ " value: 'fake-value3'"
9496
+ " }"
97+
+ " timestamp_origin: USER_SPECIFIED"
9598
+ " }"
9699
+ "}",
97100
expected);

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/MutationTest.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.bigtable.v2.Mutation.DeleteFromFamily;
2323
import com.google.bigtable.v2.Mutation.DeleteFromRow;
2424
import com.google.bigtable.v2.Mutation.MergeToCell;
25+
import com.google.bigtable.v2.Mutation.TimestampOrigin;
2526
import com.google.cloud.bigtable.data.v2.models.Range.TimestampRange;
2627
import com.google.common.primitives.Longs;
2728
import com.google.protobuf.ByteString;
@@ -30,6 +31,7 @@
3031
import java.io.IOException;
3132
import java.io.ObjectInputStream;
3233
import java.io.ObjectOutputStream;
34+
import java.time.Instant;
3335
import java.util.List;
3436
import org.junit.Before;
3537
import org.junit.Test;
@@ -48,7 +50,8 @@ public void setUp() {
4850

4951
@Test
5052
public void setCellTest() {
51-
long minTimestamp = System.currentTimeMillis() * 1_000;
53+
Instant minInstant = Instant.now();
54+
long minTimestamp = minInstant.getEpochSecond() * 1_000_000L + minInstant.getNano() / 1_000;
5255

5356
mutation
5457
.setCell(
@@ -65,7 +68,8 @@ public void setCellTest() {
6568

6669
List<com.google.bigtable.v2.Mutation> actual = mutation.getMutations();
6770

68-
long maxTimestamp = System.currentTimeMillis() * 1_000;
71+
Instant maxInstant = Instant.now();
72+
long maxTimestamp = maxInstant.getEpochSecond() * 1_000_000L + maxInstant.getNano() / 1_000;
6973
com.google.common.collect.Range<Long> expectedTimestampRange =
7074
com.google.common.collect.Range.closed(minTimestamp, maxTimestamp);
7175

@@ -77,27 +81,31 @@ public void setCellTest() {
7781
assertThat(actual.get(0).getSetCell().getValue())
7882
.isEqualTo(ByteString.copyFromUtf8("fake-value"));
7983
assertThat(actual.get(0).getSetCell().getTimestampMicros()).isEqualTo(1_000);
84+
assertThat(actual.get(0).getTimestampOrigin()).isEqualTo(TimestampOrigin.USER_SPECIFIED);
8085

8186
assertThat(actual.get(1).getSetCell().getFamilyName()).isEqualTo("fake-family");
8287
assertThat(actual.get(1).getSetCell().getColumnQualifier())
8388
.isEqualTo(ByteString.copyFromUtf8("fake-qualifier"));
8489
assertThat(actual.get(1).getSetCell().getValue())
8590
.isEqualTo(ByteString.copyFromUtf8("fake-value"));
8691
assertThat(actual.get(1).getSetCell().getTimestampMicros()).isIn(expectedTimestampRange);
92+
assertThat(actual.get(1).getTimestampOrigin()).isEqualTo(TimestampOrigin.CLIENT_AUTO_GENERATED);
8793

8894
assertThat(actual.get(2).getSetCell().getFamilyName()).isEqualTo("fake-family2");
8995
assertThat(actual.get(2).getSetCell().getColumnQualifier())
9096
.isEqualTo(ByteString.copyFromUtf8("fake-qualifier2"));
9197
assertThat(actual.get(2).getSetCell().getValue())
9298
.isEqualTo(ByteString.copyFromUtf8("fake-value2"));
9399
assertThat(actual.get(2).getSetCell().getTimestampMicros()).isEqualTo(1_000);
100+
assertThat(actual.get(2).getTimestampOrigin()).isEqualTo(TimestampOrigin.USER_SPECIFIED);
94101

95102
assertThat(actual.get(3).getSetCell().getFamilyName()).isEqualTo("fake-family2");
96103
assertThat(actual.get(3).getSetCell().getColumnQualifier())
97104
.isEqualTo(ByteString.copyFromUtf8("fake-qualifier2"));
98105
assertThat(actual.get(3).getSetCell().getValue())
99106
.isEqualTo(ByteString.copyFromUtf8("fake-value2"));
100107
assertThat(actual.get(3).getSetCell().getTimestampMicros()).isIn(expectedTimestampRange);
108+
assertThat(actual.get(3).getTimestampOrigin()).isEqualTo(TimestampOrigin.CLIENT_AUTO_GENERATED);
101109

102110
assertThat(Mutation.fromProtoUnsafe(actual).getMutations()).isEqualTo(actual);
103111
}
@@ -113,6 +121,7 @@ public void setCellWithServerSideTimestamp() {
113121
List<com.google.bigtable.v2.Mutation> actual = mutation.getMutations();
114122
assertThat(actual.get(0).getSetCell().getTimestampMicros())
115123
.isEqualTo(Mutation.SERVER_SIDE_TIMESTAMP);
124+
assertThat(actual.get(0).getTimestampOrigin()).isEqualTo(TimestampOrigin.USER_SPECIFIED);
116125
}
117126

118127
@Test
@@ -276,6 +285,10 @@ public void testWithLongValue() {
276285

277286
assertThat(actualMutation.getSetCell().getValue())
278287
.isEqualTo(ByteString.copyFrom(Longs.toByteArray(100_000L)));
288+
assertThat(mutations.get(0).getTimestampOrigin())
289+
.isEqualTo(TimestampOrigin.CLIENT_AUTO_GENERATED);
290+
assertThat(mutations.get(1).getTimestampOrigin())
291+
.isEqualTo(TimestampOrigin.CLIENT_AUTO_GENERATED);
279292

280293
assertThat(mutations.get(2).getSetCell())
281294
.isEqualTo(
@@ -285,6 +298,7 @@ public void testWithLongValue() {
285298
.setTimestampMicros(30_000L)
286299
.setValue(ByteString.copyFrom(Longs.toByteArray(20_000L)))
287300
.build());
301+
assertThat(mutations.get(2).getTimestampOrigin()).isEqualTo(TimestampOrigin.USER_SPECIFIED);
288302
}
289303

290304
@Test

java-bigtable/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/data/v2/models/RowMutationEntryTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
import com.google.bigtable.v2.MutateRowsRequest;
2121
import com.google.bigtable.v2.Mutation;
22+
import com.google.bigtable.v2.Mutation.TimestampOrigin;
2223
import com.google.common.collect.ImmutableList;
2324
import com.google.common.primitives.Longs;
2425
import com.google.protobuf.ByteString;
@@ -71,7 +72,8 @@ public void toProtoTest() {
7172
.setFamilyName("fake-family")
7273
.setColumnQualifier(ByteString.copyFromUtf8("qualifier-1"))
7374
.setTimestampMicros(timestamp)
74-
.setValue(ByteString.copyFromUtf8("fake-values"))))
75+
.setValue(ByteString.copyFromUtf8("fake-values")))
76+
.setTimestampOrigin(TimestampOrigin.USER_SPECIFIED))
7577
.build());
7678
}
7779

@@ -92,6 +94,7 @@ public void multipleMutationTest() {
9294
.setColumnQualifier(ByteString.copyFromUtf8("qualifier-1"))
9395
.setTimestampMicros(10_000L)
9496
.setValue(ByteString.copyFromUtf8("fake-values")))
97+
.setTimestampOrigin(TimestampOrigin.USER_SPECIFIED)
9598
.build(),
9699
Mutation.newBuilder()
97100
.setDeleteFromColumn(
@@ -135,6 +138,7 @@ public void unsafeMutationTest() {
135138
.setColumnQualifier(ByteString.copyFromUtf8("qualifier-1"))
136139
.setTimestampMicros(10_000L)
137140
.setValue(ByteString.copyFromUtf8("fake-values")))
141+
.setTimestampOrigin(TimestampOrigin.USER_SPECIFIED)
138142
.build(),
139143
Mutation.newBuilder()
140144
.setDeleteFromFamily(

0 commit comments

Comments
 (0)