All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.ac.ebi.interpro.scan.jms.master.StandaloneBlackBoxMaster Maven / Gradle / Ivy

The newest version!
package uk.ac.ebi.interpro.scan.jms.master;

import org.apache.log4j.Logger;
import org.springframework.jms.listener.DefaultMessageListenerContainer;
import uk.ac.ebi.interpro.scan.jms.stats.StatsUtil;
import uk.ac.ebi.interpro.scan.management.model.implementations.RunBinaryStep;
import uk.ac.ebi.interpro.scan.management.model.implementations.stepInstanceCreation.StepInstanceCreatingStep;
import uk.ac.ebi.interpro.scan.management.model.implementations.WriteOutputStep;
import uk.ac.ebi.interpro.scan.util.Utilities;
import uk.ac.ebi.interpro.scan.management.model.Step;
import uk.ac.ebi.interpro.scan.management.model.StepInstance;
import uk.ac.ebi.interpro.scan.management.model.implementations.WriteFastaFileStep;
import uk.ac.ebi.interpro.scan.management.model.implementations.prosite.RunPsScanStep;

import javax.jms.JMSException;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadFactory;

import java.util.concurrent.TimeUnit;

/**
 * Created with IntelliJ IDEA.
 * User: pjones
 */
public class StandaloneBlackBoxMaster extends AbstractBlackBoxMaster {

    private static final Logger LOGGER = Logger.getLogger(StandaloneBlackBoxMaster.class.getName());

    private StatsUtil statsUtil;

    private DefaultMessageListenerContainer workerQueueJmsContainer;

    private static final int MEGA = 1024 * 1024;

    public StandaloneBlackBoxMaster(DefaultMessageListenerContainer workerQueueJmsContainer) {
        this.workerQueueJmsContainer = workerQueueJmsContainer;
    }

    @Override
    public void run() {
        final long now = System.currentTimeMillis();
        super.run();

        Utilities.verboseLog = verboseLog;
        Utilities.verboseLogLevel = verboseLogLevel;

        int runStatus = 11;
        if(verboseLog) {
            Utilities.verboseLog("DEBUG " + "Available processors: " + Runtime.getRuntime().availableProcessors());
            Utilities.verboseLog("DEBUG " + "Memory free: " + Runtime.getRuntime().freeMemory() / MEGA + "MB total: " + Runtime.getRuntime().totalMemory() / MEGA + "MB max: " + Runtime.getRuntime().maxMemory() / MEGA + "MB");

            System.out.println(Utilities.getTimeNow() + " verboseLog: " + verboseLog + " verboseLogLevel: " + verboseLogLevel);
            System.out.println(Utilities.getTimeNow() + " DEBUG inVmWorkers min:" + getConcurrentInVmWorkerCount() + " max: " + getMaxConcurrentInVmWorkerCount());
            Utilities.verboseLog(10, "temp dir: " + getWorkingTemporaryDirectoryPath());
        }

        Utilities.verboseLog("Old values - inVmWorkers min: " + workerQueueJmsContainer.getConcurrentConsumers() + " max: " + workerQueueJmsContainer.getMaxConcurrentConsumers());

        //if user has specified CPU value

        //need more testing

        if (! (getMaxConcurrentInVmWorkerCount() == workerQueueJmsContainer.getMaxConcurrentConsumers())){
            int minNumberOfCPUCores = getMaxConcurrentInVmWorkerCount();
//            if (getMaxConcurrentInVmWorkerCount() > 4){
//                minNumberOfCPUCores = getMaxConcurrentInVmWorkerCount() / 2;
//            }
//            if (getMaxConcurrentInVmWorkerCount() < getConcurrentInVmWorkerCount()) {
//                minNumberOfCPUCores = getMaxConcurrentInVmWorkerCount();
//            }
            workerQueueJmsContainer.setConcurrentConsumers(minNumberOfCPUCores);
            workerQueueJmsContainer.setMaxConcurrentConsumers(getMaxConcurrentInVmWorkerCount());
            Utilities.verboseLog("minNumberOfCPUCores: " + minNumberOfCPUCores
                    + " MaxConcurrentInVmWorkerCount: " + getMaxConcurrentInVmWorkerCount() );
        }else{
            //set the minconsumercount to value given by user in the properties file
            //TODO check if this is necessary as the container should handle dynamic scaling
            //workerQueueJmsContainer.setConcurrentConsumers(getMaxConcurrentInVmWorkerCount());

            /*
            //the following doesnt work as expected so we will just set max = min
            int minNumberOfCPUCores = getConcurrentInVmWorkerCount();
            if (getMaxConcurrentInVmWorkerCount() > 4){
                minNumberOfCPUCores = getMaxConcurrentInVmWorkerCount() / 2;
                workerQueueJmsContainer.setConcurrentConsumers(minNumberOfCPUCores);
            }
            */
        }



        Utilities.verboseLog("New values - inVmWorkers min: " + workerQueueJmsContainer.getConcurrentConsumers()
                + " max: " + workerQueueJmsContainer.getMaxConcurrentConsumers()
                + " schedlued: " + workerQueueJmsContainer.getScheduledConsumerCount()
                + " active: " + workerQueueJmsContainer.getActiveConsumerCount()  );

        workerQueueJmsContainer.shutdown();
        if(! workerQueueJmsContainer.isRunning()){
            Utilities.verboseLog(" the workerQueueJmsContainer is shutdown ...");
        }
        workerQueueJmsContainer.afterPropertiesSet();
        workerQueueJmsContainer.start();

        Utilities.verboseLog("After Stop Start --- inVmWorkers min: " + workerQueueJmsContainer.getConcurrentConsumers()
                + " max: " + workerQueueJmsContainer.getMaxConcurrentConsumers()
                + " schedlued: " + workerQueueJmsContainer.getScheduledConsumerCount()
                + " active: " + workerQueueJmsContainer.getActiveConsumerCount()  );

        long nowAfterLoadingDatabase = now;
        try {
            loadInMemoryDatabase();
            runStatus = 21;
            nowAfterLoadingDatabase = System.currentTimeMillis();

            int stepInstancesCreatedByLoadStep = createStepInstances();


            //calculate minimum expected jobs

            int minimumStepsExpected = getMinimumStepsExpected();
            runStatus = 31;
            if(verboseLog) {
                System.out.println(Utilities.getTimeNow() + " DEBUG step instances: " + stepInstanceDAO.count());
            }
            //initialise slow steps
            List slowSteps = new ArrayList();
            slowSteps.add("stepPantherRunHmmer3");
            slowSteps.add("stepSMARTRunBinary");
            //slowSteps.add("stepPrositeProfilesRunBinary");
            // If there is an embeddedWorkerFactory (i.e. this Master is running in stand-alone mode)
            // stop running if there are no StepInstances left to complete.
            int allowedWaitTimeMultiplier = 0;
            boolean controlledLogging = false;
            while (!shutdownCalled) {
                boolean completed = true;
                runStatus = 41;
                List unfinshedStepInstances = stepInstanceDAO.retrieveUnfinishedStepInstances();
                for (StepInstance stepInstance : unfinshedStepInstances) {
                    runStatus = 51;

                    if (LOGGER.isTraceEnabled()) {
                        LOGGER.trace("Iterating over StepInstances: Currently on " + stepInstance);
                    }
                    if (stepInstance.hasFailedPermanently(jobs)) {
                        unrecoverableErrorStrategy.failed(stepInstance, jobs);
                    }
                    completed &= stepInstance.haveFinished(jobs);
                    if (stepInstance.canBeSubmitted(jobs) && stepInstanceDAO.serialGroupCanRun(stepInstance, jobs)) {
                        if (LOGGER.isDebugEnabled()) {
                            LOGGER.debug("Step submitted:" + stepInstance);
                        }
                        final boolean resubmission = stepInstance.getExecutions().size() > 0;
                        if (resubmission) {
                            LOGGER.warn("StepInstance " + stepInstance.getId() + " is being re-run following a failure.");
                        }
                        final Step step = stepInstance.getStep(jobs);
                        // Only set up message selectors for high memory requirements if a suitable worker runner has been set up.

                        // Serial groups should be high priority, however exclude WriteFastaFileStep from this
                        // as they are very abundant.
                        // RunPsScanStep should have higher priority as it is slow
                        //isHighPriorityStep(step);
                        int priority;
                        if (step instanceof RunPsScanStep) {
                            priority = HIGHER_PRIORITY;
                        }else if (step.getSerialGroup() == null || step instanceof WriteFastaFileStep){
                            priority = LOW_PRIORITY;
                        }else {
                            priority = HIGH_PRIORITY;
                        }

                        //different rules for priority
                        if(step instanceof WriteFastaFileStep){
                            priority = HIGHEST_PRIORITY;
                        }else if (slowSteps.contains(step.getId())){
                            priority = HIGHER_PRIORITY;
                        }else if (step instanceof RunBinaryStep){
                            priority = HIGH_PRIORITY;
                        }else if (step.getSerialGroup() == null){
                            priority = LOW_PRIORITY;
                        }else {
                            priority = LOW_PRIORITY;
                        }
                        //if inteproscan is onthe last step, watermark this point
                        if (step instanceof WriteOutputStep) {
                            Utilities.verboseLog("Processing WriteOutputStep ..." );
                            StatsUtil.setForceDisplayProgress(true);
                            statsUtil.displayMasterProgress();
                            StatsUtil.setForceDisplayProgress(false);
                        }

                        // Performed in a transaction.
                        if (LOGGER.isDebugEnabled()) {
                            LOGGER.debug("About to send a message for StepInstance: " + stepInstance);
                        }
                        if (this.isExcludeSites()) {
                            stepInstance.addParameter(StepInstanceCreatingStep.EXCLUDE_SITES, Boolean.TRUE.toString());
                        }
                        messageSender.sendMessage(stepInstance, false, priority, false);
                        statsUtil.addToSubmittedStepInstances(stepInstance);
                        controlledLogging = false;
                        statsUtil.addToAllAvailableJobs(stepInstance, "submitted");
                    }else{
                        statsUtil.addToAllAvailableJobs(stepInstance, "considered");
                    }
                }
                //Utilities.verboseLog("runStatus:" + runStatus);
                //check what is not completed
                long totalStepInstances = stepInstanceDAO.count();
                int totalUnfinishedStepInstances = stepInstanceDAO.retrieveUnfinishedStepInstances().size();

//                statsUtil.memoryMonitor();
                if(!controlledLogging){
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("StandAlone Master has no jobs ready .. more Jobs will be made ready ");
                        LOGGER.debug("Step instances left to run: " + totalUnfinishedStepInstances);
                        LOGGER.debug("Total StepInstances: " + totalStepInstances);
                    }
                    controlledLogging = true;
                }
//                Utilities.verboseLog("Total StepInstances: " + totalStepInstances +
//                        ", left to run: " + totalUnfinishedStepInstances);
//                Utilities.verboseLog("MaxConcurrentConsumers: " + workerQueueJmsContainer.getMaxConcurrentConsumers()
//                       + " min ConsumerCount: " + workerQueueJmsContainer.getConcurrentConsumers()
//                        +  " ActiveConsumerCount: " + workerQueueJmsContainer.getActiveConsumerCount()
//                         +  " ScheduledConsumerCount: " + workerQueueJmsContainer.getScheduledConsumerCount());

                //report progress
                statsUtil.setTotalJobs(totalStepInstances);
                statsUtil.setUnfinishedJobs(totalUnfinishedStepInstances);
//                final boolean statsAvailable = statsUtil.pollStatsBrokerJobQueue();
                statsUtil.displayMasterProgress();


                // Close down (break out of loop) if the analyses are all complete.
                // The final clause checks that the protein load steps have been created so
                // i5 doesn't finish prematurely.
                if (completed
                        && totalStepInstances == statsUtil.getSubmittedStepInstancesCount()
                        && statsUtil.getSubmittedStepInstancesCount() >= minimumStepsExpected
                        && totalUnfinishedStepInstances == 0
                        && totalStepInstances > stepInstancesCreatedByLoadStep
                        && totalStepInstances >= minimumStepsExpected) {
                    Utilities.verboseLog("stepInstanceDAO.count() " + totalStepInstances
                            + " stepInstancesCreatedByLoadStep : " + stepInstancesCreatedByLoadStep
                            + " minimumStepsExpected : " + minimumStepsExpected
                            + " SubmittedStepInstancesCount : " + statsUtil.getSubmittedStepInstancesCount()
                            +  " unfinishedSteps " + totalUnfinishedStepInstances);

                    runStatus = 0;
                    break;
                }
                if(completed
                        && totalUnfinishedStepInstances == 0 ){
                    if(allowedWaitTimeMultiplier % 25 == 0) {
                        Utilities.verboseLog("Should be finished: stepInstanceDAO.count() " + totalStepInstances
                                + " stepInstancesCreatedByLoadStep : " + stepInstancesCreatedByLoadStep
                                + " minimumStepsExpected : " + minimumStepsExpected
                                + " SubmittedStepInstancesCount : " + statsUtil.getSubmittedStepInstancesCount()
                                + " unfinishedSteps " + totalUnfinishedStepInstances);
                    }
                    if (totalStepInstances > stepInstancesCreatedByLoadStep){
                        //Utilities.verboseLog("chances are all the steps have been completed, so wait for five second then break");
                        allowedWaitTimeMultiplier ++;
                    }else{
                        Utilities.verboseLog("Should be finished: ...but rest");
                        allowedWaitTimeMultiplier = 0;
                    }

                    if (allowedWaitTimeMultiplier > 50){
                        Utilities.verboseLog("chances are all the steps have been completed, so wait for five second then break .. allowedWaitTimeMultiplier" + allowedWaitTimeMultiplier);
                        break;
                    }
                }
                //for standalone es mode this should be < 200
                Thread.sleep(100);  // Make sure the Master thread is not hogging resources required by in-memory workers.
            }
            runStatus = 0;
        } catch (JMSException e) {
            LOGGER.error("JMSException thrown by StandaloneBlackBoxMaster: ", e);
            systemExit(999);
        } catch (Exception e) {
            LOGGER.error("Exception thrown by StandaloneBlackBoxMaster: ", e);
            systemExit(999);
        }

        if (runStatus == 0) {
            System.out.println(Utilities.getTimeNow() + " 100% done:  InterProScan analyses completed");
        }else{
            LOGGER.error("InterProScan analyses failed, check log details for the errors - " + runStatus);
        }

        if(verboseLog){
            final long executionTime =   System.currentTimeMillis() - now;
            final long executionTimeExclLoadDatabase =   System.currentTimeMillis() - nowAfterLoadingDatabase;
            System.out.println("Computation time : (" + TimeUnit.MILLISECONDS.toSeconds(executionTime)+ " s) => " + String.format("%d min, %d sec",
                    TimeUnit.MILLISECONDS.toMinutes(executionTime),
                    TimeUnit.MILLISECONDS.toSeconds(executionTime) -
                            TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(executionTime))
            ));
            System.out.println("Computation time exc ldb : (" + TimeUnit.MILLISECONDS.toSeconds(executionTimeExclLoadDatabase)+ " s) => " + String.format("%d min, %d sec",
                    TimeUnit.MILLISECONDS.toMinutes(executionTimeExclLoadDatabase),
                    TimeUnit.MILLISECONDS.toSeconds(executionTimeExclLoadDatabase) -
                            TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(executionTimeExclLoadDatabase))
            ));
        }
        systemExit(runStatus);
    }

    /**
     * Exit InterProScan 5 immediately with the supplied exit code.
     * @param status Exit code to use
     */
    private void systemExit(int status){
        try {
            databaseCleaner.closeDatabaseCleaner();
            LOGGER.debug("Ending");
            Thread.sleep(500); // cool off, then exit
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            cleanUpWorkingDirectory();
            // Always exit
            if(status != 0){
                System.err.println("InterProScan analysis failed. Exception thrown by StandaloneBlackBoxMaster. Check the log file for details");           
                System.exit(status);
            }
        }
	    //let Run do the cleanup
        //System.exit(status);
    }


    /**
     *
     * @param statsUtil
     */
    public void setStatsUtil(StatsUtil statsUtil) {
        this.statsUtil = statsUtil;
    }



}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy