/*
* Copyright (c) 2008-2017, 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.internal.partition.InternalPartition;
import com.hazelcast.internal.partition.InternalPartitionService;
import com.hazelcast.internal.partition.NonFragmentedServiceNamespace;
import com.hazelcast.internal.partition.MigrationInfo;
import com.hazelcast.internal.partition.impl.InternalPartitionServiceImpl;
import com.hazelcast.internal.partition.impl.PartitionDataSerializerHook;
import com.hazelcast.nio.Address;
import com.hazelcast.spi.MigrationAwareService;
import com.hazelcast.spi.NodeEngine;
import com.hazelcast.spi.Operation;
import com.hazelcast.spi.PartitionReplicationEvent;
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;
/**
* Migration request operation used before Hazelcast version 3.9
* It runs on the migration source and transfers the whole partition data in one shot.
*/
public final class LegacyMigrationRequestOperation extends BaseMigrationSourceOperation {
public LegacyMigrationRequestOperation() {
}
public LegacyMigrationRequestOperation(MigrationInfo migrationInfo, int partitionStateVersion) {
super(migrationInfo, partitionStateVersion);
}
@Override
public void run() {
verifyMasterOnMigrationSource();
NodeEngine nodeEngine = getNodeEngine();
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);
setActiveMigration();
if (!migrationInfo.startProcessing()) {
getLogger().warning("Migration is cancelled -> " + migrationInfo);
setFailed();
return;
}
try {
executeBeforeMigrations();
Collection<Operation> tasks = prepareMigrationOperations();
InternalPartitionServiceImpl partitionService = getService();
long[] replicaVersions = partitionService.getPartitionReplicaVersionManager()
.getPartitionReplicaVersions(migrationInfo.getPartitionId(), NonFragmentedServiceNamespace.INSTANCE);
invokeMigrationOperation(destination, replicaVersions, tasks);
returnResponse = false;
} catch (Throwable e) {
logThrowable(e);
setFailed();
} finally {
migrationInfo.doneProcessing();
}
}
private void invokeMigrationOperation(Address destination, long[] replicaVersions, Collection<Operation> tasks)
throws IOException {
LegacyMigrationOperation operation =
new LegacyMigrationOperation(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 Collection<Operation> prepareMigrationOperations() {
NodeEngineImpl nodeEngine = (NodeEngineImpl) getNodeEngine();
PartitionReplicationEvent replicationEvent = getPartitionReplicationEvent();
Collection<Operation> tasks = new LinkedList<Operation>();
for (ServiceInfo serviceInfo : nodeEngine.getServiceInfos(MigrationAwareService.class)) {
MigrationAwareService service = serviceInfo.getService();
Operation op = service.prepareReplicationOperation(replicationEvent);
if (op != null) {
op.setServiceName(serviceInfo.getName());
tasks.add(op);
}
}
return tasks;
}
@Override
public int getId() {
return PartitionDataSerializerHook.LEGACY_MIGRATION_REQUEST;
}
private static final class MigrationCallback extends SimpleExecutionCallback<Object> {
final MigrationInfo migrationInfo;
final LegacyMigrationRequestOperation op;
private MigrationCallback(MigrationInfo migrationInfo, LegacyMigrationRequestOperation op) {
this.migrationInfo = migrationInfo;
this.op = op;
}
@Override
public void notify(Object result) {
op.completeMigration(Boolean.TRUE.equals(result));
}
}
}