blob: a6d5b15861911d8bf242250c68154e12d9c4ee8b [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
Thomas Vachuskab97cf282014-10-20 23:31:12 -070018import com.google.common.collect.ImmutableSet;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070019
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070025import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070026import org.onlab.onos.net.intent.Intent;
27import org.onlab.onos.net.intent.IntentEvent;
28import org.onlab.onos.net.intent.IntentId;
29import org.onlab.onos.net.intent.IntentState;
30import org.onlab.onos.net.intent.IntentStore;
31import org.onlab.onos.net.intent.IntentStoreDelegate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080032import org.onlab.onos.store.AbstractStore;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070033import org.onlab.onos.store.serializers.KryoNamespaces;
34import org.onlab.onos.store.serializers.KryoSerializer;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080035import org.onlab.onos.store.serializers.StoreSerializer;
36import org.onlab.onos.store.service.DatabaseAdminService;
37import org.onlab.onos.store.service.DatabaseService;
38import org.onlab.onos.store.service.impl.CMap;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070039import org.onlab.util.KryoNamespace;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070040import org.slf4j.Logger;
41
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080042import java.util.EnumSet;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070043import java.util.List;
44import java.util.Map;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080045import java.util.Set;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070046import java.util.concurrent.ConcurrentHashMap;
47
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070048import static com.google.common.base.Verify.verify;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070049import static org.onlab.onos.net.intent.IntentState.*;
50import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070051
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070052@Component(immediate = true)
53@Service
54public class DistributedIntentStore
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080055 extends AbstractStore<IntentEvent, IntentStoreDelegate>
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070056 implements IntentStore {
57
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080058 /** Valid parking state, which can transition to INSTALLED. */
59 private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, FAILED);
60
61 /** Valid parking state, which can transition to WITHDRAWN. */
62 private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
63
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070064 private final Logger log = getLogger(getClass());
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070065
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070066 // Assumption: IntentId will not have synonyms
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080067 private CMap<IntentId, Intent> intents;
68 private CMap<IntentId, IntentState> states;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070069
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080070 // TODO left behind transient state issue: ONOS-103
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070071 // Map to store instance local intermediate state transition
72 private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
73
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080074 private CMap<IntentId, List<Intent>> installable;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070075
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080076 private StoreSerializer serializer;
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected DatabaseAdminService dbAdminService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected DatabaseService dbService;
83
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070084 @Activate
85 public void activate() {
Yuta HIGUCHI71fa4932014-10-28 22:27:49 -070086 // FIXME: We need a way to add serializer for intents which has been plugged-in.
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070087 // As a short term workaround, relax Kryo config to
88 // registrationRequired=false
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080089 serializer = new KryoSerializer() {
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070090
91 @Override
92 protected void setupKryoPool() {
93 serializerPool = KryoNamespace.newBuilder()
94 .setRegistrationRequired(false)
95 .register(KryoNamespaces.API)
96 .build()
97 .populate(1);
98 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070099 };
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700100
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800101 intents = new CMap<>(dbAdminService, dbService, "intents", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700102
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800103 states = new CMap<>(dbAdminService, dbService, "intent-states", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700104
105 transientStates.clear();
106
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800107 installable = new CMap<>(dbAdminService, dbService, "installable-intents", serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700108
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700109 log.info("Started");
110 }
111
112 @Deactivate
113 public void deactivate() {
114 log.info("Stopped");
115 }
116
117 @Override
118 public IntentEvent createIntent(Intent intent) {
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800119 boolean absent = intents.putIfAbsent(intent.id(), intent);
120 if (!absent) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700121 // duplicate, ignore
122 return null;
123 } else {
124 return this.setState(intent, IntentState.SUBMITTED);
125 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700126 }
127
128 @Override
129 public IntentEvent removeIntent(IntentId intentId) {
130 Intent intent = intents.remove(intentId);
131 installable.remove(intentId);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700132 if (intent == null) {
133 // was already removed
134 return null;
135 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700136 IntentEvent event = this.setState(intent, WITHDRAWN);
137 states.remove(intentId);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700138 transientStates.remove(intentId);
139 // TODO: Should we callremoveInstalledIntents if this Intent was
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700140 return event;
141 }
142
143 @Override
144 public long getIntentCount() {
145 return intents.size();
146 }
147
148 @Override
149 public Iterable<Intent> getIntents() {
150 return ImmutableSet.copyOf(intents.values());
151 }
152
153 @Override
154 public Intent getIntent(IntentId intentId) {
155 return intents.get(intentId);
156 }
157
158 @Override
159 public IntentState getIntentState(IntentId id) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700160 final IntentState localState = transientStates.get(id);
161 if (localState != null) {
162 return localState;
163 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700164 return states.get(id);
165 }
166
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800167
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700168 @Override
169 public IntentEvent setState(Intent intent, IntentState state) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700170 final IntentId id = intent.id();
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700171 IntentEvent.Type type = null;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800172 final IntentState prevParking;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700173 boolean transientStateChangeOnly = false;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800174 boolean updated;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700175
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800176 // parking state transition
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700177 switch (state) {
178 case SUBMITTED:
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800179 prevParking = states.get(id);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800180 verify(prevParking == null,
181 "Illegal state transition attempted from %s to SUBMITTED",
182 prevParking);
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800183 updated = states.putIfAbsent(id, SUBMITTED);
184 verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700185 type = IntentEvent.Type.SUBMITTED;
186 break;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800187
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700188 case INSTALLED:
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800189 prevParking = states.get(id);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800190 verify(PRE_INSTALLED.contains(prevParking),
191 "Illegal state transition attempted from %s to INSTALLED",
192 prevParking);
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800193 updated = states.replace(id, prevParking, INSTALLED);
194 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALLED);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700195 type = IntentEvent.Type.INSTALLED;
196 break;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800197
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700198 case FAILED:
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800199 prevParking = states.get(id);
200 updated = states.replace(id, prevParking, FAILED);
201 verify(updated, "Conditional replace %s => %s failed", prevParking, FAILED);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700202 type = IntentEvent.Type.FAILED;
203 break;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800204
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700205 case WITHDRAWN:
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800206 prevParking = states.get(id);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800207 verify(PRE_WITHDRAWN.contains(prevParking),
208 "Illegal state transition attempted from %s to WITHDRAWN",
209 prevParking);
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800210 updated = states.replace(id, prevParking, WITHDRAWN);
211 verify(updated, "Conditional replace %s => %s failed", prevParking, WITHDRAWN);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700212 type = IntentEvent.Type.WITHDRAWN;
213 break;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800214
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700215 default:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700216 transientStateChangeOnly = true;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800217 prevParking = null;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700218 break;
219 }
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700220 if (!transientStateChangeOnly) {
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800221 log.debug("Parking State change: {} {}=>{}", id, prevParking, state);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700222 }
223 // Update instance local state, which includes non-parking state transition
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800224 final IntentState prevTransient = transientStates.put(id, state);
225 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700226
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700227 if (type == null) {
228 return null;
229 }
230 return new IntentEvent(type, intent);
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700231 }
232
233 @Override
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700234 public void setInstallableIntents(IntentId intentId, List<Intent> result) {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700235 installable.put(intentId, result);
236 }
237
238 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700239 public List<Intent> getInstallableIntents(IntentId intentId) {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700240 return installable.get(intentId);
241 }
242
243 @Override
244 public void removeInstalledIntents(IntentId intentId) {
245 installable.remove(intentId);
246 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700247}