45
45
import java .io .IOException ;
46
46
import java .time .Duration ;
47
47
import java .time .Instant ;
48
- import java .util .ArrayList ;
49
- import java .util .Comparator ;
50
- import java .util .Deque ;
51
- import java .util .HashMap ;
52
- import java .util .LinkedList ;
53
- import java .util .List ;
54
- import java .util .Map ;
55
- import java .util .Set ;
56
- import java .util .UUID ;
48
+ import java .util .*;
57
49
import java .util .concurrent .ConcurrentHashMap ;
58
50
import java .util .concurrent .ExecutorService ;
59
51
import java .util .concurrent .Executors ;
@@ -511,6 +503,8 @@ private boolean shouldWaitForBackoff(AppendRequestAndResponse requestWrapper) {
511
503
512
504
private void waitForBackoffIfNecessary (AppendRequestAndResponse requestWrapper ) {
513
505
lock .lock ();
506
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
507
+ RequestProfiler .OperationName .RETRY_BACKOFF , requestWrapper .requestUniqueId );
514
508
try {
515
509
Condition condition = lock .newCondition ();
516
510
while (shouldWaitForBackoff (requestWrapper )) {
@@ -519,6 +513,8 @@ private void waitForBackoffIfNecessary(AppendRequestAndResponse requestWrapper)
519
513
} catch (InterruptedException e ) {
520
514
throw new IllegalStateException (e );
521
515
} finally {
516
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
517
+ RequestProfiler .OperationName .RETRY_BACKOFF , requestWrapper .requestUniqueId );
522
518
lock .unlock ();
523
519
}
524
520
}
@@ -539,6 +535,8 @@ private void addMessageToWaitingQueue(
539
535
++this .inflightRequests ;
540
536
this .inflightBytes += requestWrapper .messageSize ;
541
537
hasMessageInWaitingQueue .signal ();
538
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
539
+ RequestProfiler .OperationName .WAIT_QUEUE , requestWrapper .requestUniqueId );
542
540
if (addToFront ) {
543
541
waitingRequestQueue .addFirst (requestWrapper );
544
542
} else {
@@ -547,7 +545,8 @@ private void addMessageToWaitingQueue(
547
545
}
548
546
549
547
/** Schedules the writing of rows at given offset. */
550
- ApiFuture <AppendRowsResponse > append (StreamWriter streamWriter , ProtoRows rows , long offset ) {
548
+ ApiFuture <AppendRowsResponse > append (
549
+ StreamWriter streamWriter , ProtoRows rows , long offset , String requestUniqueId ) {
551
550
if (this .location != null && !this .location .equals (streamWriter .getLocation ())) {
552
551
throw new StatusRuntimeException (
553
552
Status .fromCode (Code .INVALID_ARGUMENT )
@@ -584,7 +583,7 @@ ApiFuture<AppendRowsResponse> append(StreamWriter streamWriter, ProtoRows rows,
584
583
requestBuilder .setDefaultMissingValueInterpretation (
585
584
streamWriter .getDefaultValueInterpretation ());
586
585
}
587
- return appendInternal (streamWriter , requestBuilder .build ());
586
+ return appendInternal (streamWriter , requestBuilder .build (), requestUniqueId );
588
587
}
589
588
590
589
Boolean isUserClosed () {
@@ -601,9 +600,9 @@ String getWriteLocation() {
601
600
}
602
601
603
602
private ApiFuture <AppendRowsResponse > appendInternal (
604
- StreamWriter streamWriter , AppendRowsRequest message ) {
603
+ StreamWriter streamWriter , AppendRowsRequest message , String requestUniqueId ) {
605
604
AppendRequestAndResponse requestWrapper =
606
- new AppendRequestAndResponse (message , streamWriter , this .retrySettings );
605
+ new AppendRequestAndResponse (message , streamWriter , this .retrySettings , requestUniqueId );
607
606
if (requestWrapper .messageSize > getApiMaxRequestBytes ()) {
608
607
requestWrapper .appendResult .setException (
609
608
new StatusRuntimeException (
@@ -650,11 +649,14 @@ private ApiFuture<AppendRowsResponse> appendInternal(
650
649
writerId ));
651
650
return requestWrapper .appendResult ;
652
651
}
653
-
652
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
653
+ RequestProfiler .OperationName .WAIT_QUEUE , requestUniqueId );
654
654
++this .inflightRequests ;
655
655
this .inflightBytes += requestWrapper .messageSize ;
656
656
waitingRequestQueue .addLast (requestWrapper );
657
657
hasMessageInWaitingQueue .signal ();
658
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
659
+ RequestProfiler .OperationName .WAIT_INFLIGHT_QUOTA , requestUniqueId );
658
660
try {
659
661
maybeWaitForInflightQuota ();
660
662
} catch (StatusRuntimeException ex ) {
@@ -663,6 +665,8 @@ private ApiFuture<AppendRowsResponse> appendInternal(
663
665
this .inflightBytes -= requestWrapper .messageSize ;
664
666
throw ex ;
665
667
}
668
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
669
+ RequestProfiler .OperationName .WAIT_INFLIGHT_QUOTA , requestUniqueId );
666
670
return requestWrapper .appendResult ;
667
671
} finally {
668
672
this .lock .unlock ();
@@ -826,7 +830,12 @@ private void appendLoop() {
826
830
// prepended as they need to be sent before new requests.
827
831
while (!inflightRequestQueue .isEmpty ()) {
828
832
AppendRequestAndResponse requestWrapper = inflightRequestQueue .pollLast ();
833
+ // Consider the backend latency as completed for the current request.
834
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
835
+ RequestProfiler .OperationName .RESPONSE_LATENCY , requestWrapper .requestUniqueId );
829
836
requestWrapper .requestSendTimeStamp = null ;
837
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
838
+ RequestProfiler .OperationName .WAIT_QUEUE , requestWrapper .requestUniqueId );
830
839
waitingRequestQueue .addFirst (requestWrapper );
831
840
}
832
841
@@ -836,6 +845,8 @@ private void appendLoop() {
836
845
}
837
846
while (!this .waitingRequestQueue .isEmpty ()) {
838
847
AppendRequestAndResponse requestWrapper = this .waitingRequestQueue .pollFirst ();
848
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
849
+ RequestProfiler .OperationName .WAIT_QUEUE , requestWrapper .requestUniqueId );
839
850
waitForBackoffIfNecessary (requestWrapper );
840
851
this .inflightRequestQueue .add (requestWrapper );
841
852
localQueue .addLast (requestWrapper );
@@ -876,7 +887,9 @@ private void appendLoop() {
876
887
}
877
888
while (!localQueue .isEmpty ()) {
878
889
localQueue .peekFirst ().setRequestSendQueueTime ();
879
- AppendRowsRequest originalRequest = localQueue .pollFirst ().message ;
890
+ AppendRequestAndResponse wrapper = localQueue .pollFirst ();
891
+ AppendRowsRequest originalRequest = wrapper .message ;
892
+ String requestUniqueId = wrapper .requestUniqueId ;
880
893
AppendRowsRequest .Builder originalRequestBuilder = originalRequest .toBuilder ();
881
894
// Always respect the first writer schema seen by the loop.
882
895
if (writerSchema == null ) {
@@ -918,6 +931,9 @@ private void appendLoop() {
918
931
}
919
932
firstRequestForTableOrSchemaSwitch = false ;
920
933
934
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .startOperation (
935
+ RequestProfiler .OperationName .RESPONSE_LATENCY , requestUniqueId );
936
+
921
937
// Send should only throw an exception if there is a problem with the request. The catch
922
938
// block will handle this case, and return the exception with the result.
923
939
// Otherwise send will return:
@@ -1196,6 +1212,8 @@ private void requestCallback(AppendRowsResponse response) {
1196
1212
}
1197
1213
if (!this .inflightRequestQueue .isEmpty ()) {
1198
1214
requestWrapper = pollFirstInflightRequestQueue ();
1215
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
1216
+ RequestProfiler .OperationName .RESPONSE_LATENCY , requestWrapper .requestUniqueId );
1199
1217
} else if (inflightCleanuped ) {
1200
1218
// It is possible when requestCallback is called, the inflight queue is already drained
1201
1219
// because we timed out waiting for done.
@@ -1227,35 +1245,40 @@ private void requestCallback(AppendRowsResponse response) {
1227
1245
// the current request callback finishes.
1228
1246
threadPool .submit (
1229
1247
() -> {
1230
- if (response .hasError ()) {
1231
- Exceptions .StorageException storageException =
1232
- Exceptions .toStorageException (response .getError (), null );
1233
- log .fine (String .format ("Got error message: %s" , response .toString ()));
1234
- if (storageException != null ) {
1235
- requestWrapper .appendResult .setException (storageException );
1236
- } else if (response .getRowErrorsCount () > 0 ) {
1237
- Map <Integer , String > rowIndexToErrorMessage = new HashMap <>();
1238
- for (int i = 0 ; i < response .getRowErrorsCount (); i ++) {
1239
- RowError rowError = response .getRowErrors (i );
1240
- rowIndexToErrorMessage .put (
1241
- Math .toIntExact (rowError .getIndex ()), rowError .getMessage ());
1248
+ try {
1249
+ if (response .hasError ()) {
1250
+ Exceptions .StorageException storageException =
1251
+ Exceptions .toStorageException (response .getError (), null );
1252
+ log .fine (String .format ("Got error message: %s" , response .toString ()));
1253
+ if (storageException != null ) {
1254
+ requestWrapper .appendResult .setException (storageException );
1255
+ } else if (response .getRowErrorsCount () > 0 ) {
1256
+ Map <Integer , String > rowIndexToErrorMessage = new HashMap <>();
1257
+ for (int i = 0 ; i < response .getRowErrorsCount (); i ++) {
1258
+ RowError rowError = response .getRowErrors (i );
1259
+ rowIndexToErrorMessage .put (
1260
+ Math .toIntExact (rowError .getIndex ()), rowError .getMessage ());
1261
+ }
1262
+ AppendSerializationError exception =
1263
+ new AppendSerializationError (
1264
+ response .getError ().getCode (),
1265
+ response .getError ().getMessage (),
1266
+ streamName ,
1267
+ rowIndexToErrorMessage );
1268
+ requestWrapper .appendResult .setException (exception );
1269
+ } else {
1270
+ StatusRuntimeException exception =
1271
+ new StatusRuntimeException (
1272
+ Status .fromCodeValue (response .getError ().getCode ())
1273
+ .withDescription (response .getError ().getMessage ()));
1274
+ requestWrapper .appendResult .setException (exception );
1242
1275
}
1243
- AppendSerializationError exception =
1244
- new AppendSerializationError (
1245
- response .getError ().getCode (),
1246
- response .getError ().getMessage (),
1247
- streamName ,
1248
- rowIndexToErrorMessage );
1249
- requestWrapper .appendResult .setException (exception );
1250
1276
} else {
1251
- StatusRuntimeException exception =
1252
- new StatusRuntimeException (
1253
- Status .fromCodeValue (response .getError ().getCode ())
1254
- .withDescription (response .getError ().getMessage ()));
1255
- requestWrapper .appendResult .setException (exception );
1277
+ requestWrapper .appendResult .set (response );
1256
1278
}
1257
- } else {
1258
- requestWrapper .appendResult .set (response );
1279
+ } finally {
1280
+ RequestProfiler .REQUEST_PROFILER_SINGLETON .endOperation (
1281
+ RequestProfiler .OperationName .TOTAL_LATENCY , requestWrapper .requestUniqueId );
1259
1282
}
1260
1283
});
1261
1284
}
@@ -1367,6 +1390,9 @@ static final class AppendRequestAndResponse {
1367
1390
Instant blockMessageSendDeadline ;
1368
1391
1369
1392
Integer retryCount ;
1393
+
1394
+ // Unique identifier for the request.
1395
+ String requestUniqueId ;
1370
1396
ExponentialRetryAlgorithm retryAlgorithm ;
1371
1397
1372
1398
// The writer that issues the call of the request.
@@ -1379,11 +1405,15 @@ static final class AppendRequestAndResponse {
1379
1405
Instant requestSendTimeStamp ;
1380
1406
1381
1407
AppendRequestAndResponse (
1382
- AppendRowsRequest message , StreamWriter streamWriter , RetrySettings retrySettings ) {
1408
+ AppendRowsRequest message ,
1409
+ StreamWriter streamWriter ,
1410
+ RetrySettings retrySettings ,
1411
+ String requestUniqueId ) {
1383
1412
this .appendResult = SettableApiFuture .create ();
1384
1413
this .message = message ;
1385
1414
this .messageSize = message .getProtoRows ().getSerializedSize ();
1386
1415
this .streamWriter = streamWriter ;
1416
+ this .requestUniqueId = requestUniqueId ;
1387
1417
this .blockMessageSendDeadline = Instant .now ();
1388
1418
this .retryCount = 0 ;
1389
1419
// To be set after first retry
0 commit comments