21
21
import com .google .common .annotations .VisibleForTesting ;
22
22
import com .google .common .base .Preconditions ;
23
23
import java .util .Map ;
24
+ import java .util .Set ;
24
25
import org .apache .pinot .common .concurrency .AdjustableSemaphore ;
25
26
import org .apache .pinot .spi .config .provider .PinotClusterConfigChangeListener ;
26
27
import org .apache .pinot .spi .utils .CommonConstants ;
@@ -36,87 +37,146 @@ public class SegmentPreprocessThrottler implements PinotClusterConfigChangeListe
36
37
private static final Logger LOGGER = LoggerFactory .getLogger (SegmentPreprocessThrottler .class );
37
38
38
39
/**
39
- * _maxPreprocessConcurrency must be >= 0. To effectively disable throttling, this can be set to a very high value
40
+ * _maxPreprocessConcurrency and _maxConcurrentPreprocessesBeforeServingQueries must be >= 0. To effectively disable
41
+ * throttling, this can be set to a very high value
40
42
*/
41
43
private int _maxPreprocessConcurrency ;
44
+ private int _maxPreprocessConcurrencyBeforeServingQueries ;
42
45
private boolean _relaxThrottling ;
43
46
private final AdjustableSemaphore _semaphore ;
44
47
45
48
/**
46
49
* @param maxPreprocessConcurrency configured preprocessing concurrency
47
- * @param maxConcurrentPreprocessesBeforeServingQueries configured preprocessing concurrency before serving queries
50
+ * @param maxPreprocessConcurrencyBeforeServingQueries configured preprocessing concurrency before serving queries
48
51
* @param relaxThrottling whether to relax throttling prior to serving queries
49
52
*/
50
- public SegmentPreprocessThrottler (int maxPreprocessConcurrency , int maxConcurrentPreprocessesBeforeServingQueries ,
53
+ public SegmentPreprocessThrottler (int maxPreprocessConcurrency , int maxPreprocessConcurrencyBeforeServingQueries ,
51
54
boolean relaxThrottling ) {
52
55
LOGGER .info ("Initializing SegmentPreprocessThrottler, maxPreprocessConcurrency: {}, "
53
- + "maxConcurrentPreprocessesBeforeServingQueries : {}, relaxThrottling: {}" ,
54
- maxPreprocessConcurrency , maxConcurrentPreprocessesBeforeServingQueries , relaxThrottling );
56
+ + "maxPreprocessConcurrencyBeforeServingQueries : {}, relaxThrottling: {}" ,
57
+ maxPreprocessConcurrency , maxPreprocessConcurrencyBeforeServingQueries , relaxThrottling );
55
58
Preconditions .checkArgument (maxPreprocessConcurrency > 0 ,
56
- "Max preprocess parallelism must be >= 0, but found to be: " + maxPreprocessConcurrency );
57
- Preconditions .checkArgument (maxConcurrentPreprocessesBeforeServingQueries > 0 ,
58
- "Max preprocess parallelism before serving queries must be >= 0, but found to be: "
59
- + maxConcurrentPreprocessesBeforeServingQueries );
59
+ "Max preprocess parallelism must be > 0, but found to be: " + maxPreprocessConcurrency );
60
+ Preconditions .checkArgument (maxPreprocessConcurrencyBeforeServingQueries > 0 ,
61
+ "Max preprocess parallelism before serving queries must be > 0, but found to be: "
62
+ + maxPreprocessConcurrencyBeforeServingQueries );
60
63
61
64
_maxPreprocessConcurrency = maxPreprocessConcurrency ;
65
+ _maxPreprocessConcurrencyBeforeServingQueries = maxPreprocessConcurrencyBeforeServingQueries ;
62
66
_relaxThrottling = relaxThrottling ;
63
67
64
68
// maxConcurrentPreprocessesBeforeServingQueries is only used prior to serving queries and once the server is
65
69
// ready to serve queries this is not used again. Thus, it is safe to only pick up this configuration during
66
70
// server startup. There is no need to allow updates to this via the ZK CLUSTER config handler
67
- int relaxThrottlingThreshold = Math .max (_maxPreprocessConcurrency , maxConcurrentPreprocessesBeforeServingQueries );
71
+ int relaxThrottlingThreshold = Math .max (_maxPreprocessConcurrency , _maxPreprocessConcurrencyBeforeServingQueries );
68
72
int preprocessConcurrency = _maxPreprocessConcurrency ;
69
73
if (relaxThrottling ) {
70
74
preprocessConcurrency = relaxThrottlingThreshold ;
71
75
LOGGER .info ("Relax throttling enabled, setting preprocess concurrency to: {}" , preprocessConcurrency );
72
76
}
73
77
_semaphore = new AdjustableSemaphore (preprocessConcurrency , true );
74
- LOGGER .info ("Created semaphore with available permits: {}" , _semaphore .availablePermits ());
78
+ LOGGER .info ("Created semaphore with total permits: {}, available permits: {}" , totalPermits (),
79
+ availablePermits ());
75
80
}
76
81
77
82
public synchronized void resetThrottling () {
78
- LOGGER .info ("Reset throttling threshold for segment preprocess concurrency, available permits: {}" ,
79
- _semaphore . availablePermits ());
83
+ LOGGER .info ("Reset throttling threshold for segment preprocess concurrency, total permits: {}, available "
84
+ + "permits: {}" , totalPermits (), availablePermits ());
80
85
_relaxThrottling = false ;
81
86
_semaphore .setPermits (_maxPreprocessConcurrency );
82
- LOGGER .info ("Reset throttling completed, new concurrency: {}, available permits: {}" , _maxPreprocessConcurrency ,
83
- _semaphore . availablePermits ());
87
+ LOGGER .info ("Reset throttling completed, new concurrency: {}, total permits: {}, available permits: {}" ,
88
+ _maxPreprocessConcurrency , totalPermits (), availablePermits ());
84
89
}
85
90
86
91
@ Override
87
- public synchronized void onChange (Map <String , String > clusterConfigs ) {
92
+ public synchronized void onChange (Set < String > changedConfigs , Map <String , String > clusterConfigs ) {
88
93
if (clusterConfigs == null || clusterConfigs .isEmpty ()) {
89
94
LOGGER .info ("Skip updating SegmentPreprocessThrottler configs with empty clusterConfigs" );
90
95
return ;
91
96
}
97
+
98
+ if (changedConfigs == null || changedConfigs .isEmpty ()) {
99
+ LOGGER .info ("Skip updating SegmentPreprocessThrottler configs with unchanged clusterConfigs" );
100
+ return ;
101
+ }
102
+
92
103
LOGGER .info ("Updating SegmentPreprocessThrottler configs with latest clusterConfigs" );
104
+ handleMaxPreprocessConcurrencyChange (changedConfigs , clusterConfigs );
105
+ handleMaxPreprocessConcurrencyBeforeServingQueriesChange (changedConfigs , clusterConfigs );
106
+ LOGGER .info ("Updated SegmentPreprocessThrottler configs with latest clusterConfigs, total permits: {}" ,
107
+ totalPermits ());
108
+ }
109
+
110
+ private void handleMaxPreprocessConcurrencyChange (Set <String > changedConfigs , Map <String , String > clusterConfigs ) {
111
+ if (!changedConfigs .contains (CommonConstants .Helix .CONFIG_OF_MAX_SEGMENT_PREPROCESS_PARALLELISM )) {
112
+ LOGGER .info ("changedConfigs list indicates maxPreprocessConcurrency was not updated, skipping updates" );
113
+ return ;
114
+ }
115
+
93
116
String configName = CommonConstants .Helix .CONFIG_OF_MAX_SEGMENT_PREPROCESS_PARALLELISM ;
94
117
String defaultConfigValue = CommonConstants .Helix .DEFAULT_MAX_SEGMENT_PREPROCESS_PARALLELISM ;
95
118
String maxParallelSegmentPreprocessesStr = clusterConfigs .getOrDefault (configName , defaultConfigValue );
96
119
int maxPreprocessConcurrency = Integer .parseInt (maxParallelSegmentPreprocessesStr );
97
120
98
121
if (maxPreprocessConcurrency == _maxPreprocessConcurrency ) {
99
- LOGGER .info ("No ZK update for SegmentPreprocessThrottler, available permits: {}" , _semaphore .availablePermits ());
122
+ LOGGER .info ("No ZK update for maxPreprocessConcurrency {}, total permits: {}" , _maxPreprocessConcurrency ,
123
+ totalPermits ());
100
124
return ;
101
125
}
102
126
103
127
if (maxPreprocessConcurrency <= 0 ) {
104
- LOGGER .warn ("Invalid max preprocess parallelism set: {}, not making change, fix config and try again" ,
128
+ LOGGER .warn ("Invalid maxPreprocessConcurrency set: {}, not making change, fix config and try again" ,
105
129
maxPreprocessConcurrency );
106
130
return ;
107
131
}
108
132
109
- LOGGER .info ("Updated max preprocess parallelism from: {} to: {}" , _maxPreprocessConcurrency ,
133
+ LOGGER .info ("Updated maxPreprocessConcurrency from: {} to: {}" , _maxPreprocessConcurrency ,
110
134
maxPreprocessConcurrency );
111
-
112
135
_maxPreprocessConcurrency = maxPreprocessConcurrency ;
136
+
113
137
if (_relaxThrottling ) {
114
- LOGGER .warn ("Reset throttling has not yet been called, not updating the permits" );
138
+ LOGGER .warn ("Reset throttling hasn't been called yet , not updating the permits with maxPreprocessConcurrency " );
115
139
return ;
116
140
}
117
-
118
141
_semaphore .setPermits (_maxPreprocessConcurrency );
119
- LOGGER .info ("Updated SegmentPreprocessThrottler configs with latest clusterConfigs" );
142
+ }
143
+
144
+ private void handleMaxPreprocessConcurrencyBeforeServingQueriesChange (Set <String > changedConfigs ,
145
+ Map <String , String > clusterConfigs ) {
146
+ if (!changedConfigs .contains (
147
+ CommonConstants .Helix .CONFIG_OF_MAX_SEGMENT_PREPROCESS_PARALLELISM_BEFORE_SERVING_QUERIES )) {
148
+ LOGGER .info ("changedConfigs list indicates maxPreprocessConcurrencyBeforeServingQueries was not updated, "
149
+ + "skipping updates" );
150
+ return ;
151
+ }
152
+
153
+ String configName = CommonConstants .Helix .CONFIG_OF_MAX_SEGMENT_PREPROCESS_PARALLELISM_BEFORE_SERVING_QUERIES ;
154
+ String defaultConfigValue = CommonConstants .Helix .DEFAULT_MAX_SEGMENT_PREPROCESS_PARALLELISM_BEFORE_SERVING_QUERIES ;
155
+ String maxParallelSegmentPreprocessesBeforeServingQueriesStr =
156
+ clusterConfigs .getOrDefault (configName , defaultConfigValue );
157
+ int maxPreprocessConcurrencyBeforeServingQueries =
158
+ Integer .parseInt (maxParallelSegmentPreprocessesBeforeServingQueriesStr );
159
+
160
+ if (maxPreprocessConcurrencyBeforeServingQueries == _maxPreprocessConcurrencyBeforeServingQueries ) {
161
+ LOGGER .info ("No ZK update for maxPreprocessConcurrencyBeforeServingQueries {}, total permits: {}" ,
162
+ _maxPreprocessConcurrencyBeforeServingQueries , totalPermits ());
163
+ return ;
164
+ }
165
+
166
+ if (maxPreprocessConcurrencyBeforeServingQueries <= 0 ) {
167
+ LOGGER .warn ("Invalid maxPreprocessConcurrencyBeforeServingQueries set: {}, not making change, fix config "
168
+ + "and try again" , maxPreprocessConcurrencyBeforeServingQueries );
169
+ return ;
170
+ }
171
+
172
+ LOGGER .info ("Updated maxPreprocessConcurrencyBeforeServingQueries from: {} to: {}" ,
173
+ _maxPreprocessConcurrencyBeforeServingQueries , maxPreprocessConcurrencyBeforeServingQueries );
174
+ _maxPreprocessConcurrencyBeforeServingQueries = maxPreprocessConcurrencyBeforeServingQueries ;
175
+ if (_relaxThrottling ) {
176
+ LOGGER .warn ("maxPreprocessConcurrencyBeforeServingQueries was updated before reset throttling was called, "
177
+ + "updating the permits" );
178
+ _semaphore .setPermits (_maxPreprocessConcurrencyBeforeServingQueries );
179
+ }
120
180
}
121
181
122
182
/**
@@ -144,4 +204,9 @@ public void release() {
144
204
int availablePermits () {
145
205
return _semaphore .availablePermits ();
146
206
}
207
+
208
+ @ VisibleForTesting
209
+ int totalPermits () {
210
+ return _semaphore .getTotalPermits ();
211
+ }
147
212
}
0 commit comments