com.hazelcast.map.impl.querycache.accumulator.AccumulatorScannerTask Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hazelcast.map.impl.querycache.accumulator;
import com.hazelcast.map.impl.MapService;
import com.hazelcast.map.impl.querycache.QueryCacheContext;
import com.hazelcast.map.impl.querycache.publisher.MapPublisherRegistry;
import com.hazelcast.map.impl.querycache.publisher.PartitionAccumulatorRegistry;
import com.hazelcast.map.impl.querycache.publisher.PublisherContext;
import com.hazelcast.map.impl.querycache.publisher.PublisherRegistry;
import com.hazelcast.spi.impl.operationservice.Operation;
import com.hazelcast.spi.impl.NodeEngineImpl;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
/**
* Task for scanning all {@link Accumulator} instances of all {@link com.hazelcast.map.QueryCache}s on this node.
*
* If it finds any event that needs to be published in an accumulator, it creates and sends
* {@link ConsumeAccumulatorOperation} to relevant partitions.
*
* @see ConsumeAccumulatorOperation
*/
public class AccumulatorScannerTask implements Runnable {
private static final int MAX_PROCESSABLE_ACCUMULATOR_COUNT = 10;
private final ScannerConsumer consumer;
private final QueryCacheContext context;
public AccumulatorScannerTask(QueryCacheContext context) {
this.context = context;
this.consumer = new ScannerConsumer();
}
@Override
public void run() {
scanAccumulators();
}
void scanAccumulators() {
PublisherContext publisherContext = context.getPublisherContext();
MapPublisherRegistry mapPublisherRegistry = publisherContext.getMapPublisherRegistry();
Map publisherRegistryMap = mapPublisherRegistry.getAll();
Set> publishers = publisherRegistryMap.entrySet();
for (Map.Entry entry : publishers) {
PublisherRegistry publisherRegistry = entry.getValue();
Map accumulatorRegistryMap = publisherRegistry.getAll();
Set> accumulators = accumulatorRegistryMap.entrySet();
for (Map.Entry accumulatorRegistryEntry : accumulators) {
PartitionAccumulatorRegistry accumulatorRegistry = accumulatorRegistryEntry.getValue();
Map accumulatorMap = accumulatorRegistry.getAll();
for (Map.Entry accumulatorEntry : accumulatorMap.entrySet()) {
Integer partitionId = accumulatorEntry.getKey();
Accumulator accumulator = accumulatorEntry.getValue();
int size = accumulator.size();
if (size > 0) {
consumer.consume(accumulator, partitionId);
}
}
}
}
sendConsumerOperation();
consumer.reset();
}
private void sendConsumerOperation() {
Map> partitionAccumulators = consumer.getPartitionAccumulators();
if (partitionAccumulators == null || partitionAccumulators.isEmpty()) {
return;
}
Set>> entries = partitionAccumulators.entrySet();
for (Map.Entry> entry : entries) {
Integer partitionId = entry.getKey();
Queue accumulators = entry.getValue();
if (accumulators.isEmpty()) {
continue;
}
Operation operation = createConsumerOperation(partitionId, accumulators);
context.getInvokerWrapper().executeOperation(operation);
}
}
private Operation createConsumerOperation(int partitionId, Queue accumulators) {
PublisherContext publisherContext = context.getPublisherContext();
NodeEngineImpl nodeEngine = (NodeEngineImpl) publisherContext.getNodeEngine();
Operation operation = new ConsumeAccumulatorOperation(accumulators, MAX_PROCESSABLE_ACCUMULATOR_COUNT);
operation
.setNodeEngine(nodeEngine)
.setCallerUuid(nodeEngine.getLocalMember().getUuid())
.setPartitionId(partitionId)
.setValidateTarget(false)
.setService(nodeEngine.getService(MapService.SERVICE_NAME));
return operation;
}
/**
* Handles collected accumulators in scanning phase.
*/
private static class ScannerConsumer {
private Map> partitionAccumulators;
ScannerConsumer() {
}
void consume(Accumulator accumulator, int partitionId) {
if (partitionAccumulators == null) {
partitionAccumulators = new HashMap<>();
}
Queue accumulators = partitionAccumulators.get(partitionId);
if (accumulators == null) {
accumulators = new ArrayDeque<>();
partitionAccumulators.put(partitionId, accumulators);
}
accumulators.add(accumulator);
}
Map> getPartitionAccumulators() {
return partitionAccumulators;
}
void reset() {
if (partitionAccumulators != null) {
partitionAccumulators.clear();
}
}
}
}