@@ -856,6 +856,9 @@ object StateStore extends Logging {
856
856
857
857
private val maintenanceThreadPoolLock = new Object
858
858
859
+ private val providersQueueLock = new Object
860
+
861
+ @ GuardedBy (" providersQueueLock" )
859
862
private val unloadedProvidersToClose =
860
863
new ConcurrentLinkedQueue [(StateStoreProviderId , StateStoreProvider )]
861
864
@@ -1162,17 +1165,19 @@ object StateStore extends Logging {
1162
1165
// Wait until this partition can be processed
1163
1166
private def awaitProcessThisPartition (
1164
1167
id : StateStoreProviderId ,
1165
- timeoutMs : Long
1166
- ) : Boolean = maintenanceThreadPoolLock synchronized {
1167
- val endTime = System .currentTimeMillis() + timeoutMs
1168
+ timeoutMs : Long ) : Boolean = maintenanceThreadPoolLock synchronized {
1169
+ val startTime = System .currentTimeMillis()
1170
+ val endTime = startTime + timeoutMs
1168
1171
1169
1172
// If immediate processing fails, wait with timeout
1170
1173
var canProcessThisPartition = processThisPartition(id)
1171
1174
while (! canProcessThisPartition && System .currentTimeMillis() < endTime) {
1172
1175
canProcessThisPartition = processThisPartition(id)
1173
1176
maintenanceThreadPoolLock.wait(timeoutMs)
1174
1177
}
1175
-
1178
+ val elapsedTime = System .currentTimeMillis() - startTime
1179
+ logInfo(log " Waited for ${MDC (LogKeys .TOTAL_TIME , elapsedTime)} ms to be able to process " +
1180
+ log " maintenance for partition ${MDC (LogKeys .STATE_STORE_PROVIDER_ID , id)}" )
1176
1181
canProcessThisPartition
1177
1182
}
1178
1183
@@ -1189,20 +1194,34 @@ object StateStore extends Logging {
1189
1194
}
1190
1195
1191
1196
// Providers that couldn't be processed now and need to be added back to the queue
1192
- val providersToRequeue = new ArrayBuffer [(StateStoreProviderId , StateStoreProvider )]()
1193
-
1194
- while (! unloadedProvidersToClose.isEmpty) {
1195
- val (providerId, provider) = unloadedProvidersToClose.poll()
1197
+ val providersToRequeue = ArrayBuffer .empty[(StateStoreProviderId , StateStoreProvider )]
1198
+
1199
+ // Create a temporary list and drain the concurrent queue into it under a lock
1200
+ val tempList = providersQueueLock synchronized {
1201
+ val items = ArrayBuffer .empty[(StateStoreProviderId , StateStoreProvider )]
1202
+ while (! unloadedProvidersToClose.isEmpty) {
1203
+ val item = unloadedProvidersToClose.poll()
1204
+ items += item
1205
+ }
1206
+ items
1207
+ }
1196
1208
1209
+ // Process all items in the temporary list
1210
+ tempList.foreach { case (providerId, provider) =>
1197
1211
if (processThisPartition(providerId)) {
1198
1212
submitMaintenanceWorkForProvider(
1199
1213
providerId, provider, storeConf, MaintenanceTaskType .FromMaintenanceQueue )
1200
1214
} else {
1201
- providersToRequeue += (providerId, provider)
1215
+ providersToRequeue += (( providerId, provider) )
1202
1216
}
1203
1217
}
1204
1218
1205
- providersToRequeue.foreach(unloadedProvidersToClose.offer)
1219
+ providersQueueLock synchronized {
1220
+ // Add providers that couldn't be processed back to the original queue
1221
+ providersToRequeue.foreach { providerPair =>
1222
+ unloadedProvidersToClose.offer(providerPair)
1223
+ }
1224
+ }
1206
1225
1207
1226
loadedProviders.synchronized {
1208
1227
loadedProviders.toSeq
@@ -1239,7 +1258,9 @@ object StateStore extends Logging {
1239
1258
val ableToProcessNow = awaitProcessThisPartition(id, timeoutMs)
1240
1259
if (! ableToProcessNow) {
1241
1260
// Add to queue for later processing if we can't process now
1242
- unloadedProvidersToClose.add((id, provider))
1261
+ providersQueueLock synchronized {
1262
+ unloadedProvidersToClose.offer((id, provider))
1263
+ }
1243
1264
}
1244
1265
ableToProcessNow
1245
1266
@@ -1249,6 +1270,8 @@ object StateStore extends Logging {
1249
1270
true
1250
1271
1251
1272
case FromLoadedProviders =>
1273
+ // Provider from loadedProviders can be processed immediately
1274
+ // as it's in maintenancePartitions
1252
1275
true
1253
1276
}
1254
1277
0 commit comments