Committed by
Brian O'Connor
[Blackbird] Fixing Intent purge case (ONOS-1207)
Master needs to remove from the current map. Change-Id: I30eccbe188997949ef2d63d6dbd37b0d8d4b3f5e
Showing
13 changed files
with
172 additions
and
65 deletions
... | @@ -85,35 +85,61 @@ public class IntentRemoveCommand extends AbstractShellCommand { | ... | @@ -85,35 +85,61 @@ public class IntentRemoveCommand extends AbstractShellCommand { |
85 | Intent intent = intentService.getIntent(key); | 85 | Intent intent = intentService.getIntent(key); |
86 | 86 | ||
87 | if (intent != null) { | 87 | if (intent != null) { |
88 | - // set up latch and listener to track uninstall progress | 88 | + IntentListener listener = null; |
89 | - CountDownLatch latch = new CountDownLatch(1); | 89 | + final CountDownLatch withdrawLatch, purgeLatch; |
90 | - IntentListener listener = (IntentEvent event) -> { | 90 | + if (purgeAfterRemove || sync) { |
91 | - if (Objects.equals(event.subject().key(), key) && | 91 | + // set up latch and listener to track uninstall progress |
92 | - (event.type() == IntentEvent.Type.WITHDRAWN || | 92 | + withdrawLatch = new CountDownLatch(1); |
93 | - event.type() == IntentEvent.Type.FAILED)) { | 93 | + purgeLatch = purgeAfterRemove ? new CountDownLatch(1) : null; |
94 | - latch.countDown(); | 94 | + listener = (IntentEvent event) -> { |
95 | - } | 95 | + if (Objects.equals(event.subject().key(), key)) { |
96 | - }; | 96 | + if (event.type() == IntentEvent.Type.WITHDRAWN || |
97 | - intentService.addListener(listener); | 97 | + event.type() == IntentEvent.Type.FAILED) { |
98 | + withdrawLatch.countDown(); | ||
99 | + } else if (purgeAfterRemove && | ||
100 | + event.type() == IntentEvent.Type.PURGED) { | ||
101 | + purgeLatch.countDown(); | ||
102 | + } | ||
103 | + } | ||
104 | + }; | ||
105 | + intentService.addListener(listener); | ||
106 | + } else { | ||
107 | + purgeLatch = null; | ||
108 | + withdrawLatch = null; | ||
109 | + } | ||
98 | 110 | ||
99 | // request the withdraw | 111 | // request the withdraw |
100 | intentService.withdraw(intent); | 112 | intentService.withdraw(intent); |
101 | 113 | ||
102 | if (purgeAfterRemove || sync) { | 114 | if (purgeAfterRemove || sync) { |
103 | - try { | 115 | + try { // wait for withdraw event |
104 | - latch.await(5, TimeUnit.SECONDS); | 116 | + withdrawLatch.await(5, TimeUnit.SECONDS); |
105 | } catch (InterruptedException e) { | 117 | } catch (InterruptedException e) { |
106 | - print("Timed out waiting for intent {}", key); | 118 | + print("Timed out waiting for intent {} withdraw", key); |
107 | } | 119 | } |
108 | // double check the state | 120 | // double check the state |
109 | IntentState state = intentService.getIntentState(key); | 121 | IntentState state = intentService.getIntentState(key); |
110 | if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) { | 122 | if (purgeAfterRemove && (state == WITHDRAWN || state == FAILED)) { |
111 | - intentService.purge(key); | 123 | + intentService.purge(intent); |
124 | + } | ||
125 | + if (sync) { // wait for purge event | ||
126 | + /* TODO | ||
127 | + Technically, the event comes before map.remove() is called. | ||
128 | + If we depend on sync and purge working together, we will | ||
129 | + need to address this. | ||
130 | + */ | ||
131 | + try { | ||
132 | + purgeLatch.await(5, TimeUnit.SECONDS); | ||
133 | + } catch (InterruptedException e) { | ||
134 | + print("Timed out waiting for intent {} purge", key); | ||
135 | + } | ||
112 | } | 136 | } |
113 | } | 137 | } |
114 | - // clean up the listener | ||
115 | - intentService.removeListener(listener); | ||
116 | - } | ||
117 | 138 | ||
139 | + if (listener != null) { | ||
140 | + // clean up the listener | ||
141 | + intentService.removeListener(listener); | ||
142 | + } | ||
143 | + } | ||
118 | } | 144 | } |
119 | } | 145 | } | ... | ... |
... | @@ -46,7 +46,12 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> { | ... | @@ -46,7 +46,12 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> { |
46 | /** | 46 | /** |
47 | * Signifies that an intent has been withdrawn from the system. | 47 | * Signifies that an intent has been withdrawn from the system. |
48 | */ | 48 | */ |
49 | - WITHDRAWN | 49 | + WITHDRAWN, |
50 | + | ||
51 | + /** | ||
52 | + * Signifies that an intent has been purged from the system. | ||
53 | + */ | ||
54 | + PURGED | ||
50 | } | 55 | } |
51 | 56 | ||
52 | /** | 57 | /** |
... | @@ -110,6 +115,9 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> { | ... | @@ -110,6 +115,9 @@ public class IntentEvent extends AbstractEvent<IntentEvent.Type, Intent> { |
110 | case FAILED: | 115 | case FAILED: |
111 | type = Type.FAILED; | 116 | type = Type.FAILED; |
112 | break; | 117 | break; |
118 | + case PURGE_REQ: | ||
119 | + type = Type.PURGED; | ||
120 | + break; | ||
113 | 121 | ||
114 | // fallthrough to default from here | 122 | // fallthrough to default from here |
115 | case COMPILING: | 123 | case COMPILING: | ... | ... |
... | @@ -43,6 +43,14 @@ public interface IntentService { | ... | @@ -43,6 +43,14 @@ public interface IntentService { |
43 | void withdraw(Intent intent); | 43 | void withdraw(Intent intent); |
44 | 44 | ||
45 | /** | 45 | /** |
46 | + * Purges a specific intent from the system if it is <b>FAILED</b> or | ||
47 | + * <b>WITHDRAWN</b>. Otherwise, the intent remains in its current state. | ||
48 | + * | ||
49 | + * @param intent intent to purge | ||
50 | + */ | ||
51 | + void purge(Intent intent); | ||
52 | + | ||
53 | + /** | ||
46 | * Fetches an intent based on its key. | 54 | * Fetches an intent based on its key. |
47 | * | 55 | * |
48 | * @param key key of the intent | 56 | * @param key key of the intent |
... | @@ -112,11 +120,4 @@ public interface IntentService { | ... | @@ -112,11 +120,4 @@ public interface IntentService { |
112 | * @param listener listener to be removed | 120 | * @param listener listener to be removed |
113 | */ | 121 | */ |
114 | void removeListener(IntentListener listener); | 122 | void removeListener(IntentListener listener); |
115 | - | ||
116 | - /** | ||
117 | - * Purges a specific intent from the system if it is FAILED or WITHDRAWN. | ||
118 | - * | ||
119 | - * @param key key of the intent to purge | ||
120 | - */ | ||
121 | - void purge(Key key); | ||
122 | } | 123 | } | ... | ... |
... | @@ -92,5 +92,14 @@ public enum IntentState { | ... | @@ -92,5 +92,14 @@ 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 //TODO consider renaming to UNSAT. | 95 | + FAILED, //TODO consider renaming to UNSAT. |
96 | + | ||
97 | + /** | ||
98 | + * Indicates that the intent should be purged from the database. | ||
99 | + * <p> | ||
100 | + * Note: This operation will only be performed if the intent is already | ||
101 | + * in WITHDRAWN or FAILED. | ||
102 | + * </p> | ||
103 | + */ | ||
104 | + PURGE_REQ | ||
96 | } | 105 | } | ... | ... |
... | @@ -109,10 +109,4 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { | ... | @@ -109,10 +109,4 @@ public interface IntentStore extends Store<IntentEvent, IntentStoreDelegate> { |
109 | * @return pending intents | 109 | * @return pending intents |
110 | */ | 110 | */ |
111 | Iterable<Intent> getPending(); | 111 | Iterable<Intent> getPending(); |
112 | - | ||
113 | - /** Purges a specific intent from the system if it is FAILED or WITHDRAWN. | ||
114 | - * | ||
115 | - * @param key key of the intent to purge | ||
116 | - */ | ||
117 | - void purge(Key key); | ||
118 | } | 112 | } | ... | ... |
... | @@ -186,6 +186,17 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -186,6 +186,17 @@ public class FakeIntentManager implements TestableIntentService { |
186 | } | 186 | } |
187 | 187 | ||
188 | @Override | 188 | @Override |
189 | + public void purge(Intent intent) { | ||
190 | + IntentState currentState = intentStates.get(intent.key()); | ||
191 | + if (currentState == IntentState.WITHDRAWN | ||
192 | + || currentState == IntentState.FAILED) { | ||
193 | + intents.remove(intent.key()); | ||
194 | + installables.remove(intent.key()); | ||
195 | + intentStates.remove(intent.key()); | ||
196 | + } | ||
197 | + } | ||
198 | + | ||
199 | + @Override | ||
189 | public Set<Intent> getIntents() { | 200 | public Set<Intent> getIntents() { |
190 | return Collections.unmodifiableSet(new HashSet<>(intents.values())); | 201 | return Collections.unmodifiableSet(new HashSet<>(intents.values())); |
191 | } | 202 | } |
... | @@ -230,11 +241,6 @@ public class FakeIntentManager implements TestableIntentService { | ... | @@ -230,11 +241,6 @@ public class FakeIntentManager implements TestableIntentService { |
230 | listeners.remove(listener); | 241 | listeners.remove(listener); |
231 | } | 242 | } |
232 | 243 | ||
233 | - @Override | ||
234 | - public void purge(Key key) { | ||
235 | - // FIXME implement this | ||
236 | - } | ||
237 | - | ||
238 | private void dispatch(IntentEvent event) { | 244 | private void dispatch(IntentEvent event) { |
239 | for (IntentListener listener : listeners) { | 245 | for (IntentListener listener : listeners) { |
240 | listener.event(event); | 246 | listener.event(event); | ... | ... |
... | @@ -33,6 +33,11 @@ public class IntentServiceAdapter implements IntentService { | ... | @@ -33,6 +33,11 @@ public class IntentServiceAdapter implements IntentService { |
33 | } | 33 | } |
34 | 34 | ||
35 | @Override | 35 | @Override |
36 | + public void purge(Intent intent) { | ||
37 | + | ||
38 | + } | ||
39 | + | ||
40 | + @Override | ||
36 | public Iterable<Intent> getIntents() { | 41 | public Iterable<Intent> getIntents() { |
37 | return null; | 42 | return null; |
38 | } | 43 | } |
... | @@ -76,9 +81,4 @@ public class IntentServiceAdapter implements IntentService { | ... | @@ -76,9 +81,4 @@ public class IntentServiceAdapter implements IntentService { |
76 | public void removeListener(IntentListener listener) { | 81 | public void removeListener(IntentListener listener) { |
77 | 82 | ||
78 | } | 83 | } |
79 | - | ||
80 | - @Override | ||
81 | - public void purge(Key key) { | ||
82 | - | ||
83 | - } | ||
84 | } | 84 | } | ... | ... |
... | @@ -151,6 +151,13 @@ public class IntentManager | ... | @@ -151,6 +151,13 @@ public class IntentManager |
151 | } | 151 | } |
152 | 152 | ||
153 | @Override | 153 | @Override |
154 | + public void purge(Intent intent) { | ||
155 | + checkNotNull(intent, INTENT_NULL); | ||
156 | + IntentData data = new IntentData(intent, IntentState.PURGE_REQ, null); | ||
157 | + store.addPending(data); | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
154 | public Intent getIntent(Key key) { | 161 | public Intent getIntent(Key key) { |
155 | return store.getIntent(key); | 162 | return store.getIntent(key); |
156 | } | 163 | } |
... | @@ -193,11 +200,6 @@ public class IntentManager | ... | @@ -193,11 +200,6 @@ public class IntentManager |
193 | } | 200 | } |
194 | 201 | ||
195 | @Override | 202 | @Override |
196 | - public void purge(Key key) { | ||
197 | - store.purge(key); | ||
198 | - } | ||
199 | - | ||
200 | - @Override | ||
201 | public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) { | 203 | public <T extends Intent> void registerCompiler(Class<T> cls, IntentCompiler<T> compiler) { |
202 | compilerRegistry.registerCompiler(cls, compiler); | 204 | compilerRegistry.registerCompiler(cls, compiler); |
203 | } | 205 | } | ... | ... |
... | @@ -56,6 +56,8 @@ public interface IntentProcessPhase { | ... | @@ -56,6 +56,8 @@ public interface IntentProcessPhase { |
56 | } else { | 56 | } else { |
57 | return new WithdrawRequest(processor, data, current); | 57 | return new WithdrawRequest(processor, data, current); |
58 | } | 58 | } |
59 | + case PURGE_REQ: | ||
60 | + return new PurgeRequest(data, current); | ||
59 | default: | 61 | default: |
60 | // illegal state | 62 | // illegal state |
61 | return new CompilingFailed(data); | 63 | return new CompilingFailed(data); | ... | ... |
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.phase; | ||
17 | + | ||
18 | +import org.onosproject.net.intent.IntentData; | ||
19 | +import org.onosproject.net.intent.IntentState; | ||
20 | +import org.slf4j.Logger; | ||
21 | + | ||
22 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
23 | +import static org.slf4j.LoggerFactory.getLogger; | ||
24 | + | ||
25 | +/** | ||
26 | + * Represents a phase of requesting a purge of an intent. | ||
27 | + * <p> | ||
28 | + * Note: The purge will only succeed if the intent is FAILED or WITHDRAWN. | ||
29 | + * </p> | ||
30 | + */ | ||
31 | +final class PurgeRequest extends FinalIntentProcessPhase { | ||
32 | + | ||
33 | + private static final Logger log = getLogger(PurgeRequest.class); | ||
34 | + | ||
35 | + private final IntentData pending; | ||
36 | + private final IntentData current; | ||
37 | + | ||
38 | + PurgeRequest(IntentData intentData, IntentData current) { | ||
39 | + this.pending = checkNotNull(intentData); | ||
40 | + this.current = checkNotNull(current); | ||
41 | + } | ||
42 | + | ||
43 | + private boolean shouldAcceptPurge() { | ||
44 | + if (current.state() == IntentState.WITHDRAWN | ||
45 | + || current.state() == IntentState.FAILED) { | ||
46 | + return true; | ||
47 | + } | ||
48 | + log.info("Purge for intent {} is rejected", pending.key()); | ||
49 | + return false; | ||
50 | + } | ||
51 | + | ||
52 | + @Override | ||
53 | + public IntentData data() { | ||
54 | + if (shouldAcceptPurge()) { | ||
55 | + return pending; | ||
56 | + } else { | ||
57 | + return current; | ||
58 | + } | ||
59 | + } | ||
60 | +} |
... | @@ -412,6 +412,11 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -412,6 +412,11 @@ public class EventuallyConsistentMapImpl<K, V> |
412 | peerUpdateFunction.apply(key, value)); | 412 | peerUpdateFunction.apply(key, value)); |
413 | notifyListeners(new EventuallyConsistentMapEvent<>( | 413 | notifyListeners(new EventuallyConsistentMapEvent<>( |
414 | EventuallyConsistentMapEvent.Type.REMOVE, key, value)); | 414 | EventuallyConsistentMapEvent.Type.REMOVE, key, value)); |
415 | + } else { | ||
416 | + // TODO remove this extra call when ONOS-1207 is resolved | ||
417 | + Timestamped<V> latest = (Timestamped) items.get(key); | ||
418 | + log.info("Remove of intent {} failed; request time {} vs. latest time {}", | ||
419 | + key, timestamp, latest.timestamp()); | ||
415 | } | 420 | } |
416 | } | 421 | } |
417 | 422 | ... | ... |
... | @@ -224,6 +224,8 @@ public class GossipIntentStore | ... | @@ -224,6 +224,8 @@ public class GossipIntentStore |
224 | } | 224 | } |
225 | return true; | 225 | return true; |
226 | 226 | ||
227 | + case PURGE_REQ: | ||
228 | + return true; | ||
227 | 229 | ||
228 | case COMPILING: | 230 | case COMPILING: |
229 | case RECOMPILING: | 231 | case RECOMPILING: |
... | @@ -241,7 +243,11 @@ public class GossipIntentStore | ... | @@ -241,7 +243,11 @@ public class GossipIntentStore |
241 | if (isUpdateAcceptable(currentData, newData)) { | 243 | if (isUpdateAcceptable(currentData, newData)) { |
242 | // Only the master is modifying the current state. Therefore assume | 244 | // Only the master is modifying the current state. Therefore assume |
243 | // this always succeeds | 245 | // this always succeeds |
244 | - currentMap.put(newData.key(), copyData(newData)); | 246 | + if (newData.state() == PURGE_REQ) { |
247 | + currentMap.remove(newData.key(), newData); | ||
248 | + } else { | ||
249 | + currentMap.put(newData.key(), copyData(newData)); | ||
250 | + } | ||
245 | 251 | ||
246 | // if current.put succeeded | 252 | // if current.put succeeded |
247 | pendingMap.remove(newData.key(), newData); | 253 | pendingMap.remove(newData.key(), newData); |
... | @@ -325,14 +331,6 @@ public class GossipIntentStore | ... | @@ -325,14 +331,6 @@ public class GossipIntentStore |
325 | .collect(Collectors.toList()); | 331 | .collect(Collectors.toList()); |
326 | } | 332 | } |
327 | 333 | ||
328 | - @Override | ||
329 | - public void purge(Key key) { | ||
330 | - IntentData data = currentMap.get(key); | ||
331 | - if (data.state() == WITHDRAWN || data.state() == FAILED) { | ||
332 | - currentMap.remove(key, data); | ||
333 | - } | ||
334 | - } | ||
335 | - | ||
336 | private void notifyDelegateIfNotNull(IntentEvent event) { | 334 | private void notifyDelegateIfNotNull(IntentEvent event) { |
337 | if (event != null) { | 335 | if (event != null) { |
338 | notifyDelegate(event); | 336 | notifyDelegate(event); | ... | ... |
... | @@ -180,7 +180,11 @@ public class SimpleIntentStore | ... | @@ -180,7 +180,11 @@ public class SimpleIntentStore |
180 | IntentData pendingData = pending.get(newData.key()); | 180 | IntentData pendingData = pending.get(newData.key()); |
181 | 181 | ||
182 | if (isUpdateAcceptable(currentData, newData)) { | 182 | if (isUpdateAcceptable(currentData, newData)) { |
183 | - current.put(newData.key(), copyData(newData)); | 183 | + if (pendingData.state() == PURGE_REQ) { |
184 | + current.remove(newData.key(), newData); | ||
185 | + } else { | ||
186 | + current.put(newData.key(), copyData(newData)); | ||
187 | + } | ||
184 | 188 | ||
185 | if (pendingData != null | 189 | if (pendingData != null |
186 | // pendingData version is less than or equal to newData's | 190 | // pendingData version is less than or equal to newData's |
... | @@ -253,12 +257,4 @@ public class SimpleIntentStore | ... | @@ -253,12 +257,4 @@ public class SimpleIntentStore |
253 | .map(IntentData::intent) | 257 | .map(IntentData::intent) |
254 | .collect(Collectors.toList()); | 258 | .collect(Collectors.toList()); |
255 | } | 259 | } |
256 | - | ||
257 | - @Override | ||
258 | - public void purge(Key key) { | ||
259 | - IntentData data = current.get(key); | ||
260 | - if (data.state() == IntentState.WITHDRAWN || data.state() == IntentState.FAILED) { | ||
261 | - current.remove(key, data); | ||
262 | - } | ||
263 | - } | ||
264 | } | 260 | } | ... | ... |
-
Please register or login to post a comment