Skip to content

Commit afd7d6b

Browse files
authored
feat: include RequestID in requests and errors (#4263)
- Send a RequestID to Spanner for each request - Make sure that the attempt number of the RequestID is increased if the RPC is retried. - Include the RequestID in every error that is thrown due to an error that is returned by Spanner.
1 parent f9505a9 commit afd7d6b

File tree

47 files changed

+1392
-565
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1392
-565
lines changed

google-cloud-spanner/clirr-ignored-differences.xml

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,9 +1087,56 @@
10871087
<differenceType>7002</differenceType>
10881088
<className>com/google/cloud/spanner/CompositeTracer</className>
10891089
<method>void recordGFELatency(java.lang.Float)</method>
1090-
</difference><difference>
1091-
<differenceType>7002</differenceType>
1092-
<className>com/google/cloud/spanner/CompositeTracer</className>
1093-
<method>void recordGfeHeaderMissingCount(java.lang.Long)</method>
1094-
</difference>
1090+
</difference>
1091+
<difference>
1092+
<differenceType>7002</differenceType>
1093+
<className>com/google/cloud/spanner/CompositeTracer</className>
1094+
<method>void recordGfeHeaderMissingCount(java.lang.Long)</method>
1095+
</difference>
1096+
1097+
<difference>
1098+
<differenceType>7002</differenceType>
1099+
<className>com/google/cloud/spanner/SpannerException</className>
1100+
<method>void setRequestId(com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1101+
</difference>
1102+
<difference>
1103+
<differenceType>7002</differenceType>
1104+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1105+
<method>com.google.cloud.spanner.SpannerBatchUpdateException newSpannerBatchUpdateException(com.google.cloud.spanner.ErrorCode, java.lang.String, long[], com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1106+
</difference>
1107+
<difference>
1108+
<differenceType>7002</differenceType>
1109+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1110+
<method>com.google.cloud.spanner.SpannerException newSpannerException(com.google.cloud.spanner.ErrorCode, java.lang.String, java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1111+
</difference>
1112+
<difference>
1113+
<differenceType>7002</differenceType>
1114+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1115+
<method>com.google.cloud.spanner.SpannerException newSpannerException(com.google.cloud.spanner.ErrorCode, java.lang.String, com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1116+
</difference>
1117+
<difference>
1118+
<differenceType>7002</differenceType>
1119+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1120+
<method>com.google.cloud.spanner.SpannerException newSpannerException(java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1121+
</difference>
1122+
<difference>
1123+
<differenceType>7002</differenceType>
1124+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1125+
<method>com.google.cloud.spanner.SpannerException newSpannerException(io.grpc.Context, java.lang.Throwable, com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1126+
</difference>
1127+
<difference>
1128+
<differenceType>7002</differenceType>
1129+
<className>com/google/cloud/spanner/SpannerExceptionFactory</className>
1130+
<method>com.google.cloud.spanner.SpannerException propagateInterrupt(java.lang.InterruptedException, com.google.cloud.spanner.XGoogSpannerRequestId)</method>
1131+
</difference>
1132+
<difference>
1133+
<differenceType>6001</differenceType>
1134+
<className>com/google/cloud/spanner/XGoogSpannerRequestId</className>
1135+
<field>REQUEST_HEADER_KEY</field>
1136+
</difference>
1137+
<difference>
1138+
<differenceType>6001</differenceType>
1139+
<className>com/google/cloud/spanner/XGoogSpannerRequestId</className>
1140+
<field>REQUEST_ID</field>
1141+
</difference>
10951142
</differences>

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,16 @@ public class AbortedException extends SpannerException {
3838
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
3939
AbortedException(
4040
DoNotConstructDirectly token, @Nullable String message, @Nullable Throwable cause) {
41-
this(token, message, cause, null, null);
41+
this(token, message, cause, null);
4242
}
4343

4444
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
4545
AbortedException(
4646
DoNotConstructDirectly token,
4747
@Nullable String message,
4848
@Nullable Throwable cause,
49-
@Nullable ApiException apiException,
50-
@Nullable XGoogSpannerRequestId reqId) {
51-
super(token, ErrorCode.ABORTED, IS_RETRYABLE, message, cause, apiException, reqId);
49+
@Nullable ApiException apiException) {
50+
super(token, ErrorCode.ABORTED, IS_RETRYABLE, message, cause, apiException);
5251
if (cause instanceof AbortedException) {
5352
this.transactionID = ((AbortedException) cause).getTransactionID();
5453
}

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

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -457,30 +457,22 @@ void initTransaction() {
457457
}
458458

459459
private void initTransactionInternal(BeginTransactionRequest request) {
460-
XGoogSpannerRequestId reqId =
461-
session.getRequestIdCreator().nextRequestId(session.getChannel(), 1);
462460
try {
463461
Transaction transaction =
464-
rpc.beginTransaction(
465-
request, reqId.withOptions(getTransactionChannelHint()), isRouteToLeader());
462+
rpc.beginTransaction(request, getTransactionChannelHint(), isRouteToLeader());
466463
if (!transaction.hasReadTimestamp()) {
467464
throw SpannerExceptionFactory.newSpannerException(
468-
ErrorCode.INTERNAL,
469-
"Missing expected transaction.read_timestamp metadata field",
470-
reqId);
465+
ErrorCode.INTERNAL, "Missing expected transaction.read_timestamp metadata field");
471466
}
472467
if (transaction.getId().isEmpty()) {
473468
throw SpannerExceptionFactory.newSpannerException(
474-
ErrorCode.INTERNAL, "Missing expected transaction.id metadata field", reqId);
469+
ErrorCode.INTERNAL, "Missing expected transaction.id metadata field");
475470
}
476471
try {
477472
timestamp = Timestamp.fromProto(transaction.getReadTimestamp());
478473
} catch (IllegalArgumentException e) {
479474
throw SpannerExceptionFactory.newSpannerException(
480-
ErrorCode.INTERNAL,
481-
"Bad value in transaction.read_timestamp metadata field",
482-
e,
483-
reqId);
475+
ErrorCode.INTERNAL, "Bad value in transaction.read_timestamp metadata field", e);
484476
}
485477
transactionId = transaction.getId();
486478
span.addAnnotation(
@@ -816,7 +808,8 @@ ResultSet executeQueryInternalWithOptions(
816808
@Override
817809
CloseableIterator<PartialResultSet> startStream(
818810
@Nullable ByteString resumeToken,
819-
AsyncResultSet.StreamMessageListener streamListener) {
811+
AsyncResultSet.StreamMessageListener streamListener,
812+
XGoogSpannerRequestId requestId) {
820813
GrpcStreamIterator stream =
821814
new GrpcStreamIterator(
822815
statement,
@@ -839,12 +832,12 @@ CloseableIterator<PartialResultSet> startStream(
839832
if (selector != null) {
840833
request.setTransaction(selector);
841834
}
842-
this.ensureNonNullXGoogRequestId();
843835
SpannerRpc.StreamingCall call =
844836
rpc.executeQuery(
845837
request.build(),
846838
stream.consumer(),
847-
this.xGoogRequestId.withOptions(getTransactionChannelHint()),
839+
getTransactionChannelHint(),
840+
requestId,
848841
isRouteToLeader());
849842
session.markUsed(clock.instant());
850843
stream.setCall(call, request.getTransaction().hasBegin());
@@ -860,7 +853,7 @@ boolean prepareIteratorForRetryOnDifferentGrpcChannel() {
860853
stream, this, options.hasDecodeMode() ? options.decodeMode() : defaultDecodeMode);
861854
}
862855

863-
Map<SpannerRpc.Option, ?> getChannelHintOptions(
856+
static Map<SpannerRpc.Option, ?> getChannelHintOptions(
864857
Map<SpannerRpc.Option, ?> channelHintForSession, Long channelHintForTransaction) {
865858
if (channelHintForSession != null) {
866859
return channelHintForSession;
@@ -1030,7 +1023,8 @@ ResultSet readInternalWithOptions(
10301023
@Override
10311024
CloseableIterator<PartialResultSet> startStream(
10321025
@Nullable ByteString resumeToken,
1033-
AsyncResultSet.StreamMessageListener streamListener) {
1026+
AsyncResultSet.StreamMessageListener streamListener,
1027+
XGoogSpannerRequestId requestId) {
10341028
GrpcStreamIterator stream =
10351029
new GrpcStreamIterator(
10361030
lastStatement, prefetchChunks, cancelQueryWhenClientIsClosed);
@@ -1048,13 +1042,12 @@ CloseableIterator<PartialResultSet> startStream(
10481042
builder.setTransaction(selector);
10491043
}
10501044
builder.setRequestOptions(buildRequestOptions(readOptions));
1051-
this.incrementXGoogRequestIdAttempt();
1052-
this.xGoogRequestId.setChannelId(session.getChannel());
10531045
SpannerRpc.StreamingCall call =
10541046
rpc.read(
10551047
builder.build(),
10561048
stream.consumer(),
1057-
this.xGoogRequestId.withOptions(getTransactionChannelHint()),
1049+
getTransactionChannelHint(),
1050+
requestId,
10581051
isRouteToLeader());
10591052
session.markUsed(clock.instant());
10601053
stream.setCall(call, /* withBeginTransaction= */ builder.getTransaction().hasBegin());

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,15 @@ public class AdminRequestsPerMinuteExceededException extends SpannerException {
3232
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
3333
AdminRequestsPerMinuteExceededException(
3434
DoNotConstructDirectly token, @Nullable String message, @Nullable Throwable cause) {
35-
this(token, message, cause, null, null);
35+
this(token, message, cause, null);
3636
}
3737

3838
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
3939
AdminRequestsPerMinuteExceededException(
4040
DoNotConstructDirectly token,
4141
@Nullable String message,
4242
@Nullable Throwable cause,
43-
@Nullable ApiException apiException,
44-
@Nullable XGoogSpannerRequestId reqId) {
45-
super(token, ErrorCode.RESOURCE_EXHAUSTED, true, message, cause, apiException, reqId);
43+
@Nullable ApiException apiException) {
44+
super(token, ErrorCode.RESOURCE_EXHAUSTED, true, message, cause, apiException);
4645
}
4746
}

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,9 @@ private List<Partition> partitionReadUsingIndex(
250250
}
251251
builder.setPartitionOptions(pbuilder.build());
252252

253-
XGoogSpannerRequestId reqId =
254-
session.getRequestIdCreator().nextRequestId(session.getChannel(), 1);
255253
final PartitionReadRequest request = builder.build();
256254
try {
257-
PartitionResponse response = rpc.partitionRead(request, reqId.withOptions(options));
255+
PartitionResponse response = rpc.partitionRead(request, options);
258256
ImmutableList.Builder<Partition> partitions = ImmutableList.builder();
259257
for (com.google.spanner.v1.Partition p : response.getPartitionsList()) {
260258
Partition partition =
@@ -274,7 +272,6 @@ private List<Partition> partitionReadUsingIndex(
274272
return partitionReadUsingIndex(
275273
partitionOptions, table, index, keys, columns, true, option);
276274
}
277-
e.setRequestId(reqId);
278275
throw e;
279276
}
280277
}
@@ -316,11 +313,9 @@ private List<Partition> partitionQuery(
316313
}
317314
builder.setPartitionOptions(pbuilder.build());
318315

319-
XGoogSpannerRequestId reqId =
320-
session.getRequestIdCreator().nextRequestId(session.getChannel(), 1);
321316
final PartitionQueryRequest request = builder.build();
322317
try {
323-
PartitionResponse response = rpc.partitionQuery(request, reqId.withOptions(options));
318+
PartitionResponse response = rpc.partitionQuery(request, options);
324319
ImmutableList.Builder<Partition> partitions = ImmutableList.builder();
325320
for (com.google.spanner.v1.Partition p : response.getPartitionsList()) {
326321
Partition partition =
@@ -333,7 +328,6 @@ private List<Partition> partitionQuery(
333328
if (!isFallback && maybeMarkUnimplementedForPartitionedOps(e)) {
334329
return partitionQuery(partitionOptions, statement, true, option);
335330
}
336-
e.setRequestId(reqId);
337331
throw e;
338332
}
339333
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.google.cloud.spanner;
1818

19-
import static com.google.cloud.spanner.XGoogSpannerRequestId.REQUEST_ID;
19+
import static com.google.cloud.spanner.XGoogSpannerRequestId.REQUEST_ID_HEADER_NAME;
2020

2121
import com.google.api.core.InternalApi;
2222
import com.google.api.gax.tracing.OpenTelemetryMetricsRecorder;
@@ -98,10 +98,12 @@ public class BuiltInMetricsConstant {
9898
AttributeKey.stringKey("directpath_enabled");
9999
public static final AttributeKey<String> DIRECT_PATH_USED_KEY =
100100
AttributeKey.stringKey("directpath_used");
101-
public static final AttributeKey<String> REQUEST_ID_KEY = AttributeKey.stringKey(REQUEST_ID);
101+
public static final AttributeKey<String> REQUEST_ID_KEY =
102+
AttributeKey.stringKey(REQUEST_ID_HEADER_NAME);
102103
public static final AttributeKey<String> GRPC_XDS_RESOURCE_TYPE_KEY =
103104
AttributeKey.stringKey("grpc.xds.resource_type");
104-
public static Set<String> ALLOWED_EXEMPLARS_ATTRIBUTES = new HashSet<>(Arrays.asList(REQUEST_ID));
105+
public static Set<String> ALLOWED_EXEMPLARS_ATTRIBUTES =
106+
new HashSet<>(Arrays.asList(REQUEST_ID_HEADER_NAME));
105107

106108
// IP address prefixes allocated for DirectPath backends.
107109
public static final String DP_IPV6_PREFIX = "2001:4860:8040";

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class DatabaseNotFoundException extends ResourceNotFoundException {
3535
@Nullable String message,
3636
ResourceInfo resourceInfo,
3737
@Nullable Throwable cause) {
38-
this(token, message, resourceInfo, cause, null, null);
38+
this(token, message, resourceInfo, cause, null);
3939
}
4040

4141
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
@@ -44,8 +44,7 @@ public class DatabaseNotFoundException extends ResourceNotFoundException {
4444
@Nullable String message,
4545
ResourceInfo resourceInfo,
4646
@Nullable Throwable cause,
47-
@Nullable ApiException apiException,
48-
@Nullable XGoogSpannerRequestId reqId) {
49-
super(token, message, resourceInfo, cause, apiException, reqId);
47+
@Nullable ApiException apiException) {
48+
super(token, message, resourceInfo, cause, apiException);
5049
}
5150
}

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class InstanceNotFoundException extends ResourceNotFoundException {
3535
@Nullable String message,
3636
ResourceInfo resourceInfo,
3737
@Nullable Throwable cause) {
38-
this(token, message, resourceInfo, cause, null, null);
38+
this(token, message, resourceInfo, cause, null);
3939
}
4040

4141
/** Private constructor. Use {@link SpannerExceptionFactory} to create instances. */
@@ -44,8 +44,7 @@ public class InstanceNotFoundException extends ResourceNotFoundException {
4444
@Nullable String message,
4545
ResourceInfo resourceInfo,
4646
@Nullable Throwable cause,
47-
@Nullable ApiException apiException,
48-
@Nullable XGoogSpannerRequestId reqId) {
49-
super(token, message, resourceInfo, cause, apiException, reqId);
47+
@Nullable ApiException apiException) {
48+
super(token, message, resourceInfo, cause, apiException);
5049
}
5150
}

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ public class MissingDefaultSequenceKindException extends SpannerException {
3838
ErrorCode errorCode,
3939
String message,
4040
Throwable cause,
41-
@Nullable ApiException apiException,
42-
@Nullable XGoogSpannerRequestId reqId) {
43-
super(token, errorCode, /* retryable= */ false, message, cause, apiException, reqId);
41+
@Nullable ApiException apiException) {
42+
super(token, errorCode, /* retryable= */ false, message, cause, apiException);
4443
}
4544

4645
static boolean isMissingDefaultSequenceKindException(Throwable cause) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ public AsyncTransactionManager transactionManagerAsync(TransactionOption... opti
745745

746746
@Override
747747
public long executePartitionedUpdate(Statement stmt, UpdateOption... options) {
748-
return createMultiplexedSessionTransaction(/* singleUse= */ true)
748+
return createMultiplexedSessionTransaction(/* singleUse= */ false)
749749
.executePartitionedUpdate(stmt, options);
750750
}
751751

0 commit comments

Comments
 (0)