Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.spi.impl.operationexecutor.impl;
import com.hazelcast.cluster.Address;
import com.hazelcast.instance.impl.NodeExtension;
import com.hazelcast.internal.metrics.MetricsRegistry;
import com.hazelcast.internal.metrics.Probe;
import com.hazelcast.internal.metrics.StaticMetricsProvider;
import com.hazelcast.internal.nio.Packet;
import com.hazelcast.internal.util.ThreadAffinity;
import com.hazelcast.internal.util.concurrent.IdleStrategy;
import com.hazelcast.internal.util.concurrent.MPSCQueue;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.LoggingService;
import com.hazelcast.spi.impl.PartitionSpecificRunnable;
import com.hazelcast.spi.impl.operationexecutor.OperationExecutor;
import com.hazelcast.spi.impl.operationexecutor.OperationHostileThread;
import com.hazelcast.spi.impl.operationexecutor.OperationRunner;
import com.hazelcast.spi.impl.operationexecutor.OperationRunnerFactory;
import com.hazelcast.spi.impl.operationservice.LiveOperations;
import com.hazelcast.spi.impl.operationservice.Operation;
import com.hazelcast.spi.impl.operationservice.PartitionTaskFactory;
import com.hazelcast.spi.impl.operationservice.UrgentSystemOperation;
import com.hazelcast.spi.impl.operationservice.impl.operations.Backup;
import com.hazelcast.spi.properties.HazelcastProperties;
import com.hazelcast.spi.properties.HazelcastProperty;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.BitSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_COMPLETED_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_GENERIC_PRIORITY_QUEUE_SIZE;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_GENERIC_QUEUE_SIZE;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_GENERIC_THREAD_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_PARTITION_THREAD_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_PRIORITY_QUEUE_SIZE;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_QUEUE_SIZE;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_RUNNING_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_RUNNING_GENERIC_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_METRIC_EXECUTOR_RUNNING_PARTITION_COUNT;
import static com.hazelcast.internal.metrics.MetricDescriptorConstants.OPERATION_PREFIX;
import static com.hazelcast.internal.metrics.ProbeLevel.MANDATORY;
import static com.hazelcast.internal.util.ThreadAffinity.newSystemThreadAffinity;
import static com.hazelcast.internal.util.Preconditions.checkNotNull;
import static com.hazelcast.internal.util.ThreadUtil.createThreadPoolName;
import static com.hazelcast.spi.impl.operationservice.impl.InboundResponseHandlerSupplier.getIdleStrategy;
import static com.hazelcast.spi.properties.ClusterProperty.GENERIC_OPERATION_THREAD_COUNT;
import static com.hazelcast.spi.properties.ClusterProperty.PARTITION_COUNT;
import static com.hazelcast.spi.properties.ClusterProperty.PARTITION_OPERATION_THREAD_COUNT;
import static com.hazelcast.spi.properties.ClusterProperty.PRIORITY_GENERIC_OPERATION_THREAD_COUNT;
import static java.util.concurrent.TimeUnit.SECONDS;
/**
* An {@link OperationExecutor} that schedules:
*
*
partition-specific operations to a specific-partition operation thread (using a mod on the partition ID)
*
non-specific operations to generic operation threads
*
* The {@link #execute(Object, int, boolean)} accepts an Object instead of a runnable to prevent needing to
* create wrapper Runnables around tasks. This is done to reduce the amount of object litter and therefore
* reduce the pressure on the GC.
*
* There are 2 categories of operation threads:
*
*
partition-specific operation threads: these threads are responsible for executing e.g. a {@code map.put()}.
* Operations for the same partition always end up in the same thread.
*
*
* generic operation threads: these threads are responsible for executing operations that are not
* specific to a partition, e.g. a heart beat.
*
*
*/
@SuppressWarnings("checkstyle:methodcount")
public final class OperationExecutorImpl implements OperationExecutor, StaticMetricsProvider {
private static final HazelcastProperty IDLE_STRATEGY
= new HazelcastProperty("hazelcast.operation.partitionthread.idlestrategy", "block");
private static final int TERMINATION_TIMEOUT_SECONDS = 3;
private final ThreadAffinity threadAffinity = newSystemThreadAffinity("hazelcast.operation.thread.affinity");
private final ILogger logger;
// all operations for specific partitions will be executed on these threads, e.g. map.put(key, value)
private final PartitionOperationThread[] partitionThreads;
private final OperationRunner[] partitionOperationRunners;
private final OperationQueue genericQueue
= new OperationQueueImpl(new LinkedBlockingQueue<>(), new LinkedBlockingQueue<>());
// all operations that are not specific for a partition will be executed here, e.g. heartbeat or map.size()
private final GenericOperationThread[] genericThreads;
private final OperationRunner[] genericOperationRunners;
private final Address thisAddress;
private final OperationRunner adHocOperationRunner;
private final int priorityThreadCount;
public OperationExecutorImpl(HazelcastProperties properties,
LoggingService loggerService,
Address thisAddress,
OperationRunnerFactory runnerFactory,
NodeExtension nodeExtension,
String hzName,
ClassLoader configClassLoader) {
this.thisAddress = thisAddress;
this.logger = loggerService.getLogger(OperationExecutorImpl.class);
this.adHocOperationRunner = runnerFactory.createAdHocRunner();
this.partitionOperationRunners = initPartitionOperationRunners(properties, runnerFactory);
this.partitionThreads = initPartitionThreads(properties, hzName, nodeExtension, configClassLoader);
this.priorityThreadCount = properties.getInteger(PRIORITY_GENERIC_OPERATION_THREAD_COUNT);
this.genericOperationRunners = initGenericOperationRunners(properties, runnerFactory);
this.genericThreads = initGenericThreads(hzName, nodeExtension, configClassLoader);
}
private OperationRunner[] initPartitionOperationRunners(HazelcastProperties properties,
OperationRunnerFactory runnerFactory) {
OperationRunner[] operationRunners = new OperationRunner[properties.getInteger(PARTITION_COUNT)];
for (int partitionId = 0; partitionId < operationRunners.length; partitionId++) {
operationRunners[partitionId] = runnerFactory.createPartitionRunner(partitionId);
}
return operationRunners;
}
private OperationRunner[] initGenericOperationRunners(HazelcastProperties properties, OperationRunnerFactory runnerFactory) {
int threadCount = properties.getInteger(GENERIC_OPERATION_THREAD_COUNT);
OperationRunner[] operationRunners = new OperationRunner[threadCount + priorityThreadCount];
for (int partitionId = 0; partitionId < operationRunners.length; partitionId++) {
operationRunners[partitionId] = runnerFactory.createGenericRunner();
}
return operationRunners;
}
private PartitionOperationThread[] initPartitionThreads(HazelcastProperties properties, String hzName,
NodeExtension nodeExtension, ClassLoader configClassLoader) {
int threadCount = properties.getInteger(PARTITION_OPERATION_THREAD_COUNT);
if (threadAffinity.isEnabled()) {
threadCount = threadAffinity.getThreadCount();
}
IdleStrategy idleStrategy = getIdleStrategy(properties, IDLE_STRATEGY);
PartitionOperationThread[] threads = new PartitionOperationThread[threadCount];
for (int threadId = 0; threadId < threads.length; threadId++) {
String threadName = createThreadPoolName(hzName, "partition-operation") + threadId;
// the normalQueue will be a blocking queue. We don't want to idle, because there are many operation threads.
MPSCQueue