@@ -101,6 +101,10 @@ public class InternalResourceGroup
101
101
@ GuardedBy ("root" )
102
102
private long cpuQuotaGenerationMillisPerSecond = Long .MAX_VALUE ;
103
103
@ GuardedBy ("root" )
104
+ private long hardPhysicalDataScanLimitBytes = Long .MAX_VALUE ;
105
+ @ GuardedBy ("root" )
106
+ private long physicalDataScanQuotaGenerationBytesPerSecond = Long .MAX_VALUE ;
107
+ @ GuardedBy ("root" )
104
108
private int schedulingWeight = DEFAULT_WEIGHT ;
105
109
@ GuardedBy ("root" )
106
110
private SchedulingPolicy schedulingPolicy = FAIR ;
@@ -128,9 +132,9 @@ public class InternalResourceGroup
128
132
private int descendantRunningQueries ;
129
133
@ GuardedBy ("root" )
130
134
private int descendantQueuedQueries ;
131
- // CPU and memory usage is cached because it changes very rapidly while queries are running, and would be expensive to track continuously
135
+ // CPU, memory and physical data input usage is cached because it changes very rapidly while queries are running, and would be expensive to track continuously
132
136
@ GuardedBy ("root" )
133
- private ResourceUsage cachedResourceUsage = new ResourceUsage (0 , 0 );
137
+ private ResourceUsage cachedResourceUsage = new ResourceUsage (0 , 0 , 0 );
134
138
@ GuardedBy ("root" )
135
139
private long lastStartMillis ;
136
140
private final CounterStat timeBetweenStartsSec = new CounterStat ();
@@ -168,9 +172,11 @@ public ResourceGroupInfo getFullInfo()
168
172
succinctBytes (softMemoryLimitBytes ),
169
173
softConcurrencyLimit ,
170
174
hardConcurrencyLimit ,
175
+ succinctBytes (hardPhysicalDataScanLimitBytes ),
171
176
maxQueuedQueries ,
172
177
succinctBytes (cachedResourceUsage .getMemoryUsageBytes ()),
173
178
succinctDuration (cachedResourceUsage .getCpuUsageMillis (), MILLISECONDS ),
179
+ succinctBytes (cachedResourceUsage .getPhysicalInputDataUsageBytes ()),
174
180
getQueuedQueries (),
175
181
getRunningQueries (),
176
182
eligibleSubGroups .size (),
@@ -193,9 +199,11 @@ public ResourceGroupInfo getInfo()
193
199
succinctBytes (softMemoryLimitBytes ),
194
200
softConcurrencyLimit ,
195
201
hardConcurrencyLimit ,
202
+ succinctBytes (hardPhysicalDataScanLimitBytes ),
196
203
maxQueuedQueries ,
197
204
succinctBytes (cachedResourceUsage .getMemoryUsageBytes ()),
198
205
succinctDuration (cachedResourceUsage .getCpuUsageMillis (), MILLISECONDS ),
206
+ succinctBytes (cachedResourceUsage .getPhysicalInputDataUsageBytes ()),
199
207
getQueuedQueries (),
200
208
getRunningQueries (),
201
209
eligibleSubGroups .size (),
@@ -218,9 +226,11 @@ private ResourceGroupInfo getSummaryInfo()
218
226
succinctBytes (softMemoryLimitBytes ),
219
227
softConcurrencyLimit ,
220
228
hardConcurrencyLimit ,
229
+ succinctBytes (hardPhysicalDataScanLimitBytes ),
221
230
maxQueuedQueries ,
222
231
succinctBytes (cachedResourceUsage .getMemoryUsageBytes ()),
223
232
succinctDuration (cachedResourceUsage .getCpuUsageMillis (), MILLISECONDS ),
233
+ succinctBytes (cachedResourceUsage .getPhysicalInputDataUsageBytes ()),
224
234
getQueuedQueries (),
225
235
getRunningQueries (),
226
236
eligibleSubGroups .size (),
@@ -342,6 +352,12 @@ public long getMemoryUsageBytes()
342
352
return getResourceUsageSnapshot ().getMemoryUsageBytes ();
343
353
}
344
354
355
+ @ Managed
356
+ public long getPhysicalInputDataUsageBytes ()
357
+ {
358
+ return getResourceUsageSnapshot ().getPhysicalInputDataUsageBytes ();
359
+ }
360
+
345
361
@ Managed
346
362
@ Override
347
363
public long getSoftMemoryLimitBytes ()
@@ -443,6 +459,45 @@ public void setCpuQuotaGenerationMillisPerSecond(long rate)
443
459
}
444
460
}
445
461
462
+ @ Managed
463
+ @ Override
464
+ public long getHardPhysicalDataScanLimitBytes ()
465
+ {
466
+ synchronized (root ) {
467
+ return hardPhysicalDataScanLimitBytes ;
468
+ }
469
+ }
470
+
471
+ @ Override
472
+ public void setHardPhysicalDataScanLimitBytes (long limit )
473
+ {
474
+ synchronized (root ) {
475
+ boolean oldCanRun = canRunMore ();
476
+ this .hardPhysicalDataScanLimitBytes = limit ;
477
+ if (canRunMore () != oldCanRun ) {
478
+ updateEligibility ();
479
+ }
480
+ }
481
+ }
482
+
483
+ @ Managed
484
+ @ Override
485
+ public long getPhysicalDataScanQuotaGenerationBytesPerSecond ()
486
+ {
487
+ synchronized (root ) {
488
+ return physicalDataScanQuotaGenerationBytesPerSecond ;
489
+ }
490
+ }
491
+
492
+ @ Override
493
+ public void setPhysicalDataScanQuotaGenerationBytesPerSecond (long rate )
494
+ {
495
+ checkArgument (rate > 0 , "Physical data scan quota generation must be positive" );
496
+ synchronized (root ) {
497
+ physicalDataScanQuotaGenerationBytesPerSecond = rate ;
498
+ }
499
+ }
500
+
446
501
@ Managed
447
502
@ Override
448
503
public int getSoftConcurrencyLimit ()
@@ -731,7 +786,7 @@ private void startInBackground(ManagedQueryExecution query)
731
786
{
732
787
checkState (Thread .holdsLock (root ), "Must hold lock to start a query" );
733
788
synchronized (root ) {
734
- runningQueries .put (query , new ResourceUsage (0 , 0 ));
789
+ runningQueries .put (query , new ResourceUsage (0 , 0 , 0 ));
735
790
InternalResourceGroup group = this ;
736
791
group .getStartedQueries ().update (1 );
737
792
while (group .parent .isPresent ()) {
@@ -757,11 +812,11 @@ public void updateGroupsAndProcessQueuedQueries()
757
812
}
758
813
}
759
814
760
- public void generateCpuQuota (long elapsedSeconds )
815
+ public void generateQuotas (long elapsedSeconds )
761
816
{
762
817
synchronized (root ) {
763
818
if (elapsedSeconds > 0 ) {
764
- internalGenerateCpuQuota (elapsedSeconds );
819
+ internalGenerateQuotas (elapsedSeconds );
765
820
}
766
821
}
767
822
}
@@ -784,12 +839,12 @@ private void queryFinished(ManagedQueryExecution query)
784
839
785
840
// The query is present in runningQueries
786
841
if (lastUsage != null ) {
787
- // CPU is measured cumulatively (i.e. total CPU used until this moment by the query). Memory is measured
788
- // instantaneously (how much memory the query is using at this moment). At query completion, memory usage
789
- // drops to zero.
842
+ // CPU and data scan are measured cumulatively (i.e. total CPU & physical input data used until this moment by the query).
843
+ // Memory is measured instantaneously (how much memory the query is using at this moment). At query completion, memory usage drops to zero.
790
844
ResourceUsage finalUsage = new ResourceUsage (
791
845
query .getTotalCpuTime ().toMillis (),
792
- 0L );
846
+ 0L ,
847
+ query .getBasicQueryInfo ().getQueryStats ().getPhysicalInputDataSize ().toBytes ());
793
848
ResourceUsage delta = finalUsage .subtract (lastUsage );
794
849
795
850
runningQueries .remove (query );
@@ -827,15 +882,16 @@ private ResourceUsage updateResourceUsageAndGetDelta()
827
882
{
828
883
checkState (Thread .holdsLock (root ), "Must hold lock to refresh stats" );
829
884
synchronized (root ) {
830
- ResourceUsage groupUsageDelta = new ResourceUsage (0 , 0 );
885
+ ResourceUsage groupUsageDelta = new ResourceUsage (0 , 0 , 0 );
831
886
832
887
for (Map .Entry <ManagedQueryExecution , ResourceUsage > entry : runningQueries .entrySet ()) {
833
888
ManagedQueryExecution query = entry .getKey ();
834
889
ResourceUsage oldResourceUsage = entry .getValue ();
835
890
836
891
ResourceUsage newResourceUsage = new ResourceUsage (
837
892
query .getTotalCpuTime ().toMillis (),
838
- query .getTotalMemoryReservation ().toBytes ());
893
+ query .getTotalMemoryReservation ().toBytes (),
894
+ query .getBasicQueryInfo ().getQueryStats ().getPhysicalInputDataSize ().toBytes ());
839
895
840
896
// Compute delta and update usage
841
897
ResourceUsage queryUsageDelta = newResourceUsage .subtract (oldResourceUsage );
@@ -850,7 +906,7 @@ private ResourceUsage updateResourceUsageAndGetDelta()
850
906
groupUsageDelta = groupUsageDelta .add (subGroupUsageDelta );
851
907
cachedResourceUsage = cachedResourceUsage .add (subGroupUsageDelta );
852
908
853
- if (!subGroupUsageDelta .equals (new ResourceUsage (0 , 0 ))) {
909
+ if (!subGroupUsageDelta .equals (new ResourceUsage (0 , 0 , 0 ))) {
854
910
subGroup .updateEligibility ();
855
911
}
856
912
}
@@ -859,32 +915,40 @@ private ResourceUsage updateResourceUsageAndGetDelta()
859
915
}
860
916
}
861
917
862
- private void internalGenerateCpuQuota (long elapsedSeconds )
918
+ private void internalGenerateQuotas (long elapsedSeconds )
863
919
{
864
- checkState (Thread .holdsLock (root ), "Must hold lock to generate cpu quota " );
920
+ checkState (Thread .holdsLock (root ), "Must hold lock to generate quotas " );
865
921
synchronized (root ) {
866
- long newQuota = saturatedMultiply (elapsedSeconds , cpuQuotaGenerationMillisPerSecond );
867
-
868
- long oldUsageMillis = cachedResourceUsage .getCpuUsageMillis ();
869
- long newCpuUsageMillis = saturatedSubtract (oldUsageMillis , newQuota );
922
+ long oldCpuUsageMillis = cachedResourceUsage .getCpuUsageMillis ();
923
+ long oldDataScanBytes = cachedResourceUsage .getPhysicalInputDataUsageBytes ();
870
924
871
- if (newCpuUsageMillis < 0 || newCpuUsageMillis == Long .MAX_VALUE ) {
872
- newCpuUsageMillis = 0 ;
873
- }
874
-
875
- cachedResourceUsage = new ResourceUsage (newCpuUsageMillis , cachedResourceUsage .getMemoryUsageBytes ());
925
+ long newCpuUsageMillis = computeNewUsage (oldCpuUsageMillis , elapsedSeconds , cpuQuotaGenerationMillisPerSecond );
926
+ long newDataScanBytes = computeNewUsage (oldDataScanBytes , elapsedSeconds , physicalDataScanQuotaGenerationBytesPerSecond );
927
+ cachedResourceUsage = new ResourceUsage (newCpuUsageMillis , cachedResourceUsage .getMemoryUsageBytes (), newDataScanBytes );
876
928
877
- if ((newCpuUsageMillis < hardCpuLimitMillis && oldUsageMillis >= hardCpuLimitMillis ) ||
878
- (newCpuUsageMillis < softCpuLimitMillis && oldUsageMillis >= softCpuLimitMillis )) {
929
+ if ((newCpuUsageMillis < hardCpuLimitMillis && oldCpuUsageMillis >= hardCpuLimitMillis ) ||
930
+ (newCpuUsageMillis < softCpuLimitMillis && oldCpuUsageMillis >= softCpuLimitMillis ) ||
931
+ (newDataScanBytes < hardPhysicalDataScanLimitBytes && oldDataScanBytes >= hardPhysicalDataScanLimitBytes )) {
879
932
updateEligibility ();
880
933
}
881
934
882
935
for (InternalResourceGroup group : subGroups .values ()) {
883
- group .internalGenerateCpuQuota (elapsedSeconds );
936
+ group .internalGenerateQuotas (elapsedSeconds );
884
937
}
885
938
}
886
939
}
887
940
941
+ private static long computeNewUsage (long currentUsage , long elapsedSeconds , long generationRate )
942
+ {
943
+ long quotaToRegenerate = saturatedMultiply (elapsedSeconds , generationRate );
944
+ long newUsage = saturatedSubtract (currentUsage , quotaToRegenerate );
945
+
946
+ if (newUsage < 0 || newUsage == Long .MAX_VALUE ) {
947
+ newUsage = 0 ;
948
+ }
949
+ return newUsage ;
950
+ }
951
+
888
952
private boolean internalStartNext ()
889
953
{
890
954
checkState (Thread .holdsLock (root ), "Must hold lock to find next query" );
@@ -996,8 +1060,8 @@ private boolean canRunMore()
996
1060
synchronized (root ) {
997
1061
long cpuUsageMillis = cachedResourceUsage .getCpuUsageMillis ();
998
1062
long memoryUsageBytes = cachedResourceUsage .getMemoryUsageBytes ();
999
-
1000
- if ((cpuUsageMillis >= hardCpuLimitMillis ) || (memoryUsageBytes > softMemoryLimitBytes )) {
1063
+ long physicalInputDataUsageBytes = cachedResourceUsage . getPhysicalInputDataUsageBytes ();
1064
+ if ((cpuUsageMillis >= hardCpuLimitMillis ) || (memoryUsageBytes > softMemoryLimitBytes ) || ( physicalInputDataUsageBytes >= hardPhysicalDataScanLimitBytes ) ) {
1001
1065
return false ;
1002
1066
}
1003
1067
0 commit comments