blob: 45b4b69c762a58d09e7d92c4c2227feed6877317 [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;
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
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070031import org.apache.felix.scr.annotations.Service;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080032import org.onlab.metrics.MetricsService;
33import org.onlab.onos.core.MetricsHelper;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070034import org.onlab.onos.net.intent.Intent;
35import org.onlab.onos.net.intent.IntentEvent;
36import org.onlab.onos.net.intent.IntentId;
37import org.onlab.onos.net.intent.IntentState;
38import org.onlab.onos.net.intent.IntentStore;
39import org.onlab.onos.net.intent.IntentStoreDelegate;
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080040import org.onlab.onos.net.intent.IntentStore.BatchWrite.Operation;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080041import org.onlab.onos.store.AbstractStore;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070042import org.onlab.onos.store.serializers.KryoNamespaces;
43import org.onlab.onos.store.serializers.KryoSerializer;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080044import org.onlab.onos.store.serializers.StoreSerializer;
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080045import org.onlab.onos.store.service.BatchWriteRequest;
46import org.onlab.onos.store.service.BatchWriteRequest.Builder;
47import org.onlab.onos.store.service.BatchWriteResult;
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080048import org.onlab.onos.store.service.DatabaseAdminService;
49import org.onlab.onos.store.service.DatabaseService;
50import org.onlab.onos.store.service.impl.CMap;
Yuta HIGUCHI2befc662014-10-30 15:57:49 -070051import org.onlab.util.KryoNamespace;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070052import org.slf4j.Logger;
53
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080054import java.util.ArrayList;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080055import java.util.EnumSet;
Yuta HIGUCHIf5682452014-12-01 10:17:15 -080056import java.util.HashSet;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070057import java.util.List;
58import java.util.Map;
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080059import java.util.Set;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070060import java.util.concurrent.ConcurrentHashMap;
61
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080062import static com.google.common.base.Preconditions.checkArgument;
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -080063import static com.google.common.base.Preconditions.checkState;
Thomas Vachuskab97cf282014-10-20 23:31:12 -070064import static org.onlab.onos.net.intent.IntentState.*;
65import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080066import static org.onlab.metrics.MetricsUtil.*;
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070067
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -080068@Component(immediate = true, enabled = true)
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070069@Service
70public class DistributedIntentStore
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080071 extends AbstractStore<IntentEvent, IntentStoreDelegate>
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -080072 implements IntentStore, MetricsHelper {
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070073
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080074 /** Valid parking state, which can transition to INSTALLED. */
Yuta HIGUCHI89a7f472014-11-21 14:50:24 -080075 private static final Set<IntentState> PRE_INSTALLED = EnumSet.of(SUBMITTED, INSTALLED, FAILED);
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -080076
77 /** Valid parking state, which can transition to WITHDRAWN. */
78 private static final Set<IntentState> PRE_WITHDRAWN = EnumSet.of(INSTALLED, FAILED);
79
Yuta HIGUCHIf5682452014-12-01 10:17:15 -080080 private static final Set<IntentState> PARKING = EnumSet.of(SUBMITTED, INSTALLED, WITHDRAWN, FAILED);
81
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070082 private final Logger log = getLogger(getClass());
Yuta HIGUCHI406a5652014-10-20 22:18:16 -070083
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070084 // Assumption: IntentId will not have synonyms
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080085 private static final String INTENTS_TABLE = "intents";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080086 private CMap<IntentId, Intent> intents;
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080087
88 private static final String STATES_TABLE = "intent-states";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080089 private CMap<IntentId, IntentState> states;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070090
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080091 // TODO left behind transient state issue: ONOS-103
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070092 // Map to store instance local intermediate state transition
93 private transient Map<IntentId, IntentState> transientStates = new ConcurrentHashMap<>();
94
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080095 private static final String INSTALLABLE_TABLE = "installable-intents";
Yuta HIGUCHI4490a732014-11-18 20:20:30 -080096 private CMap<IntentId, List<Intent>> installable;
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -070097
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -080098 private LoadingCache<IntentId, String> keyCache;
99
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800100 private StoreSerializer serializer;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected DatabaseAdminService dbAdminService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected DatabaseService dbService;
107
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected MetricsService metricsService;
110
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -0800111 // TODO make this configurable
112 private boolean onlyLogTransitionError = true;
113
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800114 private Timer createIntentTimer;
115 private Timer removeIntentTimer;
116 private Timer setInstallableIntentsTimer;
117 private Timer getInstallableIntentsTimer;
118 private Timer removeInstalledIntentsTimer;
119 private Timer setStateTimer;
120 private Timer getIntentCountTimer;
121 private Timer getIntentsTimer;
122 private Timer getIntentTimer;
123 private Timer getIntentStateTimer;
124
125
126 private Timer createResponseTimer(String methodName) {
127 return createTimer("IntentStore", methodName, "responseTime");
128 }
129
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700130 @Activate
131 public void activate() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800132 createIntentTimer = createResponseTimer("createIntent");
133 removeIntentTimer = createResponseTimer("removeIntent");
134 setInstallableIntentsTimer = createResponseTimer("setInstallableIntents");
135 getInstallableIntentsTimer = createResponseTimer("getInstallableIntents");
136 removeInstalledIntentsTimer = createResponseTimer("removeInstalledIntents");
137 setStateTimer = createResponseTimer("setState");
138 getIntentCountTimer = createResponseTimer("getIntentCount");
139 getIntentsTimer = createResponseTimer("getIntents");
140 getIntentTimer = createResponseTimer("getIntent");
141 getIntentStateTimer = createResponseTimer("getIntentState");
142
Yuta HIGUCHI71fa4932014-10-28 22:27:49 -0700143 // FIXME: We need a way to add serializer for intents which has been plugged-in.
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700144 // As a short term workaround, relax Kryo config to
145 // registrationRequired=false
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800146 serializer = new KryoSerializer() {
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700147
148 @Override
149 protected void setupKryoPool() {
150 serializerPool = KryoNamespace.newBuilder()
151 .setRegistrationRequired(false)
152 .register(KryoNamespaces.API)
Yuta HIGUCHI91768e32014-11-22 05:06:35 -0800153 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
154 .build();
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700155 }
Yuta HIGUCHI2befc662014-10-30 15:57:49 -0700156 };
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700157
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800158 keyCache = CacheBuilder.newBuilder()
159 .softValues()
160 .build(new CacheLoader<IntentId, String>() {
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700161
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800162 @Override
163 public String load(IntentId key) {
164 return key.toString();
165 }
166 });
167
168 intents = new IntentIdMap<>(dbAdminService, dbService, INTENTS_TABLE, serializer);
169
170 states = new IntentIdMap<>(dbAdminService, dbService, STATES_TABLE, serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700171
172 transientStates.clear();
173
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800174 installable = new IntentIdMap<>(dbAdminService, dbService, INSTALLABLE_TABLE, serializer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700175
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700176 log.info("Started");
177 }
178
179 @Deactivate
180 public void deactivate() {
181 log.info("Stopped");
182 }
183
184 @Override
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800185 public MetricsService metricsService() {
186 return metricsService;
187 }
188
189 @Override
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700190 public IntentEvent createIntent(Intent intent) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800191 Context timer = startTimer(createIntentTimer);
192 try {
193 boolean absent = intents.putIfAbsent(intent.id(), intent);
194 if (!absent) {
195 // duplicate, ignore
196 return null;
197 } else {
198 return this.setState(intent, IntentState.SUBMITTED);
199 }
200 } finally {
201 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700202 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700203 }
204
205 @Override
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800206 public void removeIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800207 Context timer = startTimer(removeIntentTimer);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800208 checkState(getIntentState(intentId) == WITHDRAWN,
209 "Intent state for {} is not WITHDRAWN.", intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800210 try {
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800211 intents.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800212 states.remove(intentId);
213 transientStates.remove(intentId);
Thomas Vachuskae4b6bb22014-11-25 17:09:43 -0800214 installable.remove(intentId);
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800215 } finally {
216 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700217 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700218 }
219
220 @Override
221 public long getIntentCount() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800222 Context timer = startTimer(getIntentCountTimer);
223 try {
224 return intents.size();
225 } finally {
226 stopTimer(timer);
227 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700228 }
229
230 @Override
231 public Iterable<Intent> getIntents() {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800232 Context timer = startTimer(getIntentsTimer);
233 try {
234 return ImmutableSet.copyOf(intents.values());
235 } finally {
236 stopTimer(timer);
237 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700238 }
239
240 @Override
241 public Intent getIntent(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800242 Context timer = startTimer(getIntentTimer);
243 try {
244 return intents.get(intentId);
245 } finally {
246 stopTimer(timer);
247 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700248 }
249
250 @Override
251 public IntentState getIntentState(IntentId id) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800252 Context timer = startTimer(getIntentStateTimer);
253 try {
254 final IntentState localState = transientStates.get(id);
255 if (localState != null) {
256 return localState;
257 }
258 return states.get(id);
259 } finally {
260 stopTimer(timer);
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700261 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700262 }
263
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800264 // FIXME temporary workaround until we fix our state machine
Yuta HIGUCHIc8f30262014-11-20 19:14:42 -0800265 private void verify(boolean expression, String errorMessageTemplate, Object... errorMessageArgs) {
266 if (onlyLogTransitionError) {
267 if (!expression) {
268 log.error(errorMessageTemplate.replace("%s", "{}"), errorMessageArgs);
269 }
270 } else {
271 Verify.verify(expression, errorMessageTemplate, errorMessageArgs);
272 }
273 }
Yuta HIGUCHI9a2e18a2014-11-18 16:41:58 -0800274
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700275 @Override
276 public IntentEvent setState(Intent intent, IntentState state) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800277 Context timer = startTimer(setStateTimer);
278 try {
279 final IntentId id = intent.id();
280 IntentEvent.Type evtType = null;
281 final IntentState prevParking;
282 boolean transitionedToParking = true;
283 boolean updated;
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700284
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800285 // parking state transition
286 switch (state) {
287 case SUBMITTED:
288 prevParking = states.get(id);
289 if (prevParking == null) {
290 updated = states.putIfAbsent(id, SUBMITTED);
291 verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
292 } else {
293 verify(prevParking == WITHDRAWN,
294 "Illegal state transition attempted from %s to SUBMITTED",
295 prevParking);
296 updated = states.replace(id, prevParking, SUBMITTED);
297 verify(updated, "Conditional replace %s => %s failed", prevParking, SUBMITTED);
298 }
299 evtType = IntentEvent.Type.SUBMITTED;
300 break;
301
302 case INSTALLED:
303 prevParking = states.get(id);
304 verify(PRE_INSTALLED.contains(prevParking),
305 "Illegal state transition attempted from %s to INSTALLED",
306 prevParking);
307 updated = states.replace(id, prevParking, INSTALLED);
308 verify(updated, "Conditional replace %s => %s failed", prevParking, INSTALLED);
309 evtType = IntentEvent.Type.INSTALLED;
310 break;
311
312 case FAILED:
313 prevParking = states.get(id);
314 updated = states.replace(id, prevParking, FAILED);
315 verify(updated, "Conditional replace %s => %s failed", prevParking, FAILED);
316 evtType = IntentEvent.Type.FAILED;
317 break;
318
319 case WITHDRAWN:
320 prevParking = states.get(id);
321 verify(PRE_WITHDRAWN.contains(prevParking),
322 "Illegal state transition attempted from %s to WITHDRAWN",
323 prevParking);
324 updated = states.replace(id, prevParking, WITHDRAWN);
325 verify(updated, "Conditional replace %s => %s failed", prevParking, WITHDRAWN);
326 evtType = IntentEvent.Type.WITHDRAWN;
327 break;
328
329 default:
330 transitionedToParking = false;
331 prevParking = null;
332 break;
Yuta HIGUCHI89a7f472014-11-21 14:50:24 -0800333 }
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800334 if (transitionedToParking) {
335 log.debug("Parking State change: {} {}=>{}", id, prevParking, state);
336 // remove instance local state
337 transientStates.remove(id);
338 } else {
339 // Update instance local state, which includes non-parking state transition
340 final IntentState prevTransient = transientStates.put(id, state);
341 log.debug("Transient State change: {} {}=>{}", id, prevTransient, state);
342 }
Yuta HIGUCHI4490a732014-11-18 20:20:30 -0800343
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800344 if (evtType == null) {
345 return null;
346 }
347 return new IntentEvent(evtType, intent);
348 } finally {
349 stopTimer(timer);
Pavlin Radoslavovc8ccbd92014-10-22 09:59:37 -0700350 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700351 }
352
353 @Override
Yuta HIGUCHI10a31c32014-10-28 14:42:06 -0700354 public void setInstallableIntents(IntentId intentId, List<Intent> result) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800355 Context timer = startTimer(setInstallableIntentsTimer);
356 try {
357 installable.put(intentId, result);
358 } finally {
359 stopTimer(timer);
360 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700361 }
362
363 @Override
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700364 public List<Intent> getInstallableIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800365 Context timer = startTimer(getInstallableIntentsTimer);
366 try {
367 return installable.get(intentId);
368 } finally {
369 stopTimer(timer);
370 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700371 }
372
373 @Override
374 public void removeInstalledIntents(IntentId intentId) {
Yuta HIGUCHIe367fb92014-11-24 22:26:58 -0800375 Context timer = startTimer(removeInstalledIntentsTimer);
376 try {
377 installable.remove(intentId);
378 } finally {
379 stopTimer(timer);
380 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700381 }
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800382
383 protected String strIntentId(IntentId key) {
384 return keyCache.getUnchecked(key);
385 }
386
387 /**
388 * Distributed Map from IntentId to some value.
389 *
390 * @param <V> Map value type
391 */
392 final class IntentIdMap<V> extends CMap<IntentId, V> {
393
394 /**
395 * Creates a IntentIdMap instance.
396 *
397 * @param dbAdminService DatabaseAdminService to use for this instance
398 * @param dbService DatabaseService to use for this instance
399 * @param tableName table which this Map corresponds to
400 * @param serializer Value serializer
401 */
402 public IntentIdMap(DatabaseAdminService dbAdminService,
403 DatabaseService dbService,
404 String tableName,
405 StoreSerializer serializer) {
406 super(dbAdminService, dbService, tableName, serializer);
407 }
408
409 @Override
410 protected String sK(IntentId key) {
411 return strIntentId(key);
412 }
413 }
414
415 @Override
416 public List<Operation> batchWrite(BatchWrite batch) {
417
418 List<Operation> failed = new ArrayList<>();
419 final Builder builder = BatchWriteRequest.newBuilder();
420
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800421 final Set<IntentId> transitionedToParking = new HashSet<>();
422
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800423 for (Operation op : batch.operations()) {
424 switch (op.type()) {
425 case CREATE_INTENT:
426 checkArgument(op.args().size() == 1,
427 "CREATE_INTENT takes 1 argument. %s", op);
428 Intent intent = op.arg(0);
429 builder.putIfAbsent(INTENTS_TABLE, strIntentId(intent.id()), serializer.encode(intent));
430 builder.putIfAbsent(STATES_TABLE, strIntentId(intent.id()), serializer.encode(SUBMITTED));
431 break;
432
433 case REMOVE_INTENT:
434 checkArgument(op.args().size() == 1,
435 "REMOVE_INTENT takes 1 argument. %s", op);
436 IntentId intentId = (IntentId) op.arg(0);
437 builder.remove(INTENTS_TABLE, strIntentId(intentId));
438 builder.remove(STATES_TABLE, strIntentId(intentId));
439 builder.remove(INSTALLABLE_TABLE, strIntentId(intentId));
440 break;
441
442 case SET_STATE:
443 checkArgument(op.args().size() == 2,
444 "SET_STATE takes 2 arguments. %s", op);
445 intent = op.arg(0);
446 IntentState newState = op.arg(1);
447 builder.put(STATES_TABLE, strIntentId(intent.id()), serializer.encode(newState));
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800448 if (PARKING.contains(newState)) {
449 transitionedToParking.add(intent.id());
450 } else {
451 transitionedToParking.remove(intent.id());
452 }
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800453 break;
454
455 case SET_INSTALLABLE:
456 checkArgument(op.args().size() == 2,
457 "SET_INSTALLABLE takes 2 arguments. %s", op);
458 intentId = op.arg(0);
459 List<Intent> installableIntents = op.arg(1);
460 builder.put(INSTALLABLE_TABLE, strIntentId(intentId), serializer.encode(installableIntents));
461 break;
462
463 case REMOVE_INSTALLED:
464 checkArgument(op.args().size() == 1,
465 "REMOVE_INSTALLED takes 1 argument. %s", op);
466 intentId = op.arg(0);
467 builder.remove(INSTALLABLE_TABLE, strIntentId(intentId));
468 break;
469
470 default:
471 log.warn("Unknown Operation encountered: {}", op);
472 failed.add(op);
473 break;
474 }
475 }
476
477 BatchWriteResult batchWriteResult = dbService.batchWrite(builder.build());
478 if (batchWriteResult.isSuccessful()) {
479 // no-failure (except for invalid input)
Yuta HIGUCHIf5682452014-12-01 10:17:15 -0800480 transitionedToParking.forEach((intentId) -> transientStates.remove(intentId));
Yuta HIGUCHIa94c6e82014-11-28 18:49:54 -0800481 return failed;
482 } else {
483 // everything failed
484 return batch.operations();
485 }
486 }
Yuta HIGUCHI406a5652014-10-20 22:18:16 -0700487}