blob: 8c18fb0597aee45251543d245af39ebaeffe7998 [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 -070019import com.hazelcast.core.IMap;
20
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070025import org.onlab.onos.net.intent.Intent;
26import org.onlab.onos.net.intent.IntentEvent;
27import org.onlab.onos.net.intent.IntentId;
28import org.onlab.onos.net.intent.IntentState;
29import org.onlab.onos.net.intent.IntentStore;
30import org.onlab.onos.net.intent.IntentStoreDelegate;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070031import org.onlab.onos.store.hz.AbstractHazelcastStore;
32import org.onlab.onos.store.hz.SMap;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070033import org.onlab.onos.store.serializers.KryoNamespaces;
34import org.onlab.onos.store.serializers.KryoSerializer;
35import org.onlab.util.KryoNamespace;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070036import org.slf4j.Logger;
37
Thomas Vachuskab97cf282014-10-20 23:31:12 -070038import java.util.List;
39import java.util.Map;
40import java.util.concurrent.ConcurrentHashMap;
41
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070042import static com.google.common.base.Verify.verify;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070043import static org.onlab.onos.net.intent.IntentState.*;
44import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070045
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070046@Component(immediate = true)
47@Service
48public class DistributedIntentStore
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070049 extends AbstractHazelcastStore<IntentEvent, IntentStoreDelegate>
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070050 implements IntentStore {
51
52 private final Logger log = getLogger(getClass());
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070053
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070054 // Assumption: IntentId will not have synonyms
55 private SMap<IntentId, Intent> intents;
56 private SMap<IntentId, IntentState> states;
57
58 // Map to store instance local intermediate state transition
59 private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
60
61 private SMap<IntentId, List<Intent>> installable;
62
63 @Override
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070064 @Activate
65 public void activate() {
Yuta HIGUCHI71fa4932014-10-28 22:27:49 -070066 // FIXME: We need a way to add serializer for intents which has been plugged-in.
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070067 // As a short term workaround, relax Kryo config to
68 // registrationRequired=false
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070069 super.activate();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070070 super.serializer = new KryoSerializer() {
71
72 @Override
73 protected void setupKryoPool() {
74 serializerPool = KryoNamespace.newBuilder()
75 .setRegistrationRequired(false)
76 .register(KryoNamespaces.API)
77 .build()
78 .populate(1);
79 }
80
81 };
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070082
83 // TODO: enable near cache, allow read from backup for this IMap
84 IMap<byte[], byte[]> rawIntents = super.theInstance.getMap("intents");
85 intents = new SMap<>(rawIntents , super.serializer);
86
87 // TODO: disable near cache, disable read from backup for this IMap
88 IMap<byte[], byte[]> rawStates = super.theInstance.getMap("intent-states");
89 states = new SMap<>(rawStates , super.serializer);
90
91 transientStates.clear();
92
93 // TODO: disable near cache, disable read from backup for this IMap
94 IMap<byte[], byte[]> rawInstallables = super.theInstance.getMap("installable-intents");
95 installable = new SMap<>(rawInstallables , super.serializer);
96
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070097 log.info("Started");
98 }
99
100 @Deactivate
101 public void deactivate() {
102 log.info("Stopped");
103 }
104
105 @Override
106 public IntentEvent createIntent(Intent intent) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700107 Intent existing = intents.putIfAbsent(intent.id(), intent);
108 if (existing != null) {
109 // duplicate, ignore
110 return null;
111 } else {
112 return this.setState(intent, IntentState.SUBMITTED);
113 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700114 }
115
116 @Override
117 public IntentEvent removeIntent(IntentId intentId) {
118 Intent intent = intents.remove(intentId);
119 installable.remove(intentId);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700120 if (intent == null) {
121 // was already removed
122 return null;
123 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700124 IntentEvent event = this.setState(intent, WITHDRAWN);
125 states.remove(intentId);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700126 transientStates.remove(intentId);
127 // TODO: Should we callremoveInstalledIntents if this Intent was
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700128 return event;
129 }
130
131 @Override
132 public long getIntentCount() {
133 return intents.size();
134 }
135
136 @Override
137 public Iterable<Intent> getIntents() {
138 return ImmutableSet.copyOf(intents.values());
139 }
140
141 @Override
142 public Intent getIntent(IntentId intentId) {
143 return intents.get(intentId);
144 }
145
146 @Override
147 public IntentState getIntentState(IntentId id) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700148 final IntentState localState = transientStates.get(id);
149 if (localState != null) {
150 return localState;
151 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700152 return states.get(id);
153 }
154
155 @Override
156 public IntentEvent setState(Intent intent, IntentState state) {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700157 final IntentId id = intent.id();
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700158 IntentEvent.Type type = null;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700159 IntentState prev = null;
160 boolean transientStateChangeOnly = false;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700161
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700162 // TODO: enable sanity checking if Debug enabled, etc.
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700163 switch (state) {
164 case SUBMITTED:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700165 prev = states.putIfAbsent(id, SUBMITTED);
166 verify(prev == null, "Illegal state transition attempted from %s to SUBMITTED", prev);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700167 type = IntentEvent.Type.SUBMITTED;
168 break;
169 case INSTALLED:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700170 // parking state transition
171 prev = states.replace(id, INSTALLED);
172 verify(prev != null, "Illegal state transition attempted from non-SUBMITTED to INSTALLED");
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700173 type = IntentEvent.Type.INSTALLED;
174 break;
175 case FAILED:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700176 prev = states.replace(id, FAILED);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700177 type = IntentEvent.Type.FAILED;
178 break;
179 case WITHDRAWN:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700180 prev = states.replace(id, WITHDRAWN);
181 verify(prev != null, "Illegal state transition attempted from non-WITHDRAWING to WITHDRAWN");
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700182 type = IntentEvent.Type.WITHDRAWN;
183 break;
184 default:
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700185 transientStateChangeOnly = true;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700186 break;
187 }
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700188 if (!transientStateChangeOnly) {
189 log.debug("Parking State change: {} {}=>{}", id, prev, state);
190 }
191 // Update instance local state, which includes non-parking state transition
192 prev = transientStates.put(id, state);
193 log.debug("Transient State change: {} {}=>{}", id, prev, state);
194
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700195 if (type == null) {
196 return null;
197 }
198 return new IntentEvent(type, intent);
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700199 }
200
201 @Override
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700202 public void setInstallableIntents(IntentId intentId, List<Intent> result) {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700203 installable.put(intentId, result);
204 }
205
206 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700207 public List<Intent> getInstallableIntents(IntentId intentId) {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700208 return installable.get(intentId);
209 }
210
211 @Override
212 public void removeInstalledIntents(IntentId intentId) {
213 installable.remove(intentId);
214 }
215
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700216 // FIXME add handler to react to remote event
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700217}