Started refactoring Intent Manager
Introduced IntentData and reworked APIs Change-Id: I1fa437ceb1b72c4017ac2da1573bfbeb64c0632a
Showing
14 changed files
with
438 additions
and
183 deletions
... | @@ -15,35 +15,18 @@ | ... | @@ -15,35 +15,18 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.event; | 16 | package org.onosproject.event; |
17 | 17 | ||
18 | -import com.google.common.collect.Lists; | 18 | +import org.onlab.util.AbstractAccumulator; |
19 | -import org.slf4j.Logger; | ||
20 | -import org.slf4j.LoggerFactory; | ||
21 | 19 | ||
22 | -import java.util.List; | ||
23 | import java.util.Timer; | 20 | import java.util.Timer; |
24 | -import java.util.TimerTask; | ||
25 | - | ||
26 | -import static com.google.common.base.Preconditions.checkArgument; | ||
27 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
28 | 21 | ||
29 | /** | 22 | /** |
30 | * Base implementation of an event accumulator. It allows triggering based on | 23 | * Base implementation of an event accumulator. It allows triggering based on |
31 | * event inter-arrival time threshold, maximum batch life threshold and maximum | 24 | * event inter-arrival time threshold, maximum batch life threshold and maximum |
32 | * batch size. | 25 | * batch size. |
33 | */ | 26 | */ |
34 | -public abstract class AbstractEventAccumulator implements EventAccumulator { | 27 | +public abstract class AbstractEventAccumulator |
35 | - | 28 | + extends AbstractAccumulator<Event> |
36 | - private Logger log = LoggerFactory.getLogger(AbstractEventAccumulator.class); | 29 | + implements EventAccumulator { |
37 | - | ||
38 | - private final Timer timer; | ||
39 | - private final int maxEvents; | ||
40 | - private final int maxBatchMillis; | ||
41 | - private final int maxIdleMillis; | ||
42 | - | ||
43 | - private TimerTask idleTask = new ProcessorTask(); | ||
44 | - private TimerTask maxTask = new ProcessorTask(); | ||
45 | - | ||
46 | - private List<Event> events = Lists.newArrayList(); | ||
47 | 30 | ||
48 | /** | 31 | /** |
49 | * Creates an event accumulator capable of triggering on the specified | 32 | * Creates an event accumulator capable of triggering on the specified |
... | @@ -59,108 +42,6 @@ public abstract class AbstractEventAccumulator implements EventAccumulator { | ... | @@ -59,108 +42,6 @@ public abstract class AbstractEventAccumulator implements EventAccumulator { |
59 | */ | 42 | */ |
60 | protected AbstractEventAccumulator(Timer timer, int maxEvents, | 43 | protected AbstractEventAccumulator(Timer timer, int maxEvents, |
61 | int maxBatchMillis, int maxIdleMillis) { | 44 | int maxBatchMillis, int maxIdleMillis) { |
62 | - this.timer = checkNotNull(timer, "Timer cannot be null"); | 45 | + super(timer, maxEvents, maxBatchMillis, maxIdleMillis); |
63 | - | ||
64 | - checkArgument(maxEvents > 1, "Maximum number of events must be > 1"); | ||
65 | - checkArgument(maxBatchMillis > 0, "Maximum millis must be positive"); | ||
66 | - checkArgument(maxIdleMillis > 0, "Maximum idle millis must be positive"); | ||
67 | - | ||
68 | - this.maxEvents = maxEvents; | ||
69 | - this.maxBatchMillis = maxBatchMillis; | ||
70 | - this.maxIdleMillis = maxIdleMillis; | ||
71 | - } | ||
72 | - | ||
73 | - @Override | ||
74 | - public void add(Event event) { | ||
75 | - idleTask = cancelIfActive(idleTask); | ||
76 | - events.add(event); | ||
77 | - | ||
78 | - // Did we hit the max event threshold? | ||
79 | - if (events.size() == maxEvents) { | ||
80 | - maxTask = cancelIfActive(maxTask); | ||
81 | - schedule(1); | ||
82 | - } else { | ||
83 | - // Otherwise, schedule idle task and if this is a first event | ||
84 | - // also schedule the max batch age task. | ||
85 | - idleTask = schedule(maxIdleMillis); | ||
86 | - if (events.size() == 1) { | ||
87 | - maxTask = schedule(maxBatchMillis); | ||
88 | - } | ||
89 | - } | ||
90 | - } | ||
91 | - | ||
92 | - // Schedules a new processor task given number of millis in the future. | ||
93 | - private TimerTask schedule(int millis) { | ||
94 | - TimerTask task = new ProcessorTask(); | ||
95 | - timer.schedule(task, millis); | ||
96 | - return task; | ||
97 | - } | ||
98 | - | ||
99 | - // Cancels the specified task if it is active. | ||
100 | - private TimerTask cancelIfActive(TimerTask task) { | ||
101 | - if (task != null) { | ||
102 | - task.cancel(); | ||
103 | - } | ||
104 | - return task; | ||
105 | - } | ||
106 | - | ||
107 | - // Task for triggering processing of accumulated events | ||
108 | - private class ProcessorTask extends TimerTask { | ||
109 | - @Override | ||
110 | - public void run() { | ||
111 | - try { | ||
112 | - idleTask = cancelIfActive(idleTask); | ||
113 | - maxTask = cancelIfActive(maxTask); | ||
114 | - processEvents(finalizeCurrentBatch()); | ||
115 | - } catch (Exception e) { | ||
116 | - log.warn("Unable to process batch due to {}", e.getMessage()); | ||
117 | - } | ||
118 | - } | ||
119 | - } | ||
120 | - | ||
121 | - // Demotes and returns the current batch of events and promotes a new one. | ||
122 | - private synchronized List<Event> finalizeCurrentBatch() { | ||
123 | - List<Event> toBeProcessed = events; | ||
124 | - events = Lists.newArrayList(); | ||
125 | - return toBeProcessed; | ||
126 | - } | ||
127 | - | ||
128 | - /** | ||
129 | - * Returns the backing timer. | ||
130 | - * | ||
131 | - * @return backing timer | ||
132 | - */ | ||
133 | - public Timer timer() { | ||
134 | - return timer; | ||
135 | - } | ||
136 | - | ||
137 | - /** | ||
138 | - * Returns the maximum number of events allowed to accumulate before | ||
139 | - * processing is triggered. | ||
140 | - * | ||
141 | - * @return max number of events | ||
142 | - */ | ||
143 | - public int maxEvents() { | ||
144 | - return maxEvents; | ||
145 | - } | ||
146 | - | ||
147 | - /** | ||
148 | - * Returns the maximum number of millis allowed to expire since the first | ||
149 | - * event before processing is triggered. | ||
150 | - * | ||
151 | - * @return max number of millis a batch is allowed to last | ||
152 | - */ | ||
153 | - public int maxBatchMillis() { | ||
154 | - return maxBatchMillis; | ||
155 | - } | ||
156 | - | ||
157 | - /** | ||
158 | - * Returns the maximum number of millis allowed to expire since the last | ||
159 | - * event arrival before processing is triggered. | ||
160 | - * | ||
161 | - * @return max number of millis since the last event | ||
162 | - */ | ||
163 | - public int maxIdleMillis() { | ||
164 | - return maxIdleMillis; | ||
165 | } | 46 | } |
166 | } | 47 | } | ... | ... |
... | @@ -15,27 +15,11 @@ | ... | @@ -15,27 +15,11 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.event; | 16 | package org.onosproject.event; |
17 | 17 | ||
18 | -import java.util.List; | 18 | +import org.onlab.util.Accumulator; |
19 | 19 | ||
20 | /** | 20 | /** |
21 | * Abstraction of an accumulator capable of collecting events and at some | 21 | * Abstraction of an accumulator capable of collecting events and at some |
22 | * point in time triggers processing of all previously accumulated events. | 22 | * point in time triggers processing of all previously accumulated events. |
23 | */ | 23 | */ |
24 | -public interface EventAccumulator { | 24 | +public interface EventAccumulator extends Accumulator<Event> { |
25 | - | ||
26 | - /** | ||
27 | - * Adds an event to the current batch. This operation may, or may not | ||
28 | - * trigger processing of the current batch of events. | ||
29 | - * | ||
30 | - * @param event event to be added to the current batch | ||
31 | - */ | ||
32 | - void add(Event event); | ||
33 | - | ||
34 | - /** | ||
35 | - * Processes the specified list of accumulated events. | ||
36 | - * | ||
37 | - * @param events list of accumulated events | ||
38 | - */ | ||
39 | - void processEvents(List<Event> events); | ||
40 | - | ||
41 | } | 25 | } | ... | ... |
... | @@ -36,7 +36,7 @@ public abstract class Intent { | ... | @@ -36,7 +36,7 @@ public abstract class Intent { |
36 | private final IntentId id; | 36 | private final IntentId id; |
37 | 37 | ||
38 | private final ApplicationId appId; | 38 | private final ApplicationId appId; |
39 | - private final String key; | 39 | + private final String key; // TODO make this a class |
40 | 40 | ||
41 | private final Collection<NetworkResource> resources; | 41 | private final Collection<NetworkResource> resources; |
42 | 42 | ||
... | @@ -156,4 +156,8 @@ public abstract class Intent { | ... | @@ -156,4 +156,8 @@ public abstract class Intent { |
156 | idGenerator = null; | 156 | idGenerator = null; |
157 | } | 157 | } |
158 | } | 158 | } |
159 | + | ||
160 | + public String key() { | ||
161 | + return key; | ||
162 | + } | ||
159 | } | 163 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.net.intent; | ||
17 | + | ||
18 | +import com.google.common.collect.ImmutableList; | ||
19 | +import org.onosproject.store.Timestamp; | ||
20 | + | ||
21 | +import java.util.List; | ||
22 | +import java.util.Objects; | ||
23 | + | ||
24 | +/** | ||
25 | + * A wrapper class that contains an intents, its state, and other metadata for | ||
26 | + * internal use. | ||
27 | + */ | ||
28 | +public class IntentData { //FIXME need to make this "immutable" | ||
29 | + // manager should be able to mutate a local copy while processing | ||
30 | + private Intent intent; | ||
31 | + | ||
32 | + private IntentState state; | ||
33 | + private Timestamp version; | ||
34 | + | ||
35 | + private List<Intent> installables; | ||
36 | + | ||
37 | + public IntentData(Intent intent, IntentState state, Timestamp version) { | ||
38 | + this.intent = intent; | ||
39 | + this.state = state; | ||
40 | + this.version = version; | ||
41 | + } | ||
42 | + | ||
43 | + // kryo constructor | ||
44 | + protected IntentData() { | ||
45 | + } | ||
46 | + | ||
47 | + public Intent intent() { | ||
48 | + return intent; | ||
49 | + } | ||
50 | + | ||
51 | + public IntentState state() { | ||
52 | + return state; | ||
53 | + } | ||
54 | + | ||
55 | + public String key() { | ||
56 | + return intent.key(); | ||
57 | + } | ||
58 | + | ||
59 | + public void setState(IntentState newState) { | ||
60 | + this.state = newState; | ||
61 | + } | ||
62 | + | ||
63 | + public void setInstallables(List<Intent> installables) { | ||
64 | + this.installables = ImmutableList.copyOf(installables); | ||
65 | + } | ||
66 | + | ||
67 | + public List<Intent> installables() { | ||
68 | + return installables; | ||
69 | + } | ||
70 | + | ||
71 | + @Override | ||
72 | + public int hashCode() { | ||
73 | + return Objects.hash(intent, version); | ||
74 | + } | ||
75 | + | ||
76 | + @Override | ||
77 | + public boolean equals(Object obj) { | ||
78 | + if (this == obj) { | ||
79 | + return true; | ||
80 | + } | ||
81 | + if (obj == null || getClass() != obj.getClass()) { | ||
82 | + return false; | ||
83 | + } | ||
84 | + final IntentData other = (IntentData) obj; | ||
85 | + return Objects.equals(this.intent, other.intent) | ||
86 | + && Objects.equals(this.version, other.version); | ||
87 | + } | ||
88 | +} |
... | @@ -27,9 +27,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -27,9 +27,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
27 | public final class IntentOperation { | 27 | public final class IntentOperation { |
28 | 28 | ||
29 | private final Type type; | 29 | private final Type type; |
30 | - private final IntentId intentId; | ||
31 | private final Intent intent; | 30 | private final Intent intent; |
32 | - //FIXME consider pulling the key out (we will hash based on key) | ||
33 | 31 | ||
34 | /** | 32 | /** |
35 | * Operation type. | 33 | * Operation type. |
... | @@ -62,12 +60,10 @@ public final class IntentOperation { | ... | @@ -62,12 +60,10 @@ public final class IntentOperation { |
62 | * Creates an intent operation. | 60 | * Creates an intent operation. |
63 | * | 61 | * |
64 | * @param type operation type | 62 | * @param type operation type |
65 | - * @param intentId identifier of the intent subject to the operation | ||
66 | * @param intent intent subject | 63 | * @param intent intent subject |
67 | */ | 64 | */ |
68 | - IntentOperation(Type type, IntentId intentId, Intent intent) { | 65 | + public IntentOperation(Type type, Intent intent) { |
69 | this.type = checkNotNull(type); | 66 | this.type = checkNotNull(type); |
70 | - this.intentId = checkNotNull(intentId); | ||
71 | this.intent = intent; | 67 | this.intent = intent; |
72 | } | 68 | } |
73 | 69 | ||
... | @@ -86,7 +82,11 @@ public final class IntentOperation { | ... | @@ -86,7 +82,11 @@ public final class IntentOperation { |
86 | * @return intent identifier | 82 | * @return intent identifier |
87 | */ | 83 | */ |
88 | public IntentId intentId() { | 84 | public IntentId intentId() { |
89 | - return intentId; | 85 | + return intent.id(); |
86 | + } | ||
87 | + | ||
88 | + public String key() { | ||
89 | + return intent.key(); | ||
90 | } | 90 | } |
91 | 91 | ||
92 | /** | 92 | /** |
... | @@ -101,7 +101,7 @@ public final class IntentOperation { | ... | @@ -101,7 +101,7 @@ public final class IntentOperation { |
101 | 101 | ||
102 | @Override | 102 | @Override |
103 | public int hashCode() { | 103 | public int hashCode() { |
104 | - return Objects.hash(type, intentId, intent); | 104 | + return Objects.hash(type, intent); |
105 | } | 105 | } |
106 | 106 | ||
107 | @Override | 107 | @Override |
... | @@ -114,7 +114,6 @@ public final class IntentOperation { | ... | @@ -114,7 +114,6 @@ public final class IntentOperation { |
114 | } | 114 | } |
115 | final IntentOperation other = (IntentOperation) obj; | 115 | final IntentOperation other = (IntentOperation) obj; |
116 | return Objects.equals(this.type, other.type) && | 116 | return Objects.equals(this.type, other.type) && |
117 | - Objects.equals(this.intentId, other.intentId) && | ||
118 | Objects.equals(this.intent, other.intent); | 117 | Objects.equals(this.intent, other.intent); |
119 | } | 118 | } |
120 | 119 | ||
... | @@ -123,7 +122,6 @@ public final class IntentOperation { | ... | @@ -123,7 +122,6 @@ public final class IntentOperation { |
123 | public String toString() { | 122 | public String toString() { |
124 | return toStringHelper(this) | 123 | return toStringHelper(this) |
125 | .add("type", type) | 124 | .add("type", type) |
126 | - .add("intentId", intentId) | ||
127 | .add("intent", intent) | 125 | .add("intent", intent) |
128 | .toString(); | 126 | .toString(); |
129 | } | 127 | } | ... | ... |
... | @@ -31,7 +31,7 @@ import static org.onosproject.net.intent.IntentOperation.Type.WITHDRAW; | ... | @@ -31,7 +31,7 @@ import static org.onosproject.net.intent.IntentOperation.Type.WITHDRAW; |
31 | /** | 31 | /** |
32 | * Batch of intent submit/withdraw/replace operations. | 32 | * Batch of intent submit/withdraw/replace operations. |
33 | */ | 33 | */ |
34 | -@Deprecated | 34 | +@Deprecated //DELETEME |
35 | public final class IntentOperations { | 35 | public final class IntentOperations { |
36 | 36 | ||
37 | private final List<IntentOperation> operations; | 37 | private final List<IntentOperation> operations; |
... | @@ -120,7 +120,7 @@ public final class IntentOperations { | ... | @@ -120,7 +120,7 @@ public final class IntentOperations { |
120 | */ | 120 | */ |
121 | public Builder addSubmitOperation(Intent intent) { | 121 | public Builder addSubmitOperation(Intent intent) { |
122 | checkNotNull(intent, "Intent cannot be null"); | 122 | checkNotNull(intent, "Intent cannot be null"); |
123 | - builder.add(new IntentOperation(SUBMIT, intent.id(), intent)); | 123 | + builder.add(new IntentOperation(SUBMIT, intent)); |
124 | return this; | 124 | return this; |
125 | } | 125 | } |
126 | 126 | ||
... | @@ -134,7 +134,7 @@ public final class IntentOperations { | ... | @@ -134,7 +134,7 @@ public final class IntentOperations { |
134 | public Builder addReplaceOperation(IntentId oldIntentId, Intent newIntent) { | 134 | public Builder addReplaceOperation(IntentId oldIntentId, Intent newIntent) { |
135 | checkNotNull(oldIntentId, "Intent ID cannot be null"); | 135 | checkNotNull(oldIntentId, "Intent ID cannot be null"); |
136 | checkNotNull(newIntent, "Intent cannot be null"); | 136 | checkNotNull(newIntent, "Intent cannot be null"); |
137 | - builder.add(new IntentOperation(REPLACE, oldIntentId, newIntent)); | 137 | + builder.add(new IntentOperation(REPLACE, newIntent)); //FIXME |
138 | return this; | 138 | return this; |
139 | } | 139 | } |
140 | 140 | ||
... | @@ -146,7 +146,7 @@ public final class IntentOperations { | ... | @@ -146,7 +146,7 @@ public final class IntentOperations { |
146 | */ | 146 | */ |
147 | public Builder addWithdrawOperation(IntentId intentId) { | 147 | public Builder addWithdrawOperation(IntentId intentId) { |
148 | checkNotNull(intentId, "Intent ID cannot be null"); | 148 | checkNotNull(intentId, "Intent ID cannot be null"); |
149 | - builder.add(new IntentOperation(WITHDRAW, intentId, null)); | 149 | + builder.add(new IntentOperation(WITHDRAW, null)); //FIXME |
150 | return this; | 150 | return this; |
151 | } | 151 | } |
152 | 152 | ||
... | @@ -158,7 +158,7 @@ public final class IntentOperations { | ... | @@ -158,7 +158,7 @@ public final class IntentOperations { |
158 | */ | 158 | */ |
159 | public Builder addUpdateOperation(IntentId intentId) { | 159 | public Builder addUpdateOperation(IntentId intentId) { |
160 | checkNotNull(intentId, "Intent ID cannot be null"); | 160 | checkNotNull(intentId, "Intent ID cannot be null"); |
161 | - builder.add(new IntentOperation(UPDATE, intentId, null)); | 161 | + builder.add(new IntentOperation(UPDATE, null)); //FIXME |
162 | return this; | 162 | return this; |
163 | } | 163 | } |
164 | 164 | ... | ... |
... | @@ -30,7 +30,7 @@ public enum IntentState { | ... | @@ -30,7 +30,7 @@ public enum IntentState { |
30 | * Intents will also pass through this state when they are updated. | 30 | * Intents will also pass through this state when they are updated. |
31 | * </p> | 31 | * </p> |
32 | */ | 32 | */ |
33 | - INSTALL_REQ, | 33 | + INSTALL_REQ, // TODO submit_REQ? |
34 | 34 | ||
35 | /** | 35 | /** |
36 | * Signifies that the intent is being compiled into installable intents. | 36 | * Signifies that the intent is being compiled into installable intents. |
... | @@ -66,7 +66,7 @@ public enum IntentState { | ... | @@ -66,7 +66,7 @@ public enum IntentState { |
66 | * previously failed to be installed. | 66 | * previously failed to be installed. |
67 | * </p> | 67 | * </p> |
68 | */ | 68 | */ |
69 | - RECOMPILING, | 69 | + RECOMPILING, // TODO perhaps repurpose as BROKEN. |
70 | 70 | ||
71 | /** | 71 | /** |
72 | * Indicates that an application has requested that an intent be withdrawn. | 72 | * Indicates that an application has requested that an intent be withdrawn. |
... | @@ -92,5 +92,5 @@ public enum IntentState { | ... | @@ -92,5 +92,5 @@ public enum IntentState { |
92 | * Signifies that the intent has failed compiling, installing or | 92 | * Signifies that the intent has failed compiling, installing or |
93 | * recompiling states. | 93 | * recompiling states. |
94 | */ | 94 | */ |
95 | - FAILED | 95 | + FAILED //TODO consider renaming to UNSAT. |
96 | } | 96 | } | ... | ... |
... | @@ -76,9 +76,9 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { | ... | @@ -76,9 +76,9 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { |
76 | /** | 76 | /** |
77 | * Adds a new operation, which should be persisted and delegated. | 77 | * Adds a new operation, which should be persisted and delegated. |
78 | * | 78 | * |
79 | - * @param op operation | 79 | + * @param intent operation |
80 | */ | 80 | */ |
81 | - default void add(IntentOperation op) {} //FIXME remove when impl. | 81 | + default void addPending(IntentData intent) {} //FIXME remove when impl. |
82 | 82 | ||
83 | /** | 83 | /** |
84 | * Checks to see whether the calling instance is the master for processing | 84 | * Checks to see whether the calling instance is the master for processing | ... | ... |
... | @@ -23,10 +23,10 @@ import org.onosproject.store.StoreDelegate; | ... | @@ -23,10 +23,10 @@ import org.onosproject.store.StoreDelegate; |
23 | public interface IntentStoreDelegate extends StoreDelegate<IntentEvent> { | 23 | public interface IntentStoreDelegate extends StoreDelegate<IntentEvent> { |
24 | 24 | ||
25 | /** | 25 | /** |
26 | - * Provides an intent operation that should be processed (compiled and | 26 | + * Provides an intent data object that should be processed (compiled and |
27 | * installed) by this manager. | 27 | * installed) by this manager. |
28 | * | 28 | * |
29 | - * @param op intent operation | 29 | + * @param intentData intent data object |
30 | */ | 30 | */ |
31 | - void process(IntentOperation op); | 31 | + void process(IntentData intentData); |
32 | } | 32 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.net.intent.impl; | ||
17 | + | ||
18 | +import com.google.common.collect.Maps; | ||
19 | +import org.onlab.util.AbstractAccumulator; | ||
20 | +import org.onosproject.net.intent.IntentData; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | +import java.util.Map; | ||
24 | +import java.util.Timer; | ||
25 | + | ||
26 | +/** | ||
27 | + * An accumulator for building batches of intent operations. Only one batch should | ||
28 | + * be in process per instance at a time. | ||
29 | + */ | ||
30 | +public class IntentAccumulator extends AbstractAccumulator<IntentData> { | ||
31 | + | ||
32 | + private static final int DEFAULT_MAX_EVENTS = 1000; | ||
33 | + private static final int DEFAULT_MAX_IDLE_MS = 10; | ||
34 | + private static final int DEFAULT_MAX_BATCH_MS = 50; | ||
35 | + | ||
36 | + // FIXME: Replace with a system-wide timer instance; | ||
37 | + // TODO: Convert to use HashedWheelTimer or produce a variant of that; then decide which we want to adopt | ||
38 | + private static final Timer TIMER = new Timer("intent-op-batching"); | ||
39 | + | ||
40 | + /** | ||
41 | + * Creates an intent operation accumulator. | ||
42 | + */ | ||
43 | + protected IntentAccumulator() { | ||
44 | + super(TIMER, DEFAULT_MAX_EVENTS, DEFAULT_MAX_BATCH_MS, DEFAULT_MAX_IDLE_MS); | ||
45 | + } | ||
46 | + | ||
47 | + @Override | ||
48 | + public void processEvents(List<IntentData> ops) { | ||
49 | + Map<String, IntentData> opMap = reduce(ops); | ||
50 | + // FIXME kick off the work | ||
51 | + //for (IntentData data : opMap.values()) {} | ||
52 | + } | ||
53 | + | ||
54 | + private Map<String, IntentData> reduce(List<IntentData> ops) { | ||
55 | + Map<String, IntentData> map = Maps.newHashMap(); | ||
56 | + for (IntentData op : ops) { | ||
57 | + map.put(op.key(), op); | ||
58 | + } | ||
59 | + //TODO check the version... or maybe store will handle this. | ||
60 | + return map; | ||
61 | + } | ||
62 | +} |
... | @@ -37,6 +37,7 @@ import org.onosproject.net.intent.Intent; | ... | @@ -37,6 +37,7 @@ import org.onosproject.net.intent.Intent; |
37 | import org.onosproject.net.intent.IntentBatchDelegate; | 37 | import org.onosproject.net.intent.IntentBatchDelegate; |
38 | import org.onosproject.net.intent.IntentBatchService; | 38 | import org.onosproject.net.intent.IntentBatchService; |
39 | import org.onosproject.net.intent.IntentCompiler; | 39 | import org.onosproject.net.intent.IntentCompiler; |
40 | +import org.onosproject.net.intent.IntentData; | ||
40 | import org.onosproject.net.intent.IntentEvent; | 41 | import org.onosproject.net.intent.IntentEvent; |
41 | import org.onosproject.net.intent.IntentException; | 42 | import org.onosproject.net.intent.IntentException; |
42 | import org.onosproject.net.intent.IntentExtensionService; | 43 | import org.onosproject.net.intent.IntentExtensionService; |
... | @@ -128,6 +129,8 @@ public class IntentManager | ... | @@ -128,6 +129,8 @@ public class IntentManager |
128 | private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate(); | 129 | private final IntentBatchDelegate batchDelegate = new InternalBatchDelegate(); |
129 | private IdGenerator idGenerator; | 130 | private IdGenerator idGenerator; |
130 | 131 | ||
132 | + private final IntentAccumulator accumulator = new IntentAccumulator(); | ||
133 | + | ||
131 | @Activate | 134 | @Activate |
132 | public void activate() { | 135 | public void activate() { |
133 | store.setDelegate(delegate); | 136 | store.setDelegate(delegate); |
... | @@ -154,32 +157,41 @@ public class IntentManager | ... | @@ -154,32 +157,41 @@ public class IntentManager |
154 | @Override | 157 | @Override |
155 | public void submit(Intent intent) { | 158 | public void submit(Intent intent) { |
156 | checkNotNull(intent, INTENT_NULL); | 159 | checkNotNull(intent, INTENT_NULL); |
157 | - execute(IntentOperations.builder(intent.appId()) | 160 | + IntentData data = new IntentData(intent, IntentState.INSTALL_REQ, null); |
158 | - .addSubmitOperation(intent).build()); | 161 | + //FIXME timestamp? |
162 | + store.addPending(data); | ||
159 | } | 163 | } |
160 | 164 | ||
161 | @Override | 165 | @Override |
162 | public void withdraw(Intent intent) { | 166 | public void withdraw(Intent intent) { |
163 | checkNotNull(intent, INTENT_NULL); | 167 | checkNotNull(intent, INTENT_NULL); |
164 | - execute(IntentOperations.builder(intent.appId()) | 168 | + IntentData data = new IntentData(intent, IntentState.WITHDRAW_REQ, null); |
165 | - .addWithdrawOperation(intent.id()).build()); | 169 | + //FIXME timestamp? |
170 | + store.addPending(data); | ||
166 | } | 171 | } |
167 | 172 | ||
168 | @Override | 173 | @Override |
169 | public void replace(IntentId oldIntentId, Intent newIntent) { | 174 | public void replace(IntentId oldIntentId, Intent newIntent) { |
170 | - checkNotNull(oldIntentId, INTENT_ID_NULL); | 175 | + throw new UnsupportedOperationException("replace is not implemented"); |
171 | - checkNotNull(newIntent, INTENT_NULL); | ||
172 | - execute(IntentOperations.builder(newIntent.appId()) | ||
173 | - .addReplaceOperation(oldIntentId, newIntent) | ||
174 | - .build()); | ||
175 | } | 176 | } |
176 | 177 | ||
177 | @Override | 178 | @Override |
178 | public void execute(IntentOperations operations) { | 179 | public void execute(IntentOperations operations) { |
179 | - if (operations.operations().isEmpty()) { | 180 | + for (IntentOperation op : operations.operations()) { |
180 | - return; | 181 | + switch (op.type()) { |
182 | + case SUBMIT: | ||
183 | + case UPDATE: | ||
184 | + submit(op.intent()); | ||
185 | + break; | ||
186 | + case WITHDRAW: | ||
187 | + withdraw(op.intent()); | ||
188 | + break; | ||
189 | + //fallthrough | ||
190 | + case REPLACE: | ||
191 | + default: | ||
192 | + throw new UnsupportedOperationException("replace not supported"); | ||
193 | + } | ||
181 | } | 194 | } |
182 | - batchService.addIntentOperations(operations); | ||
183 | } | 195 | } |
184 | 196 | ||
185 | @Override | 197 | @Override |
... | @@ -382,8 +394,8 @@ public class IntentManager | ... | @@ -382,8 +394,8 @@ public class IntentManager |
382 | } | 394 | } |
383 | 395 | ||
384 | @Override | 396 | @Override |
385 | - public void process(IntentOperation op) { | 397 | + public void process(IntentData data) { |
386 | - //FIXME | 398 | + accumulator.add(data); |
387 | } | 399 | } |
388 | } | 400 | } |
389 | 401 | ||
... | @@ -488,6 +500,7 @@ public class IntentManager | ... | @@ -488,6 +500,7 @@ public class IntentManager |
488 | } | 500 | } |
489 | } | 501 | } |
490 | 502 | ||
503 | + // TODO pull out the IntentUpdate inner classes | ||
491 | private class InstallRequest implements IntentUpdate { | 504 | private class InstallRequest implements IntentUpdate { |
492 | 505 | ||
493 | private final Intent intent; | 506 | private final Intent intent; | ... | ... |
... | @@ -17,19 +17,19 @@ package org.onosproject.store.trivial.impl; | ... | @@ -17,19 +17,19 @@ package org.onosproject.store.trivial.impl; |
17 | 17 | ||
18 | import com.google.common.collect.ImmutableSet; | 18 | import com.google.common.collect.ImmutableSet; |
19 | import com.google.common.collect.Lists; | 19 | import com.google.common.collect.Lists; |
20 | - | ||
21 | import org.apache.felix.scr.annotations.Activate; | 20 | import org.apache.felix.scr.annotations.Activate; |
22 | import org.apache.felix.scr.annotations.Component; | 21 | import org.apache.felix.scr.annotations.Component; |
23 | import org.apache.felix.scr.annotations.Deactivate; | 22 | import org.apache.felix.scr.annotations.Deactivate; |
24 | import org.apache.felix.scr.annotations.Service; | 23 | import org.apache.felix.scr.annotations.Service; |
25 | import org.onosproject.net.intent.BatchWrite; | 24 | import org.onosproject.net.intent.BatchWrite; |
25 | +import org.onosproject.net.intent.BatchWrite.Operation; | ||
26 | import org.onosproject.net.intent.Intent; | 26 | import org.onosproject.net.intent.Intent; |
27 | +import org.onosproject.net.intent.IntentData; | ||
27 | import org.onosproject.net.intent.IntentEvent; | 28 | import org.onosproject.net.intent.IntentEvent; |
28 | import org.onosproject.net.intent.IntentId; | 29 | import org.onosproject.net.intent.IntentId; |
29 | import org.onosproject.net.intent.IntentState; | 30 | import org.onosproject.net.intent.IntentState; |
30 | import org.onosproject.net.intent.IntentStore; | 31 | import org.onosproject.net.intent.IntentStore; |
31 | import org.onosproject.net.intent.IntentStoreDelegate; | 32 | import org.onosproject.net.intent.IntentStoreDelegate; |
32 | -import org.onosproject.net.intent.BatchWrite.Operation; | ||
33 | import org.onosproject.store.AbstractStore; | 33 | import org.onosproject.store.AbstractStore; |
34 | import org.slf4j.Logger; | 34 | import org.slf4j.Logger; |
35 | 35 | ||
... | @@ -38,8 +38,7 @@ import java.util.List; | ... | @@ -38,8 +38,7 @@ import java.util.List; |
38 | import java.util.Map; | 38 | import java.util.Map; |
39 | import java.util.concurrent.ConcurrentHashMap; | 39 | import java.util.concurrent.ConcurrentHashMap; |
40 | 40 | ||
41 | -import static com.google.common.base.Preconditions.checkArgument; | 41 | +import static com.google.common.base.Preconditions.*; |
42 | -import static com.google.common.base.Preconditions.checkState; | ||
43 | import static org.onosproject.net.intent.IntentState.WITHDRAWN; | 42 | import static org.onosproject.net.intent.IntentState.WITHDRAWN; |
44 | import static org.slf4j.LoggerFactory.getLogger; | 43 | import static org.slf4j.LoggerFactory.getLogger; |
45 | 44 | ||
... | @@ -50,10 +49,13 @@ public class SimpleIntentStore | ... | @@ -50,10 +49,13 @@ public class SimpleIntentStore |
50 | implements IntentStore { | 49 | implements IntentStore { |
51 | 50 | ||
52 | private final Logger log = getLogger(getClass()); | 51 | private final Logger log = getLogger(getClass()); |
52 | + | ||
53 | + // current state maps FIXME.. make this a IntentData map | ||
53 | private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>(); | 54 | private final Map<IntentId, Intent> intents = new ConcurrentHashMap<>(); |
54 | private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>(); | 55 | private final Map<IntentId, IntentState> states = new ConcurrentHashMap<>(); |
55 | private final Map<IntentId, List<Intent>> installable = new ConcurrentHashMap<>(); | 56 | private final Map<IntentId, List<Intent>> installable = new ConcurrentHashMap<>(); |
56 | 57 | ||
58 | + private final Map<String, IntentData> pending = new ConcurrentHashMap<>(); //String is "key" | ||
57 | 59 | ||
58 | @Activate | 60 | @Activate |
59 | public void activate() { | 61 | public void activate() { |
... | @@ -203,4 +205,19 @@ public class SimpleIntentStore | ... | @@ -203,4 +205,19 @@ public class SimpleIntentStore |
203 | } | 205 | } |
204 | return failed; | 206 | return failed; |
205 | } | 207 | } |
208 | + | ||
209 | + @Override | ||
210 | + public void addPending(IntentData data) { | ||
211 | + //FIXME need to compare versions | ||
212 | + pending.put(data.key(), data); | ||
213 | + checkNotNull(delegate, "Store delegate is not set") | ||
214 | + .process(data); | ||
215 | + } | ||
216 | + // FIXME!!! pending.remove(intent.key()); // TODO check version | ||
217 | + | ||
218 | + | ||
219 | + @Override | ||
220 | + public boolean isMaster(Intent intent) { | ||
221 | + return true; | ||
222 | + } | ||
206 | } | 223 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.util; | ||
17 | + | ||
18 | +import com.google.common.collect.Lists; | ||
19 | +import org.slf4j.Logger; | ||
20 | +import org.slf4j.LoggerFactory; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | +import java.util.Timer; | ||
24 | +import java.util.TimerTask; | ||
25 | + | ||
26 | +import static com.google.common.base.Preconditions.checkArgument; | ||
27 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
28 | + | ||
29 | +/** | ||
30 | + * Base implementation of an event accumulator. It allows triggering based on | ||
31 | + * event inter-arrival time threshold, maximum batch life threshold and maximum | ||
32 | + * batch size. | ||
33 | + */ | ||
34 | +// FIXME refactor the names here | ||
35 | +public abstract class AbstractAccumulator<T> implements Accumulator<T> { | ||
36 | + | ||
37 | + private Logger log = LoggerFactory.getLogger(AbstractAccumulator.class); | ||
38 | + | ||
39 | + private final Timer timer; | ||
40 | + private final int maxEvents; | ||
41 | + private final int maxBatchMillis; | ||
42 | + private final int maxIdleMillis; | ||
43 | + | ||
44 | + private TimerTask idleTask = new ProcessorTask(); | ||
45 | + private TimerTask maxTask = new ProcessorTask(); | ||
46 | + | ||
47 | + private List<T> events = Lists.newArrayList(); | ||
48 | + | ||
49 | + /** | ||
50 | + * Creates an event accumulator capable of triggering on the specified | ||
51 | + * thresholds. | ||
52 | + * | ||
53 | + * @param timer timer to use for scheduling check-points | ||
54 | + * @param maxEvents maximum number of events to accumulate before | ||
55 | + * processing is triggered | ||
56 | + * @param maxBatchMillis maximum number of millis allowed since the first | ||
57 | + * event before processing is triggered | ||
58 | + * @param maxIdleMillis maximum number millis between events before | ||
59 | + * processing is triggered | ||
60 | + */ | ||
61 | + protected AbstractAccumulator(Timer timer, int maxEvents, | ||
62 | + int maxBatchMillis, int maxIdleMillis) { | ||
63 | + this.timer = checkNotNull(timer, "Timer cannot be null"); | ||
64 | + | ||
65 | + checkArgument(maxEvents > 1, "Maximum number of events must be > 1"); | ||
66 | + checkArgument(maxBatchMillis > 0, "Maximum millis must be positive"); | ||
67 | + checkArgument(maxIdleMillis > 0, "Maximum idle millis must be positive"); | ||
68 | + | ||
69 | + this.maxEvents = maxEvents; | ||
70 | + this.maxBatchMillis = maxBatchMillis; | ||
71 | + this.maxIdleMillis = maxIdleMillis; | ||
72 | + } | ||
73 | + | ||
74 | + @Override | ||
75 | + public void add(T event) { | ||
76 | + idleTask = cancelIfActive(idleTask); | ||
77 | + events.add(event); | ||
78 | + | ||
79 | + // Did we hit the max event threshold? | ||
80 | + if (events.size() == maxEvents) { | ||
81 | + maxTask = cancelIfActive(maxTask); | ||
82 | + schedule(1); | ||
83 | + } else { | ||
84 | + // Otherwise, schedule idle task and if this is a first event | ||
85 | + // also schedule the max batch age task. | ||
86 | + idleTask = schedule(maxIdleMillis); | ||
87 | + if (events.size() == 1) { | ||
88 | + maxTask = schedule(maxBatchMillis); | ||
89 | + } | ||
90 | + } | ||
91 | + } | ||
92 | + | ||
93 | + // Schedules a new processor task given number of millis in the future. | ||
94 | + private TimerTask schedule(int millis) { | ||
95 | + TimerTask task = new ProcessorTask(); | ||
96 | + timer.schedule(task, millis); | ||
97 | + return task; | ||
98 | + } | ||
99 | + | ||
100 | + // Cancels the specified task if it is active. | ||
101 | + private TimerTask cancelIfActive(TimerTask task) { | ||
102 | + if (task != null) { | ||
103 | + task.cancel(); | ||
104 | + } | ||
105 | + return task; | ||
106 | + } | ||
107 | + | ||
108 | + // Task for triggering processing of accumulated events | ||
109 | + private class ProcessorTask extends TimerTask { | ||
110 | + @Override | ||
111 | + public void run() { | ||
112 | + try { | ||
113 | + idleTask = cancelIfActive(idleTask); | ||
114 | + maxTask = cancelIfActive(maxTask); | ||
115 | + processEvents(finalizeCurrentBatch()); | ||
116 | + } catch (Exception e) { | ||
117 | + log.warn("Unable to process batch due to {}", e.getMessage()); | ||
118 | + } | ||
119 | + } | ||
120 | + } | ||
121 | + | ||
122 | + // Demotes and returns the current batch of events and promotes a new one. | ||
123 | + private synchronized List<T> finalizeCurrentBatch() { | ||
124 | + List<T> toBeProcessed = events; | ||
125 | + events = Lists.newArrayList(); | ||
126 | + return toBeProcessed; | ||
127 | + } | ||
128 | + | ||
129 | + /** | ||
130 | + * Returns the backing timer. | ||
131 | + * | ||
132 | + * @return backing timer | ||
133 | + */ | ||
134 | + public Timer timer() { | ||
135 | + return timer; | ||
136 | + } | ||
137 | + | ||
138 | + /** | ||
139 | + * Returns the maximum number of events allowed to accumulate before | ||
140 | + * processing is triggered. | ||
141 | + * | ||
142 | + * @return max number of events | ||
143 | + */ | ||
144 | + public int maxEvents() { | ||
145 | + return maxEvents; | ||
146 | + } | ||
147 | + | ||
148 | + /** | ||
149 | + * Returns the maximum number of millis allowed to expire since the first | ||
150 | + * event before processing is triggered. | ||
151 | + * | ||
152 | + * @return max number of millis a batch is allowed to last | ||
153 | + */ | ||
154 | + public int maxBatchMillis() { | ||
155 | + return maxBatchMillis; | ||
156 | + } | ||
157 | + | ||
158 | + /** | ||
159 | + * Returns the maximum number of millis allowed to expire since the last | ||
160 | + * event arrival before processing is triggered. | ||
161 | + * | ||
162 | + * @return max number of millis since the last event | ||
163 | + */ | ||
164 | + public int maxIdleMillis() { | ||
165 | + return maxIdleMillis; | ||
166 | + } | ||
167 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onlab.util; | ||
17 | + | ||
18 | +import java.util.List; | ||
19 | + | ||
20 | +/** | ||
21 | + * Abstraction of an accumulator capable of collecting events and at some | ||
22 | + * point in time triggers processing of all previously accumulated events. | ||
23 | + */ | ||
24 | +public interface Accumulator<T> { | ||
25 | + | ||
26 | + /** | ||
27 | + * Adds an event to the current batch. This operation may, or may not | ||
28 | + * trigger processing of the current batch of events. | ||
29 | + * | ||
30 | + * @param event event to be added to the current batch | ||
31 | + */ | ||
32 | + void add(T event); | ||
33 | + | ||
34 | + /** | ||
35 | + * Processes the specified list of accumulated events. | ||
36 | + * | ||
37 | + * @param events list of accumulated events | ||
38 | + */ | ||
39 | + void processEvents(List<T> events); | ||
40 | + | ||
41 | +} |
-
Please register or login to post a comment