blob: 5f1cbd4b0bc9a38554aa0790dd5a299b1ca94b80 [file] [log] [blame]
Brian O'Connorb488b192015-02-06 17:58:58 -08001/*
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 */
16package org.onosproject.store.intent.impl;
17
18import com.google.common.collect.Maps;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Service;
Brian O'Connorb488b192015-02-06 17:58:58 -080023import org.onosproject.net.intent.Intent;
24import org.onosproject.net.intent.IntentData;
25import org.onosproject.net.intent.IntentEvent;
Brian O'Connorb488b192015-02-06 17:58:58 -080026import org.onosproject.net.intent.IntentState;
27import org.onosproject.net.intent.IntentStore;
28import org.onosproject.net.intent.IntentStoreDelegate;
29import org.onosproject.net.intent.Key;
30import org.onosproject.store.AbstractStore;
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080031import org.onosproject.store.impl.SystemClockTimestamp;
Brian O'Connorb488b192015-02-06 17:58:58 -080032import org.slf4j.Logger;
33
34import java.util.List;
35import java.util.Map;
Brian O'Connorb488b192015-02-06 17:58:58 -080036import java.util.stream.Collectors;
37
38import static com.google.common.base.Preconditions.checkNotNull;
Ray Milkey9f74c082015-02-11 15:40:16 -080039import static org.onosproject.net.intent.IntentState.*;
Brian O'Connorb488b192015-02-06 17:58:58 -080040import static org.slf4j.LoggerFactory.getLogger;
41
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080042//TODO Note: this store will be removed once the GossipIntentStore is stable
43
Jonathan Hart07e58be2015-02-12 09:57:16 -080044@Component(immediate = true, enabled = false)
Brian O'Connorb488b192015-02-06 17:58:58 -080045@Service
46//FIXME remove this
47public class SimpleIntentStore
48 extends AbstractStore<IntentEvent, IntentStoreDelegate>
49 implements IntentStore {
50
51 private final Logger log = getLogger(getClass());
52
Brian O'Connorb488b192015-02-06 17:58:58 -080053 private final Map<Key, IntentData> current = Maps.newConcurrentMap();
Brian O'Connor2ba63fd2015-02-09 22:48:11 -080054 private final Map<Key, IntentData> pending = Maps.newConcurrentMap();
Brian O'Connorb488b192015-02-06 17:58:58 -080055
Ray Milkey9f74c082015-02-11 15:40:16 -080056 private IntentData copyData(IntentData original) {
57 if (original == null) {
58 return null;
59 }
60 IntentData result =
61 new IntentData(original.intent(), original.state(), original.version());
62
63 if (original.installables() != null) {
64 result.setInstallables(original.installables());
65 }
66 return result;
67 }
68
Brian O'Connorb488b192015-02-06 17:58:58 -080069 @Activate
70 public void activate() {
71 log.info("Started");
72 }
73
74 @Deactivate
75 public void deactivate() {
76 log.info("Stopped");
77 }
78
79 @Override
80 public long getIntentCount() {
81 return current.size();
82 }
83
84 @Override
85 public Iterable<Intent> getIntents() {
86 return current.values().stream()
87 .map(IntentData::intent)
88 .collect(Collectors.toList());
89 }
90
91 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -080092 public IntentState getIntentState(Key intentKey) {
93 IntentData data = current.get(intentKey);
94 return (data != null) ? data.state() : null;
Brian O'Connorb488b192015-02-06 17:58:58 -080095 }
96
97 @Override
Ray Milkeyf9af43c2015-02-09 16:45:48 -080098 public List<Intent> getInstallableIntents(Key intentKey) {
99 // TODO: implement this or delete class
Brian O'Connorb488b192015-02-06 17:58:58 -0800100 return null;
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800101 /*
Brian O'Connorb488b192015-02-06 17:58:58 -0800102 for (IntentData data : current.values()) {
103 if (Objects.equals(data.intent().id(), intentId)) {
104 return data.installables();
105 }
106 }
107 return null;
Ray Milkeyf9af43c2015-02-09 16:45:48 -0800108 */
Brian O'Connorb488b192015-02-06 17:58:58 -0800109 }
110
Ray Milkey9f74c082015-02-11 15:40:16 -0800111
112 /**
Jonathan Hart2085e072015-02-12 11:44:03 -0800113 * Determines whether an intent data update is allowed. The update must
114 * either have a higher version than the current data, or the state
115 * transition between two updates of the same version must be sane.
116 *
117 * @param currentData existing intent data in the store
118 * @param newData new intent data update proposal
119 * @return true if we can apply the update, otherwise false
Ray Milkey9f74c082015-02-11 15:40:16 -0800120 */
121 private boolean isUpdateAcceptable(IntentData currentData, IntentData newData) {
122
123 if (currentData == null) {
124 return true;
125 } else if (currentData.version().compareTo(newData.version()) < 0) {
126 return true;
127 } else if (currentData.version().compareTo(newData.version()) > 0) {
128 return false;
129 }
130
131 // current and new data versions are the same
132 IntentState currentState = currentData.state();
133 IntentState newState = newData.state();
134
135 switch (newState) {
136 case INSTALLING:
137 if (currentState == INSTALLING) {
138 return false;
139 }
140 // FALLTHROUGH
141 case INSTALLED:
142 if (currentState == INSTALLED) {
143 return false;
144 } else if (currentState == WITHDRAWING || currentState == WITHDRAWN) {
145 log.warn("Invalid state transition from {} to {} for intent {}",
146 currentState, newState, newData.key());
147 return false;
148 }
149 return true;
150
151 case WITHDRAWING:
152 if (currentState == WITHDRAWING) {
153 return false;
154 }
155 // FALLTHOUGH
156 case WITHDRAWN:
157 if (currentState == WITHDRAWN) {
158 return false;
159 } else if (currentState == INSTALLING || currentState == INSTALLED) {
160 log.warn("Invalid state transition from {} to {} for intent {}",
161 currentState, newState, newData.key());
162 return false;
163 }
164 return true;
165
166
167 case FAILED:
168 if (currentState == FAILED) {
169 return false;
170 }
171 return true;
172
173
174 case COMPILING:
175 case RECOMPILING:
176 case INSTALL_REQ:
177 case WITHDRAW_REQ:
178 default:
179 log.warn("Invalid state {} for intent {}", newState, newData.key());
180 return false;
181 }
182 }
183
Brian O'Connorb488b192015-02-06 17:58:58 -0800184 @Override
185 public void write(IntentData newData) {
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800186 synchronized (this) {
187 // TODO this could be refactored/cleaned up
188 IntentData currentData = current.get(newData.key());
189 IntentData pendingData = pending.get(newData.key());
Ray Milkey9f74c082015-02-11 15:40:16 -0800190
191 if (isUpdateAcceptable(currentData, newData)) {
192 current.put(newData.key(), copyData(newData));
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800193
194 if (pendingData != null
195 // pendingData version is less than or equal to newData's
196 // Note: a new update for this key could be pending (it's version will be greater)
197 && pendingData.version().compareTo(newData.version()) <= 0) {
198 pending.remove(newData.key());
199 }
200
Jonathan Hart92888362015-02-13 13:14:59 -0800201 notifyDelegateIfNotNull(IntentEvent.getEvent(newData));
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800202 }
Brian O'Connorb488b192015-02-06 17:58:58 -0800203 }
204 }
205
Jonathan Hart92888362015-02-13 13:14:59 -0800206 private void notifyDelegateIfNotNull(IntentEvent event) {
207 if (event != null) {
208 notifyDelegate(event);
209 }
210 }
211
Brian O'Connorb488b192015-02-06 17:58:58 -0800212 @Override
213 public void batchWrite(Iterable<IntentData> updates) {
214 for (IntentData data : updates) {
215 write(data);
216 }
217 }
218
219 @Override
220 public Intent getIntent(Key key) {
221 IntentData data = current.get(key);
222 return (data != null) ? data.intent() : null;
223 }
224
Brian O'Connorb488b192015-02-06 17:58:58 -0800225 @Override
Ray Milkey9f74c082015-02-11 15:40:16 -0800226 public IntentData getIntentData(Key key) {
227 return copyData(current.get(key));
228 }
229
230 @Override
Brian O'Connorb488b192015-02-06 17:58:58 -0800231 public void addPending(IntentData data) {
Ray Milkey9f74c082015-02-11 15:40:16 -0800232 if (data.version() == null) { // recompiled intents will already have a version
Brian O'Connor47bc8552015-02-11 11:03:32 -0800233 data.setVersion(new SystemClockTimestamp());
234 }
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800235 synchronized (this) {
236 IntentData existingData = pending.get(data.key());
237 if (existingData == null ||
238 // existing version is strictly less than data's version
239 // Note: if they are equal, we already have the update
240 // TODO maybe we should still make this <= to be safe?
241 existingData.version().compareTo(data.version()) < 0) {
242 pending.put(data.key(), data);
243 checkNotNull(delegate, "Store delegate is not set")
244 .process(data);
Jonathan Hart92888362015-02-13 13:14:59 -0800245 notifyDelegateIfNotNull(IntentEvent.getEvent(data));
Brian O'Connor2ba63fd2015-02-09 22:48:11 -0800246 } else {
247 log.debug("IntentData {} is older than existing: {}",
248 data, existingData);
249 }
250 //TODO consider also checking the current map at this point
251 }
Brian O'Connorb488b192015-02-06 17:58:58 -0800252 }
253
Brian O'Connorb488b192015-02-06 17:58:58 -0800254 @Override
Brian O'Connorbe28a872015-02-19 21:44:37 -0800255 public boolean isMaster(Key intentKey) {
Brian O'Connorb488b192015-02-06 17:58:58 -0800256 return true;
257 }
258}