Initial Repository Push
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
|
||||
/**
|
||||
* Provides mandatory base implementation for all 'Job's'.
|
||||
*
|
||||
* @author
|
||||
*/
|
||||
public abstract class AbstractJob implements Runnable {
|
||||
|
||||
public enum JobRunStatus {
|
||||
CREATED, RUNNING, FINISHED;
|
||||
};
|
||||
|
||||
public enum JobCompletionStatus {
|
||||
NOTCOMPLETEDYET, SUCCESS, SUCCESSWITHERRORS, FAIL;
|
||||
};
|
||||
|
||||
/**
|
||||
* Keep fields private. All access through getters n setters for Thread
|
||||
* Safety.
|
||||
*/
|
||||
private JobRunStatus runStatus;
|
||||
private JobCompletionStatus completeStatus;
|
||||
private UUID uuid = null;
|
||||
|
||||
private final AtomicReference<String> workerID;
|
||||
private static final String DEFAULT_WORKERID = "UNPROCESSED_JOB";
|
||||
|
||||
private long submitTime = 0L;
|
||||
private long startTime = 0L;
|
||||
private long stopTime = 0L;
|
||||
|
||||
public AbstractJob() {
|
||||
//Tests against DEFAULT_WORKERID to ensure single execution
|
||||
this.workerID = new AtomicReference<>(DEFAULT_WORKERID);
|
||||
this.runStatus = JobRunStatus.RUNNING;
|
||||
this.completeStatus = JobCompletionStatus.NOTCOMPLETEDYET;
|
||||
this.uuid = UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if(workerID.get().equals(DEFAULT_WORKERID)) {
|
||||
Logger.warn("FIX ME! Job ran through 'run()' directly. Use executeJob(String) instead.");
|
||||
}
|
||||
|
||||
this.markStartRunTime();
|
||||
|
||||
this.setRunStatus(JobRunStatus.RUNNING);
|
||||
try {
|
||||
this.doJob();
|
||||
} catch (Exception e) {
|
||||
Logger.error(e);
|
||||
}
|
||||
|
||||
this.setRunStatus(JobRunStatus.FINISHED);
|
||||
|
||||
this.markStopRunTime();
|
||||
}
|
||||
|
||||
protected abstract void doJob();
|
||||
|
||||
public void executeJob(String threadName) {
|
||||
this.workerID.set(threadName);
|
||||
this.run();
|
||||
}
|
||||
|
||||
protected void setRunStatus(JobRunStatus status) {
|
||||
synchronized (this.runStatus) {
|
||||
this.runStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
public JobRunStatus getRunStatus() {
|
||||
synchronized (this.runStatus) {
|
||||
return runStatus;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setCompletionStatus(JobCompletionStatus status) {
|
||||
synchronized (this.completeStatus) {
|
||||
this.completeStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
public JobCompletionStatus getCompletionStatus() {
|
||||
synchronized (this.completeStatus) {
|
||||
return completeStatus;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setJobId(UUID id) {
|
||||
synchronized (this.uuid) {
|
||||
this.uuid = id;
|
||||
}
|
||||
}
|
||||
|
||||
public UUID getJobId() {
|
||||
synchronized (this.uuid) {
|
||||
return uuid;
|
||||
}
|
||||
}
|
||||
|
||||
public String getWorkerID() {
|
||||
return workerID.get();
|
||||
}
|
||||
|
||||
/*
|
||||
* Time markers
|
||||
*/
|
||||
|
||||
protected void markSubmitTime() {
|
||||
this.submitTime = System.currentTimeMillis()-2;
|
||||
}
|
||||
|
||||
protected void markStartRunTime() {
|
||||
this.startTime = System.currentTimeMillis()-1;
|
||||
}
|
||||
|
||||
protected void markStopRunTime() {
|
||||
this.stopTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
public final long getSubmitTime() {
|
||||
return submitTime;
|
||||
}
|
||||
|
||||
public final long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public final long getStopTime() {
|
||||
return stopTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
public abstract class AbstractJobStatistics {
|
||||
|
||||
private String objectName;
|
||||
private long totalServiceTime = 0L;
|
||||
private long totalQueueTime = 0L;
|
||||
private long executions = 0L;
|
||||
private long maxServiceTime = 0L;
|
||||
private long minServiceTime = 0L;
|
||||
private long minQueueTime = 0L;
|
||||
private long maxQueueTime = 0L;
|
||||
|
||||
|
||||
public AbstractJobStatistics() {
|
||||
this.objectName = "Unknown";
|
||||
}
|
||||
|
||||
public AbstractJobStatistics(String objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
|
||||
public void setObjectName (String objectName) {
|
||||
this.objectName = objectName;
|
||||
}
|
||||
|
||||
public String getObjectName () {
|
||||
return this.objectName;
|
||||
}
|
||||
|
||||
public long getExecutions() {
|
||||
return this.executions;
|
||||
}
|
||||
|
||||
public long getTotalServiceTime() {
|
||||
return this.totalServiceTime;
|
||||
}
|
||||
|
||||
public long getTotalQueueTime() {
|
||||
return this.totalQueueTime;
|
||||
}
|
||||
|
||||
public long getAvgQueueTime() {
|
||||
if (this.executions > 0L && this.totalQueueTime > 0L)
|
||||
return this.totalQueueTime / this.executions;
|
||||
else
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long getAvgServiceTime() {
|
||||
if (this.executions > 0L && this.totalServiceTime > 0L)
|
||||
return this.totalServiceTime / this.executions;
|
||||
else
|
||||
return 0L;
|
||||
}
|
||||
|
||||
public long getMinServiceTime() {
|
||||
return this.minServiceTime;
|
||||
}
|
||||
|
||||
public long getMinQueueTime() {
|
||||
return this.minQueueTime;
|
||||
}
|
||||
|
||||
public long getMaxServiceTime() {
|
||||
return this.maxServiceTime;
|
||||
}
|
||||
|
||||
public long getMaxQueueTime() {
|
||||
return this.maxQueueTime;
|
||||
}
|
||||
|
||||
public void incrExecutions() {
|
||||
this.executions++;
|
||||
}
|
||||
|
||||
public void addServiceTime(long svcTime) {
|
||||
this.totalServiceTime += svcTime;
|
||||
this.incrExecutions();
|
||||
if (svcTime > this.maxServiceTime)
|
||||
this.maxServiceTime = svcTime;
|
||||
if (svcTime < this.minServiceTime || this.minServiceTime == 0L)
|
||||
this.minServiceTime = svcTime;
|
||||
|
||||
}
|
||||
|
||||
public void addQueueTime(long queueTime) {
|
||||
this.totalQueueTime += queueTime;
|
||||
this.incrExecutions();
|
||||
if (queueTime > this.maxQueueTime)
|
||||
this.maxQueueTime = queueTime;
|
||||
if (queueTime < this.minQueueTime || this.minQueueTime == 0L)
|
||||
this.minQueueTime = queueTime;
|
||||
|
||||
}
|
||||
|
||||
public String asString() {
|
||||
return this.objectName + " execs=" + this.executions + " avg_svc_ms=" + this.getAvgServiceTime() +
|
||||
" min_svc_ms=" + this.minServiceTime + " max_svc_ms=" + this.maxServiceTime +
|
||||
" avg_q_ms=" + this.getAvgQueueTime() + " min_q_ms=" + this.minQueueTime +
|
||||
" max_q_ms=" + this.maxQueueTime;
|
||||
}
|
||||
|
||||
public String asChatMsg() {
|
||||
return this.objectName + "=>" + this.executions + ',' + this.getAvgServiceTime() + '/' + this.minServiceTime +
|
||||
'/' + this.maxServiceTime + " "+ this.getAvgQueueTime() + '/' +
|
||||
this.minQueueTime + '/' + this.maxQueueTime + '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
|
||||
public abstract class AbstractScheduleJob extends AbstractJob {
|
||||
|
||||
public AbstractScheduleJob() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract void doJob();
|
||||
|
||||
public void cancelJob() {
|
||||
JobScheduler.getInstance().cancelScheduledJob(this);
|
||||
_cancelJob();
|
||||
}
|
||||
|
||||
protected abstract void _cancelJob();
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
public class ClassJobStatistics extends AbstractJobStatistics {
|
||||
|
||||
public ClassJobStatistics (String className) {
|
||||
super(className);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
|
||||
public class JobContainer implements Comparable<JobContainer> {
|
||||
|
||||
final AbstractJob job;
|
||||
final long timeOfExecution;
|
||||
final boolean noTimer;
|
||||
|
||||
JobContainer(AbstractJob job, long timeOfExecution) {
|
||||
if (job == null) {
|
||||
throw new IllegalArgumentException("No 'null' jobs allowed.");
|
||||
}
|
||||
this.job = job;
|
||||
this.timeOfExecution = timeOfExecution;
|
||||
this.noTimer = false;
|
||||
}
|
||||
|
||||
public JobContainer(AbstractJob job) {
|
||||
if (job == null) {
|
||||
throw new IllegalArgumentException("No 'null' jobs allowed.");
|
||||
}
|
||||
this.job = job;
|
||||
this.timeOfExecution = Long.MAX_VALUE;
|
||||
this.noTimer = true;
|
||||
}
|
||||
|
||||
public AbstractJob getJob() {
|
||||
return job;
|
||||
}
|
||||
|
||||
public boolean noTimer() {
|
||||
return noTimer;
|
||||
}
|
||||
|
||||
public long timeOfExection() {
|
||||
return this.timeOfExecution;
|
||||
}
|
||||
|
||||
public int timeToExecutionLeft() {
|
||||
if (JobScheduler.getInstance().isAlive()) {
|
||||
int timeLeft = (int) (timeOfExecution - System.currentTimeMillis());
|
||||
if (timeLeft < 0)
|
||||
timeLeft = 0;
|
||||
return timeLeft;
|
||||
} else
|
||||
return (int) (timeOfExecution - JobScheduler.getInstance().getTimeOfKill());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(JobContainer compared) {
|
||||
if (timeOfExecution < compared.timeOfExecution) {
|
||||
return -1;
|
||||
}
|
||||
if (timeOfExecution > compared.timeOfExecution) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return job.equals(((JobContainer) obj).job);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return job.hashCode();
|
||||
}
|
||||
|
||||
public void cancelJob() {
|
||||
if (job != null && job instanceof AbstractScheduleJob)
|
||||
((AbstractScheduleJob)job).cancelJob();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
import engine.core.ControlledRunnable;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.util.ThreadUtils;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* Note to DEVs. When attempting to log something in this class, use logDIRECT
|
||||
* only.
|
||||
*/
|
||||
public class JobManager extends ControlledRunnable {
|
||||
|
||||
/*
|
||||
* Singleton implementation.
|
||||
*/
|
||||
private static volatile JobManager INSTANCE;
|
||||
public static JobManager getInstance() {
|
||||
if (JobManager.INSTANCE == null) {
|
||||
synchronized (JobManager.class) {
|
||||
if (JobManager.INSTANCE == null) {
|
||||
JobManager.INSTANCE = new JobManager();
|
||||
JobManager.INSTANCE.startup();
|
||||
}
|
||||
}
|
||||
}
|
||||
return JobManager.INSTANCE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class implementation
|
||||
*/
|
||||
|
||||
private final ArrayList<JobPool> jobPoolList = new ArrayList<>();
|
||||
private final ConcurrentHashMap<String, JobPool> jobQueueMapping= new ConcurrentHashMap<>(MBServerStatics.CHM_INIT_CAP, MBServerStatics.CHM_LOAD, MBServerStatics.CHM_THREAD_HIGH);
|
||||
|
||||
private boolean shutdownNowFlag = false;
|
||||
|
||||
private JobManager() {
|
||||
super("JobManager");
|
||||
|
||||
// create the initial job pools with the correct sizes
|
||||
// based on the number of array elements in the initial_jo_workers
|
||||
// definition in Statisc
|
||||
|
||||
if (MBServerStatics.INITIAL_JOBPOOL_WORKERS != null && MBServerStatics.INITIAL_JOBPOOL_WORKERS.length >0 ) {
|
||||
for (int i=0; i<MBServerStatics.INITIAL_JOBPOOL_WORKERS.length; i++) {
|
||||
JobPool jp = new JobPool(i,MBServerStatics.INITIAL_JOBPOOL_WORKERS[i]);
|
||||
this.jobPoolList.add(jp);
|
||||
Logger.info( "Adding JobPool_" + jp.getJobPoolID() + " with " + MBServerStatics.INITIAL_JOBPOOL_WORKERS[i] + " workers");
|
||||
}
|
||||
} else {
|
||||
// not defined or empty in statics so just create 1 JobPool with 25 workers
|
||||
System.out.println("Creating 1 pool called 0");
|
||||
JobPool jp = new JobPool(0,25);
|
||||
this.jobPoolList.add(jp);
|
||||
Logger.info( "Adding JobPool_" + jp.getJobPoolID() + " with 25 workers");
|
||||
}
|
||||
|
||||
JobScheduler.getInstance();
|
||||
|
||||
// if you want any jobs to default onto a given queue put it here
|
||||
// otherwise everything goes on the P1 queue by default
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a job to be processed by the JobManager. There is no guarantee
|
||||
* that the job will be executed immediately.
|
||||
*
|
||||
* @param aj
|
||||
* AbstractJob to be submitted.
|
||||
* @return boolean value indicating whether the job was submitted or not.
|
||||
*/
|
||||
public boolean submitJob(AbstractJob aj) {
|
||||
|
||||
if (jobQueueMapping.containsKey(aj.getClass().getSimpleName())) {
|
||||
return this.jobQueueMapping.get(aj.getClass().getSimpleName()).submitJob(aj);
|
||||
} else {
|
||||
return this.jobPoolList.get(0).submitJob(aj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void auditAllWorkers() {
|
||||
|
||||
for (JobPool jp : this.jobPoolList) {
|
||||
jp.auditWorkers();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _Run() {
|
||||
// This thread is to be used to JM internal monitoring.
|
||||
|
||||
// Startup workers:
|
||||
this.auditAllWorkers();
|
||||
ThreadUtils.sleep(MBServerStatics.JOBMANAGER_INTERNAL_MONITORING_INTERVAL_MS * 2);
|
||||
|
||||
this.runStatus = true;
|
||||
|
||||
// Monitoring loop
|
||||
while (this.runCmd) {
|
||||
this.auditAllWorkers();
|
||||
ThreadUtils.sleep(MBServerStatics.JOBMANAGER_INTERNAL_MONITORING_INTERVAL_MS);
|
||||
}
|
||||
|
||||
// No new submissions
|
||||
for (JobPool jp : this.jobPoolList){
|
||||
jp.setBlockNewSubmissions(true);
|
||||
}
|
||||
|
||||
if (this.shutdownNowFlag == false) {
|
||||
// shutdown each pool
|
||||
for (JobPool jp : this.jobPoolList) {
|
||||
jp.shutdown();
|
||||
}
|
||||
} else {
|
||||
// Emergency Stop each pool
|
||||
for (JobPool jp : this.jobPoolList) {
|
||||
jp.emergencyStop();
|
||||
}
|
||||
}
|
||||
this.runStatus = false;
|
||||
Logger.info("JM Shutdown");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _postRun() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _preRun() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _shutdown() {
|
||||
Logger.info("JM Shutdown Requested");
|
||||
JobScheduler.getInstance().shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _startup() {
|
||||
Logger.info("JM Starting up... ");
|
||||
}
|
||||
|
||||
public void shutdownNow() {
|
||||
this.shutdownNowFlag = true;
|
||||
this.shutdown();
|
||||
}
|
||||
|
||||
public String moveJob(String simpleClassName, String jobPoolID) {
|
||||
// moves a job to a different queue
|
||||
|
||||
try {
|
||||
// parse string into an int
|
||||
Integer i = Integer.parseInt(jobPoolID);
|
||||
for (JobPool jp : this.jobPoolList) {
|
||||
if (jp.getJobPoolID() == i) {
|
||||
// move the job to the new queue
|
||||
this.jobQueueMapping.put(simpleClassName, jp);
|
||||
return simpleClassName + " moved to JobPool ID " + jp.getJobPoolID();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
return "jobPoolID is not a valid number";
|
||||
}
|
||||
|
||||
//Verify jobpool ID
|
||||
return "Invalid parameters <simpleClassName - case sensitive> <jobPoolID> required";
|
||||
}
|
||||
|
||||
public String resetJobs() {
|
||||
// moves all jobs to the P1 queue
|
||||
this.jobQueueMapping.clear();
|
||||
return "All Jobs reset onto P1 queue";
|
||||
}
|
||||
|
||||
public String showJobs() {
|
||||
String out = "";
|
||||
Iterator<String> jmi = this.jobQueueMapping.keySet().iterator();
|
||||
|
||||
while (jmi.hasNext()) {
|
||||
String jmiKey = jmi.next();
|
||||
out += jmiKey + ' ' + this.jobQueueMapping.get(jmiKey).getJobPoolID() + '\n';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
public ArrayList<JobPool> getJobPoolList() {
|
||||
|
||||
return this.jobPoolList;
|
||||
}
|
||||
|
||||
public String modifyJobPoolWorkers(String jobPoolID, String maxWorkers) {
|
||||
|
||||
try {
|
||||
// parse string into an int
|
||||
Integer jid = Integer.parseInt(jobPoolID);
|
||||
Integer mw = Integer.parseInt(maxWorkers);
|
||||
for (JobPool jp : this.jobPoolList) {
|
||||
if (jp.getJobPoolID() == jid) {
|
||||
// change the number of workers
|
||||
return jp.setMaxWorkers(mw);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
return "Invalid parameters <jobPoolID> <maxWorkers> required";
|
||||
}
|
||||
|
||||
return "Invalid parameters <jobPoolID> <maxWorkers> required";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
|
||||
import engine.jobs.AttackJob;
|
||||
import engine.jobs.UsePowerJob;
|
||||
import engine.net.CheckNetMsgFactoryJob;
|
||||
import engine.net.ConnectionMonitorJob;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
public class JobPool {
|
||||
|
||||
int jobPoolID;
|
||||
int maxWorkers;
|
||||
int nextWorkerID;
|
||||
private final LinkedBlockingQueue<AbstractJob> jobWaitQueue = new LinkedBlockingQueue<>();
|
||||
private final LinkedBlockingQueue<JobWorker> jobWorkerQueue = new LinkedBlockingQueue<>();
|
||||
private final ArrayList<JobWorker> jobWorkerList = new ArrayList<>();
|
||||
private final LinkedBlockingQueue<AbstractJob> jobRunList = new LinkedBlockingQueue<>();
|
||||
private boolean blockNewSubmissions = false;
|
||||
|
||||
public JobPool(int id, int workers) {
|
||||
this.jobPoolID = id;
|
||||
|
||||
// default to 1 unless workers parameter is higher
|
||||
int actualWorkers = 1;
|
||||
if (workers > 1)
|
||||
actualWorkers = workers;
|
||||
|
||||
this.maxWorkers = actualWorkers;
|
||||
for (int i=0;i<actualWorkers; i++) {
|
||||
this.startWorker(i);
|
||||
}
|
||||
|
||||
this.nextWorkerID = this.maxWorkers;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private int getNextWorkerID () {
|
||||
return this.nextWorkerID++;
|
||||
|
||||
|
||||
}
|
||||
public int getJobPoolID () {
|
||||
return this.jobPoolID;
|
||||
}
|
||||
|
||||
public void setBlockNewSubmissions(boolean blocked) {
|
||||
this.blockNewSubmissions = blocked;
|
||||
}
|
||||
|
||||
public boolean submitJob(AbstractJob aj) {
|
||||
|
||||
if (blockNewSubmissions) {
|
||||
Logger.warn("A '" + aj.getClass().getSimpleName() + "' job was submitted, but submissions are currently blocked.");
|
||||
return false;
|
||||
}
|
||||
|
||||
aj.markSubmitTime();
|
||||
jobWaitQueue.add(aj);
|
||||
|
||||
// keep notifying workers if the wait queue has items
|
||||
// commented out as the price of polling the wait queue
|
||||
// size while it is being updated out-weighs the gain
|
||||
// for not just blindly waking all workers
|
||||
// unless we have a stupidly large pool vs CPU threads
|
||||
|
||||
JobWorker jw = jobWorkerQueue.poll();
|
||||
if(jw != null) {
|
||||
synchronized (jw) {
|
||||
jw.notify();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startWorker(int workerID) {
|
||||
|
||||
// check we dont already have a jobWorker with that ID
|
||||
synchronized(this.jobWorkerList) {
|
||||
for (JobWorker jwi : this.jobWorkerList) {
|
||||
if (jwi.getWorkerId() == workerID) {
|
||||
Logger.error("Attempt to create worker with ID " + workerID + " failed in JobPool " + jobPoolID + " as worker ID already exists");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ID is unique, create worker
|
||||
JobWorker jw;
|
||||
jw = new JobWorker(workerID, this.jobPoolID, this.jobWaitQueue, this.jobWorkerQueue);
|
||||
|
||||
synchronized(this.jobWorkerList) {
|
||||
//Adds to the overall list..
|
||||
jobWorkerList.add(jw);
|
||||
}
|
||||
|
||||
//Returns to the free worker queue..
|
||||
jw.startup();
|
||||
}
|
||||
|
||||
private String getQueueByClassAsString(Queue<AbstractJob> q) {
|
||||
HashMap<String, Integer> ch = new HashMap<>();
|
||||
int cnt = 0;
|
||||
|
||||
|
||||
// iterate through the linked queue and get every item
|
||||
// putting classname and incrementing the value each time in the hashmap
|
||||
Iterator<AbstractJob> wi = q.iterator();
|
||||
|
||||
while (cnt < q.size() && wi.hasNext()) {
|
||||
AbstractJob aj = wi.next();
|
||||
if (ch.containsKey(aj.getClass().getSimpleName())) {
|
||||
int newValue = ch.get(aj.getClass().getSimpleName()) + 1;
|
||||
ch.put(aj.getClass().getSimpleName(), newValue);
|
||||
} else {
|
||||
ch.put(aj.getClass().getSimpleName(), 1);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
// iterate through the hashmap outputting the classname and number of jobs
|
||||
Iterator<String> i = ch.keySet().iterator();
|
||||
String out = "";
|
||||
while(i.hasNext()) {
|
||||
Object key = i.next();
|
||||
out += "JobPoolID_" + this.jobPoolID + ' ' + key.toString() + "=>" + ch.get(key) + '\n';
|
||||
}
|
||||
if (out.isEmpty())
|
||||
return "No Jobs on queue\n";
|
||||
else
|
||||
return out;
|
||||
}
|
||||
|
||||
public void auditWorkers() {
|
||||
|
||||
if(!MBServerStatics.ENABLE_AUDIT_JOB_WORKERS) {
|
||||
return;
|
||||
}
|
||||
ArrayList<AbstractJob> problemJobs = new ArrayList<>();
|
||||
|
||||
// Checked for stalled Workers
|
||||
Iterator<JobWorker> it = jobWorkerList.iterator();
|
||||
|
||||
while (it.hasNext()) {
|
||||
JobWorker jw = it.next();
|
||||
AbstractJob curJob = jw.getCurrentJob();
|
||||
|
||||
if (curJob != null) { // Has a job
|
||||
|
||||
if (JobPool.isExemptJobFromAudit(curJob)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine whether the job is being executed or waiting to
|
||||
// start;
|
||||
|
||||
if (curJob.getStartTime() <= 0) {
|
||||
// Waiting to start
|
||||
long diff = System.currentTimeMillis() - curJob.getSubmitTime();
|
||||
|
||||
if (diff >= MBServerStatics.JOB_STALL_THRESHOLD_MS) {
|
||||
Logger.warn("Job did not start within threshold. Stopping worker#" + jw.getWorkerId() + " JobData:"
|
||||
+ curJob.toString());
|
||||
jw.EmergencyStop();
|
||||
problemJobs.add(jw.getCurrentJob());
|
||||
it.remove();
|
||||
} // end if (diff >=
|
||||
|
||||
} else if (curJob.getStopTime() <= 0L) {
|
||||
// is executing it
|
||||
long diff = System.currentTimeMillis() - curJob.getStartTime();
|
||||
|
||||
if (diff >= MBServerStatics.JOB_STALL_THRESHOLD_MS) {
|
||||
Logger.warn("Job execution time exceeded threshold(" + diff + "). Stopping worker#" + jw.getWorkerId() + " JobData:"
|
||||
+ curJob.toString());
|
||||
jw.EmergencyStop();
|
||||
problemJobs.add(jw.getCurrentJob());
|
||||
it.remove();
|
||||
} // end if (diff >=
|
||||
} // end if(curJob.getStopTime()
|
||||
} // end if(curJob != null)
|
||||
} // end While
|
||||
|
||||
// Check Worker Count and add workers as necessary;
|
||||
int workerCount = jobWorkerList.size();
|
||||
|
||||
int maxThreads = this.maxWorkers;
|
||||
|
||||
|
||||
// no pool can go below a single thread
|
||||
if (maxThreads < 1)
|
||||
maxThreads = 1;
|
||||
|
||||
while (workerCount != maxThreads) {
|
||||
Logger.info("Resizing JobPool " + this.jobPoolID + " from " + workerCount + " to " + maxThreads);
|
||||
|
||||
if (workerCount < maxThreads) {
|
||||
this.startWorker(this.getNextWorkerID());
|
||||
|
||||
|
||||
if (jobWorkerList.size() <= workerCount) {
|
||||
// Something didnt work correctly
|
||||
Logger.warn("auditWorkers() failed to add a new JobWorker to JobPool " + this.jobPoolID + ". Worker count " + workerCount + " Worker pool size " + jobWorkerList.size() + " Aborting Audit.");
|
||||
return;
|
||||
}
|
||||
|
||||
} else if (workerCount > maxThreads) {
|
||||
synchronized(this.jobWorkerList) {
|
||||
Logger.warn("Reducing workers in JobPool " + this.jobPoolID + " Worker Count: " + workerCount + " to Max threads: " + maxThreads);
|
||||
// pick a worker off the list and shut it down
|
||||
|
||||
JobWorker toRemove = null;
|
||||
int loopTries = 5;
|
||||
do {
|
||||
//Infinite loop could be bad..
|
||||
toRemove = jobWorkerQueue.poll();
|
||||
} while (toRemove == null && --loopTries >= 0);
|
||||
|
||||
//remove it from the list
|
||||
toRemove.shutdown();
|
||||
jobWorkerList.remove(toRemove);
|
||||
}
|
||||
}
|
||||
|
||||
// update value for next loop pass
|
||||
workerCount = jobWorkerList.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isExemptJobFromAudit(AbstractJob aj) {
|
||||
// If the job is any of the following classes, exempt it from auditWorkers
|
||||
if (aj instanceof ConnectionMonitorJob) {
|
||||
return true;
|
||||
} else
|
||||
return aj instanceof CheckNetMsgFactoryJob || aj instanceof AttackJob || aj instanceof UsePowerJob;
|
||||
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
synchronized(this.jobWorkerList) {
|
||||
for (JobWorker jw : this.jobWorkerList)
|
||||
jw.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void emergencyStop() {
|
||||
synchronized(this.jobWorkerList) {
|
||||
for (JobWorker jw : this.jobWorkerList)
|
||||
jw.EmergencyStop();
|
||||
}
|
||||
}
|
||||
|
||||
public String getRunningQueueByClassAsString() {
|
||||
return this.getQueueByClassAsString(this.jobRunList);
|
||||
}
|
||||
|
||||
public String getWaitQueueByClassAsString () {
|
||||
return this.getQueueByClassAsString(this.jobWaitQueue);
|
||||
}
|
||||
|
||||
|
||||
// used by devcmds
|
||||
public String setMaxWorkers (int maxWorkers) {
|
||||
|
||||
if (maxWorkers > 0 && maxWorkers < 101) {
|
||||
this.maxWorkers = maxWorkers;
|
||||
// audit workers reduces the cap
|
||||
this.auditWorkers();
|
||||
return "Max workers set to " + maxWorkers + " for JobPool_" + this.jobPoolID;
|
||||
} else {
|
||||
return "Max workers not set, value must be from 1-100";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
import engine.server.MBServerStatics;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
|
||||
public class JobScheduler {
|
||||
|
||||
private static final JobScheduler INSTANCE = new JobScheduler();
|
||||
|
||||
private final PriorityQueue<JobContainer> jobs;
|
||||
private volatile boolean alive;
|
||||
private long timeOfKill = -1;
|
||||
|
||||
public static JobScheduler getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
private JobScheduler() {
|
||||
jobs = new PriorityQueue<>(MBServerStatics.SCHEDULER_INITIAL_CAPACITY);
|
||||
Runnable worker = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
execution();
|
||||
}
|
||||
};
|
||||
|
||||
alive = true;
|
||||
|
||||
Thread t = new Thread(worker, "JobScheduler");
|
||||
t.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function schedules a job to execute in <i>timeToExecution</i>
|
||||
* milliseconds from now.
|
||||
*
|
||||
* @param job
|
||||
* @param timeToExecution
|
||||
* @return
|
||||
*/
|
||||
public JobContainer scheduleJob(AbstractJob job, int timeToExecution) {
|
||||
long timeOfExecution = System.currentTimeMillis() + timeToExecution;
|
||||
JobContainer container = new JobContainer(job, timeOfExecution);
|
||||
|
||||
synchronized (jobs) {
|
||||
jobs.offer(container);
|
||||
jobs.notify();
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function schedules a job to execute at the absolute time of
|
||||
* <i>timeOfExecution</i> (milliseconds).
|
||||
*
|
||||
* @param job
|
||||
* @param timeOfExecution
|
||||
* @return
|
||||
*/
|
||||
public JobContainer scheduleJob(AbstractJob job, long timeOfExecution) {
|
||||
JobContainer container = new JobContainer(job, timeOfExecution);
|
||||
|
||||
synchronized (jobs) {
|
||||
jobs.offer(container);
|
||||
jobs.notify();
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public boolean cancelScheduledJob(JobContainer container) {
|
||||
return cancelScheduledJob(container.getJob());
|
||||
}
|
||||
|
||||
public boolean cancelScheduledJob(AbstractJob job) {
|
||||
JobContainer container = new JobContainer(job, -1);
|
||||
|
||||
boolean success = false;
|
||||
synchronized (jobs) {
|
||||
success = jobs.remove(container);
|
||||
jobs.notify();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the jobScheduler
|
||||
*/
|
||||
public void shutdown() {
|
||||
if (alive) {
|
||||
alive = false;
|
||||
timeOfKill = System.currentTimeMillis();
|
||||
synchronized (jobs) {
|
||||
jobs.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JobContainer pollNextJobContainer() {
|
||||
if (alive) {
|
||||
throw new IllegalStateException("Can't poll jobs from a live scheduler.");
|
||||
}
|
||||
|
||||
synchronized (jobs) {
|
||||
return jobs.poll();
|
||||
}
|
||||
}
|
||||
|
||||
public long getTimeOfKill() {
|
||||
return this.timeOfKill;
|
||||
}
|
||||
|
||||
public boolean isAlive() {
|
||||
return this.alive;
|
||||
}
|
||||
|
||||
private void execution() {
|
||||
long duration;
|
||||
JobContainer container;
|
||||
int compensation = MBServerStatics.SCHEDULER_EXECUTION_TIME_COMPENSATION;
|
||||
|
||||
while (alive) {
|
||||
synchronized (jobs) {
|
||||
container = jobs.peek();
|
||||
if (container == null) {
|
||||
// queue is empty, wait until notified (which happens after
|
||||
// a new job is offered)
|
||||
try {
|
||||
jobs.wait(0);
|
||||
} catch (InterruptedException ie) {
|
||||
// do nothing
|
||||
}
|
||||
} else {
|
||||
duration = container.timeOfExecution - System.currentTimeMillis();
|
||||
if (duration < compensation) {
|
||||
jobs.poll();
|
||||
} else {
|
||||
// enforce new loop
|
||||
container = null;
|
||||
|
||||
// sleep until the head job execution time
|
||||
try {
|
||||
jobs.wait(duration);
|
||||
} catch (InterruptedException ie) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (container != null) {
|
||||
JobManager.getInstance().submitJob(container.job);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2022
|
||||
// www.magicbane.com
|
||||
|
||||
|
||||
package engine.job;
|
||||
|
||||
import engine.core.ControlledRunnable;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.Queue;
|
||||
|
||||
|
||||
public class JobWorker extends ControlledRunnable {
|
||||
private final int workerId;
|
||||
|
||||
private final Queue<AbstractJob> jobWaitQueue;
|
||||
private final Queue<JobWorker> jobWorkerList;
|
||||
|
||||
private AbstractJob currentJob;
|
||||
|
||||
public JobWorker(final int workerID, int priorityQueue,
|
||||
Queue<AbstractJob> jobWaitQueue,
|
||||
Queue<JobWorker> jobWorkerList) {
|
||||
super("JobWorker_" + priorityQueue + '_' + workerID);
|
||||
|
||||
workerId = workerID;
|
||||
this.jobWaitQueue = jobWaitQueue;
|
||||
this.jobWorkerList = jobWorkerList;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _Run() {
|
||||
|
||||
while (this.runCmd) {
|
||||
// Access to Queue is synchronized internal to JobManager
|
||||
this.currentJob = this.jobWaitQueue.poll();
|
||||
|
||||
if (this.currentJob == null) {
|
||||
try {
|
||||
// use self as MUTEX
|
||||
synchronized (this) {
|
||||
this.jobWorkerList.add(this);
|
||||
this.wait();
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
Logger.error(this.getThreadName(), e.getClass()
|
||||
.getSimpleName()
|
||||
+ ": " + e.getMessage());
|
||||
break;
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
// execute the new job..
|
||||
this.currentJob.executeJob(this.getThreadName());
|
||||
this.currentJob = null;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _postRun() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean _preRun() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _shutdown() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void _startup() {
|
||||
//this.logDirectINFO(this.getThreadName(), "Starting up...");
|
||||
}
|
||||
|
||||
public final int getWorkerId() {
|
||||
return workerId;
|
||||
}
|
||||
|
||||
public final AbstractJob getCurrentJob() {
|
||||
return currentJob;
|
||||
}
|
||||
|
||||
public final boolean hasCurrentJob() {
|
||||
return (currentJob != null);
|
||||
}
|
||||
|
||||
protected void EmergencyStop() {
|
||||
this.runCmd = false;
|
||||
String out = "Stack Trace";
|
||||
for(StackTraceElement e : this.getThisThread().getStackTrace()) {
|
||||
out += " -> " + e.toString();
|
||||
}
|
||||
Logger.info(out);
|
||||
this.getThisThread().interrupt();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user