use of com.hazelcast.internal.partition.PartitionReplica in project hazelcast by hazelcast.
the class MigrationManager method commitMigrationToDestinationAsync.
/**
* Sends a {@link MigrationCommitOperation} to the destination and returns {@code true} if the new partition state
* was applied on the destination.
*/
@SuppressWarnings({ "checkstyle:npathcomplexity", "checkstyle:cyclomaticcomplexity", "checkstyle:methodlength" })
private CompletionStage<Boolean> commitMigrationToDestinationAsync(final MigrationInfo migration) {
PartitionReplica destination = migration.getDestination();
if (destination.isIdentical(node.getLocalMember())) {
if (logger.isFinestEnabled()) {
logger.finest("Shortcutting migration commit, since destination is master. -> " + migration);
}
return CompletableFuture.completedFuture(Boolean.TRUE);
}
Member member = node.getClusterService().getMember(destination.address(), destination.uuid());
if (member == null) {
logger.warning("Cannot commit " + migration + ". Destination " + destination + " is not a member anymore");
return CompletableFuture.completedFuture(Boolean.FALSE);
}
try {
if (logger.isFinestEnabled()) {
logger.finest("Sending migration commit operation to " + destination + " for " + migration);
}
migration.setStatus(MigrationStatus.SUCCESS);
UUID destinationUuid = member.getUuid();
MigrationCommitOperation operation = new MigrationCommitOperation(migration, destinationUuid);
InvocationFuture<Boolean> future = nodeEngine.getOperationService().createInvocationBuilder(SERVICE_NAME, operation, destination.address()).setTryCount(Integer.MAX_VALUE).setCallTimeout(memberHeartbeatTimeoutMillis).invoke();
return future.handleAsync((done, t) -> {
// Inspect commit result;
// - if there's an exception, either retry or fail
// - if result is true then success, otherwise failure
logger.fine("Migration commit response received -> " + migration + ", success: " + done + ", failure: " + t);
if (t != null) {
logMigrationCommitFailure(migration, t);
if (t instanceof OperationTimeoutException || t.getCause() instanceof OperationTimeoutException) {
return COMMIT_RETRY;
}
return COMMIT_FAILURE;
}
return done ? COMMIT_SUCCESS : COMMIT_FAILURE;
}, asyncExecutor).thenComposeAsync(result -> {
switch(result) {
case COMMIT_SUCCESS:
return CompletableFuture.completedFuture(true);
case COMMIT_FAILURE:
return CompletableFuture.completedFuture(false);
case COMMIT_RETRY:
logger.fine("Retrying migration commit for -> " + migration);
return commitMigrationToDestinationAsync(migration);
default:
throw new IllegalArgumentException("Unknown migration commit result: " + result);
}
}, asyncExecutor).handleAsync((result, t) -> {
if (t != null) {
logMigrationCommitFailure(migration, t);
return false;
}
if (logger.isFineEnabled()) {
logger.fine("Migration commit result " + result + " from " + destination + " for " + migration);
}
return result;
}, asyncExecutor);
} catch (Throwable t) {
logMigrationCommitFailure(migration, t);
return CompletableFuture.completedFuture(Boolean.FALSE);
}
}
use of com.hazelcast.internal.partition.PartitionReplica in project hazelcast by hazelcast.
the class MigrationManager method scheduleActiveMigrationFinalization.
/**
* Finalizes the active migration if it is equal to the {@code migrationInfo} or if this node was a backup replica before
* the migration (see {@link FinalizeMigrationOperation}).
* Acquires the partition service lock.
*/
void scheduleActiveMigrationFinalization(final MigrationInfo migrationInfo) {
partitionServiceLock.lock();
try {
MigrationInfo activeMigrationInfo = getActiveMigration(migrationInfo.getPartitionId());
if (migrationInfo.equals(activeMigrationInfo)) {
activeMigrationInfo.setStatus(migrationInfo.getStatus());
if (logger.isFineEnabled()) {
logger.fine("Scheduled finalization of " + activeMigrationInfo);
}
finalizeMigration(activeMigrationInfo);
return;
}
PartitionReplica source = migrationInfo.getSource();
if (source != null && migrationInfo.getSourceCurrentReplicaIndex() > 0 && source.isIdentical(node.getLocalMember())) {
// This is former backup replica owner.
// Former backup owner does not participate in migration transaction, data always copied
// from the primary replica. Former backup replica is not notified about this migration
// until the migration is committed on destination. Active migration is not set
// for this migration.
// This path can be executed multiple times,
// when a periodic update (latest completed migrations or the whole partition table) is received
// and a new migration request is submitted concurrently.
// That's why, migration should be validated by partition table, to determine whether
// this migration finalization is already processed or not.
InternalPartitionImpl partition = partitionStateManager.getPartitionImpl(migrationInfo.getPartitionId());
if (migrationInfo.getStatus() == MigrationStatus.SUCCESS && migrationInfo.getSourceNewReplicaIndex() != partition.getReplicaIndex(source)) {
if (logger.isFinestEnabled()) {
logger.finest("Already finalized " + migrationInfo + " on former backup replica. -> " + partition);
}
return;
}
if (logger.isFineEnabled()) {
logger.fine("Scheduled finalization of " + migrationInfo + " on former backup replica.");
}
finalizeMigration(migrationInfo);
}
} finally {
partitionServiceLock.unlock();
}
}
use of com.hazelcast.internal.partition.PartitionReplica in project hazelcast by hazelcast.
the class PartitionReplicaStateChecker method hasMissingReplicaOwners.
private boolean hasMissingReplicaOwners() {
if (!needsReplicaStateCheck()) {
return false;
}
int memberGroupsSize = partitionStateManager.getMemberGroupsSize();
int replicaCount = Math.min(InternalPartition.MAX_REPLICA_COUNT, memberGroupsSize);
ClusterServiceImpl clusterService = node.getClusterService();
ClusterState clusterState = clusterService.getClusterState();
for (InternalPartition partition : partitionStateManager.getPartitions()) {
for (int index = 0; index < replicaCount; index++) {
PartitionReplica replica = partition.getReplica(index);
if (replica == null) {
if (logger.isFinestEnabled()) {
logger.finest("Missing replica=" + index + " for partitionId=" + partition.getPartitionId());
}
return true;
}
// because to be able to change cluster state, we ensure that there are no ongoing/pending migrations
if (clusterService.getMember(replica.address(), replica.uuid()) == null && (clusterState.isJoinAllowed() || !clusterService.isMissingMember(replica.address(), replica.uuid()))) {
if (logger.isFinestEnabled()) {
logger.finest("Unknown replica owner= " + replica + ", partitionId=" + partition.getPartitionId() + ", replica=" + index);
}
return true;
}
}
}
return false;
}
use of com.hazelcast.internal.partition.PartitionReplica in project hazelcast by hazelcast.
the class PartitionStateManager method initializePartitionAssignments.
/**
* Arranges the partitions if:
* <ul>
* <li>this instance {@link NodeExtension#isStartCompleted()}</li>
* <li>the cluster state allows migrations. See {@link ClusterState#isMigrationAllowed()}</li>
* </ul>
* This will also set the manager state to initialized (if not already) and invoke the
* {@link DefaultPartitionReplicaInterceptor} for all changed replicas which
* will cancel replica synchronizations and increase the partition state version.
*
* @param excludedMembers members which are to be excluded from the new layout
* @return if the new partition was assigned
* @throws HazelcastException if the partition state generator failed to arrange the partitions
*/
boolean initializePartitionAssignments(Set<Member> excludedMembers) {
if (!isPartitionAssignmentAllowed()) {
return false;
}
Collection<MemberGroup> memberGroups = createMemberGroups(excludedMembers);
if (memberGroups.isEmpty()) {
logger.warning("No member group is available to assign partition ownership...");
return false;
}
logger.info("Initializing cluster partition table arrangement...");
PartitionReplica[][] newState = partitionStateGenerator.arrange(memberGroups, partitions);
if (newState.length != partitionCount) {
throw new HazelcastException("Invalid partition count! " + "Expected: " + partitionCount + ", Actual: " + newState.length);
}
for (int partitionId = 0; partitionId < partitionCount; partitionId++) {
InternalPartitionImpl partition = partitions[partitionId];
PartitionReplica[] replicas = newState[partitionId];
partition.setReplicas(replicas);
}
ClusterState clusterState = node.getClusterService().getClusterState();
if (!clusterState.isMigrationAllowed()) {
// cluster state is either changed or locked, reset state back and fail.
reset();
logger.warning("Partitions can't be assigned since cluster-state= " + clusterState);
return false;
}
setInitialized();
return true;
}
use of com.hazelcast.internal.partition.PartitionReplica in project hazelcast by hazelcast.
the class PartitionStateManager method setInitialState.
/**
* Sets the initial partition table and state version. If any partition has a replica, the partition state manager is
* set to initialized, otherwise {@link #isInitialized()} stays uninitialized but the current state will be updated
* nevertheless.
*
* @param partitionTable the initial partition table
* @throws IllegalStateException if the partition manager has already been initialized
*/
void setInitialState(PartitionTableView partitionTable) {
if (initialized) {
throw new IllegalStateException("Partition table is already initialized!");
}
logger.info("Setting cluster partition table...");
boolean foundReplica = false;
PartitionReplica localReplica = PartitionReplica.from(node.getLocalMember());
for (int partitionId = 0; partitionId < partitionCount; partitionId++) {
InternalPartitionImpl partition = partitions[partitionId];
InternalPartition newPartition = partitionTable.getPartition(partitionId);
if (!foundReplica && newPartition != null) {
for (int i = 0; i < InternalPartition.MAX_REPLICA_COUNT; i++) {
foundReplica |= newPartition.getReplica(i) != null;
}
}
partition.reset(localReplica);
if (newPartition != null) {
partition.setReplicasAndVersion(newPartition);
}
}
if (foundReplica) {
setInitialized();
}
}
Aggregations