/*==========================================================================*\
| $Id: ManagedQueueDescriptor.java,v 1.5 2011/12/09 02:05:35 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2008-2009 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.jobqueue;
import com.webobjects.eoaccess.*;
import com.webobjects.eocontrol.*;
import com.webobjects.foundation.*;
import er.extensions.eof.ERXConstant;
import er.extensions.eof.ERXKey;
import java.util.Enumeration;
import org.apache.log4j.Logger;
import org.webcat.core.IndependentEOManager;
// -------------------------------------------------------------------------
/**
* A subclass of IndependentEOManager that holds one {@link QueueDescriptor}.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.5 $, $Date: 2011/12/09 02:05:35 $
*/
public class ManagedQueueDescriptor
extends IndependentEOManager
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new object.
* @param descriptor the queue descriptor to wrap
*/
public ManagedQueueDescriptor(QueueDescriptor descriptor)
{
super(descriptor);
}
//~ Methods ...............................................................
// ----------------------------------------------------------
/**
* Retrieve this object's <code>defaultJobProcessingTime</code> value.
* @return the value of the attribute
*/
public long defaultJobProcessingTime()
{
Number result = (Number)valueForKey(
QueueDescriptor.DEFAULT_JOB_PROCESSING_TIME_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>jobsProcessed</code> value.
* @return the value of the attribute
*/
public long jobsProcessed()
{
Number result =
(Number)valueForKey(QueueDescriptor.JOBS_PROCESSED_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>jobEntityName</code> value.
* @return the value of the attribute
*/
public String jobEntityName()
{
return (String)valueForKey(QueueDescriptor.JOB_ENTITY_NAME_KEY);
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>mostRecentJobWait</code> value.
* @return the value of the attribute
*/
public long mostRecentJobWait()
{
Number result =
(Number)valueForKey(QueueDescriptor.MOST_RECENT_JOB_WAIT_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>newestEntryId</code> value.
* @return the value of the attribute
*/
public long newestEntryId()
{
Number result =
(Number)valueForKey(QueueDescriptor.NEWEST_ENTRY_ID_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>requiresExclusiveHostAccess</code> value.
* @return the value of the attribute
*/
public boolean requiresExclusiveHostAccess()
{
Number result = (Number)valueForKey(
QueueDescriptor.REQUIRES_EXCLUSIVE_HOST_ACCESS_KEY);
return (result == null)
? false
: (result.intValue() > 0);
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>cumulativeProcessingTime</code> value.
* @return the value of the attribute
*/
public long cumulativeProcessingTime()
{
Number result =
(Number)valueForKey(QueueDescriptor.CUMULATIVE_PROCESSING_TIME_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve this object's <code>movingAverageProcessingTime</code> value.
* @return the value of the attribute
*/
public long movingAverageProcessingTime()
{
Number result = (Number)valueForKey(
QueueDescriptor.MOVING_AVERAGE_PROCESSING_TIME_KEY);
return (result == null)
? 0L
: result.longValue();
}
// ----------------------------------------------------------
/**
* Retrieve the entities pointed to by the <code>workers</code>
* relationship.
* @return an NSArray of the entities in the relationship
*/
public NSArray workers()
{
return (NSArray)valueForKey(QueueDescriptor.WORKERS_KEY);
}
// ----------------------------------------------------------
/**
* Add a new entity to the <code>workers</code>
* relationship.
*
* @param value The new entity to relate to
*/
public void addToWorkersRelationship(WorkerDescriptor value)
{
addObjectToBothSidesOfRelationshipWithKey(
value, QueueDescriptor.WORKERS_KEY);
}
// ----------------------------------------------------------
/**
* Remove a specific entity from the <code>workers</code>
* relationship.
*
* @param value The entity to remove from the relationship
*/
public void removeFromWorkersRelationship(WorkerDescriptor value)
{
removeObjectFromBothSidesOfRelationshipWithKey(
value, QueueDescriptor.WORKERS_KEY);
}
// ----------------------------------------------------------
/**
* Increment all the necessary accumulation stats to indicate that
* one more job has been processed.
*
* @param duration The time (in ms) taken to complete the job
*/
public void addCompletedJobStats(long duration, long waitTime)
{
saveChanges();
boolean saved = false;
while (!saved)
{
takeValueForKey(
waitTime, QueueDescriptor.MOST_RECENT_JOB_WAIT_KEY);
takeValueForKey(
1L + jobsProcessed(), QueueDescriptor.JOBS_PROCESSED_KEY);
takeValueForKey(cumulativeProcessingTime() + duration,
QueueDescriptor.CUMULATIVE_PROCESSING_TIME_KEY);
// Calculate the exponential moving average
// First, get the old value:
long ema = movingAverageProcessingTime();
if (ema == 0L)
{
// If we have no past data, first try to use the actual
// long-term average as the initial EMA:
ema = cumulativeProcessingTime();
if (ema != 0L && jobsProcessed() > 0L)
{
ema /= jobsProcessed();
}
else
{
// If there is no data for a long-term average, just
// use the default value.
ema = defaultJobProcessingTime();
}
}
if (ema == 0L)
{
// No past history at all, so just use first value we get
ema = duration;
}
else
{
// We're using the formula for an exponential moving average
// (EMA) from http://en.wikipedia.org/wiki/Rolling_average,
// using the "S_t,alternate" and "EMA_today" formulae
// in the section on Exponential Moving Average.
//
// EMA_new = EMA_old + alpha * (Duration - EMA_old)
//
// Here, alpha is a fraction between 0-1 that represents the
// rate of decay in the exponential moving average. The decay
// factor we are using is the MOVING_AVERAGE_DECAY_FACTOR
// in the QueueDescriptor class. This decay factor
// corresponds to 1/alpha, and roughly determines the "half
// life" of data samples in the average. We do the math in
// floating point to ensure we get the right effects for small
// durations (truncation wouldn't significantly affect
// results for larger numbers).
ema = (long)(ema + ((double)duration - ema)
/ QueueDescriptor.MOVING_AVERAGE_DECAY_FACTOR);
}
takeValueForKey(
ema, QueueDescriptor.MOVING_AVERAGE_PROCESSING_TIME_KEY);
if (tryToSaveChanges() == null)
{
saved = true;
}
else
{
refresh();
}
}
}
// ----------------------------------------------------------
public void waitForNextJob()
{
EOEditingContext ec = clientContext();
QueueDescriptor qd = (QueueDescriptor)localInstanceIn(ec);
QueueDescriptor.waitForNextJob(qd);
}
//~ Instance/static variables .............................................
static Logger log = Logger.getLogger( QueueDescriptor.class );
}