blob: 8da72cf7d9e985c7fc94c68d238663d1dee067de [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 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 */
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070016package org.onlab.onos.store.intent.impl;
17
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080018import com.codahale.metrics.Timer;
19import com.codahale.metrics.Timer.Context;
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -080020import com.google.common.base.Verify;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070021import com.google.common.collect.ImmutableSet;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070022
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070028import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080029import org.onlab.metrics.MetricsService;
30import org.onlab.onos.core.MetricsHelper;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070031import org.onlab.onos.net.intent.Intent;
32import org.onlab.onos.net.intent.IntentEvent;
33import org.onlab.onos.net.intent.IntentId;
34import org.onlab.onos.net.intent.IntentState;
35import org.onlab.onos.net.intent.IntentStore;
36import org.onlab.onos.net.intent.IntentStoreDelegate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080037import org.onlab.onos.store.AbstractStore;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070038import org.onlab.onos.store.serializers.KryoNamespaces;
39import org.onlab.onos.store.serializers.KryoSerializer;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080040import org.onlab.onos.store.serializers.StoreSerializer;
41import org.onlab.onos.store.service.DatabaseAdminService;
42import org.onlab.onos.store.service.DatabaseService;
43import org.onlab.onos.store.service.impl.CMap;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070044import org.onlab.util.KryoNamespace;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070045import org.slf4j.Logger;
46
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080047import java.util.EnumSet;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070048import java.util.List;
49import java.util.Map;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080050import java.util.Set;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070051import java.util.concurrent.ConcurrentHashMap;
52
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -080053import static com.google.common.base.Preconditions.checkState;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070054import static org.onlab.onos.net.intent.IntentState.*;
55import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080056import static org.onlab.metrics.MetricsUtil.*;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070057
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -080058@Component(immediate = true, enabled = true)
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070059@Service
60public class DistributedIntentStore
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080061 extends AbstractStore<IntentEvent, IntentStoreDelegate>
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080062 implements IntentStore, MetricsHelper {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070063
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080064 /** Valid parking state, which can transition to INSTALLED. */
Yuta HIGUCHI89a7f472014-11-21 14:50:24 -080065 private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080066
67 /** Valid parking state, which can transition to WITHDRAWN. */
68 private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
69
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070070 private final Logger log = getLogger(getClass());
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070071
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070072 // Assumption: IntentId will not have synonyms
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080073 private CMap<IntentId, Intent> intents;
74 private CMap<IntentId, IntentState> states;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070075
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080076 // TODO left behind transient state issue: ONOS-103
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070077 // Map to store instance local intermediate state transition
78 private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
79
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080080 private CMap<IntentId, List<Intent>> installable;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070081
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080082 private StoreSerializer serializer;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected DatabaseAdminService dbAdminService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DatabaseService dbService;
89
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected MetricsService metricsService;
92
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -080093 // TODO make this configurable
94 private boolean onlyLogTransitionError = true;
95
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080096 private Timer createIntentTimer;
97 private Timer removeIntentTimer;
98 private Timer setInstallableIntentsTimer;
99 private Timer getInstallableIntentsTimer;
100 private Timer removeInstalledIntentsTimer;
101 private Timer setStateTimer;
102 private Timer getIntentCountTimer;
103 private Timer getIntentsTimer;
104 private Timer getIntentTimer;
105 private Timer getIntentStateTimer;
106
107
108 private Timer createResponseTimer(String methodName) {
109 return createTimer("IntentStore", methodName, "responseTime");
110 }
111
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700112 @Activate
113 public void activate() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800114 createIntentTimer = createResponseTimer("createIntent");
115 removeIntentTimer = createResponseTimer("removeIntent");
116 setInstallableIntentsTimer = createResponseTimer("setInstallableIntents");
117 getInstallableIntentsTimer = createResponseTimer("getInstallableIntents");
118 removeInstalledIntentsTimer = createResponseTimer("removeInstalledIntents");
119 setStateTimer = createResponseTimer("setState");
120 getIntentCountTimer = createResponseTimer("getIntentCount");
121 getIntentsTimer = createResponseTimer("getIntents");
122 getIntentTimer = createResponseTimer("getIntent");
123 getIntentStateTimer = createResponseTimer("getIntentState");
124
Yuta HIGUCHI71fa4932014-10-28 22:27:49 -0700125 // FIXME: We need a way to add serializer for intents which has been plugged-in.
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700126 // As a short term workaround, relax Kryo config to
127 // registrationRequired=false
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800128 serializer = new KryoSerializer() {
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700129
130 @Override
131 protected void setupKryoPool() {
132 serializerPool = KryoNamespace.newBuilder()
133 .setRegistrationRequired(false)
134 .register(KryoNamespaces.API)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800135 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
136 .build();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700137 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700138 };
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700139
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800140 intents = new CMap<>(dbAdminService, dbService, "intents", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700141
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800142 states = new CMap<>(dbAdminService, dbService, "intent-states", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700143
144 transientStates.clear();
145
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800146 installable = new CMap<>(dbAdminService, dbService, "installable-intents", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700147
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700148 log.info("Started");
149 }
150
151 @Deactivate
152 public void deactivate() {
153 log.info("Stopped");
154 }
155
156 @Override
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800157 public MetricsService metricsService() {
158 return metricsService;
159 }
160
161 @Override
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700162 public IntentEvent createIntent(Intent intent) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800163 Context timer = startTimer(createIntentTimer);
164 try {
165 boolean absent = intents.putIfAbsent(intent.id(), intent);
166 if (!absent) {
167 // duplicate, ignore
168 return null;
169 } else {
170 return this.setState(intent, IntentState.SUBMITTED);
171 }
172 } finally {
173 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700174 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700175 }
176
177 @Override
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800178 public void removeIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800179 Context timer = startTimer(removeIntentTimer);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800180 checkState(getIntentState(intentId) == WITHDRAWN,
181 "Intent state for {} is not WITHDRAWN.", intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800182 try {
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800183 intents.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800184 states.remove(intentId);
185 transientStates.remove(intentId);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800186 installable.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800187 } finally {
188 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700189 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700190 }
191
192 @Override
193 public long getIntentCount() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800194 Context timer = startTimer(getIntentCountTimer);
195 try {
196 return intents.size();
197 } finally {
198 stopTimer(timer);
199 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700200 }
201
202 @Override
203 public Iterable<Intent> getIntents() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800204 Context timer = startTimer(getIntentsTimer);
205 try {
206 return ImmutableSet.copyOf(intents.values());
207 } finally {
208 stopTimer(timer);
209 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700210 }
211
212 @Override
213 public Intent getIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800214 Context timer = startTimer(getIntentTimer);
215 try {
216 return intents.get(intentId);
217 } finally {
218 stopTimer(timer);
219 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700220 }
221
222 @Override
223 public IntentState getIntentState(IntentId id) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800224 Context timer = startTimer(getIntentStateTimer);
225 try {
226 final IntentState localState = transientStates.get(id);
227 if (localState != null) {
228 return localState;
229 }
230 return states.get(id);
231 } finally {
232 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700233 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700234 }
235
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800236 // FIXME temporary workaround until we fix our state machine
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -0800237 private void verify(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
238 if (onlyLogTransitionError) {
239 if (!expression) {
240 log.error(errorMessageTemplate.replace("%s", "{}"), errorMessageArgs);
241 }
242 } else {
243 Verify.verify(expression, errorMessageTemplate, errorMessageArgs);
244 }
245 }
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800246
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700247 @Override
248 public IntentEvent setState(Intent intent, IntentState state) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800249 Context timer = startTimer(setStateTimer);
250 try {
251 final IntentId id = intent.id();
252 IntentEvent.Type evtType = null;
253 final IntentState prevParking;
254 boolean transitionedToParking = true;
255 boolean updated;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700256
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800257 // parking state transition
258 switch (state) {
259 case SUBMITTED:
260 prevParking = states.get(id);
261 if (prevParking == null) {
262 updated = states.putIfAbsent(id, SUBMITTED);
263 verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
264 } else {
265 verify(prevParking == WITHDRAWN,
266 "Illegal state transition attempted from %s to SUBMITTED",
267 prevParking);
268 updated = states.replace(id, prevParking, SUBMITTED);
269 verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
270 }
271 evtType = IntentEvent.Type.SUBMITTED;
272 break;
273
274 case INSTALLED:
275 prevParking = states.get(id);
276 verify(PRE_INSTALLED.contains(prevParking),
277 "Illegal state transition attempted from %s to INSTALLED",
278 prevParking);
279 updated = states.replace(id, prevParking, INSTALLED);
280 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALLED);
281 evtType = IntentEvent.Type.INSTALLED;
282 break;
283
284 case FAILED:
285 prevParking = states.get(id);
286 updated = states.replace(id, prevParking, FAILED);
287 verify(updated, "Conditional replace %s => %s failed", prevParking, FAILED);
288 evtType = IntentEvent.Type.FAILED;
289 break;
290
291 case WITHDRAWN:
292 prevParking = states.get(id);
293 verify(PRE_WITHDRAWN.contains(prevParking),
294 "Illegal state transition attempted from %s to WITHDRAWN",
295 prevParking);
296 updated = states.replace(id, prevParking, WITHDRAWN);
297 verify(updated, "Conditional replace %s => %s failed", prevParking, WITHDRAWN);
298 evtType = IntentEvent.Type.WITHDRAWN;
299 break;
300
301 default:
302 transitionedToParking = false;
303 prevParking = null;
304 break;
Yuta HIGUCHI89a7f472014-11-21 14:50:24 -0800305 }
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800306 if (transitionedToParking) {
307 log.debug("Parking State change: {} {}=>{}", id, prevParking, state);
308 // remove instance local state
309 transientStates.remove(id);
310 } else {
311 // Update instance local state, which includes non-parking state transition
312 final IntentState prevTransient = transientStates.put(id, state);
313 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
314 }
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800315
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800316 if (evtType == null) {
317 return null;
318 }
319 return new IntentEvent(evtType, intent);
320 } finally {
321 stopTimer(timer);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700322 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700323 }
324
325 @Override
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700326 public void setInstallableIntents(IntentId intentId, List<Intent> result) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800327 Context timer = startTimer(setInstallableIntentsTimer);
328 try {
329 installable.put(intentId, result);
330 } finally {
331 stopTimer(timer);
332 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700333 }
334
335 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700336 public List<Intent> getInstallableIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800337 Context timer = startTimer(getInstallableIntentsTimer);
338 try {
339 return installable.get(intentId);
340 } finally {
341 stopTimer(timer);
342 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700343 }
344
345 @Override
346 public void removeInstalledIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800347 Context timer = startTimer(removeInstalledIntentsTimer);
348 try {
349 installable.remove(intentId);
350 } finally {
351 stopTimer(timer);
352 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700353 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700354}