@@ -94,6 +94,9 @@ void setUp() throws Exception {
9494 testBigQueryWrite = new FakeBigQueryWrite ();
9595 ConnectionWorker .setMaxInflightQueueWaitTime (300000 );
9696 ConnectionWorker .setMaxInflightRequestWaitTime (Duration .ofMinutes (10 ));
97+ ConnectionWorker .Load .setOverwhelmedCountsThreshold (0.2 );
98+ ConnectionWorker .Load .setOverwhelmedBytesThreshold (0.2 );
99+ ConnectionWorker .Load .setOverwhelmedTimeSinceLastCallbackThreshold (Duration .ofSeconds (3 ));
97100 serviceHelper =
98101 new MockServiceHelper (
99102 UUID .randomUUID ().toString (), Arrays .<MockGrpcService >asList (testBigQueryWrite ));
@@ -865,29 +868,116 @@ void testLoadCompare_compareLoad() {
865868 // In flight bytes bucket is split as per 1024 requests per bucket.
866869 // When in flight bytes is in lower bucket, even destination count is higher and request count
867870 // is higher, the load is still smaller.
868- Load load1 = ConnectionWorker .Load .create (1000 , 2000 , 100 , 1000 , 10 );
869- Load load2 = ConnectionWorker .Load .create (2000 , 1000 , 10 , 1000 , 10 );
871+ Load load1 = ConnectionWorker .Load .create (Duration . ZERO , 1000 , 2000 , 100 , 1000 , 10 );
872+ Load load2 = ConnectionWorker .Load .create (Duration . ZERO , 2000 , 1000 , 10 , 1000 , 10 );
870873 assertThat (Load .LOAD_COMPARATOR .compare (load1 , load2 )).isLessThan (0 );
871874
872875 // In flight bytes in the same bucke of request bytes will compare request count.
873- Load load3 = ConnectionWorker .Load .create (1 , 300 , 10 , 0 , 10 );
874- Load load4 = ConnectionWorker .Load .create (10 , 1 , 10 , 0 , 10 );
876+ Load load3 = ConnectionWorker .Load .create (Duration . ZERO , 1 , 300 , 10 , 0 , 10 );
877+ Load load4 = ConnectionWorker .Load .create (Duration . ZERO , 10 , 1 , 10 , 0 , 10 );
875878 assertThat (Load .LOAD_COMPARATOR .compare (load3 , load4 )).isGreaterThan (0 );
876879
877880 // In flight request and bytes in the same bucket will compare the destination count.
878- Load load5 = ConnectionWorker .Load .create (200 , 1 , 10 , 1000 , 10 );
879- Load load6 = ConnectionWorker .Load .create (100 , 10 , 10 , 1000 , 10 );
881+ Load load5 = ConnectionWorker .Load .create (Duration . ZERO , 200 , 1 , 10 , 1000 , 10 );
882+ Load load6 = ConnectionWorker .Load .create (Duration . ZERO , 100 , 10 , 10 , 1000 , 10 );
880883 assertThat (Load .LOAD_COMPARATOR .compare (load5 , load6 ) == 0 ).isTrue ();
884+
885+ // timeSinceLastCallback has the highest priority.
886+ // load7 has higher timeSinceLastCallback (2s -> bucket 2) but lower other parameters.
887+ // load8 has lower timeSinceLastCallback (0s -> bucket 0) but higher other parameters.
888+ Load load7 = ConnectionWorker .Load .create (Duration .ofSeconds (2 ), 0 , 0 , 0 , 10 , 10 );
889+ Load load8 = ConnectionWorker .Load .create (Duration .ZERO , 10000 , 10000 , 100 , 10 , 10 );
890+ assertThat (Load .LOAD_COMPARATOR .compare (load7 , load8 )).isGreaterThan (0 );
881891 }
882892
883893 @ Test
884894 void testLoadIsOverWhelmed () {
885- // Only in flight request is considered in current overwhelmed calculation.
886- Load load1 = ConnectionWorker .Load .create (60 , 10 , 100 , 90 , 100 );
895+ // In-flight requests, bytes, and timeSinceLastCallback are considered in overwhelmed
896+ // calculation.
897+
898+ // Overwhelmed by request count
899+ Load load1 = ConnectionWorker .Load .create (Duration .ZERO , 60 , 10 , 100 , 90 , 100 );
887900 assertThat (load1 .isOverwhelmed ()).isTrue ();
888901
889- Load load2 = ConnectionWorker .Load .create (1 , 1 , 100 , 100 , 100 );
890- assertThat (load2 .isOverwhelmed ()).isFalse ();
902+ // Not overwhelmed
903+ Load load2 = ConnectionWorker .Load .create (Duration .ZERO , 1 , 1 , 100 , 100 , 100 );
904+ assertFalse (load2 .isOverwhelmed ());
905+
906+ // Under threshold (3s) for timeSinceLastCallback
907+ Load load3 = ConnectionWorker .Load .create (Duration .ofSeconds (2 ), 0 , 0 , 0 , 100 , 100 );
908+ assertFalse (load3 .isOverwhelmed ());
909+
910+ // Over threshold (3s) for timeSinceLastCallback
911+ Load load4 = ConnectionWorker .Load .create (Duration .ofSeconds (4 ), 0 , 0 , 0 , 100 , 100 );
912+ assertTrue (load4 .isOverwhelmed ());
913+ }
914+
915+ @ Test
916+ void testGetLoad_timeSinceLastCallback () throws Exception {
917+ ProtoSchema schema1 = createProtoSchema ("foo" );
918+ StreamWriter sw1 =
919+ StreamWriter .newBuilder (TEST_STREAM_1 , client ).setWriterSchema (schema1 ).build ();
920+ try (ConnectionWorker connectionWorker =
921+ new ConnectionWorker (
922+ TEST_STREAM_1 ,
923+ null ,
924+ createProtoSchema ("foo" ),
925+ 10 ,
926+ 100000 ,
927+ Duration .ofSeconds (100 ),
928+ FlowController .LimitExceededBehavior .Block ,
929+ TEST_TRACE_ID ,
930+ null ,
931+ client .getSettings (),
932+ retrySettings ,
933+ /* enableRequestProfiler= */ false ,
934+ /* enableOpenTelemetry= */ false ,
935+ /*isMultiplexing*/ false )) {
936+
937+ // Initially empty, should be zero.
938+ assertThat (connectionWorker .getLoad ().timeSinceLastCallback ()).isEqualTo (Duration .ZERO );
939+
940+ // Keep response in flight
941+ testBigQueryWrite .setResponseSleep (java .time .Duration .ofSeconds (5 ));
942+
943+ // Send a message
944+ ApiFuture <AppendRowsResponse > future =
945+ sendTestMessage (connectionWorker , sw1 , createFooProtoRows (new String [] {"hello" }), 0 );
946+
947+ // Wait a bit to ensure it is sent and in flight queue
948+ Thread .sleep (500 );
949+
950+ Load load = connectionWorker .getLoad ();
951+ assertThat (load .timeSinceLastCallback ()).isGreaterThan (Duration .ZERO );
952+ assertThat (load .timeSinceLastCallback ())
953+ .isLessThan (Duration .ofSeconds (2 )); // Should be around 500ms
954+ }
955+ }
956+
957+ @ Test
958+ void testLoadCompare_timeSinceLastCallback () {
959+ // Same bytes, same count, same destination, different timeSinceLastCallback
960+ // Bucketed by 1 second (1000ms).
961+
962+ // 100ms and 200ms are in the same bucket (0).
963+ Load load1 = ConnectionWorker .Load .create (Duration .ofMillis (100 ), 0 , 0 , 0 , 0 , 0 );
964+ Load load2 = ConnectionWorker .Load .create (Duration .ofMillis (200 ), 0 , 0 , 0 , 0 , 0 );
965+ assertThat (Load .LOAD_COMPARATOR .compare (load1 , load2 )).isEqualTo (0 );
966+
967+ // 100ms and 1200ms are in different buckets (0 vs 1).
968+ Load load3 = ConnectionWorker .Load .create (Duration .ofMillis (1200 ), 0 , 0 , 0 , 0 , 0 );
969+ assertThat (Load .LOAD_COMPARATOR .compare (load1 , load3 )).isLessThan (0 );
970+ assertThat (Load .LOAD_COMPARATOR .compare (load3 , load1 )).isGreaterThan (0 );
971+ }
972+
973+ @ Test
974+ void testTestLoadCompare_timeSinceLastCallback () {
975+ // TEST_LOAD_COMPARATOR compares timeSinceLastCallback unbucketed.
976+ // 1s and 2s should be different.
977+ Load load1 = ConnectionWorker .Load .create (Duration .ofSeconds (1 ), 0 , 0 , 0 , 0 , 0 );
978+ Load load2 = ConnectionWorker .Load .create (Duration .ofSeconds (2 ), 0 , 0 , 0 , 0 , 0 );
979+ assertThat (Load .TEST_LOAD_COMPARATOR .compare (load1 , load2 )).isLessThan (0 );
980+ assertThat (Load .TEST_LOAD_COMPARATOR .compare (load2 , load1 )).isGreaterThan (0 );
891981 }
892982
893983 @ Test
0 commit comments