blob: 556f4cbc95c39eba7857cff08bdf949a7834b026 [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.intent.impl;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070017
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;
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080021import com.google.common.cache.CacheBuilder;
22import com.google.common.cache.CacheLoader;
23import com.google.common.cache.LoadingCache;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070024import com.google.common.collect.ImmutableSet;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070025
alshabiba9819bf2014-11-30 18:15:52 -080026import com.google.common.collect.Lists;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070027import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080030import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070032import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080033import org.onlab.metrics.MetricsService;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.core.MetricsHelper;
Sho SHIMIZU64ae11c2014-12-03 15:17:47 -080035import org.onosproject.net.intent.BatchWrite;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.intent.Intent;
37import org.onosproject.net.intent.IntentEvent;
38import org.onosproject.net.intent.IntentId;
39import org.onosproject.net.intent.IntentState;
40import org.onosproject.net.intent.IntentStore;
41import org.onosproject.net.intent.IntentStoreDelegate;
Sho SHIMIZU64ae11c2014-12-03 15:17:47 -080042import org.onosproject.net.intent.BatchWrite.Operation;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.store.AbstractStore;
44import org.onosproject.store.serializers.KryoNamespaces;
45import org.onosproject.store.serializers.KryoSerializer;
46import org.onosproject.store.serializers.StoreSerializer;
47import org.onosproject.store.service.BatchWriteRequest;
48import org.onosproject.store.service.BatchWriteRequest.Builder;
49import org.onosproject.store.service.BatchWriteResult;
50import org.onosproject.store.service.DatabaseAdminService;
51import org.onosproject.store.service.DatabaseService;
52import org.onosproject.store.service.impl.CMap;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070053import org.onlab.util.KryoNamespace;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070054import org.slf4j.Logger;
55
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080056import java.util.ArrayList;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080057import java.util.EnumSet;
Yuta HIGUCHIf5682452014-12-01 10:17:15 -080058import java.util.HashSet;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070059import java.util.List;
60import java.util.Map;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080061import java.util.Set;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070062import java.util.concurrent.ConcurrentHashMap;
63
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080064import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -080065import static com.google.common.base.Preconditions.checkState;
Brian O'Connorabafb502014-12-02 22:26:20 -080066import static org.onosproject.net.intent.IntentState.*;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070067import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080068import static org.onlab.metrics.MetricsUtil.*;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070069
Yuta HIGUCHI9b108b32014-12-01 11:10:26 -080070@Component(immediate = true, enabled = false)
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070071@Service
72public class DistributedIntentStore
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080073 extends AbstractStore<IntentEvent, IntentStoreDelegate>
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080074 implements IntentStore, MetricsHelper {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070075
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080076 /** Valid parking state, which can transition to INSTALLED. */
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080077 private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(INSTALL_REQ, INSTALLED, FAILED);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080078
79 /** Valid parking state, which can transition to WITHDRAWN. */
80 private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
81
Brian O'Connor7a71d5d2014-12-02 00:12:27 -080082 private static final Set<IntentState> PARKING = EnumSet.of(INSTALL_REQ, INSTALLED, WITHDRAWN, FAILED);
Yuta HIGUCHIf5682452014-12-01 10:17:15 -080083
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070084 private final Logger log = getLogger(getClass());
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070085
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070086 // Assumption: IntentId will not have synonyms
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080087 private static final String INTENTS_TABLE = "intents";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080088 private CMap<IntentId, Intent> intents;
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080089
90 private static final String STATES_TABLE = "intent-states";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080091 private CMap<IntentId, IntentState> states;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070092
Yuta HIGUCHI65934892014-12-04 17:47:44 -080093 // TODO transient state issue remains for this impl.: ONOS-103
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070094 // Map to store instance local intermediate state transition
95 private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
96
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080097 private static final String INSTALLABLE_TABLE = "installable-intents";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080098 private CMap<IntentId, List<Intent>> installable;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070099
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800100 private LoadingCache<IntentId, String> keyCache;
101
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800102 private StoreSerializer serializer;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DatabaseAdminService dbAdminService;
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected DatabaseService dbService;
109
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected MetricsService metricsService;
112
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -0800113 // TODO make this configurable
114 private boolean onlyLogTransitionError = true;
115
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800116 private Timer createIntentTimer;
117 private Timer removeIntentTimer;
118 private Timer setInstallableIntentsTimer;
119 private Timer getInstallableIntentsTimer;
120 private Timer removeInstalledIntentsTimer;
121 private Timer setStateTimer;
122 private Timer getIntentCountTimer;
123 private Timer getIntentsTimer;
124 private Timer getIntentTimer;
125 private Timer getIntentStateTimer;
126
127
128 private Timer createResponseTimer(String methodName) {
129 return createTimer("IntentStore", methodName, "responseTime");
130 }
131
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700132 @Activate
133 public void activate() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800134 createIntentTimer = createResponseTimer("createIntent");
135 removeIntentTimer = createResponseTimer("removeIntent");
136 setInstallableIntentsTimer = createResponseTimer("setInstallableIntents");
137 getInstallableIntentsTimer = createResponseTimer("getInstallableIntents");
138 removeInstalledIntentsTimer = createResponseTimer("removeInstalledIntents");
139 setStateTimer = createResponseTimer("setState");
140 getIntentCountTimer = createResponseTimer("getIntentCount");
141 getIntentsTimer = createResponseTimer("getIntents");
142 getIntentTimer = createResponseTimer("getIntent");
143 getIntentStateTimer = createResponseTimer("getIntentState");
144
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800145 // We need a way to add serializer for intents which has been plugged-in.
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700146 // As a short term workaround, relax Kryo config to
147 // registrationRequired=false
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800148 serializer = new KryoSerializer() {
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700149
150 @Override
151 protected void setupKryoPool() {
152 serializerPool = KryoNamespace.newBuilder()
153 .setRegistrationRequired(false)
154 .register(KryoNamespaces.API)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800155 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
156 .build();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700157 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700158 };
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700159
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800160 keyCache = CacheBuilder.newBuilder()
161 .softValues()
162 .build(new CacheLoader<IntentId, String>() {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700163
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800164 @Override
165 public String load(IntentId key) {
166 return key.toString();
167 }
168 });
169
170 intents = new IntentIdMap<>(dbAdminService, dbService, INTENTS_TABLE, serializer);
171
172 states = new IntentIdMap<>(dbAdminService, dbService, STATES_TABLE, serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700173
174 transientStates.clear();
175
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800176 installable = new IntentIdMap<>(dbAdminService, dbService, INSTALLABLE_TABLE, serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700177
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700178 log.info("Started");
179 }
180
181 @Deactivate
182 public void deactivate() {
183 log.info("Stopped");
184 }
185
186 @Override
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800187 public MetricsService metricsService() {
188 return metricsService;
189 }
190
191 @Override
alshabiba9819bf2014-11-30 18:15:52 -0800192 public void createIntent(Intent intent) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800193 Context timer = startTimer(createIntentTimer);
194 try {
195 boolean absent = intents.putIfAbsent(intent.id(), intent);
196 if (!absent) {
197 // duplicate, ignore
alshabiba9819bf2014-11-30 18:15:52 -0800198 return;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800199 } else {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800200 this.setState(intent, IntentState.INSTALL_REQ);
alshabiba9819bf2014-11-30 18:15:52 -0800201 return;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800202 }
203 } finally {
204 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700205 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700206 }
207
208 @Override
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800209 public void removeIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800210 Context timer = startTimer(removeIntentTimer);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800211 checkState(getIntentState(intentId) == WITHDRAWN,
212 "Intent state for {} is not WITHDRAWN.", intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800213 try {
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800214 intents.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800215 states.remove(intentId);
216 transientStates.remove(intentId);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800217 installable.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800218 } finally {
219 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700220 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700221 }
222
223 @Override
224 public long getIntentCount() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800225 Context timer = startTimer(getIntentCountTimer);
226 try {
227 return intents.size();
228 } finally {
229 stopTimer(timer);
230 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700231 }
232
233 @Override
234 public Iterable<Intent> getIntents() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800235 Context timer = startTimer(getIntentsTimer);
236 try {
237 return ImmutableSet.copyOf(intents.values());
238 } finally {
239 stopTimer(timer);
240 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700241 }
242
243 @Override
244 public Intent getIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800245 Context timer = startTimer(getIntentTimer);
246 try {
247 return intents.get(intentId);
248 } finally {
249 stopTimer(timer);
250 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700251 }
252
253 @Override
254 public IntentState getIntentState(IntentId id) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800255 Context timer = startTimer(getIntentStateTimer);
256 try {
257 final IntentState localState = transientStates.get(id);
258 if (localState != null) {
259 return localState;
260 }
261 return states.get(id);
262 } finally {
263 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700264 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700265 }
266
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -0800267 private void verify(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
268 if (onlyLogTransitionError) {
269 if (!expression) {
270 log.error(errorMessageTemplate.replace("%s", "{}"), errorMessageArgs);
271 }
272 } else {
273 Verify.verify(expression, errorMessageTemplate, errorMessageArgs);
274 }
275 }
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800276
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700277 @Override
alshabiba9819bf2014-11-30 18:15:52 -0800278 public void setState(Intent intent, IntentState state) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800279 Context timer = startTimer(setStateTimer);
280 try {
281 final IntentId id = intent.id();
282 IntentEvent.Type evtType = null;
283 final IntentState prevParking;
284 boolean transitionedToParking = true;
285 boolean updated;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700286
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800287 // parking state transition
288 switch (state) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800289 case INSTALL_REQ:
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800290 prevParking = states.get(id);
291 if (prevParking == null) {
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800292 updated = states.putIfAbsent(id, INSTALL_REQ);
293 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800294 } else {
295 verify(prevParking == WITHDRAWN,
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800296 "Illegal state transition attempted from %s to INSTALL_REQ",
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800297 prevParking);
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800298 updated = states.replace(id, prevParking, INSTALL_REQ);
299 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALL_REQ);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800300 }
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800301 evtType = IntentEvent.Type.INSTALL_REQ;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800302 break;
303
304 case INSTALLED:
305 prevParking = states.get(id);
306 verify(PRE_INSTALLED.contains(prevParking),
307 "Illegal state transition attempted from %s to INSTALLED",
308 prevParking);
309 updated = states.replace(id, prevParking, INSTALLED);
310 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALLED);
311 evtType = IntentEvent.Type.INSTALLED;
312 break;
313
314 case FAILED:
315 prevParking = states.get(id);
316 updated = states.replace(id, prevParking, FAILED);
317 verify(updated, "Conditional replace %s => %s failed", prevParking, FAILED);
318 evtType = IntentEvent.Type.FAILED;
319 break;
320
321 case WITHDRAWN:
322 prevParking = states.get(id);
323 verify(PRE_WITHDRAWN.contains(prevParking),
324 "Illegal state transition attempted from %s to WITHDRAWN",
325 prevParking);
326 updated = states.replace(id, prevParking, WITHDRAWN);
327 verify(updated, "Conditional replace %s => %s failed", prevParking, WITHDRAWN);
328 evtType = IntentEvent.Type.WITHDRAWN;
329 break;
330
331 default:
332 transitionedToParking = false;
333 prevParking = null;
334 break;
Yuta HIGUCHI89a7f472014-11-21 14:50:24 -0800335 }
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800336 if (transitionedToParking) {
337 log.debug("Parking State change: {} {}=>{}", id, prevParking, state);
338 // remove instance local state
339 transientStates.remove(id);
340 } else {
341 // Update instance local state, which includes non-parking state transition
342 final IntentState prevTransient = transientStates.put(id, state);
343 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
344 }
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800345
alshabiba9819bf2014-11-30 18:15:52 -0800346 if (evtType != null) {
347 notifyDelegate(new IntentEvent(evtType, intent));
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800348 }
alshabiba9819bf2014-11-30 18:15:52 -0800349 return;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800350 } finally {
351 stopTimer(timer);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700352 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700353 }
354
355 @Override
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700356 public void setInstallableIntents(IntentId intentId, List<Intent> result) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800357 Context timer = startTimer(setInstallableIntentsTimer);
358 try {
359 installable.put(intentId, result);
360 } finally {
361 stopTimer(timer);
362 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700363 }
364
365 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700366 public List<Intent> getInstallableIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800367 Context timer = startTimer(getInstallableIntentsTimer);
368 try {
369 return installable.get(intentId);
370 } finally {
371 stopTimer(timer);
372 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700373 }
374
375 @Override
376 public void removeInstalledIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800377 Context timer = startTimer(removeInstalledIntentsTimer);
378 try {
379 installable.remove(intentId);
380 } finally {
381 stopTimer(timer);
382 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700383 }
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800384
385 protected String strIntentId(IntentId key) {
386 return keyCache.getUnchecked(key);
387 }
388
389 /**
390 * Distributed Map from IntentId to some value.
391 *
392 * @param <V> Map value type
393 */
394 final class IntentIdMap<V> extends CMap<IntentId, V> {
395
396 /**
397 * Creates a IntentIdMap instance.
398 *
399 * @param dbAdminService DatabaseAdminService to use for this instance
400 * @param dbService DatabaseService to use for this instance
401 * @param tableName table which this Map corresponds to
402 * @param serializer Value serializer
403 */
404 public IntentIdMap(DatabaseAdminService dbAdminService,
405 DatabaseService dbService,
406 String tableName,
407 StoreSerializer serializer) {
408 super(dbAdminService, dbService, tableName, serializer);
409 }
410
411 @Override
412 protected String sK(IntentId key) {
413 return strIntentId(key);
414 }
415 }
416
417 @Override
418 public List<Operation> batchWrite(BatchWrite batch) {
419
420 List<Operation> failed = new ArrayList<>();
421 final Builder builder = BatchWriteRequest.newBuilder();
alshabiba9819bf2014-11-30 18:15:52 -0800422 List<IntentEvent> events = Lists.newArrayList();
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800423
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800424 final Set<IntentId> transitionedToParking = new HashSet<>();
425
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800426 for (Operation op : batch.operations()) {
427 switch (op.type()) {
428 case CREATE_INTENT:
429 checkArgument(op.args().size() == 1,
430 "CREATE_INTENT takes 1 argument. %s", op);
431 Intent intent = op.arg(0);
432 builder.putIfAbsent(INTENTS_TABLE, strIntentId(intent.id()), serializer.encode(intent));
Brian O'Connor7a71d5d2014-12-02 00:12:27 -0800433 builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(INSTALL_REQ));
434 events.add(IntentEvent.getEvent(INSTALL_REQ, intent));
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800435 break;
436
437 case REMOVE_INTENT:
438 checkArgument(op.args().size() == 1,
439 "REMOVE_INTENT takes 1 argument. %s", op);
440 IntentId intentId = (IntentId) op.arg(0);
441 builder.remove(INTENTS_TABLE, strIntentId(intentId));
442 builder.remove(STATES_TABLE, strIntentId(intentId));
443 builder.remove(INSTALLABLE_TABLE, strIntentId(intentId));
444 break;
445
446 case SET_STATE:
447 checkArgument(op.args().size() == 2,
448 "SET_STATE takes 2 arguments. %s", op);
449 intent = op.arg(0);
450 IntentState newState = op.arg(1);
451 builder.put(STATES_TABLE, strIntentId(intent.id()), serializer.encode(newState));
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800452 if (PARKING.contains(newState)) {
453 transitionedToParking.add(intent.id());
Yuta HIGUCHI5cd352d2014-12-01 20:16:02 -0800454 events.add(IntentEvent.getEvent(newState, intent));
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800455 } else {
456 transitionedToParking.remove(intent.id());
457 }
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800458 break;
459
460 case SET_INSTALLABLE:
461 checkArgument(op.args().size() == 2,
462 "SET_INSTALLABLE takes 2 arguments. %s", op);
463 intentId = op.arg(0);
464 List<Intent> installableIntents = op.arg(1);
465 builder.put(INSTALLABLE_TABLE, strIntentId(intentId), serializer.encode(installableIntents));
466 break;
467
468 case REMOVE_INSTALLED:
469 checkArgument(op.args().size() == 1,
470 "REMOVE_INSTALLED takes 1 argument. %s", op);
471 intentId = op.arg(0);
472 builder.remove(INSTALLABLE_TABLE, strIntentId(intentId));
473 break;
474
475 default:
476 log.warn("Unknown Operation encountered: {}", op);
477 failed.add(op);
478 break;
479 }
480 }
481
482 BatchWriteResult batchWriteResult = dbService.batchWrite(builder.build());
483 if (batchWriteResult.isSuccessful()) {
484 // no-failure (except for invalid input)
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800485 transitionedToParking.forEach((intentId) -> transientStates.remove(intentId));
alshabiba9819bf2014-11-30 18:15:52 -0800486 notifyDelegate(events);
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800487 return failed;
488 } else {
489 // everything failed
490 return batch.operations();
491 }
492 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700493}