public static String puInstancesToString(Collection<ProcessingUnitInstance> instances) { StringBuilder builder = new StringBuilder(); for (ProcessingUnitInstance instance : instances) { builder.append(RebalancingUtils.puInstanceToString(instance)); builder.append(File.separator); } return builder.toString(); }
static FutureStatefulProcessingUnitInstance relocateProcessingUnitInstanceAsync( final GridServiceContainer targetContainer, final ProcessingUnitInstance puInstance, final Log logger, final long duration, final TimeUnit timeUnit) { final ProcessingUnit pu = puInstance.getProcessingUnit(); final GridServiceContainer[] replicationSourceContainers = getReplicationSourceContainers(puInstance); final int instanceId = puInstance.getInstanceId(); final AtomicReference<Throwable> relocateThrowable = new AtomicReference<Throwable>(); final Admin admin = puInstance.getAdmin(); final int runningNumber = puInstance.getClusterInfo().getRunningNumber(); final String puName = puInstance.getName(); final GridServiceContainer sourceContainer = puInstance.getGridServiceContainer(); final Set<ProcessingUnitInstance> puInstancesFromSamePartition = getOtherInstancesFromSamePartition(puInstance); if (logger.isDebugEnabled()) { logger.debug( "Found instances from the same partition as " + RebalancingUtils.puInstanceToString(puInstance) + " : " + RebalancingUtils.puInstancesToString(puInstancesFromSamePartition)); } if (puInstancesFromSamePartition.size() != pu.getNumberOfBackups()) { // total number of instances per partition = numberOfBackups + 1 throw new IllegalStateException( "puInstancesFromSamePartition has " + puInstancesFromSamePartition.size() + " instances instead of " + pu.getNumberOfBackups()); } final long start = System.currentTimeMillis(); final long end = start + timeUnit.toMillis(duration); ((InternalAdmin) admin) .scheduleAdminOperation( new Runnable() { public void run() { try { logger.debug( "Relocation of " + RebalancingUtils.puInstanceToString(puInstance) + " to " + ContainersSlaUtils.gscToString(targetContainer) + " has started."); puInstance.relocate(targetContainer); } catch (AdminException e) { logger.error("Admin exception " + e.getMessage(), e); relocateThrowable.set(e); } catch (Throwable e) { logger.error("Unexpected exception " + e.getMessage(), e); relocateThrowable.set(e); } } }); return new FutureStatefulProcessingUnitInstance() { Throwable throwable; ProcessingUnitInstance newInstance; public boolean isTimedOut() { return System.currentTimeMillis() > end; } public boolean isDone() { endRelocation(); return isTimedOut() || throwable != null || newInstance != null; } public ProcessingUnitInstance get() throws ExecutionException, IllegalStateException, TimeoutException { endRelocation(); ExecutionException exception = getException(); if (exception != null) { throw exception; } if (newInstance == null) { if (isTimedOut()) { throw new TimeoutException("Relocation timeout"); } throw new IllegalStateException("Async operation is not done yet."); } return newInstance; } public Date getTimestamp() { return new Date(start); } public ExecutionException getException() { endRelocation(); if (throwable != null) { return new ExecutionException(throwable.getMessage(), throwable); } return null; } /** populates this.exception or this.newInstance if relocation is complete */ private void endRelocation() { boolean inProgress = true; tryStateChange(); // this makes relocation synchronous if (newInstance != null || throwable != null) { inProgress = false; } if (inProgress) { if (logger.isDebugEnabled()) { logger.debug( "Relocation from " + ContainersSlaUtils.gscToString(getSourceContainer()) + " to " + ContainersSlaUtils.gscToString(getTargetContainer()) + " is in progress."); } // do nothing. relocate() method running on another thread has not returned yet. } } private void tryStateChange() { ProcessingUnitInstance relocatedInstance = getRelocatedProcessingUnitInstance(); if (relocatedInstance != null) { if (relocatedInstance.getGridServiceContainer().equals(targetContainer)) { if (relocatedInstance.getSpaceInstance() != null && relocatedInstance.getSpaceInstance().getMode() != SpaceMode.NONE) { if (logger.isDebugEnabled()) { logger.debug( "Relocation from " + ContainersSlaUtils.gscToString(getSourceContainer()) + " to " + ContainersSlaUtils.gscToString(getTargetContainer()) + " had ended successfully."); } newInstance = relocatedInstance; } } else { if (logger.isDebugEnabled()) { logger.debug( "Relocation from " + ContainersSlaUtils.gscToString(getSourceContainer()) + " to " + ContainersSlaUtils.gscToString(getTargetContainer()) + " has ended with an error."); } throwable = new WrongContainerProcessingUnitRelocationException(puInstance, targetContainer); } } } private ProcessingUnitInstance getRelocatedProcessingUnitInstance() { for (GridServiceContainer container : admin.getGridServiceContainers()) { for (ProcessingUnitInstance instance : container.getProcessingUnitInstances(puName)) { if (!instance.equals(puInstance) && instance.getClusterInfo().getRunningNumber() == runningNumber && !puInstancesFromSamePartition.contains(instance)) { return instance; } } } return null; } private boolean isAtLeastOneInstanceValid(Set<ProcessingUnitInstance> instances) { boolean isValidState = false; for (ProcessingUnitInstance instance : instances) { if (instance.isDiscovered() && instance.getGridServiceContainer().isDiscovered()) { isValidState = true; break; } } return isValidState; } public String getFailureMessage() { if (isTimedOut()) { return "relocation timeout of processing unit instance " + instanceId + " from " + gscToString(sourceContainer) + " to " + gscToString(targetContainer); } if (getException() != null) { return getException().getMessage(); } throw new IllegalStateException("Relocation has not encountered any failure."); } public GridServiceContainer getTargetContainer() { return targetContainer; } public ProcessingUnit getProcessingUnit() { return pu; } public int getInstanceId() { return instanceId; } public GridServiceContainer getSourceContainer() { return sourceContainer; } public GridServiceContainer[] getReplicaitonSourceContainers() { return replicationSourceContainers; } }; }