Skip to content

Instantly share code, notes, and snippets.

@RSchulz
Created September 20, 2010 14:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RSchulz/587992 to your computer and use it in GitHub Desktop.
Save RSchulz/587992 to your computer and use it in GitHub Desktop.
/* ____ __
** / __ \ / /_ ____
** / /_/ // __ \ / __ \ © 2009 H&S Information Systems
** / _, _// / / // /_/ / ALL RIGHTS RESERVED
** /_/ |_|/_/ /_/ \____/
*/
/*
Limiter.scala
Copyright © 2009 H&S Information Systems. ALL RIGHTS RESERVED
$Id$
*/
package rrs.util
import java.lang.System.currentTimeMillis
/**
class Limiter: Resource consumption limiter
@param timeLimit Elapsed time limit in seconds
@param opLimit Operation count limit
@param signal A non-returning function accepting this '''Limiter''' called when a limit is exceeded
@param startNow Start the timer upon constuction of this instance.
@param autoStart Start the timer when the first operation is recorded.
*/
class Limiter(val timeLimit: Float,
val opLimit: Long,
signal: Option[(Limiter => Nothing)],
startNow: Boolean,
autoStart: Boolean)
{
private var opCounter = 0L
private var startTime = 0L
private var lastCountTime = 0L
private val msLimit = (timeLimit * 1000).toLong
/** Start the timer */
def
startTimer: Limiter = {
startTime = currentTimeMillis
this
}
/** Reset operation counter and timer, put the timer in its "stopped" state */
def
reset: Limiter = {
opCounter = 0L
startTime = 0L
lastCountTime = 0L
this
}
/**
Count another operation and note the elapsed time;
If no limit is exceeded return '''true''' otherwise
throw signal if requested or return '''false''' if not
*/
def
op: Boolean = {
if (startTime == 0 && autoStart)
startTimer
if (startTime != 0)
lastCountTime = currentTimeMillis
opCounter += 1
if (opLimit > 0 && opCounter > opLimit
|| timeLimit > 0 && startTime > 0 && (lastCountTime - startTime > msLimit))
if (signal.isDefined)
signal.get.apply(this)
else
false
else
true
}
/** Ascertain the current operation count */
def
opCount: Long =
opCounter
/** Ascertain whether the operation count has been exceeded */
def
countExceeded: Boolean =
opLimit > 0 && opCounter > opLimit
/** Ascertain the time elapsed between staring the time and the most recent operation */
def
timeElapsed: Float =
(lastCountTime - startTime) / 1000.0f
/** Ascertain whether the most recently counted operation occurred at a time in excess of the limit */
def
timeExceeded: Boolean =
timeLimit > 0 && startTime > 0 && (lastCountTime - startTime > timeLimit)
}
/**
class LimiteBuilder: A helper for constructing '''Limiter''' instances a piece at a time.
*/
class LimiterBuilder
{
private var aStart = false
private var sNow = false
private var tLimit = 0.0f
private var oLimit = 0L
private var sig: Option[(Limiter => Nothing)] = None
/** Make the '''Limiter''' start its timer automatically upon the first call to '''Limiter.op''' */
def
autoStart: LimiterBuilder = {
aStart = true
this
}
/** Make the '''Limiter''' auto-start its timer */
def
startNow: LimiterBuilder = {
sNow = true
this
}
/** Establish the '''Limiter''''s time limit */
def
timeLimit(limit: Float): LimiterBuilder = {
tLimit = limit
this
}
/** Establish the '''Limiter''''s time limit */
def
timeLimit(limit: Double): LimiterBuilder = {
tLimit = limit.toFloat
this
}
/** Establish the '''Limiter''''s operation limit */
def
opLimit(limit: Long): LimiterBuilder = {
oLimit = limit
this
}
/**
Make the '''Limiter''' use ''sigGen'' to synthesize
the signal that will be thrown when a limit is exceeded
*/
def
signal(sigGen: Limiter => Nothing): LimiterBuilder = {
sig = Some(sigGen)
this
}
/** Make the '''Limiter''' use the standard signal generator, '''Limiter'''.signalF */
def
signal: LimiterBuilder = {
sig = Some(Limiter.signalF)
this
}
/** Create a '''Limiter''' using the current parameters of this '''LimiterBuilder''' */
def
limiter: Limiter =
new Limiter(tLimit, oLimit, sig, sNow, aStart)
}
object Limiter
{
/** Create a new '''LimiterBuilder''' */
def
build: LimiterBuilder =
new LimiterBuilder
/** Synthesize an instance of (a subtype of) '''LimitExceeded''' suitable to the current state of ''limiter'' */
def
signaler(limiter: Limiter): LimitExceeded =
if (limiter.timeExceeded) new TimeLimitExceeded(limiter)
else if (limiter.countExceeded) new OpLimitExceeded(limiter)
else new NoLimitExceeded(limiter)
/** The default signal throwing method */
def
signal(limiter: Limiter): Nothing =
throw signaler(limiter)
/** The default signal throwing function */
val
signalF = signal _
}
/**
abstract class LimitExceeded: Exceptions used to signal exceeding a resource limit
*/
abstract
class LimitExceeded(val limiter: Limiter, message: String)
extends Exception(message)
class TimeLimitExceeded(limiter: Limiter)
extends LimitExceeded(limiter, "Time limit exceeded (" + limiter.timeElapsed + ")")
class OpLimitExceeded(limiter: Limiter)
extends LimitExceeded(limiter, "Operation limit exceeded (" + limiter.opCount + ")")
class NoLimitExceeded(limiter: Limiter)
extends LimitExceeded(limiter, "No limit exceeded")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment