Policy
Policies dictate how Fork, Join, and Queue nodes behave, from which complex scenarios can be built from. For example, a custom Queue node policy to preferentially send out Company A’s vehicles creates the basis to observe the effects on port throughput by prioritising a specific company.
Fork and Join Policies
Generic Policies
Due to the symmetrical nature of push forks and pull joins, some policies are shared between the two nodes. For example, RandomPolicy is shared, and can be converted into a ForkPolicy or JoinPolicy where needed.
open class RandomPolicy<ChannelT> : GenericPolicy<ChannelT>()
...
.thenQueue("Queue")
.thenPump()
.thenFork("Example Push Fork", numLanes, RandomPolicy<PushOutputChannel<T>>().asForkPolicy()) {
i, lane ->
lane
.thenQueue("Inner queue")
...
}
.thenJoin("Example Pull Join", RandomPolicy<PullInputChannel<T>>().asJoinPolicy())
...
Other policies that are shared include:
RoundRobinPolicyPriorityPolicywhere some comparator is needed to compare channelsFirstAvailablePolicywhich picks the first channel whenever available.
To create custom generic policies, simply inherit the GenericPolicy abstract class:
abstract class GenericPolicy<ChannelT> {
abstract fun selectChannel(): ChannelT
abstract fun onChannelAvailable(channel: ChannelT)
abstract fun onChannelUnavailable(channel: ChannelT)
abstract fun allClosed(): Boolean
context(_: Simulator)
abstract fun initialize(channels: List<ChannelT>)
}
Push Fork Policies
Some policies may only be useful for push forks, such as LeastFullForkPolicy:
class LeastFullForkPolicy<T>(
private val tags: Iterable<ForwardWalkTag<Container<*>>>,
) : ForkPolicy<T>
Which performs a traversal through its downstream lanes to identify the first container in each lane, and forwards items to the lane with the lowest occupancy.
To create custom push-fork exclusive policies, simply inherit the ForkPolicy interface:
interface ForkPolicy<T> {
fun selectChannel(obj: T): PushOutputChannel<T>
fun onChannelOpen(channel: PushOutputChannel<T>)
fun onChannelClose(channel: PushOutputChannel<T>)
fun allClosed(): Boolean
// default implementation provided to join the channels to the policy class
context(_: Simulator)
fun initialize(source: PushInputChannel<T>, destinations: List<PushOutputChannel<T>>)
}
Pull Join Policies
Some policies may only be useful for pull joins, such as MostFullJoinPolicy:
class MostFullJoinPolicy<T>(
private val tags: Iterable<BackwardWalkTag<Container<*>>>
) : JoinPolicy<T>
Which performs a reverse traversal through its upstream lanes being merged together, to find the lane with the highest occupancy, and draws from there first.
To create custom pull-join exclusive policies, simply inherit the JoinPolicy interface:
interface JoinPolicy<T> {
fun selectChannel(): PullInputChannel<T>
fun onChannelReady(channel: PullInputChannel<T>)
fun onChannelNotReady(channel: PullInputChannel<T>)
fun allClosed(): Boolean
// default implementation provided
context(_: Simulator)
fun initialize(sources: List<PullInputChannel<T>>, destination: PullOutputChannel<T>)
}
Queue Policies
Queue policies control the behaviour of queues, which by default are FIFO. Custom queue policies can be created through implementing the QueuePolicy interface:
interface QueuePolicy<T> {
val contents: Sequence<T>
fun enqueue(obj: T)
fun dequeue(): T
fun reportOccupancy(): Int
}
Provided queue policies include:
FIFOQueuePolicywhich simulates a normal FIFO queue, and is the default parameter for a queue defined in DSL without passing an explicit policy.RandomQueuePolicyPriorityQueuePolicy