
com.hazelcast.internal.partition.operation.MigrationRequestOperation Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2016, 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.internal.partition.operation;
import com.hazelcast.core.Member;
import com.hazelcast.core.MemberLeftException;
import com.hazelcast.internal.partition.InternalPartition;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.internal.partition.MigrationInfo;
import com.hazelcast.internal.partition.impl.InternalMigrationListener.MigrationParticipant;
import com.hazelcast.internal.partition.impl.InternalPartitionServiceImpl;
import com.hazelcast.nio.Address;
import com.hazelcast.internal.partition.impl.MigrationManager;
import com.hazelcast.spi.partition.MigrationEndpoint;
import com.hazelcast.spi.ExceptionAction;
import com.hazelcast.spi.MigrationAwareService;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.PartitionMigrationEvent;
import com.hazelcast.spi.PartitionReplicationEvent;
import com.hazelcast.spi.exception.RetryableHazelcastException;
import com.hazelcast.spi.exception.TargetNotMemberException;
import com.hazelcast.spi.impl.NodeEngineImpl;
import com.hazelcast.spi.impl.SimpleExecutionCallback;
import com.hazelcast.spi.impl.servicemanager.ServiceInfo;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
public final class MigrationRequestOperation extends BaseMigrationOperation {
private boolean returnResponse = true;
public MigrationRequestOperation() {
}
public MigrationRequestOperation(MigrationInfo migrationInfo, int partitionStateVersion) {
super(migrationInfo, partitionStateVersion);
}
@Override
public void run() {
NodeEngine nodeEngine = getNodeEngine();
verifyGoodMaster(nodeEngine);
Address source = migrationInfo.getSource();
Address destination = migrationInfo.getDestination();
verifyExistingTarget(nodeEngine, destination);
if (destination.equals(source)) {
getLogger().warning("Source and destination addresses are the same! => " + toString());
setFailed();
return;
}
InternalPartition partition = getPartition();
verifySource(nodeEngine.getThisAddress(), partition);
if (!migrationInfo.startProcessing()) {
getLogger().warning("Migration is cancelled -> " + migrationInfo);
setFailed();
return;
}
InternalPartitionServiceImpl partitionService = getService();
MigrationManager migrationManager = partitionService.getMigrationManager();
if (!migrationManager.addActiveMigration(migrationInfo)) {
setFailed();
return;
}
try {
Collection tasks = prepareMigrationOperations();
long[] replicaVersions = partitionService.getPartitionReplicaVersions(migrationInfo.getPartitionId());
invokeMigrationOperation(destination, replicaVersions, tasks);
returnResponse = false;
} catch (Throwable e) {
logThrowable(e);
setFailed();
} finally {
migrationInfo.doneProcessing();
}
}
private void setFailed() {
success = false;
onMigrationComplete(false);
}
@Override
protected MigrationParticipant getMigrationParticipantType() {
return MigrationParticipant.SOURCE;
}
private void logThrowable(Throwable t) {
Throwable throwableToLog = t;
if (throwableToLog instanceof ExecutionException) {
throwableToLog = throwableToLog.getCause() != null ? throwableToLog.getCause() : throwableToLog;
}
Level level = getLogLevel(throwableToLog);
getLogger().log(level, throwableToLog.getMessage(), throwableToLog);
}
private Level getLogLevel(Throwable e) {
return (e instanceof MemberLeftException || e instanceof InterruptedException)
|| !getNodeEngine().isRunning() ? Level.INFO : Level.WARNING;
}
private void verifySource(Address thisAddress, InternalPartition partition) {
Address owner = partition.getOwnerOrNull();
if (owner == null) {
throw new RetryableHazelcastException("Cannot migrate at the moment! Owner of the partition is null => "
+ migrationInfo);
}
if (!thisAddress.equals(owner)) {
throw new RetryableHazelcastException("Owner of partition is not this node! => " + toString());
}
}
private void invokeMigrationOperation(Address destination, long[] replicaVersions, Collection tasks)
throws IOException {
MigrationOperation operation = new MigrationOperation(migrationInfo, replicaVersions, tasks, partitionStateVersion);
NodeEngine nodeEngine = getNodeEngine();
InternalPartitionServiceImpl partitionService = getService();
nodeEngine.getOperationService()
.createInvocationBuilder(InternalPartitionService.SERVICE_NAME, operation, destination)
.setExecutionCallback(new MigrationCallback(migrationInfo, this))
.setResultDeserialized(true)
.setCallTimeout(partitionService.getPartitionMigrationTimeout())
.setTryCount(InternalPartitionService.MIGRATION_RETRY_COUNT)
.setTryPauseMillis(InternalPartitionService.MIGRATION_RETRY_PAUSE)
.setReplicaIndex(getReplicaIndex())
.invoke();
}
private void verifyGoodMaster(NodeEngine nodeEngine) {
Address masterAddress = nodeEngine.getMasterAddress();
if (!masterAddress.equals(migrationInfo.getMaster())) {
throw new RetryableHazelcastException("Migration initiator is not master node! => " + toString());
}
if (!masterAddress.equals(getCallerAddress())) {
throw new RetryableHazelcastException("Caller is not master node! => " + toString());
}
}
private void verifyExistingTarget(NodeEngine nodeEngine, Address destination) {
Member target = nodeEngine.getClusterService().getMember(destination);
if (target == null) {
throw new TargetNotMemberException("Destination of migration could not be found! => " + toString());
}
}
@Override
public ExceptionAction onInvocationException(Throwable throwable) {
if (throwable instanceof TargetNotMemberException) {
return ExceptionAction.THROW_EXCEPTION;
}
return super.onInvocationException(throwable);
}
@Override
public boolean returnsResponse() {
return returnResponse;
}
public void handleMigrationResultFromTarget(Object result) {
migrationInfo.doneProcessing();
onMigrationComplete(Boolean.TRUE.equals(result));
sendResponse(result);
}
private Collection prepareMigrationOperations() {
NodeEngineImpl nodeEngine = (NodeEngineImpl) getNodeEngine();
PartitionReplicationEvent replicationEvent = new PartitionReplicationEvent(migrationInfo.getPartitionId(),
migrationInfo.getDestinationNewReplicaIndex());
boolean ownerMigration = nodeEngine.getThisAddress().equals(migrationInfo.getSource());
PartitionMigrationEvent migrationEvent = null;
if (ownerMigration) {
migrationEvent = new PartitionMigrationEvent(MigrationEndpoint.SOURCE, migrationInfo.getPartitionId(),
migrationInfo.getSourceCurrentReplicaIndex(), migrationInfo.getSourceNewReplicaIndex());
}
Collection tasks = new LinkedList();
for (ServiceInfo serviceInfo : nodeEngine.getServiceInfos(MigrationAwareService.class)) {
MigrationAwareService service = (MigrationAwareService) serviceInfo.getService();
if (ownerMigration) {
service.beforeMigration(migrationEvent);
}
Operation op = service.prepareReplicationOperation(replicationEvent);
if (op != null) {
op.setServiceName(serviceInfo.getName());
tasks.add(op);
}
}
return tasks;
}
private static final class MigrationCallback extends SimpleExecutionCallback
© 2015 - 2025 Weber Informatics LLC | Privacy Policy