2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and
31 * documentation are those of the authors and should not be
32 * interpreted as representing official policies, either expressed
33 * or implied, of GRNET S.A.
36 package gr.grnet.aquarium.computation
39 import scala.collection.mutable
40 import gr.grnet.aquarium.util.ContextualLogger
41 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
42 import gr.grnet.aquarium.computation.state.parts.{IgnoredFirstResourceEventsWorker, ImplicitlyIssuedResourceEventsWorker, LatestResourceEventsWorker}
43 import gr.grnet.aquarium.policy.ResourceType
44 import gr.grnet.aquarium.Aquarium
47 * A helper object holding intermediate state/results during resource event processing.
49 * @author Christos KK Loverdos <loverdos@gmail.com>
51 case class UserStateWorker(
55 * This is a collection of all the latest resource events.
56 * We want these in order to correlate incoming resource events with their previous (in `occurredMillis` time)
57 * ones. Will be updated on processing the next resource event.
59 previousResourceEvents: LatestResourceEventsWorker,
62 * The implicitly issued resource events at the beginning of the billing period.
64 implicitlyIssuedStartEvents: ImplicitlyIssuedResourceEventsWorker,
67 * The resource events that were first (and unused) of their kind.
69 ignoredFirstResourceEvents: IgnoredFirstResourceEventsWorker,
70 resourceTypesMap: Map[String, ResourceType]
74 * Finds the previous resource event by checking two possible sources: a) The implicitly terminated resource
75 * events and b) the explicit previous resource events. If the event is found, it is removed from the
78 * If the event is not found, then this must be for a new resource instance.
79 * (and probably then some `zero` resource event must be implied as the previous one)
85 def findAndRemovePreviousResourceEvent(resource: String, instanceId: String): Option[ResourceEventModel] = {
86 // implicitly issued events are checked first
87 implicitlyIssuedStartEvents.findAndRemoveResourceEvent(resource, instanceId) match {
91 // explicit previous resource events are checked second
92 previousResourceEvents.findAndRemoveResourceEvent(resource, instanceId) match {
101 def updateIgnored(resourceEvent: ResourceEventModel): Unit = {
102 ignoredFirstResourceEvents.updateResourceEvent(resourceEvent)
105 def updatePrevious(resourceEvent: ResourceEventModel): Unit = {
106 previousResourceEvents.updateResourceEvent(resourceEvent)
109 def debugTheMaps(clog: ContextualLogger)(rcDebugInfo: ResourceEventModel ⇒ String): Unit = {
110 if(previousResourceEvents.size > 0) {
111 val map = previousResourceEvents.latestEventsMap.map {
112 case (k, v) => (k, rcDebugInfo(v))
114 clog.debugMap("previousResourceEvents", map, 0)
116 if(implicitlyIssuedStartEvents.size > 0) {
117 val map = implicitlyIssuedStartEvents.implicitlyIssuedEventsMap.map {
118 case (k, v) => (k, rcDebugInfo(v))
120 clog.debugMap("implicitlyTerminatedResourceEvents", map, 0)
122 if(ignoredFirstResourceEvents.size > 0) {
123 val map = ignoredFirstResourceEvents.ignoredFirstEventsMap.map {
124 case (k, v) => (k, rcDebugInfo(v))
126 clog.debugMap("ignoredFirstResourceEvents", map, 0)
131 // def allPreviousAndAllImplicitlyStarted: List[ResourceEvent] = {
132 // val buffer: FullMutableResourceTypeMap = scala.collection.mutable.Map[FullResourceType, ResourceEvent]()
134 // buffer ++= implicitlyIssuedStartEvents.implicitlyIssuedEventsMap
135 // buffer ++= previousResourceEvents.latestEventsMap
137 // buffer.valuesIterator.toList
141 * Find those events from `implicitlyIssuedStartEvents` and `previousResourceEvents` that will generate implicit
142 * end events along with those implicitly issued events. Before returning, remove the events that generated the
143 * implicit ends from the internal state of this instance.
145 * @see [[gr.grnet.aquarium.charging.ChargingBehavior]]
147 def findAndRemoveGeneratorsOfImplicitEndEvents(
150 * The `occurredMillis` that will be recorded in the synthetic implicit OFFs.
151 * Normally, this will be the end of a billing month.
153 newOccuredMillis: Long
154 ): (List[ResourceEventModel], List[ResourceEventModel]) = {
156 val buffer = mutable.ListBuffer[(ResourceEventModel, ResourceEventModel)]()
157 val checkSet = mutable.Set[ResourceEventModel]()
159 def doItFor(map: ResourceEventModel.FullMutableResourceTypeMap): Unit = {
160 val resourceEvents = map.valuesIterator
162 resourceEvent ← resourceEvents
163 resourceType ← resourceTypesMap.get(resourceEvent.safeResource)
164 chargingBehavior = aquarium.chargingBehaviorOf(resourceType)
166 if(chargingBehavior.supportsImplicitEvents) {
167 if(chargingBehavior.mustConstructImplicitEndEventFor(resourceEvent)) {
168 val implicitEnd = chargingBehavior.constructImplicitEndEventFor(resourceEvent, newOccuredMillis)
170 if(!checkSet.contains(resourceEvent)) {
171 checkSet.add(resourceEvent)
172 buffer append ((resourceEvent, implicitEnd))
176 map.remove((resourceEvent.safeResource, resourceEvent.safeInstanceID))
182 doItFor(previousResourceEvents.latestEventsMap) // we give priority for previous
183 doItFor(implicitlyIssuedStartEvents.implicitlyIssuedEventsMap) // ... over implicitly issued...
185 (buffer.view.map(_._1).toList, buffer.view.map(_._2).toList)
189 object UserStateWorker {
190 def fromUserState(userState: UserState, resourceTypesMap: Map[String, ResourceType]): UserStateWorker = {
193 userState.latestResourceEventsSnapshot.toMutableWorker,
194 userState.implicitlyIssuedSnapshot.toMutableWorker,
195 IgnoredFirstResourceEventsWorker.Empty,