Skip to content

Commit c58680b

Browse files
authored
Subscription: optimize prefetching queue report state overhead (#15664)
* setup * add comments
1 parent a477562 commit c58680b

2 files changed

Lines changed: 63 additions & 4 deletions

File tree

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.Set;
3838
import java.util.concurrent.ConcurrentHashMap;
3939
import java.util.concurrent.atomic.AtomicBoolean;
40+
import java.util.function.Supplier;
4041

4142
public class SubscriptionBrokerAgent {
4243

@@ -45,6 +46,9 @@ public class SubscriptionBrokerAgent {
4546
private final Map<String, SubscriptionBroker> consumerGroupIdToSubscriptionBroker =
4647
new ConcurrentHashMap<>();
4748

49+
private final Cache<Integer> prefetchingQueueCount =
50+
new Cache<>(this::getPrefetchingQueueCountInternal);
51+
4852
//////////////////////////// provided for subscription agent ////////////////////////////
4953

5054
public List<SubscriptionEvent> poll(
@@ -193,6 +197,7 @@ public void bindPrefetchingQueue(final SubscriptionConnectorSubtask subtask) {
193197
return broker;
194198
})
195199
.bindPrefetchingQueue(subtask.getTopicName(), subtask.getInputPendingQueue());
200+
prefetchingQueueCount.invalidate();
196201
}
197202

198203
public void updateCompletedTopicNames(final String consumerGroupId, final String topicName) {
@@ -213,6 +218,7 @@ public void unbindPrefetchingQueue(final String consumerGroupId, final String to
213218
return;
214219
}
215220
broker.unbindPrefetchingQueue(topicName);
221+
prefetchingQueueCount.invalidate();
216222
}
217223

218224
public void removePrefetchingQueue(final String consumerGroupId, final String topicName) {
@@ -223,6 +229,7 @@ public void removePrefetchingQueue(final String consumerGroupId, final String to
223229
return;
224230
}
225231
broker.removePrefetchingQueue(topicName);
232+
prefetchingQueueCount.invalidate();
226233
}
227234

228235
public boolean executePrefetch(final String consumerGroupId, final String topicName) {
@@ -251,8 +258,56 @@ public int getPipeEventCount(final String consumerGroupId, final String topicNam
251258
}
252259

253260
public int getPrefetchingQueueCount() {
261+
return prefetchingQueueCount.get();
262+
}
263+
264+
private int getPrefetchingQueueCountInternal() {
254265
return consumerGroupIdToSubscriptionBroker.values().stream()
255266
.map(SubscriptionBroker::getPrefetchingQueueCount)
256267
.reduce(0, Integer::sum);
257268
}
269+
270+
/////////////////////////////// Cache ///////////////////////////////
271+
272+
/**
273+
* A simple generic cache that computes and stores a value on demand.
274+
*
275+
* <p>Note that since the get() and invalidate() methods are not modified with synchronized, the
276+
* value obtained may not be entirely accurate.
277+
*
278+
* @param <T> the type of the cached value
279+
*/
280+
private static class Cache<T> {
281+
282+
private T value;
283+
private volatile boolean valid = false;
284+
private final Supplier<T> supplier;
285+
286+
/**
287+
* Construct a cache with a supplier that knows how to compute the value.
288+
*
289+
* @param supplier a Supplier that computes the value when needed
290+
*/
291+
private Cache(final Supplier<T> supplier) {
292+
this.supplier = supplier;
293+
}
294+
295+
/** Invalidate the cache. The next call to get() will recompute the value. */
296+
private void invalidate() {
297+
valid = false;
298+
}
299+
300+
/**
301+
* Return the cached value, recomputing it if the cache is invalid.
302+
*
303+
* @return the current value, recomputed if necessary
304+
*/
305+
private T get() {
306+
if (!valid) {
307+
value = supplier.get();
308+
valid = true;
309+
}
310+
return value;
311+
}
312+
}
258313
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.apache.iotdb.db.subscription.agent.SubscriptionAgent;
3131
import org.apache.iotdb.db.subscription.event.SubscriptionEvent;
3232
import org.apache.iotdb.db.subscription.event.batch.SubscriptionPipeEventBatches;
33-
import org.apache.iotdb.db.subscription.resource.SubscriptionDataNodeResourceManager;
3433
import org.apache.iotdb.db.subscription.task.subtask.SubscriptionReceiverSubtask;
3534
import org.apache.iotdb.pipe.api.event.Event;
3635
import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent;
@@ -101,6 +100,8 @@ public abstract class SubscriptionPrefetchingQueue {
101100

102101
private final SubscriptionPrefetchingQueueStates states;
103102

103+
private long lastStateReportTimestamp = System.currentTimeMillis();
104+
104105
private volatile boolean isCompleted = false;
105106
private volatile boolean isClosed = false;
106107

@@ -283,9 +284,12 @@ public boolean executePrefetch() {
283284
}
284285

285286
private void reportStateIfNeeded() {
286-
SubscriptionDataNodeResourceManager.log()
287-
.schedule(SubscriptionPrefetchingQueue.class, brokerId, topicName)
288-
.ifPresent(l -> l.info("Subscription: SubscriptionPrefetchingQueue state {}", this));
287+
if (System.currentTimeMillis() - lastStateReportTimestamp
288+
> SubscriptionConfig.getInstance().getSubscriptionLogManagerBaseIntervalMs()
289+
* SubscriptionAgent.broker().getPrefetchingQueueCount()) {
290+
LOGGER.info("Subscription: SubscriptionPrefetchingQueue state {}", this);
291+
lastStateReportTimestamp = System.currentTimeMillis();
292+
}
289293
}
290294

291295
@SafeVarargs

0 commit comments

Comments
 (0)