Skip to content

Commit f16ae42

Browse files
sagarwaalSagar Agarwal
authored andcommitted
Merge branch 'googleapis:main' into interval_support
2 parents df6ebe7 + 16cc6ee commit f16ae42

29 files changed

+1135
-221
lines changed

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractReadContext.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import com.google.spanner.v1.ExecuteSqlRequest;
4949
import com.google.spanner.v1.ExecuteSqlRequest.QueryMode;
5050
import com.google.spanner.v1.ExecuteSqlRequest.QueryOptions;
51+
import com.google.spanner.v1.MultiplexedSessionPrecommitToken;
5152
import com.google.spanner.v1.PartialResultSet;
5253
import com.google.spanner.v1.ReadRequest;
5354
import com.google.spanner.v1.RequestOptions;
@@ -893,6 +894,13 @@ public void onDone(boolean withBeginTransaction) {
893894
this.session.onReadDone();
894895
}
895896

897+
/**
898+
* For transactions other than read-write, the MultiplexedSessionPrecommitToken will not be
899+
* present in the RPC response. In such cases, this method will be a no-op.
900+
*/
901+
@Override
902+
public void onPrecommitToken(MultiplexedSessionPrecommitToken token) {}
903+
896904
private ResultSet readInternal(
897905
String table,
898906
@Nullable String index,

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AbstractResultSet.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.google.protobuf.ListValue;
2828
import com.google.protobuf.ProtocolMessageEnum;
2929
import com.google.protobuf.Value.KindCase;
30+
import com.google.spanner.v1.MultiplexedSessionPrecommitToken;
3031
import com.google.spanner.v1.Transaction;
3132
import java.io.IOException;
3233
import java.io.Serializable;
@@ -57,6 +58,12 @@ void onTransactionMetadata(Transaction transaction, boolean shouldIncludeId)
5758

5859
/** Called when the read finishes normally. */
5960
void onDone(boolean withBeginTransaction);
61+
62+
/**
63+
* Called when the RPC response contains a MultiplexedSessionPrecommitToken. A precommit token
64+
* will be included if the read-write transaction is executed on a multiplexed session.
65+
*/
66+
void onPrecommitToken(MultiplexedSessionPrecommitToken token);
6067
}
6168

6269
static final class LazyByteArray implements Serializable {

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.google.common.base.MoreObjects;
2929
import com.google.common.base.Preconditions;
3030
import com.google.common.util.concurrent.MoreExecutors;
31+
import com.google.protobuf.ByteString;
3132

3233
/** Implementation of {@link AsyncTransactionManager}. */
3334
final class AsyncTransactionManagerImpl
@@ -80,7 +81,19 @@ public TransactionContextFutureImpl beginAsync() {
8081

8182
private ApiFuture<TransactionContext> internalBeginAsync(boolean firstAttempt) {
8283
txnState = TransactionState.STARTED;
83-
txn = session.newTransaction(options);
84+
85+
// Determine the latest transactionId when using a multiplexed session.
86+
ByteString multiplexedSessionPreviousTransactionId = ByteString.EMPTY;
87+
if (txn != null && session.getIsMultiplexed() && !firstAttempt) {
88+
// Use the current transactionId if available, otherwise fallback to the previous aborted
89+
// transactionId.
90+
multiplexedSessionPreviousTransactionId =
91+
txn.transactionId != null ? txn.transactionId : txn.getPreviousTransactionId();
92+
}
93+
94+
txn =
95+
session.newTransaction(
96+
options, /* previousTransactionId = */ multiplexedSessionPreviousTransactionId);
8497
if (firstAttempt) {
8598
session.setActive(this);
8699
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/BuiltInOpenTelemetryMetricsProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_HASH_KEY;
2121
import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_NAME_KEY;
2222
import static com.google.cloud.spanner.BuiltInMetricsConstant.CLIENT_UID_KEY;
23+
import static com.google.cloud.spanner.BuiltInMetricsConstant.DIRECT_PATH_ENABLED_KEY;
2324
import static com.google.cloud.spanner.BuiltInMetricsConstant.INSTANCE_CONFIG_ID_KEY;
2425
import static com.google.cloud.spanner.BuiltInMetricsConstant.LOCATION_ID_KEY;
2526
import static com.google.cloud.spanner.BuiltInMetricsConstant.PROJECT_ID_KEY;
@@ -83,6 +84,7 @@ Map<String, String> createClientAttributes(String projectId, String client_name)
8384
clientAttributes.put(LOCATION_ID_KEY.getKey(), detectClientLocation());
8485
clientAttributes.put(PROJECT_ID_KEY.getKey(), projectId);
8586
// TODO: Replace this with real value.
87+
clientAttributes.put(DIRECT_PATH_ENABLED_KEY.getKey(), "false");
8688
clientAttributes.put(INSTANCE_CONFIG_ID_KEY.getKey(), "unknown");
8789
clientAttributes.put(CLIENT_NAME_KEY.getKey(), client_name);
8890
String clientUid = getDefaultTaskValue();

google-cloud-spanner/src/main/java/com/google/cloud/spanner/CompositeTracer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ public void addAttributes(Map<String, String> attributes) {
184184
for (ApiTracer child : children) {
185185
if (child instanceof MetricsTracer) {
186186
MetricsTracer metricsTracer = (MetricsTracer) child;
187-
attributes.forEach((key, value) -> metricsTracer.addAttributes(key, value));
187+
metricsTracer.addAttributes(attributes);
188188
}
189189
}
190190
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/DatabaseClientImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class DatabaseClientImpl implements DatabaseClient {
5959
/* useMultiplexedSessionBlindWrite = */ false,
6060
/* multiplexedSessionDatabaseClient = */ null,
6161
tracer,
62-
false);
62+
/* useMultiplexedSessionForRW = */ false);
6363
}
6464

6565
DatabaseClientImpl(

google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcResultSet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class GrpcResultSet extends AbstractResultSet<List<Object>> implements ProtobufR
4747

4848
GrpcResultSet(
4949
CloseableIterator<PartialResultSet> iterator, Listener listener, DecodeMode decodeMode) {
50-
this.iterator = new GrpcValueIterator(iterator);
50+
this.iterator = new GrpcValueIterator(iterator, listener);
5151
this.listener = listener;
5252
this.decodeMode = decodeMode;
5353
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/GrpcValueIterator.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import static com.google.common.base.Preconditions.checkState;
2121

2222
import com.google.cloud.spanner.AbstractResultSet.CloseableIterator;
23+
import com.google.cloud.spanner.AbstractResultSet.Listener;
2324
import com.google.common.collect.AbstractIterator;
2425
import com.google.protobuf.ListValue;
2526
import com.google.protobuf.Value.KindCase;
@@ -44,9 +45,11 @@ private enum StreamValue {
4445
private PartialResultSet current;
4546
private int pos;
4647
private ResultSetStats statistics;
48+
private final Listener listener;
4749

48-
GrpcValueIterator(CloseableIterator<PartialResultSet> stream) {
50+
GrpcValueIterator(CloseableIterator<PartialResultSet> stream, Listener listener) {
4951
this.stream = stream;
52+
this.listener = listener;
5053
}
5154

5255
@SuppressWarnings("unchecked")
@@ -154,6 +157,10 @@ private boolean ensureReady(StreamValue requiredValue) throws SpannerException {
154157
ErrorCode.INTERNAL, "Invalid type metadata: " + e.getMessage(), e);
155158
}
156159
}
160+
// collect the precommit token from each PartialResultSet
161+
if (current.hasPrecommitToken()) {
162+
listener.onPrecommitToken(current.getPrecommitToken());
163+
}
157164
if (current.hasStats()) {
158165
statistics = current.getStats();
159166
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/Interval.java

Lines changed: 73 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727

2828
@AutoValue
2929
@Immutable
30-
public abstract class Interval implements Comparable<Interval>, Serializable {
30+
public abstract class Interval implements Serializable {
3131
public static final long MONTHS_PER_YEAR = 12;
3232
public static final long DAYS_PER_MONTH = 30;
3333
public static final long HOURS_PER_DAY = 24;
@@ -53,48 +53,92 @@ public abstract class Interval implements Comparable<Interval>, Serializable {
5353
Pattern.compile(
5454
"^P(?!$)(-?\\d+Y)?(-?\\d+M)?(-?\\d+D)?(T(?=-?\\d)(-?\\d+H)?(-?\\d+M)?(-?\\d+(\\.\\d{1,9})?S)?)?$");
5555

56-
public abstract long months();
56+
/** Returns the months component of the interval. */
57+
public abstract int months();
5758

58-
public abstract long days();
59+
/** Returns the days component of the interval. */
60+
public abstract int days();
5961

62+
/** Returns the microseconds component of the interval. */
6063
public abstract long micros();
6164

65+
/** Returns the nanoFractions component of the interval. */
6266
public abstract short nanoFractions();
6367

6468
public static Builder builder() {
6569
return new AutoValue_Interval.Builder();
6670
}
6771

72+
/** Returns the nanoseconds component of the interval. */
6873
public BigInteger nanos() {
6974
return BigInteger.valueOf(micros())
7075
.multiply(BigInteger.valueOf(NANOS_PER_MICRO))
7176
.add(BigInteger.valueOf(nanoFractions()));
7277
}
7378

74-
/** Returns the total micros represented by the Interval. */
79+
/** Returns the total microseconds represented by the interval. */
7580
public long getAsMicros() {
7681
return months() * MICROS_PER_MONTH + days() * MICROS_PER_DAY + micros();
7782
}
7883

79-
/** Returns the total nanos represented by the Interval. */
84+
/** Returns the total nanoseconds represented by the interval. */
8085
public BigInteger getAsNanos() {
8186
return BigInteger.valueOf(getAsMicros())
8287
.multiply(BigInteger.valueOf(NANOS_PER_MICRO))
8388
.add(BigInteger.valueOf(nanoFractions()));
8489
}
8590

86-
/** Creates an Interval consisting of the given number of months. */
87-
public static Interval ofMonths(long months) {
91+
/** Creates an interval with specified number of months. */
92+
public static Interval ofMonths(int months) {
8893
return builder().setMonths(months).setDays(0).setMicros(0).setNanoFractions((short) 0).build();
8994
}
9095

91-
/** Creates an Interval consisting of the given number of days. */
92-
public static Interval ofDays(long days) {
96+
/** Creates an interval with specified number of days. */
97+
public static Interval ofDays(int days) {
9398
return builder().setMonths(0).setDays(days).setMicros(0).setNanoFractions((short) 0).build();
9499
}
95100

96-
/** Creates an Interval with specified months, days and micros. */
97-
public static Interval fromMonthsDaysMicros(long months, long days, long micros) {
101+
/** Creates an interval with specified number of seconds. */
102+
public static Interval ofSeconds(long seconds) {
103+
return builder()
104+
.setMonths(0)
105+
.setDays(0)
106+
.setMicros(seconds * MICROS_PER_SECOND)
107+
.setNanoFractions((short) 0)
108+
.build();
109+
}
110+
111+
/** Creates an interval with specified number of milliseconds. */
112+
public static Interval ofMilliseconds(long milliseconds) {
113+
return builder()
114+
.setMonths(0)
115+
.setDays(0)
116+
.setMicros(milliseconds * MICROS_PER_MILLI)
117+
.setNanoFractions((short) 0)
118+
.build();
119+
}
120+
121+
/** Creates an interval with specified number of microseconds. */
122+
public static Interval ofMicros(long micros) {
123+
return builder().months(0).days(0).micros(micros).nanoFractions((short) 0).build();
124+
}
125+
126+
/** Creates an interval with specified number of nanoseconds. */
127+
public static Interval ofNanos(@NotNull BigInteger nanos) {
128+
BigInteger micros = nanos.divide(BigInteger.valueOf(NANOS_PER_MICRO));
129+
BigInteger nanoFractions = nanos.subtract(micros.multiply(BigInteger.valueOf(NANOS_PER_MICRO)));
130+
long microsValue = micros.longValueExact();
131+
short nanoFractionsValue = nanoFractions.shortValueExact();
132+
return builder()
133+
.setMonths(0)
134+
.setDays(0)
135+
.setMicros(microsValue)
136+
.setNanoFractions(nanoFractionsValue)
137+
.build();
138+
}
139+
140+
/** Creates an interval with specified number of months, days and microseconds. */
141+
public static Interval fromMonthsDaysMicros(int months, int days, long micros) {
98142
return builder()
99143
.setMonths(months)
100144
.setDays(days)
@@ -103,13 +147,15 @@ public static Interval fromMonthsDaysMicros(long months, long days, long micros)
103147
.build();
104148
}
105149

106-
/** Creates an Interval with specified months, days and nanos. */
107-
public static Interval fromMonthsDaysNanos(long months, long days, BigInteger nanos) {
108-
long micros = nanos.divide(BigInteger.valueOf(NANOS_PER_MICRO)).longValue();
150+
/** Creates an interval with specified number of months, days and nanoseconds. */
151+
public static Interval fromMonthsDaysNanos(int months, int days, BigInteger nanos) {
152+
long micros = (nanos.divide(BigInteger.valueOf(NANOS_PER_MICRO))).longValueExact();
109153
short nanoFractions =
110-
nanos
111-
.subtract(BigInteger.valueOf(micros).multiply(BigInteger.valueOf(NANOS_PER_MICRO)))
154+
(nanos.subtract(BigInteger.valueOf(micros).multiply(BigInteger.valueOf(NANOS_PER_MICRO))))
112155
.shortValue();
156+
157+
System.out.println("Micros: " + micros + " Nanos: " + nanoFractions);
158+
113159
return builder()
114160
.setMonths(months)
115161
.setDays(days)
@@ -149,14 +195,14 @@ public static Interval parseFromString(String interval) {
149195
totalNanos.subtract(totalMicros.multiply(BigInteger.valueOf(NANOS_PER_MICRO)));
150196

151197
return Interval.builder()
152-
.setMonths(totalMonths)
153-
.setDays(days)
154-
.setMicros(totalMicros.longValue())
155-
.setNanoFractions(nanoFractions.shortValue())
198+
.setMonths(Math.toIntExact(totalMonths))
199+
.setDays(Math.toIntExact(days))
200+
.setMicros(totalMicros.longValueExact())
201+
.setNanoFractions(nanoFractions.shortValueExact())
156202
.build();
157203
}
158204

159-
/** @return the Interval in ISO801 duration format. */
205+
/** Converts Interval to ISO8601 Duration Formatted String. */
160206
public String ToISO8601() {
161207
StringBuilder result = new StringBuilder();
162208
result.append("P");
@@ -197,7 +243,7 @@ public String ToISO8601() {
197243
BigDecimal seconds = new BigDecimal(nanos).movePointLeft(9);
198244

199245
if (seconds.compareTo(new BigDecimal(zero)) != 0) {
200-
result.append(String.format("%sS", seconds));
246+
result.append(String.format("%sS", seconds.stripTrailingZeros()));
201247
}
202248
}
203249

@@ -208,47 +254,7 @@ public String ToISO8601() {
208254
return result.toString();
209255
}
210256

211-
/** Creates an Interval consisting of the given number of seconds. */
212-
public static Interval ofSeconds(long seconds) {
213-
return builder()
214-
.setMonths(0)
215-
.setDays(0)
216-
.setMicros(seconds * MICROS_PER_SECOND)
217-
.setNanoFractions((short) 0)
218-
.build();
219-
}
220-
221-
/** Creates an Interval consisting of the given number of milliseconds. */
222-
public static Interval ofMilliseconds(long milliseconds) {
223-
return builder()
224-
.setMonths(0)
225-
.setDays(0)
226-
.setMicros(milliseconds * MICROS_PER_MILLI)
227-
.setNanoFractions((short) 0)
228-
.build();
229-
}
230-
231-
/** Creates an Interval consisting of the given number of microseconds. */
232-
public static Interval ofMicros(long micros) {
233-
return builder().months(0).days(0).micros(micros).nanoFractions((short) 0).build();
234-
}
235-
236-
/** Creates an Interval consisting of the given number of nanoseconds. */
237-
public static Interval ofNanos(@NotNull BigInteger nanos) {
238-
BigInteger micros = nanos.divide(BigInteger.valueOf(NANOS_PER_MICRO));
239-
BigInteger nanoFractions = nanos.subtract(micros.multiply(BigInteger.valueOf(NANOS_PER_MICRO)));
240-
241-
long microsValue = micros.longValue();
242-
long nanoFractionsValue = nanoFractions.longValue();
243-
244-
return builder()
245-
.setMonths(0)
246-
.setDays(0)
247-
.setMicros(microsValue)
248-
.setNanoFractions((short) nanoFractionsValue)
249-
.build();
250-
}
251-
257+
/** Creates an interval which representing 0-duration. */
252258
public static Interval zeroInterval() {
253259
return builder().setMonths(0).setDays(0).setMicros(0).setNanoFractions((short) 0).build();
254260
}
@@ -265,14 +271,6 @@ && days() == anotherInterval.days()
265271
&& nanos().equals(anotherInterval.nanos());
266272
}
267273

268-
@Override
269-
public int compareTo(@NotNull Interval anotherInterval) {
270-
if (equals(anotherInterval)) {
271-
return 0;
272-
}
273-
return getAsNanos().compareTo(anotherInterval.getAsNanos());
274-
}
275-
276274
@Override
277275
public int hashCode() {
278276
int result = 17;
@@ -284,19 +282,19 @@ public int hashCode() {
284282

285283
@AutoValue.Builder
286284
public abstract static class Builder {
287-
abstract Builder months(long months);
285+
abstract Builder months(int months);
288286

289-
abstract Builder days(long days);
287+
abstract Builder days(int days);
290288

291289
abstract Builder micros(long micros);
292290

293291
abstract Builder nanoFractions(short nanoFractions);
294292

295-
public Builder setMonths(long months) {
293+
public Builder setMonths(int months) {
296294
return months(months);
297295
}
298296

299-
public Builder setDays(long days) {
297+
public Builder setDays(int days) {
300298
return days(days);
301299
}
302300

0 commit comments

Comments
 (0)