/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.job;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.StringTokenizer;
import com.sleepycat.je.DatabaseException;
import com.slamd.asn1.ASN1Boolean;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1Integer;
import com.slamd.asn1.ASN1OctetString;
import com.slamd.asn1.ASN1Sequence;
import com.slamd.common.Constants;
import com.slamd.db.DecodeException;
import com.slamd.parameter.LabelParameter;
import com.slamd.parameter.Parameter;
import com.slamd.parameter.ParameterList;
import com.slamd.parameter.PlaceholderParameter;
import com.slamd.server.SLAMDServer;
import com.slamd.server.SLAMDServerException;
import com.slamd.server.SMTPMailer;
import com.slamd.server.Scheduler;
/**
* This class defines an optimizing job, which is a special kind of job that
* has the ability to execute the same job multiple times varying only the
* number of threads per client in an attempt to automatically determine the
* highest or lowest value for a particular statistic.
*
*
* @author Neil A. Wilson
*/
public class OptimizingJob
implements Comparable, JobItem
{
/**
* The name of the encoded element that holds the optimizing job ID.
*/
public static final String ELEMENT_OPTIMIZING_JOB_ID = "optimizing_job_id";
/**
* The name of the encoded element that holds the job IDs of the standard
* iterations.
*/
public static final String ELEMENT_ITERATION_IDS = "iteration_ids";
/**
* The name of the encoded element that holds the job IDs of the rerun
* iteration.
*/
public static final String ELEMENT_RERUN_ID = "rerun_id";
/**
* The name of the encoded element that holds the job class name.
*/
public static final String ELEMENT_JOB_CLASS = "job_class";
/**
* The name of the encoded element that holds the job group name.
*/
public static final String ELEMENT_JOB_GROUP = "job_group";
/**
* The name of the encoded element that holds the job state.
*/
public static final String ELEMENT_JOB_STATE = "job_state";
/**
* The name of the encoded element that holds the job description.
*/
public static final String ELEMENT_DESCRIPTION = "description";
/**
* The name of the encoded element that indicates whether to include the
* number of threads in the job descriptions.
*/
public static final String ELEMENT_INCLUDE_THREADS_IN_DESCRIPTION =
"include_threads_in_description";
/**
* The name of the encoded element that indicates whether the job should be
* displayed in restricted read-only mode.
*/
public static final String ELEMENT_DISPLAY_IN_READ_ONLY =
"display_in_read_only";
/**
* The name of the encoded element that holds the scheduled start time.
*/
public static final String ELEMENT_START_TIME = "start_time";
/**
* The name of the encoded element that holds the scheduled duration.
*/
public static final String ELEMENT_DURATION = "duration";
/**
* The name of the encoded element that holds the delay between iterations.
*/
public static final String ELEMENT_DELAY_BETWEEN_ITERATIONS =
"delay_between_iterations";
/**
* The name of the encoded element that holds the number of clients.
*/
public static final String ELEMENT_NUM_CLIENTS = "num_clients";
/**
* The name of the encoded element that holds the requested clients.
*/
public static final String ELEMENT_REQUESTED_CLIENTS = "requested_clients";
/**
* The name of the encoded element that holds the requested monitor clients.
*/
public static final String ELEMENT_MONITOR_CLIENTS = "monitor_clients";
/**
* The name of the encoded element that indicates whether to monitor clients
* if they are also running resource monitor clients.
*/
public static final String ELEMENT_MONITOR_CLIENTS_IF_AVAILABLE =
"monitor_clients_if_available";
/**
* The name of the encoded element that holds the minimum number of threads to
* use.
*/
public static final String ELEMENT_MIN_THREADS = "min_threads";
/**
* The name of the encoded element that holds the maximum number of threads to
* use.
*/
public static final String ELEMENT_MAX_THREADS = "max_threads";
/**
* The name of the encoded element that holds the thread increment.
*/
public static final String ELEMENT_THREAD_INCREMENT = "thread_increment";
/**
* The name of the encoded element that holds the thread startup delay.
*/
public static final String ELEMENT_THREAD_STARTUP_DELAY =
"thread_startup_delay";
/**
* The name of the encoded element that holds the collection interval.
*/
public static final String ELEMENT_COLLECTION_INTERVAL =
"collection_interval";
/**
* The name of the encoded element that holds the job folder name.
*/
public static final String ELEMENT_FOLDER_NAME = "folder_name";
/**
* The name of the encoded element that holds the maximum allowed nonimproving
* iterations.
*/
public static final String ELEMENT_MAX_NONIMPROVING = "max_nonimproving";
/**
* The name of the encoded element that indicates whether to rerun the best
* iteration.
*/
public static final String ELEMENT_RERUN_BEST_ITERATION =
"rerun_best_iteration";
/**
* The name of the encoded element that holds the scheduled duration for the
* rerun iteration.
*/
public static final String ELEMENT_RERUN_DURATION = "rerun_duration";
/**
* The name of the encoded element that holds the addresses of the users to
* notify when the optimizing job is done running.
*/
public static final String ELEMENT_NOTIFY_ADDRESSES = "notify_addresses";
/**
* The name of the encoded element that holds the dependencies.
*/
public static final String ELEMENT_DEPENDENCIES = "dependencies";
/**
* The name of the encoded element that holds the information about the
* optimization algorithm.
*/
public static final String ELEMENT_OPTIMIZATION_ALGORITHM =
"optimization_algorithm";
/**
* The name of the encoded element that holds the job parameters.
*/
public static final String ELEMENT_PARAMETERS = "parameters";
/**
* The name of the encoded element that holds the actual start time.
*/
public static final String ELEMENT_ACTUAL_START_TIME = "actual_start_time";
/**
* The name of the encoded element that holds the actual stop time.
*/
public static final String ELEMENT_ACTUAL_STOP_TIME = "actual_stop_time";
/**
* The name of the encoded element that holds the stop reason.
*/
public static final String ELEMENT_STOP_REASON = "stop_reason";
/**
* The name of the encoded element that indicates whether the optimizing job
* should make the next iteration disabled when it is scheduled.
*/
public static final String ELEMENT_PAUSE_REQUESTED = "pause_requested";
/**
* The name of the encoded element that holds the set of comments for an
* optimizing job.
*/
public static final String ELEMENT_COMMENTS = "comments";
// The set of job iterations associated with this optimizing job.
private ArrayList<Job> jobList;
// Indicates whether a request has been received to cancel this job.
private boolean cancelRequested;
// Indicates whether this optimizing job should be displayed in restricted
// read-only mode.
private boolean displayInReadOnlyMode;
// Indicates whether to include the number of threads in the description of
// the job for each iteration.
private boolean includeThreadsInDescription;
// Indicates whether an attempt should be made to use any resource monitor
// clients running on the same system as the client system(s) used to process
// this job.
private boolean monitorClientsIfAvailable;
// Indicates whether a request has been received to pause this job.
private boolean pauseRequested;
// Indicates whether the best iteration should be rerun after the job has
// otherwise completed.
private boolean reRunBestIteration;
// The time at which the first iteration of the optimizing job actually
// started.
private Date actualStartTime;
// The time at which the last iteration of the optimizing job completed.
private Date actualStopTime;
// The initial start time for the optimizing job.
private Date startTime;
// The statistics collection interval for the jobs.
private int collectionInterval;
// The current number of non-improving iterations that have been encountered.
private int currentNonImproving;
// The number of threads that has yielded the best result so far.
private int currentOptimalThreads;
// The length of time in seconds between individual job iterations.
private int delayBetweenIterations;
// The maximum length of time for the individual job iterations.
private int duration;
// The current state of this optimizing job.
private int jobState;
// The maximum number of consecutive non-improving iterations that should be
// allowed before ending the job.
private int maxNonImproving;
// The maximum number of threads that will be allowed for an iteration.
private int maxThreads;
// The minimum number of threads that will be allowed for an iteration.
private int minThreads;
// The number of clients that will be used for each iteration.
private int numClients;
// The duration that should be used to re-run the best iteration of this
// optimizing job.
private int reRunDuration;
// The thread increment that will be used between iterations.
private int threadIncrement;
// The thread startup delay that will be used for each iteration.
private int threadStartupDelay;
// The iteration of this job that was a re-run of the best iteration,
// potentially with a different duration.
private Job reRunIteration;
// The job class associated with this optimizing job.
private JobClass jobClass;
// The optimization algorithm to use for this optimizing job.
private OptimizationAlgorithm optimizationAlgorithm;
// The set of job-specific parameters associated with this optimizing job.
private ParameterList parameters;
// The SLAMD server with which this optimizing job is associated.
protected SLAMDServer slamdServer;
// The set of comments for the optimizing job.
private String comments;
// The job ID of the "best" iteration that has been seen so far.
private String currentOptimalID;
// The base description that will be used for each iteration.
private String description;
// The name of the job folder in which this optimizing job should be placed.
private String folderName;
// The name of the job group with which this optimizing job is associated.
private String jobGroup;
// The job ID for this optimizing job.
private String optimizingJobID;
// The reason that the optimization process stopped.
private String stopReason;
// The set of dependencies associated with this optimizing job.
private String[] dependencies;
// The set of resource monitor clients that have been requested for executing
// the jobs.
private String[] monitorClients;
// The e-mail addresses of the users to notify when the optimization process
// is complete.
private String[] notifyAddresses;
// The set of clients that have been requested for executing the jobs.
private String[] requestedClients;
/**
* Creates a new instance of an optimizing job based on the provided
* information.
*
* @param slamdServer The SLAMD server with which this
* optimizing job is associated.
* @param optimizingJobID The unique ID for this optimizing job.
* @param optimizationAlgorithm The optimization algorithm to use for
* this optimizing job.
* @param baseJob The base job that should be used to
* provide parameter information for this
* optimizing job.
* @param folderName The name of the job folder in which
* the optimizing job should be placed.
* @param description The base description for each job
* iteration.
* @param includeThreadsInDescription Indicates whether the thread count
* should be included in the description
* for each job iteration.
* @param startTime The time that the first iteration
* should start running.
* @param duration The maximum length of time any job
* iteration should be allowed to run.
* @param delayBetweenIterations The length of time in seconds that
* should be left between job iterations.
* @param numClients The number of clients that should be
* used to run each iteration.
* @param requestedClients The set of clients that have been
* requested for each iteration.
* @param monitorClients The set of resource monitor clients
* that have been requested for this
* optimizing job.
* @param monitorClientsIfAvailable Indicates whether any resource monitor
* clients on the same system(s) as the
* job clients should automatically be
* used.
* @param minThreads The minimum number of threads that
* should be used on each client.
* @param maxThreads The maximum number of threads that
* should be used for each client. If
* there is no maximum, this should be
* negative.
* @param threadIncrement The increase in threads that should be
* used between iterations.
* @param collectionInterval The statistics collection interval
* that should be used for the job
* iterations.
* @param maxNonImproving The maximum number of consecutive
* non-improving iterations that will be
* allowed before ending the job.
* @param notifyAddresses The e-mail addresses of the users that
* should be notified when the
* optimization process is complete.
* @param reRunBestIteration Indicates whether the best iteration
* should be re-run once the optimizing
* job is otherwise complete.
* @param reRunDuration The duration that should be used when
* re-running the best iteration.
* @param displayInReadOnlyMode Indicates whether this optimizing job
* should be displayed in restricted
* read-only mode.
*/
public OptimizingJob(SLAMDServer slamdServer, String optimizingJobID,
OptimizationAlgorithm optimizationAlgorithm, Job baseJob,
String folderName, String description,
boolean includeThreadsInDescription, Date startTime,
int duration, int delayBetweenIterations,
int numClients, String[] requestedClients,
String[] monitorClients,
boolean monitorClientsIfAvailable, int minThreads,
int maxThreads, int threadIncrement,
int collectionInterval, int maxNonImproving,
String[] notifyAddresses, boolean reRunBestIteration,
int reRunDuration, boolean displayInReadOnlyMode)
{
this.slamdServer = slamdServer;
this.optimizingJobID = optimizingJobID;
this.optimizationAlgorithm = optimizationAlgorithm;
this.folderName = folderName;
this.description = description;
this.includeThreadsInDescription = includeThreadsInDescription;
this.startTime = startTime;
this.duration = duration;
this.delayBetweenIterations = delayBetweenIterations;
this.numClients = numClients;
this.requestedClients = requestedClients;
this.monitorClients = monitorClients;
this.monitorClientsIfAvailable = monitorClientsIfAvailable;
this.minThreads = minThreads;
this.maxThreads = maxThreads;
this.threadIncrement = threadIncrement;
this.collectionInterval = collectionInterval;
this.maxNonImproving = maxNonImproving;
this.notifyAddresses = notifyAddresses;
this.reRunBestIteration = reRunBestIteration;
this.reRunDuration = reRunDuration;
this.displayInReadOnlyMode = displayInReadOnlyMode;
cancelRequested = false;
jobClass = baseJob.getJobClass();
parameters = baseJob.getParameterList();
currentOptimalID = null;
currentOptimalThreads = 0;
currentNonImproving = 0;
actualStartTime = null;
actualStopTime = null;
stopReason = null;
jobState = Constants.JOB_STATE_NOT_YET_STARTED;
reRunIteration = null;
jobList = new ArrayList<Job>();
dependencies = new String[0];
}
/**
* Creates a new instance of an optimizing job based on the provided
* information.
*
* @param slamdServer The SLAMD server with which this
* optimizing job is associated.
* @param optimizingJobID The unique ID for this optimizing job.
* @param optimizationAlgorithm The optimization algorithm to use for
* this optimizing job.
* @param jobClass The job class associated with this
* optimizing job.
* @param folderName The name of the folder in which this
* optimizing job should be placed.
* @param description The base description for each job
* iteration.
* @param includeThreadsInDescription Indicates whether the thread count
* should be included in the description
* for each job iteration.
* @param startTime The time that the first iteration
* should start running.
* @param duration The maximum length of time any job
* iteration should be allowed to run.
* @param delayBetweenIterations The length of time in seconds that
* should be left between job iterations.
* @param numClients The number of clients that should be
* used to run each iteration.
* @param requestedClients The set of clients that have been
* requested for each iteration.
* @param monitorClients The set of resource monitor clients
* that have been requested for this
* optimizing job.
* @param monitorClientsIfAvailable Indicates whether any resource monitor
* clients on the same system(s) as the
* job clients should automatically be
* used.
* @param minThreads The minimum number of threads that
* should be used on each client.
* @param maxThreads The maximum number of threads that
* should be used for each client. If
* there is no maximum, this should be
* negative.
* @param threadIncrement The increase in threads that should be
* used between iterations.
* @param collectionInterval The statistics collection interval
* that should be used for the job
* iterations.
* @param maxNonImproving The maximum number of consecutive
* non-improving iterations that will be
* allowed before ending the job.
* @param notifyAddresses The e-mail addresses of the users that
* should be notified when the
* optimization process is complete.
* @param reRunBestIteration Indicates whether the best iteration
* should be re-run once the optimizing
* job is otherwise complete.
* @param reRunDuration The duration that should be used when
* re-running the best iteration.
* @param parameters The parameter list for this optimizing
* job.
* @param displayInReadOnlyMode Indicates whether this optimizing job
* should be displayed in restricted
* read-only mode.
*/
public OptimizingJob(SLAMDServer slamdServer, String optimizingJobID,
OptimizationAlgorithm optimizationAlgorithm,
JobClass jobClass, String folderName, String description,
boolean includeThreadsInDescription, Date startTime,
int duration, int delayBetweenIterations,
int numClients, String[] requestedClients,
String[] monitorClients,
boolean monitorClientsIfAvailable, int minThreads,
int maxThreads, int threadIncrement,
int collectionInterval, int maxNonImproving,
String[] notifyAddresses, boolean reRunBestIteration,
int reRunDuration, ParameterList parameters,
boolean displayInReadOnlyMode)
{
this.slamdServer = slamdServer;
this.optimizingJobID = optimizingJobID;
this.optimizationAlgorithm = optimizationAlgorithm;
this.jobClass = jobClass;
this.folderName = folderName;
this.description = description;
this.includeThreadsInDescription = includeThreadsInDescription;
this.startTime = startTime;
this.duration = duration;
this.delayBetweenIterations = delayBetweenIterations;
this.numClients = numClients;
this.requestedClients = requestedClients;
this.monitorClients = monitorClients;
this.monitorClientsIfAvailable = monitorClientsIfAvailable;
this.minThreads = minThreads;
this.maxThreads = maxThreads;
this.threadIncrement = threadIncrement;
this.collectionInterval = collectionInterval;
this.maxNonImproving = maxNonImproving;
this.notifyAddresses = notifyAddresses;
this.reRunBestIteration = reRunBestIteration;
this.reRunDuration = reRunDuration;
this.parameters = parameters;
this.displayInReadOnlyMode = displayInReadOnlyMode;
cancelRequested = false;
currentOptimalID = null;
currentOptimalThreads = 0;
currentNonImproving = 0;
actualStartTime = null;
actualStopTime = null;
stopReason = null;
jobState = Constants.JOB_STATE_NOT_YET_STARTED;
reRunIteration = null;
jobList = new ArrayList<Job>();
dependencies = new String[0];
}
/**
* Retrieves the unique ID associated with this optimizing job.
*
* @return The unique ID associated with this optimizing job.
*/
public String getOptimizingJobID()
{
return optimizingJobID;
}
/**
* Retrieves the optimization algorithm associated with this optimizing job.
*
* @return The optimization algorithm associated with this optimizing job.
*/
public OptimizationAlgorithm getOptimizationAlgorithm()
{
return optimizationAlgorithm;
}
/**
* Retrieves the job class associated with this optimizing job.
*
* @return The job class associated with this optimizing job.
*/
public JobClass getJobClass()
{
return jobClass;
}
/**
* Retrieves the name of the job class associated with this optimizing job.
*
* @return The name of the job class associated with this optimizing job.
*/
public String getJobClassName()
{
return jobClass.getClass().getName();
}
/**
* Retrieves the job name for the job class associated with this optimizing
* job.
*
* @return The job name for the job class associated with this optimizing
* job.
*/
public String getJobName()
{
return jobClass.getJobName();
}
/**
* Retrieves the description for the job class associated with this optimizing
* job.
*
* @return The description for the job class associated with this optimizing
* job.
*/
public String getJobClassDescription()
{
return jobClass.getShortDescription();
}
/**
* Retrieves the name of the job group with which this optimizing job is
* associated.
*
* @return The name of the job group with which this optimizing job is
* associated, or <CODE>null</CODE> if it was not scheduled as part
* of a job group.
*/
public String getJobGroup()
{
return jobGroup;
}
/**
* Specifies the name of the job group with which this optimizing job is
* associated.
*
* @param jobGroup The name of the job group with which this optimizing job
* is associated.
*/
public void setJobGroup(String jobGroup)
{
this.jobGroup = jobGroup;
}
/**
* Indicates whether this optimizing job should be displayed in restricted
* read-only mode.
*
* @return <CODE>true</CODE> if this optimizing job should be displayed in
* restricted read-only mode, or <CODE>false</CODE> if not.
*/
public boolean displayInReadOnlyMode()
{
return displayInReadOnlyMode;
}
/**
* Specifies whether this optimizing job should be displayed in restricted
* read-only mode.
*
* @param displayInReadOnlyMode Indicates whether this optimizing job should
* be displayed in restricted read-only mode.
*/
public void setDisplayInReadOnlyMode(boolean displayInReadOnlyMode)
{
this.displayInReadOnlyMode = displayInReadOnlyMode;
}
/**
* Retrieves the name of the job folder in which this optimizing job is
* located.
*
* @return The name of the job folder in which this optimizing job is
* located.
*/
public String getFolderName()
{
return folderName;
}
/**
* Specifies the name of the job folder in which this optimizing job is
* located.
*
* @param folderName The name of the job folder in which this optimizing job
* is located.
*/
public void setFolderName(String folderName)
{
this.folderName = folderName;
}
/**
* Retrieves the set of parameter stubs associated with this optimizing job.
*
* @return The set of parameter stubs associated with this optimizing job.
*/
public ParameterList getParameterStubs()
{
return jobClass.getParameterStubs();
}
/**
* Retrieves the set of parameter stubs associated with the optimization
* algorithm.
*
* @return The set of parameter stubs associated with the optimization
* algorithm.
*/
public ParameterList getOptimizationParameterStubs()
{
return
optimizationAlgorithm.getOptimizationAlgorithmParameterStubs(jobClass);
}
/**
* Retrieves the parameter list associated with this optimizing job.
*
* @return The parameter list associated with this optimizing job.
*/
public ParameterList getParameters()
{
return parameters;
}
/**
* Retrieves the set of parameters associated with the optimization algorithm.
*
* @return The set of parameters associated with the optimization algorithm.
*/
public ParameterList getOptimizationParameters()
{
return optimizationAlgorithm.getOptimizationAlgorithmParameters();
}
/**
* Retrieves the base description for this optimizing job.
*
* @return The base description for this optimizing job.
*/
public String getDescription()
{
return description;
}
/**
* Retrieves the comments for this optimizing job.
*
* @return The comments for this optimizing job, or <CODE>null</CODE> if
* there are none.
*/
public String getComments()
{
return comments;
}
/**
* Specifies the set of comments for this optimizing job.
*
* @param comments The set of comments for this optimizing job.
*/
public void setComments(String comments)
{
this.comments = comments;
}
/**
* Indicates whether the number of threads should be included in the
* description for each iteration of this optimizing job.
*
* @return <CODE>true</CODE> if the number of threads should be included
* in the description for this optimizing job, or <CODE>false</CODE>
* if not.
*/
public boolean includeThreadsInDescription()
{
return includeThreadsInDescription;
}
/**
* Retrieves the time at which the first iteration of this optimizing job
* should start running.
*
* @return The time at which the first iteration of this optimizing job.
*/
public Date getStartTime()
{
return startTime;
}
/**
* Retrieves the maximum length of time that any iteration of this optimizing
* job should be allowed to run.
*
* @return The maximum length of time that any iteration of this optimizing
* job should be allowed to run.
*/
public int getDuration()
{
return duration;
}
/**
* Retrieves the length of time in seconds that should be scheduled between
* iterations of this optimizing job.
*
* @return The length of time in seconds that should be scheduled between
* iterations of this optimizing job.
*/
public int getDelayBetweenIterations()
{
return delayBetweenIterations;
}
/**
* Indicates whether the best iteration should be re-run once the job has
* completed.
*
* @return <CODE>true</CODE> if the best iteration should be re-run after the
* job has completed, or <CODE>false</CODE> if not.
*/
public boolean reRunBestIteration()
{
return reRunBestIteration;
}
/**
* Retrieves the duration that should be used when re-running the best
* iteration of the optimizing job.
*
* @return The duration that should be used when re-running the best
* iteration of the optimizing job.
*/
public int getReRunDuration()
{
return reRunDuration;
}
/**
* Retrieves the job iteration that was a re-run of the best iteration for
* this optimizing job.
*
* @return The job iteration that was a re-run of the best iteration for this
* optimizing job, or <CODE>null</CODE> if there is none or it hasn't
* run yet.
*/
public Job getReRunIteration()
{
return reRunIteration;
}
/**
* Specifies the job that is a re-run of the best iteration of this optimizing
* job.
*
* @param reRunIteration The job that is a re-run of the best iteration of
* this optimizing job.
*/
public void setReRunIteration(Job reRunIteration)
{
this.reRunIteration = reRunIteration;
}
/**
* Retrieves the number of clients that should be used to run each iteration
* of this optimizing job.
*
* @return The number of clients that should be used to run each iteration
* of this optimizing job.
*/
public int getNumClients()
{
return numClients;
}
/**
* Retrieves the set of clients that have been requested to run each iteration
* of this optimizing job.
*
* @return The number of clients that should be used to run each iteration of
* this optimizing job.
*/
public String[] getRequestedClients()
{
return requestedClients;
}
/**
* Retrieves the set of resource monitor clients that have been requested for
* this optimizing job.
*
* @return The set of resource monitor clients that have been requested for
* this optimizing job.
*/
public String[] getResourceMonitorClients()
{
return monitorClients;
}
/**
* Indicates whether an attempt will be made to use resource monitor clients
* on the same systems as the clients used to run this job.
*
* @return <CODE>true</CODE> if resource monitor clients on the same systems
* as the clients will be used, or <CODE>false</CODE> if not.
*/
public boolean monitorClientsIfAvailable()
{
return monitorClientsIfAvailable;
}
/**
* Specifies whether an attempt should be made to use resource monitor clients
* on the same systems as the clients used to run this job.
*
* @param monitorClientsIfAvailable Specifies whether an attempt should be
* made to use resource monitor clients
* on the same systems as the clients used
* to run this job.
*/
public void setMonitorClientsIfAvailable(boolean monitorClientsIfAvailable)
{
this.monitorClientsIfAvailable = monitorClientsIfAvailable;
}
/**
* Retrieves the minimum number of threads that should be used in an iteration
* of this optimizing job.
*
* @return The minimum number of threads that should be used in an iteration
* of this optimizing job.
*/
public int getMinThreads()
{
return minThreads;
}
/**
* Retrieves the maximum number of threads that should be used in an iteration
* of this optimizing job.
*
* @return The maximum number of threads that should be used in an iteration
* of this optimizing job.
*/
public int getMaxThreads()
{
return maxThreads;
}
/**
* Retrieves the increment that should be used when increasing the number of
* threads used between iterations of this optimizing job.
*
* @return The increment that should be used when increasing the number of
* threads used between iterations of this optimizing job.
*/
public int getThreadIncrement()
{
return threadIncrement;
}
/**
* Retrieves the thread startup delay for iterations of this optimizing job.
*
* @return The thread startup delay for iterations of this optimizing job.
*/
public int getThreadStartupDelay()
{
return threadStartupDelay;
}
/**
* Specifies the thread startup delay for iterations of this optimizing job.
*
* @param threadStartupDelay The thread startup delay for iterations of this
* optimizing job.
*/
public void setThreadStartupDelay(int threadStartupDelay)
{
this.threadStartupDelay = threadStartupDelay;
}
/**
* Retrieves the statistics collection interval that should be used for each
* iteration of this optimizing job.
*
* @return The statistics collection interval that should be used for each
* iteration of this optimizing job.
*/
public int getCollectionInterval()
{
return collectionInterval;
}
/**
* Retrieves the maximum number of consecutive non-improving iterations that
* will be allowed before the job is determined to have found the optimum
* value.
*
* @return The maximum number of consecutive non-improving iterations that
* will be allowed before the job is determined to have found the
* optimum value.
*/
public int getMaxNonImproving()
{
return maxNonImproving;
}
/**
* Retrieves the e-mail address(es) of the user(s) that should be notified
* whenever the optimization process has completed.
*
* @return The e-mail address(es) of the user(s) that should be notified
* whenever the optimization process has completed.
*/
public String[] getNotifyAddresses()
{
return notifyAddresses;
}
/**
* Retrieves the time at which the first iteration of this job actually
* started running.
*
* @return The time at which the first iteration of this job actually started
* running.
*/
public Date getActualStartTime()
{
return actualStartTime;
}
/**
* Specifies the time at which the first iteration of this job actually
* started running.
*
* @param actualStartTime The time at which the first iteration of this job
* actually started running.
*/
public void setActualStartTime(Date actualStartTime)
{
this.actualStartTime = actualStartTime;
}
/**
* Retrieves the time at which the last iteration of this job actually
* completed running.
*
* @return The time at which the last iteration of this job actually
* completed running.
*/
public Date getActualStopTime()
{
return actualStopTime;
}
/**
* Specifies the time at which the last iteration of this job actually
* completed running.
*
* @param actualStopTime The time at which the last iteration of this job
* actually completed running.
*/
public void setActualStopTime(Date actualStopTime)
{
this.actualStopTime = actualStopTime;
}
/**
* Retrieves the current state of this optimizing job.
*
* @return The current state of this optimizing job.
*/
public int getJobState()
{
return jobState;
}
/**
* Specifies the current state of this optimizing job.
*
* @param jobState The current state of this optimizing job.
*/
public void setJobState(int jobState)
{
this.jobState = jobState;
}
/**
* Retrieves the string representation of the current state for this
* optimizing job.
*
* @return The string representation of the current state for this optimizing
* job.
*/
public String getJobStateString()
{
return Constants.jobStateToString(jobState);
}
/**
* Retrieves the reason that the job stopped running.
*
* @return The reason that the job stopped running.
*/
public String getStopReason()
{
return stopReason;
}
/**
* Specifies the reason that the job stopped running.
*
* @param stopReason The reason that the job stopped running.
*/
public void setStopReason(String stopReason)
{
this.stopReason = stopReason;
}
/**
* Retrieves the set of jobs scheduled as iterations of this optimizing job.
*
* @return The set of jobs scheduled as iterations of this optimizing job.
*/
public Job[] getAssociatedJobs()
{
if ((jobList == null) || jobList.isEmpty())
{
return new Job[0];
}
Job[] jobs = new Job[jobList.size()];
jobList.toArray(jobs);
return jobs;
}
/**
* Retrieves the set of jobs scheduled as iterations of this optimizing job,
* including the re-run iteration if there is one.
*
* @return The set of jobs scheduled as iterations of this optimizing job,
* including the re-run iteration if there is one.
*/
public Job[] getAssociatedJobsIncludingReRun()
{
ArrayList<Job> list = new ArrayList<Job>();
if (jobList != null)
{
list.addAll(jobList);
}
if (reRunIteration != null)
{
list.add(reRunIteration);
}
Job[] jobs = new Job[list.size()];
list.toArray(jobs);
return jobs;
}
/**
* Specifies the set of jobs scheduled as iterations of this optimizing job.
*
* @param associatedJobs The set of jobs scheduled as iterations of this
* optimizing job.
*/
public void setAssociatedJobs(Job[] associatedJobs)
{
// If the provided list of jobs is empty or null, then just clear the
// list and reset the optimum values.
if ((associatedJobs == null) || (associatedJobs.length == 0))
{
jobList.clear();
currentOptimalID = null;
currentOptimalThreads = 0;
currentNonImproving = 0;
return;
}
// First, sort the jobs in the order that they were started.
Arrays.sort(associatedJobs);
// Add the jobs into the job list.
jobList.clear();
for (int i=0; i < associatedJobs.length; i++)
{
jobList.add(associatedJobs[i]);
}
// Set the first job to be the optimum so far.
currentOptimalID = null;
currentOptimalThreads = 0;
currentNonImproving = 0;
optimizationAlgorithm.reInitializeOptimizationAlgorithm();
// Iterate through the list of remaining jobs and extract the optimum values
// from them.
for (int i=0; i < associatedJobs.length; i++)
{
if (! associatedJobs[i].doneRunning())
{
break;
}
try
{
if (optimizationAlgorithm.isBestIterationSoFar(associatedJobs[i]))
{
currentOptimalID = associatedJobs[i].getJobID();
currentOptimalThreads = associatedJobs[i].getThreadsPerClient();
currentNonImproving = 0;
}
else
{
currentNonImproving++;
}
}
catch (Exception e)
{
// There's really not much that can be done about this. However, it
// should never happen for any case except the last iteration.
currentNonImproving++;
}
}
}
/**
* Retrieves the set of dependencies associated with this optimizing job.
*
* @return The set of dependencies associated with this optimizing job.
*/
public String[] getDependencies()
{
return dependencies;
}
/**
* Specifies the set of dependencies for this optimizing job.
*
* @param dependencies The set of dependencies for this optimizing job.
*/
public void setDependencies(String[] dependencies)
{
if (dependencies == null)
{
this.dependencies = new String[0];
}
else
{
this.dependencies = dependencies;
}
}
/**
* Indicates whether the optimization process has completed (i.e., no
* additional iterations will be performed, for whatever reason).
*
* @return <CODE>true</CODE> if the optimization process has completed, or
* <CODE>false</CODE> if not.
*/
public boolean doneRunning()
{
switch (jobState)
{
case Constants.JOB_STATE_NOT_YET_STARTED:
case Constants.JOB_STATE_RUNNING:
case Constants.JOB_STATE_DISABLED:
case Constants.JOB_STATE_UNINITIALIZED:
return false;
default:
return true;
}
}
/**
* Indicates whether at least some statistical information is available for
* this optimizing job.
*
* @return <CODE>true</CODE> if there is statistical information available
* for this optimizing job, or <CODE>false</CODE> if not.
*/
public boolean hasStats()
{
if (jobList.isEmpty())
{
return false;
}
for (int i=0; i < jobList.size(); i++)
{
Job job = jobList.get(i);
if (job.hasStats())
{
return true;
}
}
return false;
}
/**
* Retrieves the optimal thread count that has been identified. Note that
* this may not be accurate if the job has not yet completed.
*
* @return The optimal thread count that has been identified, or -1 if no
* optimal thread count has been determined.
*/
public int getOptimalThreadCount()
{
return currentOptimalThreads;
}
/**
* Retrieves the optimal value that has been identified. Note that this
* may not be accurate if the job has not yet completed.
*
* @return The optimal value that has been identified, or -1.0 if no
* optimal value has been determined.
*/
public double getOptimalValue()
{
if (currentOptimalID != null)
{
for (int i=0; i < jobList.size(); i++)
{
Job iteration = jobList.get(i);
if (iteration.getJobID().equals(currentOptimalID))
{
try
{
return
optimizationAlgorithm.getIterationOptimizationValue(iteration);
}
catch (Exception e)
{
return -1.0;
}
}
}
}
return -1.0;
}
/**
* Retrieves the job ID of the optimal iteration. Note that this may not be
* accurate if the job has not yet completed.
*
* @return The job ID of the optimal iteration, or <CODE>null</CODE> if no
* optimal iteration has been determined.
*/
public String getOptimalJobID()
{
return currentOptimalID;
}
/**
* Specifies the optimal iteration for this optimizing job. This method
* should only be used by optimization algorithms.
*
* @param optimalIteration The job that is the optimal iteration for this
* optimizing job.
*/
public void setOptimalIteration(Job optimalIteration)
{
currentOptimalID = optimalIteration.getJobID();
currentOptimalThreads = optimalIteration.getThreadsPerClient();
}
/**
* Retrieves the job that was the optimal iteration for this optimizing job.
* Note that this may not be accurate if the job has not yet completed.
*
* @return The job that was the optimal iteration for this optimizing job.
*/
public Job getOptimalIteration()
{
if (currentOptimalID == null)
{
return null;
}
for (int i=0; i < jobList.size(); i++)
{
Job job = jobList.get(i);
if (job.getJobID().equals(currentOptimalID))
{
return job;
}
}
return null;
}
/**
* Causes the first iteration of this optimizing job to be scheduled for
* execution in the SLAMD server.
*
* @throws SLAMDServerException If a problem occurs while scheduling the
* optimizing job.
*/
public void schedule()
throws SLAMDServerException
{
try
{
Job job = new Job(slamdServer, jobClass.getClass().getName(),
numClients, minThreads, 0, startTime, null, duration,
collectionInterval, parameters, displayInReadOnlyMode);
job.setOptimizingJobID(optimizingJobID);
job.setJobID(optimizingJobID + '-' + minThreads);
job.setFolderName(folderName);
job.setRequestedClients(requestedClients);
job.setResourceMonitorClients(monitorClients);
job.setMonitorClientsIfAvailable(monitorClientsIfAvailable);
job.setWaitForClients(true);
job.setDependencies(dependencies);
job.setThreadStartupDelay(threadStartupDelay);
job.setJobComments(comments);
String threadStr = minThreads + " Thread";
if (minThreads > 1)
{
threadStr += "s";
}
if ((description == null) || (description.length() == 0))
{
if (includeThreadsInDescription)
{
job.setJobDescription(threadStr);
}
}
else
{
if (includeThreadsInDescription)
{
job.setJobDescription(description + " (" + threadStr + ')');
}
else
{
job.setJobDescription(description);
}
}
jobList.add(job);
slamdServer.getConfigDB().writeOptimizingJob(this);
slamdServer.getScheduler().scheduleJob(job, folderName);
}
catch (Exception e)
{
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(e));
throw new SLAMDServerException("Unable to schedule optimizing job " +
optimizingJobID + ": " + e, e);
}
}
/**
* Handles the work of cancelling this optimizing job.
*
* @throws SLAMDServerException If a problem occurs while cancelling the
* job.
*/
public void cancel()
throws SLAMDServerException
{
// If this job is done running, then we don't need to do anything.
if (doneRunning())
{
return;
}
// Indicate that a cancel has been requested and cancel any iteration that
// may be pending or running.
cancelRequested = true;
boolean runningFound = slamdServer.getScheduler().cancelOptimizingJob(this);
// Update the job state to indicate that it has been cancelled.
jobState = Constants.JOB_STATE_CANCELLED;
stopReason = "The optimizing job was cancelled by administrative " +
"request.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate the job was cancelled:" + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
// If a running iteration was found, then we shouldn't send the notification
// yet. Let that be done by the jobIterationComplete when the job is
// actually done.
if (! runningFound)
{
sendJobCompleteNotification();
}
}
/**
* Indicates whether a request has been submitted to pause this optimizing
* job.
*
* @return <CODE>true</CODE> if a request has been made to pause this
* optimizing job, or <CODE>false</CODE> if not.
*/
public boolean pauseRequested()
{
return pauseRequested;
}
/**
* Requests that this optimizing job be paused before its next iteration. If
* this is done, the next iteration will be disabled when it is scheduled so
* that it will not automatically start running when the appropriate start
* time arrives.
*/
public void pauseBeforeNextIteration()
{
pauseRequested = true;
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (Exception e)
{
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(e));
}
}
/**
* Indicates that this optimizing job does not need to be paused before the
* next iteration.
*/
public void cancelPause()
{
pauseRequested = false;
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (Exception e)
{
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(e));
}
}
/**
* Indicates that one iteration of this optimizing job is complete and that
* any appropriate action should be taken. If necessary, it will schedule
* the next iteration. Otherwise, it will indicate that processing is
* complete.
*
* @param jobIteration The job iteration that has completed.
*/
public void jobIterationComplete(Job jobIteration)
{
// Get a reference to the scheduler.
Scheduler scheduler = slamdServer.getScheduler();
// First, make sure the job is not null. That should never happen.
if (jobIteration == null)
{
jobState = Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
stopReason = "Reported complete iteration was NULL.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate stopped due to null " +
"iteration: " + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
// Now check to see if a request has been submitted to cancel this job. If
// so, then we're done.
if (cancelRequested)
{
jobState = Constants.JOB_STATE_CANCELLED;
stopReason = "The optimizing job was cancelled by administrative " +
"request.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate the job was cancelled:" + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
scheduler.decacheOptimizingJob(optimizingJobID);
// Next, check to see if the job stopped for an acceptable reason.
boolean acceptableStopReason = false;
switch (jobIteration.getJobState())
{
case Constants.JOB_STATE_COMPLETED_SUCCESSFULLY:
case Constants.JOB_STATE_STOPPED_DUE_TO_DURATION:
case Constants.JOB_STATE_STOPPED_DUE_TO_STOP_TIME:
acceptableStopReason = true;
}
if (! acceptableStopReason)
{
jobState = Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
stopReason = "Job \"" + jobIteration.getJobID() +
"\" stopped with a stop reason that was not acceptable " +
"for continuing (" +
Constants.jobStateToString(jobIteration.getJobState()) +
").";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate stopped due to unacceptable job " +
"iteration state:" + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
// See if this was the re-run of the best iteration. If so, then we know
// that we won't be running any more.
if ((reRunIteration != null) &&
reRunIteration.getJobID().equals(jobIteration.getJobID()))
{
jobState = Constants.JOB_STATE_COMPLETED_SUCCESSFULLY;
stopReason = "The optimizing job completed successfully after " +
"re-running the best iteration.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate stopped successfully after " +
"re-running the best iteration: " + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
// Check to see if the job had reached the maximum number of threads.
if ((maxThreads > 0) && (jobIteration.getThreadsPerClient() >= maxThreads))
{
// If we should re-run the best iteration, then do so now.
if (reRunBestIteration && (currentOptimalThreads > 0))
{
scheduleReRunOfBestIteration();
return;
}
else
{
jobState = Constants.JOB_STATE_COMPLETED_SUCCESSFULLY;
stopReason = "The maximum number of threads per client was reached.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job " +
"information for optimizing job " +
optimizingJobID + " to indicate stopped due " +
"to maximum number of threads per client: " +
de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
}
// Check to see if the maximum number of consecutive non-improving
// iterations has been reached.
if (currentNonImproving >= maxNonImproving)
{
if (reRunBestIteration && (currentOptimalThreads > 0))
{
scheduleReRunOfBestIteration();
return;
}
else
{
jobState = Constants.JOB_STATE_COMPLETED_SUCCESSFULLY;
stopReason = "The maximum number of consecutive non-improving " +
"iterations was reached.";
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job " +
"information for optimizing job " +
optimizingJobID + " to indicate stopped due " +
"to maximum number of non-improving " +
"iterations: " + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
}
// If we have gotten here, then the optimization process is not yet
// complete. Therefore, we need to schedule the next iteration.
try
{
int numThreads = jobIteration.getThreadsPerClient() + threadIncrement;
if ((maxThreads > 0) && (numThreads > maxThreads))
{
numThreads = maxThreads;
}
long nextStartTimeMillis = System.currentTimeMillis() +
(1000 * delayBetweenIterations);
Date nextStartTime = new Date(nextStartTimeMillis);
Job job = new Job(slamdServer, jobClass.getClass().getName(),
numClients, numThreads, 0, nextStartTime, null,
duration, collectionInterval,
parameters, displayInReadOnlyMode);
job.setOptimizingJobID(optimizingJobID);
job.setJobID(optimizingJobID + '-' + numThreads);
job.setFolderName(folderName);
job.setRequestedClients(requestedClients);
job.setResourceMonitorClients(monitorClients);
job.setMonitorClientsIfAvailable(monitorClientsIfAvailable);
job.setWaitForClients(true);
job.setJobComments(comments);
// If this optimizing job should be paused, then do so now. We will also
// unset the pause requested flag.
if (pauseRequested)
{
job.setJobState(Constants.JOB_STATE_DISABLED);
pauseRequested = false;
}
String threadStr = numThreads + " Threads";
if ((description == null) || (description.length() == 0))
{
if (includeThreadsInDescription)
{
job.setJobDescription(threadStr);
}
}
else
{
if (includeThreadsInDescription)
{
job.setJobDescription(description + " (" + threadStr + ')');
}
else
{
job.setJobDescription(description);
}
}
jobList.add(job);
slamdServer.getConfigDB().writeOptimizingJob(this);
slamdServer.getScheduler().scheduleJob(job, folderName);
}
catch (Exception e)
{
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(e));
jobState = Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
stopReason = "Unable to schedule a new iteration: " + e;
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate stopped due to scheduling " +
"failure: " + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
scheduler.decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
}
/**
* This schedules a second run of the iteration that yielded the best result.
*/
public void scheduleReRunOfBestIteration()
{
try
{
long nextStartTimeMillis = System.currentTimeMillis() +
(1000 * delayBetweenIterations);
Date nextStartTime = new Date(nextStartTimeMillis);
Job job = new Job(slamdServer, jobClass.getClass().getName(),
numClients, currentOptimalThreads, 0, nextStartTime,
null, reRunDuration, collectionInterval, parameters,
displayInReadOnlyMode);
job.setOptimizingJobID(optimizingJobID);
job.setJobID(optimizingJobID + '-' + currentOptimalThreads + "-rerun");
job.setFolderName(folderName);
job.setRequestedClients(requestedClients);
job.setResourceMonitorClients(monitorClients);
job.setMonitorClientsIfAvailable(monitorClientsIfAvailable);
job.setWaitForClients(true);
job.setThreadStartupDelay(threadStartupDelay);
job.setJobComments(comments);
// If this optimizing job should be paused, then do so now. We will also
// unset the pause requested flag.
if (pauseRequested)
{
job.setJobState(Constants.JOB_STATE_DISABLED);
pauseRequested = false;
}
String threadStr = currentOptimalThreads + " Threads";
if ((description == null) || (description.length() == 0))
{
if (includeThreadsInDescription)
{
job.setJobDescription(threadStr + ", re-run best iteration");
}
}
else
{
if (includeThreadsInDescription)
{
job.setJobDescription(description + " (" + threadStr +
", re-run best iteration)");
}
else
{
job.setJobDescription(description + " (re-run best iteration)");
}
}
reRunIteration = job;
slamdServer.getConfigDB().writeOptimizingJob(this);
slamdServer.getScheduler().scheduleJob(job, folderName);
}
catch (Exception e)
{
jobState = Constants.JOB_STATE_STOPPED_DUE_TO_ERROR;
stopReason = "Unable to schedule a re-run of the best iteration: " + e;
try
{
slamdServer.getConfigDB().writeOptimizingJob(this);
}
catch (DatabaseException de)
{
slamdServer.logMessage(Constants.LOG_LEVEL_ANY,
"Unable to update optimizing job information " +
"for optimizing job " + optimizingJobID +
" to indicate stopped due to scheduling " +
"failure: " + de);
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(de));
}
slamdServer.getScheduler().decacheOptimizingJob(optimizingJobID);
sendJobCompleteNotification();
return;
}
}
/**
* Sends an e-mail message to any configured recipients indicating that the
* optimization process has completed.
*/
public void sendJobCompleteNotification()
{
// If there is no one to notify, then don't do anything.
if ((notifyAddresses == null) || (notifyAddresses.length == 0))
{
return;
}
// Initialize variables we will use later.
SMTPMailer mailer = slamdServer.getMailer();
SimpleDateFormat dateFormat =
new SimpleDateFormat(Constants.DISPLAY_DATE_FORMAT);
// Construct an e-mail message with information about the optimizing job.
String EOL = Constants.SMTP_EOL;
String subject = "SLAMD optimizing job " + optimizingJobID + " completed";
StringBuilder message = new StringBuilder();
message.append("The optimization process for the SLAMD optimizing job " +
optimizingJobID + " has completed." + EOL + EOL);
String baseURI = mailer.getServletBaseURI();
if ((baseURI != null) && (baseURI.length() > 0))
{
message.append("For more detailed information about this job, go to" +
EOL);
message.append(baseURI + '?' + Constants.SERVLET_PARAM_SECTION + '=' +
Constants.SERVLET_SECTION_JOB + '&' +
Constants.SERVLET_PARAM_SUBSECTION + '=' +
Constants.SERVLET_SECTION_JOB_VIEW_OPTIMIZING + '&' +
Constants.SERVLET_PARAM_OPTIMIZING_JOB_ID + '=' +
optimizingJobID + EOL + EOL);
}
message.append("Optimizing job ID: " + optimizingJobID + EOL);
if (actualStartTime != null)
{
message.append("Actual Start Time: " +
dateFormat.format(actualStartTime) + EOL);
}
if (actualStopTime != null)
{
message.append("Actual Stop Time: " + dateFormat.format(actualStopTime) +
EOL);
}
message.append("Current State: " + Constants.jobStateToString(jobState) +
EOL);
message.append("Stop Reason: " + stopReason + EOL);
DecimalFormat decimalFormat = new DecimalFormat("0.000");
if (currentOptimalThreads > 0)
{
message.append(EOL);
ParameterList paramList =
optimizationAlgorithm.getOptimizationAlgorithmParameters();
Parameter[] params = paramList.getParameters();
for (int i=0; i < params.length; i++)
{
message.append(params[i].getDisplayName() + ": " +
params[i].getDisplayValue() + EOL);
}
message.append("Optimal Number of Threads: " + currentOptimalThreads +
EOL);
message.append("Optimal Value : " +
decimalFormat.format(getOptimalValue()) + EOL);
message.append(EOL);
}
if (reRunIteration != null)
{
try
{
double reRunValue =
optimizationAlgorithm.getIterationOptimizationValue(
reRunIteration);
message.append("Re-Run Value: " + decimalFormat.format(reRunValue) +
EOL);
message.append(EOL);
} catch (Exception e) {}
}
mailer.sendMessage(notifyAddresses, subject, message.toString());
}
/**
* Encodes information about this optimizing job to a byte array suitable for
* storage in the configuration database.
*
* @return The byte array containing the encoded optimizing job.
*/
public byte[] encode()
{
ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>();
SimpleDateFormat dateFormat =
new SimpleDateFormat(Constants.ATTRIBUTE_DATE_FORMAT);
elementList.add(new ASN1OctetString(ELEMENT_OPTIMIZING_JOB_ID));
elementList.add(new ASN1OctetString(optimizingJobID));
elementList.add(new ASN1OctetString(ELEMENT_FOLDER_NAME));
elementList.add(new ASN1OctetString(folderName));
elementList.add(new ASN1OctetString(ELEMENT_PAUSE_REQUESTED));
elementList.add(new ASN1Boolean(pauseRequested));
if ((jobList != null) && (! jobList.isEmpty()))
{
ASN1Element[] idElements = new ASN1Element[jobList.size()];
for (int i=0; i < idElements.length; i++)
{
Job job = jobList.get(i);
idElements[i] = new ASN1OctetString(job.getJobID());
}
elementList.add(new ASN1OctetString(ELEMENT_ITERATION_IDS));
elementList.add(new ASN1Sequence(idElements));
}
if (reRunIteration != null)
{
elementList.add(new ASN1OctetString(ELEMENT_RERUN_ID));
elementList.add(new ASN1OctetString(reRunIteration.getJobID()));
}
elementList.add(new ASN1OctetString(ELEMENT_JOB_CLASS));
elementList.add(new ASN1OctetString(jobClass.getClass().getName()));
elementList.add(new ASN1OctetString(ELEMENT_JOB_STATE));
elementList.add(new ASN1Integer(jobState));
if ((jobGroup != null) && (jobGroup.length() > 0))
{
elementList.add(new ASN1OctetString(ELEMENT_JOB_GROUP));
elementList.add(new ASN1OctetString(jobGroup));
}
if ((description != null) && (description.length() > 0))
{
elementList.add(new ASN1OctetString(ELEMENT_DESCRIPTION));
elementList.add(new ASN1OctetString(description));
}
elementList.add(new ASN1OctetString(
ELEMENT_INCLUDE_THREADS_IN_DESCRIPTION));
elementList.add(new ASN1Boolean(includeThreadsInDescription));
elementList.add(new ASN1OctetString(ELEMENT_DISPLAY_IN_READ_ONLY));
elementList.add(new ASN1Boolean(displayInReadOnlyMode));
if (startTime != null)
{
elementList.add(new ASN1OctetString(ELEMENT_START_TIME));
elementList.add(new ASN1OctetString(dateFormat.format(startTime)));
}
elementList.add(new ASN1OctetString(ELEMENT_DURATION));
elementList.add(new ASN1Integer(duration));
elementList.add(new ASN1OctetString(ELEMENT_DELAY_BETWEEN_ITERATIONS));
elementList.add(new ASN1Integer(delayBetweenIterations));
elementList.add(new ASN1OctetString(ELEMENT_NUM_CLIENTS));
elementList.add(new ASN1Integer(numClients));
if ((requestedClients != null) && (requestedClients.length > 0))
{
ASN1Element[] clientElements = new ASN1Element[requestedClients.length];
for (int i=0; i < requestedClients.length; i++)
{
clientElements[i] = new ASN1OctetString(requestedClients[i]);
}
elementList.add(new ASN1OctetString(ELEMENT_REQUESTED_CLIENTS));
elementList.add(new ASN1Sequence(clientElements));
}
if ((monitorClients != null) && (monitorClients.length > 0))
{
ASN1Element[] clientElements = new ASN1Element[monitorClients.length];
for (int i=0; i < monitorClients.length; i++)
{
clientElements[i] = new ASN1OctetString(monitorClients[i]);
}
elementList.add(new ASN1OctetString(ELEMENT_MONITOR_CLIENTS));
elementList.add(new ASN1Sequence(clientElements));
}
elementList.add(new ASN1OctetString(ELEMENT_MONITOR_CLIENTS_IF_AVAILABLE));
elementList.add(new ASN1Boolean(monitorClientsIfAvailable));
elementList.add(new ASN1OctetString(ELEMENT_MIN_THREADS));
elementList.add(new ASN1Integer(minThreads));
elementList.add(new ASN1OctetString(ELEMENT_MAX_THREADS));
elementList.add(new ASN1Integer(maxThreads));
elementList.add(new ASN1OctetString(ELEMENT_THREAD_INCREMENT));
elementList.add(new ASN1Integer(threadIncrement));
elementList.add(new ASN1OctetString(ELEMENT_COLLECTION_INTERVAL));
elementList.add(new ASN1Integer(collectionInterval));
elementList.add(new ASN1OctetString(ELEMENT_MAX_NONIMPROVING));
elementList.add(new ASN1Integer(maxNonImproving));
elementList.add(new ASN1OctetString(ELEMENT_RERUN_BEST_ITERATION));
elementList.add(new ASN1Boolean(reRunBestIteration));
elementList.add(new ASN1OctetString(ELEMENT_RERUN_DURATION));
elementList.add(new ASN1Integer(reRunDuration));
if (threadStartupDelay > 0)
{
elementList.add(new ASN1OctetString(ELEMENT_THREAD_STARTUP_DELAY));
elementList.add(new ASN1Integer(threadStartupDelay));
}
if ((notifyAddresses != null) && (notifyAddresses.length > 0))
{
ASN1Element[] addrElements = new ASN1Element[notifyAddresses.length];
for (int i=0; i < notifyAddresses.length; i++)
{
addrElements[i] = new ASN1OctetString(notifyAddresses[i]);
}
elementList.add(new ASN1OctetString(ELEMENT_NOTIFY_ADDRESSES));
elementList.add(new ASN1Sequence(addrElements));
}
if ((dependencies != null) && (dependencies.length > 0))
{
ASN1Element[] dependencyElements = new ASN1Element[dependencies.length];
for (int i=0; i < dependencies.length; i++)
{
dependencyElements[i] = new ASN1OctetString(dependencies[i]);
}
elementList.add(new ASN1OctetString(ELEMENT_DEPENDENCIES));
elementList.add(new ASN1Sequence(dependencyElements));
}
if (jobClass instanceof UnknownJobClass)
{
ASN1Element[] optimizationAlgorithmElements = new ASN1Element[]
{
new ASN1OctetString(optimizationAlgorithm.getClass().getName()),
new ASN1Sequence()
};
elementList.add(new ASN1OctetString(ELEMENT_OPTIMIZATION_ALGORITHM));
elementList.add(new ASN1Sequence(optimizationAlgorithmElements));
}
else
{
Parameter[] optimizationParams =
optimizationAlgorithm.getOptimizationAlgorithmParameters().
getParameters();
ASN1Element[] optParamsElements =
new ASN1Element[optimizationParams.length];
for (int i=0; i < optimizationParams.length; i++)
{
ASN1Element[] optParamElements = new ASN1Element[]
{
new ASN1OctetString(optimizationParams[i].getName()),
new ASN1OctetString(optimizationParams[i].getValueString())
};
optParamsElements[i] = new ASN1Sequence(optParamElements);
}
ASN1Element[] optimizationAlgorithmElements = new ASN1Element[]
{
new ASN1OctetString(optimizationAlgorithm.getClass().getName()),
new ASN1Sequence(optParamsElements)
};
elementList.add(new ASN1OctetString(ELEMENT_OPTIMIZATION_ALGORITHM));
elementList.add(new ASN1Sequence(optimizationAlgorithmElements));
}
Parameter[] params = parameters.getParameters();
ArrayList<ASN1Element> paramList = new ArrayList<ASN1Element>();
for (int i=0; i < params.length; i++)
{
if ((params[i] instanceof PlaceholderParameter) ||
(params[i] instanceof LabelParameter))
{
continue;
}
ASN1Element[] paramElements = new ASN1Element[]
{
new ASN1OctetString(params[i].getName()),
new ASN1OctetString(params[i].getValueString())
};
paramList.add(new ASN1Sequence(paramElements));
}
ASN1Element[] paramsElements = new ASN1Element[paramList.size()];
paramList.toArray(paramsElements);
elementList.add(new ASN1OctetString(ELEMENT_PARAMETERS));
elementList.add(new ASN1Sequence(paramsElements));
if (actualStartTime != null)
{
elementList.add(new ASN1OctetString(ELEMENT_ACTUAL_START_TIME));
elementList.add(new ASN1OctetString(dateFormat.format(actualStartTime)));
}
if (actualStopTime != null)
{
elementList.add(new ASN1OctetString(ELEMENT_ACTUAL_STOP_TIME));
elementList.add(new ASN1OctetString(dateFormat.format(actualStopTime)));
}
if ((stopReason != null) && (stopReason.length() > 0))
{
elementList.add(new ASN1OctetString(ELEMENT_STOP_REASON));
elementList.add(new ASN1OctetString(stopReason));
}
if ((comments != null) && (comments.length() > 0))
{
elementList.add(new ASN1OctetString(ELEMENT_COMMENTS));
elementList.add(new ASN1OctetString(comments));
}
ASN1Element[] elements = new ASN1Element[elementList.size()];
elementList.toArray(elements);
return new ASN1Sequence(elements).encode();
}
/**
* Decodes the provided byte array as an optimizing job.
*
* @param slamdServer The SLAMD server with which the optimizing
* job is associated.
* @param encodedOptimizingJob The byte array containing the encoded
* optimizing job.
*
* @return The optimizing job decoded from the provided byte array.
*
* @throws DecodeException If a problem occurs while attempting to decode
* the provided byte array as an optimizing job.
*/
public static OptimizingJob decode(SLAMDServer slamdServer,
byte[] encodedOptimizingJob)
throws DecodeException
{
try
{
boolean displayInReadOnlyMode = false;
boolean includeThreadsInDescription = false;
boolean monitorClientsIfAvailable = false;
boolean pauseRequested = false;
boolean reRunBestIteration = false;
Date actualStartTime = null;
Date actualStopTime = null;
Date startTime = null;
int collectionInterval = -1;
int delayBetweenIterations = 0;
int duration = -1;
int jobState = -1;
int maxNonImproving = 1;
int maxThreads = 1;
int minThreads = 1;
int numClients = -1;
int reRunDuration = -1;
int threadIncrement = 1;
int threadStartupDelay = 0;
Job reRunIteration = null;
Job[] iterations = new Job[0];
JobClass jobClass = null;
OptimizationAlgorithm optimizationAlgorithm = null;
ParameterList parameters = new ParameterList();
ParameterList optimizationParameters = new ParameterList();
String comments = null;
String description = null;
String folderName = null;
String jobGroup = null;
String optimizingJobID = null;
String stopReason = null;
String[] dependencies = new String[0];
String[] monitorClients = new String[0];
String[] notifyAddresses = new String[0];
String[] requestedClients = new String[0];
SimpleDateFormat dateFormat =
new SimpleDateFormat(Constants.ATTRIBUTE_DATE_FORMAT);
ASN1Element element = ASN1Element.decode(encodedOptimizingJob);
ASN1Element[] elements = element.decodeAsSequence().getElements();
for (int i=0; i < elements.length; i += 2)
{
String elementName = elements[i].decodeAsOctetString().getStringValue();
if (elementName.equals(ELEMENT_OPTIMIZING_JOB_ID))
{
optimizingJobID =
elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_FOLDER_NAME))
{
folderName = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_PAUSE_REQUESTED))
{
pauseRequested = elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_ITERATION_IDS))
{
ASN1Element[] idElements =
elements[i+1].decodeAsSequence().getElements();
ArrayList<Job> jobList = new ArrayList<Job>(idElements.length);
for (int j=0; j < idElements.length; j++)
{
String jobID = idElements[j].decodeAsOctetString().getStringValue();
Job job = slamdServer.getConfigDB().getJob(jobID);
if (job != null)
{
jobList.add(job);
}
}
iterations = new Job[jobList.size()];
jobList.toArray(iterations);
}
else if (elementName.equals(ELEMENT_RERUN_ID))
{
String jobID = elements[i+1].decodeAsOctetString().getStringValue();
reRunIteration = slamdServer.getConfigDB().getJob(jobID);
}
else if (elementName.equals(ELEMENT_JOB_CLASS))
{
String jobClassName =
elements[i+1].decodeAsOctetString().getStringValue();
jobClass = slamdServer.getOrLoadJobClass(jobClassName);
}
else if (elementName.equals(ELEMENT_JOB_STATE))
{
jobState = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_JOB_GROUP))
{
jobGroup = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_DESCRIPTION))
{
description = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_INCLUDE_THREADS_IN_DESCRIPTION))
{
includeThreadsInDescription =
elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_DISPLAY_IN_READ_ONLY))
{
displayInReadOnlyMode =
elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_START_TIME))
{
String timeStr = elements[i+1].decodeAsOctetString().getStringValue();
startTime = dateFormat.parse(timeStr);
}
else if (elementName.equals(ELEMENT_DURATION))
{
duration = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_DELAY_BETWEEN_ITERATIONS))
{
delayBetweenIterations =
elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_NUM_CLIENTS))
{
numClients = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_REQUESTED_CLIENTS))
{
ASN1Element[] clientElements =
elements[i+1].decodeAsSequence().getElements();
requestedClients = new String[clientElements.length];
for (int j=0; j < requestedClients.length; j++)
{
requestedClients[j] =
clientElements[j].decodeAsOctetString().getStringValue();
}
}
else if (elementName.equals(ELEMENT_MONITOR_CLIENTS))
{
ASN1Element[] clientElements =
elements[i+1].decodeAsSequence().getElements();
monitorClients = new String[clientElements.length];
for (int j=0; j < monitorClients.length; j++)
{
monitorClients[j] =
clientElements[j].decodeAsOctetString().getStringValue();
}
}
else if (elementName.equals(ELEMENT_MONITOR_CLIENTS_IF_AVAILABLE))
{
monitorClientsIfAvailable =
elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_MIN_THREADS))
{
minThreads = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_MAX_THREADS))
{
maxThreads = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_THREAD_INCREMENT))
{
threadIncrement = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_THREAD_STARTUP_DELAY))
{
threadStartupDelay = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_COLLECTION_INTERVAL))
{
collectionInterval = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_MAX_NONIMPROVING))
{
maxNonImproving = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_RERUN_BEST_ITERATION))
{
reRunBestIteration =
elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_RERUN_DURATION))
{
reRunDuration = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_NOTIFY_ADDRESSES))
{
ASN1Element[] addrElements =
elements[i+1].decodeAsSequence().getElements();
notifyAddresses = new String[addrElements.length];
for (int j=0; j < notifyAddresses.length; j++)
{
notifyAddresses[j] =
addrElements[j].decodeAsOctetString().getStringValue();
}
}
else if (elementName.equals(ELEMENT_DEPENDENCIES))
{
ASN1Element[] dependencyElements =
elements[i+1].decodeAsSequence().getElements();
dependencies = new String[dependencyElements.length];
for (int j=0; j < dependencies.length; j++)
{
dependencies[j] =
dependencyElements[j].decodeAsOctetString().getStringValue();
}
}
else if (elementName.equals(ELEMENT_OPTIMIZATION_ALGORITHM))
{
if (jobClass == null)
{
for (int j=i+2; j < elements.length; j += 2)
{
String name = elements[j].decodeAsOctetString().getStringValue();
if (name.equals(ELEMENT_JOB_CLASS))
{
String className =
elements[j+1].decodeAsOctetString().getStringValue();
jobClass = slamdServer.getOrLoadJobClass(className);
break;
}
}
}
ASN1Element[] algorithmElements =
elements[i+1].decodeAsSequence().getElements();
String algorithmName =
algorithmElements[0].decodeAsOctetString().getStringValue();
optimizationAlgorithm = (OptimizationAlgorithm)
Constants.classForName(algorithmName).newInstance();
optimizationParameters = optimizationAlgorithm.
getOptimizationAlgorithmParameterStubs(jobClass).clone();
ASN1Element[] paramsElements =
algorithmElements[1].decodeAsSequence().getElements();
for (int j=0; j < paramsElements.length; j++)
{
ASN1Element[] paramElements =
paramsElements[j].decodeAsSequence().getElements();
String name =
paramElements[0].decodeAsOctetString().getStringValue();
String value =
paramElements[1].decodeAsOctetString().getStringValue();
Parameter p = optimizationParameters.getParameter(name);
if (p != null)
{
p.setValueFromString(value);
}
}
}
else if (elementName.equals(ELEMENT_PARAMETERS))
{
if (jobClass == null)
{
for (int j=i+2; j < elements.length; j += 2)
{
String name = elements[j].decodeAsOctetString().getStringValue();
if (name.equals(ELEMENT_JOB_CLASS))
{
String jobClassName =
elements[j+1].decodeAsOctetString().getStringValue();
jobClass = slamdServer.getOrLoadJobClass(jobClassName);
break;
}
}
}
parameters = jobClass.getClientSideParameterStubs().clone();
ASN1Element[] paramsElements =
elements[i+1].decodeAsSequence().getElements();
for (int j=0; j < paramsElements.length; j++)
{
ASN1Element[] paramElements =
paramsElements[j].decodeAsSequence().getElements();
String name =
paramElements[0].decodeAsOctetString().getStringValue();
String value =
paramElements[1].decodeAsOctetString().getStringValue();
Parameter p = parameters.getParameter(name);
if (p != null)
{
p.setValueFromString(value);
}
}
}
else if (elementName.equals(ELEMENT_ACTUAL_START_TIME))
{
String timeStr = elements[i+1].decodeAsOctetString().getStringValue();
actualStartTime = dateFormat.parse(timeStr);
}
else if (elementName.equals(ELEMENT_ACTUAL_STOP_TIME))
{
String timeStr = elements[i+1].decodeAsOctetString().getStringValue();
actualStopTime = dateFormat.parse(timeStr);
}
else if (elementName.equals(ELEMENT_STOP_REASON))
{
stopReason = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_COMMENTS))
{
comments = elements[i+1].decodeAsOctetString().getStringValue();
}
}
OptimizingJob optimizingJob =
new OptimizingJob(slamdServer, optimizingJobID,
optimizationAlgorithm, jobClass, folderName,
description, includeThreadsInDescription,
startTime, duration, delayBetweenIterations,
numClients, requestedClients, monitorClients,
monitorClientsIfAvailable, minThreads, maxThreads,
threadIncrement, collectionInterval,
maxNonImproving, notifyAddresses,
reRunBestIteration, reRunDuration, parameters,
displayInReadOnlyMode);
if (! (jobClass instanceof UnknownJobClass))
{
optimizationAlgorithm.initializeOptimizationAlgorithm(optimizingJob,
optimizationParameters);
}
optimizingJob.setActualStartTime(actualStartTime);
optimizingJob.setActualStopTime(actualStopTime);
optimizingJob.setAssociatedJobs(iterations);
optimizingJob.setDependencies(dependencies);
optimizingJob.setJobState(jobState);
optimizingJob.setJobGroup(jobGroup);
optimizingJob.setReRunIteration(reRunIteration);
optimizingJob.setStopReason(stopReason);
optimizingJob.setThreadStartupDelay(threadStartupDelay);
optimizingJob.setComments(comments);
optimizingJob.pauseRequested = pauseRequested;
return optimizingJob;
}
catch (Exception e)
{
throw new DecodeException("Unable to decode optimizing job: " + e, e);
}
}
/**
* Decodes the provided byte array as an optimizing job, but only including
* summary information.
*
* @param slamdServer The SLAMD server with which the optimizing
* job is associated.
* @param encodedOptimizingJob The byte array containing the encoded
* optimizing job.
*
* @return The summary optimizing job decoded from the provided byte array.
*
* @throws DecodeException If a problem occurs while attempting to decode
* the provided byte array as an optimizing job.
*/
public static OptimizingJob decodeSummary(SLAMDServer slamdServer,
byte[] encodedOptimizingJob)
throws DecodeException
{
try
{
boolean displayInReadOnlyMode = false;
Date actualStartTime = null;
Date startTime = null;
int jobState = -1;
JobClass jobClass = null;
String description = null;
String folderName = null;
String optimizingJobID = null;
SimpleDateFormat dateFormat =
new SimpleDateFormat(Constants.ATTRIBUTE_DATE_FORMAT);
ASN1Element element = ASN1Element.decode(encodedOptimizingJob);
ASN1Element[] elements = element.decodeAsSequence().getElements();
for (int i=0; i < elements.length; i += 2)
{
String elementName = elements[i].decodeAsOctetString().getStringValue();
if (elementName.equals(ELEMENT_OPTIMIZING_JOB_ID))
{
optimizingJobID =
elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_FOLDER_NAME))
{
folderName = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_JOB_CLASS))
{
String jobClassName =
elements[i+1].decodeAsOctetString().getStringValue();
jobClass = slamdServer.getOrLoadJobClass(jobClassName);
}
else if (elementName.equals(ELEMENT_JOB_STATE))
{
jobState = elements[i+1].decodeAsInteger().getIntValue();
}
else if (elementName.equals(ELEMENT_DESCRIPTION))
{
description = elements[i+1].decodeAsOctetString().getStringValue();
}
else if (elementName.equals(ELEMENT_DISPLAY_IN_READ_ONLY))
{
displayInReadOnlyMode =
elements[i+1].decodeAsBoolean().getBooleanValue();
}
else if (elementName.equals(ELEMENT_START_TIME))
{
String timeStr = elements[i+1].decodeAsOctetString().getStringValue();
startTime = dateFormat.parse(timeStr);
}
else if (elementName.equals(ELEMENT_ACTUAL_START_TIME))
{
String timeStr = elements[i+1].decodeAsOctetString().getStringValue();
actualStartTime = dateFormat.parse(timeStr);
}
}
OptimizingJob optimizingJob =
new OptimizingJob(slamdServer, optimizingJobID, null, jobClass,
folderName, description, false, startTime, -1, 0,
-1, null, null, false, 1, -1, 1, 1, 1, null, false,
-1, null, displayInReadOnlyMode);
optimizingJob.setActualStartTime(actualStartTime);
optimizingJob.setJobState(jobState);
return optimizingJob;
}
catch (Exception e)
{
throw new DecodeException("Unable to decode optimizing job: " + e, e);
}
}
/**
* Compares this optimizing job with the provided object to determine the
* relative order of the two in a sorted list. The comparison will be based
* first by start time, then by optimizing job ID.
*
* @param o The object to compare with this optimizing job. It must be an
* OptimizingJob.
*
* @return A negative value if this optimizing job should be ordered before
* the provided object, a positive value if this optimizing job
* should be ordered after the provided object, or zero if there is
* no difference in ordering.
*
* @throws ClassCastException If the provided object is not an
* OptimizingJob.
*/
public int compareTo(Object o)
throws ClassCastException
{
if (o == null)
{
return -1;
}
String optimizingJobID2 = "";
try
{
OptimizingJob oj = (OptimizingJob) o;
optimizingJobID2 = oj.getOptimizingJobID();
StringTokenizer t1 = new StringTokenizer(optimizingJobID, "-");
StringTokenizer t2 = new StringTokenizer(optimizingJobID2, "-");
// Get the timestamp string. If they differ, then use the
// String.compareTo method.
String date1 = t1.nextToken();
String date2 = t2.nextToken();
if (! date1.equals(date2))
{
return date1.compareTo(date2);
}
// Get the random + counter portion. If they differ, then compare the
// numeric counter portions.
String counterStr1 = t1.nextToken();
String counterStr2 = t2.nextToken();
if (! counterStr1.equals(counterStr2))
{
Integer counter1 = new Integer(counterStr1.substring(6));
Integer counter2 = new Integer(counterStr2.substring(6));
return counter1.compareTo(counter2);
}
// We shouldn't get this far for an optimizing job, so just use a string
// comparison.
return optimizingJobID.compareTo(optimizingJobID2);
}
catch (Exception e)
{
slamdServer.logMessage(Constants.LOG_LEVEL_EXCEPTION_DEBUG,
JobClass.stackTraceToString(e));
return optimizingJobID.compareTo(optimizingJobID2);
}
}
}