blob: b41b68a0c4760ed320fbe67a4235bba5f3714b27 [file] [log] [blame]
Jonathan Hartaa380972014-04-03 10:24:46 -07001package net.onrc.onos.core.intent.runtime;
Toshio Koide4f308732014-02-18 15:19:48 -08002
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
Toshio Koide798bc1b2014-02-20 14:02:40 -08006import java.util.HashSet;
Toshio Koidedf2eab92014-02-20 11:24:59 -08007import java.util.Iterator;
Toshio Koidebf875662014-02-24 12:19:15 -08008import java.util.LinkedList;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -07009import java.util.List;
Toshio Koide4f308732014-02-18 15:19:48 -080010import java.util.Map;
Toshio Koide066506e2014-02-20 19:52:09 -080011import java.util.Map.Entry;
TeruUf9111652014-05-14 23:10:35 -070012import java.util.Set;
13import java.util.concurrent.ConcurrentHashMap;
Toshio Koide353a9e12014-06-09 21:03:40 -070014import java.util.concurrent.ConcurrentMap;
Toshio Koide93be5d62014-02-23 19:30:57 -080015import java.util.concurrent.locks.ReentrantLock;
Toshio Koide4f308732014-02-18 15:19:48 -080016
17import net.floodlightcontroller.core.module.FloodlightModuleContext;
18import net.floodlightcontroller.core.module.FloodlightModuleException;
19import net.floodlightcontroller.core.module.IFloodlightModule;
20import net.floodlightcontroller.core.module.IFloodlightService;
Pavlin Radoslavov13669052014-05-13 10:33:39 -070021import net.floodlightcontroller.restserver.IRestApiService;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070022import net.floodlightcontroller.util.MACAddress;
23import net.onrc.onos.api.intent.ApplicationIntent;
Jonathan Hart6df90172014-04-03 10:13:11 -070024import net.onrc.onos.core.datagrid.IDatagridService;
25import net.onrc.onos.core.datagrid.IEventChannel;
26import net.onrc.onos.core.datagrid.IEventChannelListener;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070027import net.onrc.onos.core.intent.ConstrainedShortestPathIntent;
Jonathan Hartaa380972014-04-03 10:24:46 -070028import net.onrc.onos.core.intent.Intent;
Jonathan Harta99ec672014-04-03 11:30:34 -070029import net.onrc.onos.core.intent.Intent.IntentState;
Jonathan Hartaa380972014-04-03 10:24:46 -070030import net.onrc.onos.core.intent.IntentMap;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070031import net.onrc.onos.core.intent.IntentMap.ChangedEvent;
32import net.onrc.onos.core.intent.IntentMap.ChangedListener;
Jonathan Hartaa380972014-04-03 10:24:46 -070033import net.onrc.onos.core.intent.IntentOperation;
Jonathan Harta99ec672014-04-03 11:30:34 -070034import net.onrc.onos.core.intent.IntentOperation.Operator;
Jonathan Hartaa380972014-04-03 10:24:46 -070035import net.onrc.onos.core.intent.IntentOperationList;
36import net.onrc.onos.core.intent.PathIntent;
37import net.onrc.onos.core.intent.PathIntentMap;
38import net.onrc.onos.core.intent.ShortestPathIntent;
Pavlin Radoslavov13669052014-05-13 10:33:39 -070039import net.onrc.onos.core.intent.runtime.web.IntentWebRoutable;
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070040import net.onrc.onos.core.registry.IControllerRegistryService;
Jonathan Hart472062d2014-04-03 10:56:48 -070041import net.onrc.onos.core.topology.DeviceEvent;
Jonathan Harte37e4e22014-05-13 19:12:02 -070042import net.onrc.onos.core.topology.ITopologyListener;
43import net.onrc.onos.core.topology.ITopologyService;
Jonathan Hart472062d2014-04-03 10:56:48 -070044import net.onrc.onos.core.topology.LinkEvent;
45import net.onrc.onos.core.topology.PortEvent;
46import net.onrc.onos.core.topology.SwitchEvent;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -070047import net.onrc.onos.core.util.Dpid;
Toshio Koide4f308732014-02-18 15:19:48 -080048
Jonathan Harta99ec672014-04-03 11:30:34 -070049import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
51
Toshio Koide0c9106d2014-02-19 15:26:38 -080052/**
Toshio Koidefdb75932014-06-16 17:59:24 -070053 * The PathCalcRuntimeModule contains the PathCalcRuntime and PersistIntent.
54 * <p>
55 * It is responsible for converting operations for application level intents
56 * into operations for path level intents and send the converted operations
57 * to PlanCalcRuntimeModule in order to calculate flow entries and install them.
Toshio Koide0c9106d2014-02-19 15:26:38 -080058 */
Jonathan Hartc00f5c22014-06-10 15:14:40 -070059public class PathCalcRuntimeModule implements IFloodlightModule,
60 IPathCalcRuntimeService,
61 ITopologyListener,
62 IEventChannelListener<Long, IntentStateList> {
Toshio Koidefdb75932014-06-16 17:59:24 -070063
64 /**
65 * Logging object for performance measurement.
66 * TODO: merge this into measurement framework
67 */
Pavlin Radoslavovfee80982014-04-10 12:12:04 -070068 static class PerfLog {
Ray Milkey269ffb92014-04-03 14:43:30 -070069 private String step;
70 private long time;
Toshio Koidebf875662014-02-24 12:19:15 -080071
Ray Milkey269ffb92014-04-03 14:43:30 -070072 public PerfLog(String step) {
73 this.step = step;
74 this.time = System.nanoTime();
75 }
Toshio Koidebf875662014-02-24 12:19:15 -080076
Ray Milkey269ffb92014-04-03 14:43:30 -070077 public void logThis() {
Pavlin Radoslavov964f8ae2014-04-18 16:44:14 -070078 log.debug("Time:{}, Step:{}", time, step);
Ray Milkey269ffb92014-04-03 14:43:30 -070079 }
80 }
Toshio Koidebf875662014-02-24 12:19:15 -080081
Toshio Koidefdb75932014-06-16 17:59:24 -070082 /**
83 * Formatted logger for performance measurement.
84 * TODO: merge this into measurement framework
85 */
Pavlin Radoslavov53ad5e32014-04-10 14:24:26 -070086 static class PerfLogger {
Ray Milkey269ffb92014-04-03 14:43:30 -070087 private LinkedList<PerfLog> logData = new LinkedList<>();
Toshio Koidebf875662014-02-24 12:19:15 -080088
Ray Milkey269ffb92014-04-03 14:43:30 -070089 public PerfLogger(String logPhase) {
90 log("start_" + logPhase);
91 }
Toshio Koidebf875662014-02-24 12:19:15 -080092
Ray Milkey269ffb92014-04-03 14:43:30 -070093 public void log(String step) {
94 logData.add(new PerfLog(step));
95 }
Toshio Koide27ffd412014-02-18 19:15:27 -080096
Ray Milkey269ffb92014-04-03 14:43:30 -070097 public void flushLog() {
98 log("finish");
Ray Milkey5df613b2014-04-15 10:50:56 -070099 for (PerfLog perfLog : logData) {
100 perfLog.logThis();
Ray Milkey269ffb92014-04-03 14:43:30 -0700101 }
102 logData.clear();
103 }
104 }
Toshio Koide4f308732014-02-18 15:19:48 -0800105
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700106 /**
107 * A class to track the deletion of intents and purge them as appropriate.
108 */
109 private class DeleteIntentsTracker implements ChangedListener {
110 @Override
111 public void intentsChange(LinkedList<ChangedEvent> events) {
112 List<String> removeIntentIds = new LinkedList<String>();
113 List<String> removePathIds = new LinkedList<String>();
114
115 //
116 // Process the events one-by-one and collect the Intent IDs of
117 // those intents that should be purged.
118 //
119 for (ChangedEvent event : events) {
120 log.debug("DeleteIntentsTracker: Intent ID {}, eventType {}",
121 event.intent.getId() , event.eventType);
122 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(event.intent.getId());
123 if (pathIntent == null) {
124 continue;
125 }
126
127 //
128 // Test whether the new Intent state allows the Intent
129 // to be purged.
130 //
131 boolean shouldPurge = false;
132 switch (event.eventType) {
133 case ADDED:
134 break;
135 case REMOVED:
136 break;
137 case STATE_CHANGED:
138 IntentState state = pathIntent.getState();
139 switch (state) {
140 case INST_REQ:
141 break;
142 case INST_ACK:
143 break;
144 case INST_NACK:
145 shouldPurge = true;
146 break;
147 case DEL_REQ:
148 break;
149 case DEL_ACK:
150 shouldPurge = true;
151 break;
152 case DEL_PENDING:
153 break;
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700154 case REROUTE_REQ:
155 break;
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700156 default:
157 break;
158 }
159 break;
160 default:
161 break;
162 }
163
164 if (shouldPurge) {
165 removePathIds.add(pathIntent.getId());
166 Intent parentIntent = pathIntent.getParentIntent();
167 if (parentIntent != null) {
168 //
169 // Remove the High-level Intent only if it was
170 // explicitly deleted by the user via the API.
171 //
172 String intentId = parentIntent.getId();
173 if (removedApplicationIntentIds.contains(intentId)) {
174 removeIntentIds.add(intentId);
175 removedApplicationIntentIds.remove(intentId);
176 }
177 }
178 }
179 }
180
181 // Purge the intents
182 if (!removeIntentIds.isEmpty()) {
183 highLevelIntents.purge(removeIntentIds);
184 }
185 if (!removePathIds.isEmpty()) {
186 pathIntents.purge(removePathIds);
187 }
188 }
189 }
190
Ray Milkey269ffb92014-04-03 14:43:30 -0700191 private PathCalcRuntime runtime;
192 private IDatagridService datagridService;
Jonathan Harte37e4e22014-05-13 19:12:02 -0700193 private ITopologyService topologyService;
Ray Milkey269ffb92014-04-03 14:43:30 -0700194 private IntentMap highLevelIntents;
195 private PathIntentMap pathIntents;
196 private IControllerRegistryService controllerRegistry;
197 private PersistIntent persistIntent;
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700198 private IRestApiService restApi;
Toshio Koide798bc1b2014-02-20 14:02:40 -0800199
Ray Milkey269ffb92014-04-03 14:43:30 -0700200 private IEventChannel<Long, IntentOperationList> opEventChannel;
TeruU9e530662014-05-18 11:49:37 -0700201 private final ReentrantLock lock = new ReentrantLock(true);
Ray Milkey269ffb92014-04-03 14:43:30 -0700202 private static final String INTENT_OP_EVENT_CHANNEL_NAME = "onos.pathintent";
203 private static final String INTENT_STATE_EVENT_CHANNEL_NAME = "onos.pathintent_state";
204 private static final Logger log = LoggerFactory.getLogger(PathCalcRuntimeModule.class);
Toshio Koidea10c0372014-02-20 17:28:10 -0800205
Toshio Koide353a9e12014-06-09 21:03:40 -0700206 private HashSet<LinkEvent> unmatchedLinkEvents = new HashSet<>();
207 private ConcurrentMap<String, Set<Long>> intentInstalledMap = new ConcurrentHashMap<String, Set<Long>>();
208 private ConcurrentMap<String, Intent> staleIntents = new ConcurrentHashMap<String, Intent>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700209 private DeleteIntentsTracker deleteIntentsTracker = new DeleteIntentsTracker();
210 private Set<String> removedApplicationIntentIds = new HashSet<String>();
Toshio Koide353a9e12014-06-09 21:03:40 -0700211
Ray Milkey269ffb92014-04-03 14:43:30 -0700212 // ================================================================================
213 // private methods
214 // ================================================================================
215
Toshio Koidefdb75932014-06-16 17:59:24 -0700216 /**
217 * Creates operations (IntentOperationList) for Application-level
218 * intents that should be rerouted because of topology change,
219 * and execute the created operations.
220 *
221 * @param oldPaths a list of invalid path intents (which should be rerouted)
222 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700223 private void reroutePaths(Collection<Intent> oldPaths) {
Ray Milkeyb29e6262014-04-09 16:02:14 -0700224 if (oldPaths == null || oldPaths.isEmpty()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700225 return;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700226 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700227
228 IntentOperationList reroutingOperation = new IntentOperationList();
229 for (Intent intent : oldPaths) {
230 PathIntent pathIntent = (PathIntent) intent;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700231 if (pathIntent.isPathFrozen()) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700232 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700233 }
Toshio Koide353a9e12014-06-09 21:03:40 -0700234 Intent parentIntent = pathIntent.getParentIntent();
235 if (parentIntent == null) {
236 continue;
237 }
238 if (pathIntent.getState().equals(IntentState.INST_ACK)) {
239 if (!reroutingOperation.contains(parentIntent)) {
240 // reroute now
241 reroutingOperation.add(Operator.ADD, parentIntent);
242 }
243 } else if (pathIntent.getState().equals(IntentState.INST_REQ)) {
244 // reroute after the completion of the current execution
245 staleIntents.put(parentIntent.getId(), parentIntent);
246 log.debug("pending reroute execution for intent ID:{}", parentIntent.getId());
Ray Milkey269ffb92014-04-03 14:43:30 -0700247 }
248 }
249 executeIntentOperations(reroutingOperation);
250 }
Toshio Koidea94060f2014-02-21 22:58:32 -0800251
Toshio Koidefdb75932014-06-16 17:59:24 -0700252 /**
253 * Checks whether the entire path's flow entries are installed or not.
254 *
255 * @param pathIntent : The pathIntent to be checked
256 * @param installedDpids : The dpids installed on one ONOS instance
257 * @return The result of whether a pathIntent has been installed or not.
258 */
259 private boolean isFlowInstalled(PathIntent pathIntent, Set<Long> installedDpids) {
260 String pathIntentId = pathIntent.getId();
261
262 if (intentInstalledMap.containsKey(pathIntentId)) {
263 if (!installedDpids.isEmpty()) {
264 intentInstalledMap.get(pathIntentId).addAll(installedDpids);
265 }
266 } else {
267 // This is the creation of an entry.
268 intentInstalledMap.put(pathIntentId, installedDpids);
269 }
270
271 Set<Long> allSwitchesForPath = new HashSet<Long>();
272 ShortestPathIntent spfIntent = (ShortestPathIntent) pathIntent.getParentIntent();
273
274 for (LinkEvent linkEvent : pathIntent.getPath()) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700275 long sw = linkEvent.getSrc().getDpid().value();
Toshio Koidefdb75932014-06-16 17:59:24 -0700276 allSwitchesForPath.add(sw);
277 }
278 allSwitchesForPath.add(spfIntent.getDstSwitchDpid());
279
280 if (log.isDebugEnabled()) {
281 log.debug("checking flow installation. ID:{}, dpids:{}, installed:{}",
282 pathIntentId,
283 allSwitchesForPath,
284 intentInstalledMap.get(pathIntentId));
285 }
286
287 if (allSwitchesForPath.equals(intentInstalledMap.get(pathIntentId))) {
288 intentInstalledMap.remove(pathIntentId);
289 return true;
290 }
291
292 return false;
293 }
294
295 /**
296 * Enumerates switch dpids along the specified path and inside the specified domain.
297 *
298 * @param pathIntent the path for enumeration
299 * @param domainSwitchDpids a set of the domain switch dpids
300 * @return a set of switch dpids along the specified path and inside the specified domain
301 */
302 private Set<Long> calcInstalledDpids(PathIntent pathIntent, Set<Long> domainSwitchDpids) {
303 Set<Long> allSwitchesForPath = new HashSet<Long>();
304 ShortestPathIntent spfIntent = (ShortestPathIntent) pathIntent.getParentIntent();
305
306 for (LinkEvent linkEvent : pathIntent.getPath()) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700307 long sw = linkEvent.getSrc().getDpid().value();
Toshio Koidefdb75932014-06-16 17:59:24 -0700308
309 if (domainSwitchDpids.contains(sw)) {
310 allSwitchesForPath.add(sw);
311 }
312 }
313
314 if (domainSwitchDpids.contains(spfIntent.getDstSwitchDpid())) {
315 allSwitchesForPath.add(spfIntent.getDstSwitchDpid());
316 }
317
318 if (log.isTraceEnabled()) {
319 log.trace("All switches for a path {}, domain switch dpids {}", allSwitchesForPath, domainSwitchDpids);
320 }
321
322 return allSwitchesForPath;
323 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800324
Ray Milkey269ffb92014-04-03 14:43:30 -0700325 // ================================================================================
326 // IFloodlightModule implementations
327 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800328
Toshio Koidefdb75932014-06-16 17:59:24 -0700329 /**
330 * {@inheritDoc}
331 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700332 @Override
333 public Collection<Class<? extends IFloodlightService>> getModuleServices() {
334 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(1);
335 l.add(IPathCalcRuntimeService.class);
336 return l;
337 }
Toshio Koide4f308732014-02-18 15:19:48 -0800338
Toshio Koidefdb75932014-06-16 17:59:24 -0700339 /**
340 * {@inheritDoc}
341 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700342 @Override
343 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
344 Map<Class<? extends IFloodlightService>, IFloodlightService> m = new HashMap<>();
345 m.put(IPathCalcRuntimeService.class, this);
346 return m;
347 }
Toshio Koide4f308732014-02-18 15:19:48 -0800348
Toshio Koidefdb75932014-06-16 17:59:24 -0700349 /**
350 * {@inheritDoc}
351 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700352 @Override
353 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
354 Collection<Class<? extends IFloodlightService>> l = new ArrayList<>(2);
355 l.add(IDatagridService.class);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700356 l.add(IRestApiService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700357 l.add(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700358 return l;
359 }
Toshio Koide4f308732014-02-18 15:19:48 -0800360
Toshio Koidefdb75932014-06-16 17:59:24 -0700361 /**
362 * {@inheritDoc}
363 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700364 @Override
365 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
366 datagridService = context.getServiceImpl(IDatagridService.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700367 topologyService = context.getServiceImpl(ITopologyService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700368 controllerRegistry = context.getServiceImpl(IControllerRegistryService.class);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700369 restApi = context.getServiceImpl(IRestApiService.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700370 }
Toshio Koide4f308732014-02-18 15:19:48 -0800371
Toshio Koidefdb75932014-06-16 17:59:24 -0700372 /**
373 * {@inheritDoc}
374 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700375 @Override
376 public void startUp(FloodlightModuleContext context) {
377 highLevelIntents = new IntentMap();
Jonathan Harte37e4e22014-05-13 19:12:02 -0700378 runtime = new PathCalcRuntime(topologyService.getTopology());
Ray Milkey269ffb92014-04-03 14:43:30 -0700379 pathIntents = new PathIntentMap();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700380 pathIntents.addChangeListener(deleteIntentsTracker);
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700381 opEventChannel = datagridService.createChannel(
382 INTENT_OP_EVENT_CHANNEL_NAME, Long.class, IntentOperationList.class);
Ray Milkey269ffb92014-04-03 14:43:30 -0700383 datagridService.addListener(INTENT_STATE_EVENT_CHANNEL_NAME, this, Long.class, IntentStateList.class);
Jonathan Harte37e4e22014-05-13 19:12:02 -0700384 topologyService.registerTopologyListener(this);
Pavlin Radoslavov0294e052014-04-10 13:36:45 -0700385 persistIntent = new PersistIntent(controllerRegistry);
Pavlin Radoslavov13669052014-05-13 10:33:39 -0700386 restApi.addRestletRoutable(new IntentWebRoutable());
Ray Milkey269ffb92014-04-03 14:43:30 -0700387 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800388
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700389 // ======================================================================
Ray Milkey269ffb92014-04-03 14:43:30 -0700390 // IPathCalcRuntimeService implementations
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700391 // ======================================================================
392
393 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700394 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700395 */
396 @Override
397 public boolean addApplicationIntents(
398 final String appId,
399 Collection<ApplicationIntent> appIntents) {
400 //
401 // Process all intents one-by-one
402 //
403 // TODO: The Intent Type should be enum instead of a string,
404 // and we should use a switch statement below to process the
405 // different type of intents.
406 //
407 IntentOperationList intentOperations = new IntentOperationList();
408 for (ApplicationIntent appIntent : appIntents) {
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700409 String appIntentId = appId + ":" + appIntent.getIntentId();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700410
411 IntentOperation.Operator operator = IntentOperation.Operator.ADD;
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700412 Dpid srcSwitchDpid = new Dpid(appIntent.getSrcSwitchDpid());
413 Dpid dstSwitchDpid = new Dpid(appIntent.getDstSwitchDpid());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700414
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700415 if (appIntent.getIntentType().equals("SHORTEST_PATH")) {
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700416 //
417 // Process Shortest-Path Intent
418 //
419 ShortestPathIntent spi =
420 new ShortestPathIntent(appIntentId,
421 srcSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700422 appIntent.getSrcSwitchPort(),
423 MACAddress.valueOf(appIntent.getMatchSrcMac()).toLong(),
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700424 dstSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700425 appIntent.getDstSwitchPort(),
426 MACAddress.valueOf(appIntent.getMatchDstMac()).toLong());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700427 spi.setPathFrozen(appIntent.isStaticPath());
428 intentOperations.add(operator, spi);
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700429 } else if (appIntent.getIntentType().equals("CONSTRAINED_SHORTEST_PATH")) {
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700430 //
431 // Process Constrained Shortest-Path Intent
432 //
433 ConstrainedShortestPathIntent cspi =
434 new ConstrainedShortestPathIntent(appIntentId,
435 srcSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700436 appIntent.getSrcSwitchPort(),
437 MACAddress.valueOf(appIntent.getMatchSrcMac()).toLong(),
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700438 dstSwitchDpid.value(),
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700439 appIntent.getDstSwitchPort(),
440 MACAddress.valueOf(appIntent.getMatchDstMac()).toLong(),
441 appIntent.getBandwidth());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700442 cspi.setPathFrozen(appIntent.isStaticPath());
443 intentOperations.add(operator, cspi);
444 } else {
445 log.error("Unknown Application Intent Type: {}",
Pavlin Radoslavov954e0822014-06-24 12:59:44 -0700446 appIntent.getIntentType());
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700447 return false;
448 }
449 removedApplicationIntentIds.remove(appIntentId);
450 }
451 // Apply the Intent Operations
452 executeIntentOperations(intentOperations);
453 return true;
454 }
455
456 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700457 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700458 */
459 @Override
460 public boolean removeApplicationIntents(final String appId,
461 Collection<String> intentIds) {
462 IntentMap intentMap = getHighLevelIntents();
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700463 List<String> removeIntentIds = new LinkedList<String>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700464
465 //
466 // Process all intents one-by-one
467 //
468 IntentOperationList operations = new IntentOperationList();
469 for (String intentId : intentIds) {
470 String appIntentId = appId + ":" + intentId;
471 Intent intent = intentMap.getIntent(appIntentId);
472 if (intent != null) {
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700473 if (intent.getState() == IntentState.INST_NACK) {
474 // TODO: A hack to remove intents stuck in INST_NACK state
475 removeIntentIds.add(intent.getId());
476 continue;
477 }
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700478 operations.add(IntentOperation.Operator.REMOVE, intent);
479 removedApplicationIntentIds.add(appIntentId);
480 }
481 }
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700482
483 // Purge intents
484 if (!removeIntentIds.isEmpty()) {
485 lock.lock(); // TODO optimize locking using smaller steps
486 try {
487 highLevelIntents.purge(removeIntentIds);
488 } finally {
489 lock.unlock();
490 }
491 }
492
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700493 executeIntentOperations(operations);
494
495 return true;
496 }
497
498 /**
Toshio Koidefdb75932014-06-16 17:59:24 -0700499 * {@inheritDoc}
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700500 */
501 @Override
502 public boolean removeAllApplicationIntents(final String appId) {
503 IntentMap intentMap = getHighLevelIntents();
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700504 List<String> removeIntentIds = new LinkedList<String>();
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700505
506 //
507 // Remove all intents
508 //
509 IntentOperationList operations = new IntentOperationList();
510 for (Intent intent : intentMap.getAllIntents()) {
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700511 if (intent.getState() == IntentState.INST_NACK) {
512 // TODO: A hack to remove intents stuck in INST_NACK state
513 removeIntentIds.add(intent.getId());
514 continue;
515 }
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700516 operations.add(IntentOperation.Operator.REMOVE, intent);
517 removedApplicationIntentIds.add(intent.getId());
518 }
Pavlin Radoslavovda147842014-06-13 20:08:09 -0700519
520 // Purge intents
521 if (!removeIntentIds.isEmpty()) {
522 lock.lock(); // TODO optimize locking using smaller steps
523 try {
524 highLevelIntents.purge(removeIntentIds);
525 } finally {
526 lock.unlock();
527 }
528 }
529
Pavlin Radoslavove2238bc2014-06-09 18:05:23 -0700530 executeIntentOperations(operations);
531
532 return true;
533 }
Toshio Koide798bc1b2014-02-20 14:02:40 -0800534
Toshio Koidefdb75932014-06-16 17:59:24 -0700535 /**
536 * {@inheritDoc}
537 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700538 @Override
539 public IntentOperationList executeIntentOperations(IntentOperationList list) {
TeruU9e530662014-05-18 11:49:37 -0700540
Ray Milkeyb29e6262014-04-09 16:02:14 -0700541 if (list == null || list.size() == 0) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700542 return null;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700543 }
Toshio Koide275d8142014-02-24 16:41:52 -0800544
Ray Milkey269ffb92014-04-03 14:43:30 -0700545 lock.lock(); // TODO optimize locking using smaller steps
546 try {
TeruU9e530662014-05-18 11:49:37 -0700547 log.trace("lock executeIntentOperations, lock obj is already locked? {}", lock.isLocked());
Ray Milkey269ffb92014-04-03 14:43:30 -0700548 // update the map of high-level intents
TeruU9e530662014-05-18 11:49:37 -0700549
Ray Milkey269ffb92014-04-03 14:43:30 -0700550 highLevelIntents.executeOperations(list);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800551
Ray Milkey269ffb92014-04-03 14:43:30 -0700552 // change states of high-level intents
553 IntentStateList states = new IntentStateList();
554 for (IntentOperation op : list) {
555 switch (op.operator) {
556 case ADD:
557 switch (op.intent.getState()) {
558 case CREATED:
559 states.put(op.intent.getId(), IntentState.INST_REQ);
560 break;
561 case INST_ACK:
562 states.put(op.intent.getId(), IntentState.REROUTE_REQ);
563 break;
564 default:
565 break;
566 }
567 break;
568 case REMOVE:
569 switch (op.intent.getState()) {
570 case CREATED:
571 states.put(op.intent.getId(), IntentState.DEL_REQ);
572 break;
573 default:
574 break;
575 }
576 break;
577 default:
578 break;
579 }
580 }
581 highLevelIntents.changeStates(states);
Toshio Koidedf2eab92014-02-20 11:24:59 -0800582
Ray Milkey269ffb92014-04-03 14:43:30 -0700583 // calculate path-intents (low-level operations)
Ray Milkey269ffb92014-04-03 14:43:30 -0700584 IntentOperationList pathIntentOperations = runtime.calcPathIntents(list, highLevelIntents, pathIntents);
Toshio Koide600ae5f2014-02-20 18:42:00 -0800585
Ray Milkey269ffb92014-04-03 14:43:30 -0700586 // persist calculated low-level operations into data store
Ray Milkey269ffb92014-04-03 14:43:30 -0700587 long key = persistIntent.getKey();
588 persistIntent.persistIfLeader(key, pathIntentOperations);
Toshio Koide93be5d62014-02-23 19:30:57 -0800589
Ray Milkey269ffb92014-04-03 14:43:30 -0700590 // remove error-intents and reflect them to high-level intents
Ray Milkey269ffb92014-04-03 14:43:30 -0700591 states.clear();
592 Iterator<IntentOperation> i = pathIntentOperations.iterator();
593 while (i.hasNext()) {
594 IntentOperation op = i.next();
595 if (op.operator.equals(Operator.ERROR)) {
596 states.put(op.intent.getId(), IntentState.INST_NACK);
597 i.remove();
598 }
599 }
600 highLevelIntents.changeStates(states);
Toshio Koidea94060f2014-02-21 22:58:32 -0800601
Ray Milkey269ffb92014-04-03 14:43:30 -0700602 // update the map of path intents and publish the path operations
Ray Milkey269ffb92014-04-03 14:43:30 -0700603 pathIntents.executeOperations(pathIntentOperations);
Toshio Koide93be5d62014-02-23 19:30:57 -0800604
Ray Milkey269ffb92014-04-03 14:43:30 -0700605 // send notification
Ray Milkey269ffb92014-04-03 14:43:30 -0700606 // XXX: Send notifications using the same key every time
607 // and receive them by entryAdded() and entryUpdated()
608 opEventChannel.addEntry(0L, pathIntentOperations);
Ray Milkey269ffb92014-04-03 14:43:30 -0700609 //opEventChannel.removeEntry(key);
610 return pathIntentOperations;
611 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700612 lock.unlock();
TeruU9e530662014-05-18 11:49:37 -0700613 log.trace("unlock executeIntentOperations");
Ray Milkey269ffb92014-04-03 14:43:30 -0700614 }
615 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800616
Toshio Koidefdb75932014-06-16 17:59:24 -0700617 /**
618 * {@inheritDoc}
619 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700620 @Override
621 public IntentMap getHighLevelIntents() {
622 return highLevelIntents;
623 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800624
Toshio Koidefdb75932014-06-16 17:59:24 -0700625 /**
626 * {@inheritDoc}
627 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700628 @Override
629 public IntentMap getPathIntents() {
630 return pathIntents;
631 }
Toshio Koide27ffd412014-02-18 19:15:27 -0800632
Toshio Koidefdb75932014-06-16 17:59:24 -0700633 /**
634 * {@inheritDoc}
635 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700636 @Override
637 public void purgeIntents() {
638 highLevelIntents.purge();
639 pathIntents.purge();
640 }
Toshio Koide0c9106d2014-02-19 15:26:38 -0800641
Ray Milkey269ffb92014-04-03 14:43:30 -0700642 // ================================================================================
Jonathan Harte37e4e22014-05-13 19:12:02 -0700643 // ITopologyListener implementations
Ray Milkey269ffb92014-04-03 14:43:30 -0700644 // ================================================================================
Toshio Koide798bc1b2014-02-20 14:02:40 -0800645
Ray Milkeya5450cc2014-04-17 14:31:30 -0700646 // CHECKSTYLE:OFF suppress warning about too many parameters
Toshio Koidefdb75932014-06-16 17:59:24 -0700647 /**
648 * {@inheritDoc}
649 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700650 @Override
Jonathan Harte37e4e22014-05-13 19:12:02 -0700651 public void topologyEvents(Collection<SwitchEvent> addedSwitchEvents,
Ray Milkey269ffb92014-04-03 14:43:30 -0700652 Collection<SwitchEvent> removedSwitchEvents,
653 Collection<PortEvent> addedPortEvents,
654 Collection<PortEvent> removedPortEvents,
655 Collection<LinkEvent> addedLinkEvents,
656 Collection<LinkEvent> removedLinkEvents,
657 Collection<DeviceEvent> addedDeviceEvents,
658 Collection<DeviceEvent> removedDeviceEvents) {
Ray Milkeya5450cc2014-04-17 14:31:30 -0700659 // CHECKSTYLE:ON
Toshio Koidea9078af2014-02-21 16:57:04 -0800660
Ray Milkey269ffb92014-04-03 14:43:30 -0700661 PerfLogger p = new PerfLogger("networkGraphEvents");
662 HashSet<Intent> affectedPaths = new HashSet<>();
Toshio Koide93797dc2014-02-27 23:54:26 -0800663
Ray Milkey269ffb92014-04-03 14:43:30 -0700664 boolean rerouteAll = false;
665 for (LinkEvent le : addedLinkEvents) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700666 LinkEvent rev = new LinkEvent(le.getDst().getDpid(),
667 le.getDst().getNumber(), le.getSrc().getDpid(),
668 le.getSrc().getNumber());
Ray Milkey269ffb92014-04-03 14:43:30 -0700669 if (unmatchedLinkEvents.contains(rev)) {
670 rerouteAll = true;
671 unmatchedLinkEvents.remove(rev);
672 log.debug("Found matched LinkEvent: {} {}", rev, le);
673 } else {
674 unmatchedLinkEvents.add(le);
675 log.debug("Adding unmatched LinkEvent: {}", le);
676 }
677 }
678 for (LinkEvent le : removedLinkEvents) {
679 if (unmatchedLinkEvents.contains(le)) {
680 unmatchedLinkEvents.remove(le);
681 log.debug("Removing LinkEvent: {}", le);
682 }
683 }
684 if (unmatchedLinkEvents.size() > 0) {
685 log.debug("Unmatched link events: {} events", unmatchedLinkEvents.size());
686 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800687
Ray Milkey7f1567c2014-04-08 13:53:32 -0700688 if (rerouteAll) { //addedLinkEvents.size() > 0) { // ||
Ray Milkey269ffb92014-04-03 14:43:30 -0700689// addedPortEvents.size() > 0 ||
690// addedSwitchEvents.size() > 0) {
691 p.log("begin_getAllIntents");
692 affectedPaths.addAll(getPathIntents().getAllIntents());
693 p.log("end_getAllIntents");
694 } else if (removedSwitchEvents.size() > 0 ||
695 removedLinkEvents.size() > 0 ||
696 removedPortEvents.size() > 0) {
697 p.log("begin_getIntentsByLink");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700698 for (LinkEvent linkEvent : removedLinkEvents) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700699 affectedPaths.addAll(pathIntents.getIntentsByLink(linkEvent));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700700 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700701 p.log("end_getIntentsByLink");
Toshio Koidea9078af2014-02-21 16:57:04 -0800702
Ray Milkey269ffb92014-04-03 14:43:30 -0700703 p.log("begin_getIntentsByPort");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700704 for (PortEvent portEvent : removedPortEvents) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700705 affectedPaths.addAll(pathIntents.getIntentsByPort(
706 portEvent.getDpid().value(),
707 (long) portEvent.getNumber().value()));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700708 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700709 p.log("end_getIntentsByPort");
Toshio Koidea9078af2014-02-21 16:57:04 -0800710
Ray Milkey269ffb92014-04-03 14:43:30 -0700711 p.log("begin_getIntentsByDpid");
Ray Milkeyb29e6262014-04-09 16:02:14 -0700712 for (SwitchEvent switchEvent : removedSwitchEvents) {
Yuta HIGUCHI8f3dfa32014-06-25 00:14:25 -0700713 affectedPaths.addAll(pathIntents.getIntentsByDpid(switchEvent.getDpid().value()));
Ray Milkeyb29e6262014-04-09 16:02:14 -0700714 }
Ray Milkey269ffb92014-04-03 14:43:30 -0700715 p.log("end_getIntentsByDpid");
716 }
717 p.log("begin_reroutePaths");
718 reroutePaths(affectedPaths);
719 p.log("end_reroutePaths");
720 p.flushLog();
721 }
Toshio Koide066506e2014-02-20 19:52:09 -0800722
Ray Milkey269ffb92014-04-03 14:43:30 -0700723 // ================================================================================
724 // IEventChannelListener implementations
725 // ================================================================================
Toshio Koide066506e2014-02-20 19:52:09 -0800726
Toshio Koidefdb75932014-06-16 17:59:24 -0700727 /**
728 * {@inheritDoc}
729 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700730 @Override
731 public void entryAdded(IntentStateList value) {
732 entryUpdated(value);
733 }
Toshio Koide066506e2014-02-20 19:52:09 -0800734
Toshio Koidefdb75932014-06-16 17:59:24 -0700735 /**
736 * {@inheritDoc}
737 */
Ray Milkey269ffb92014-04-03 14:43:30 -0700738 @Override
739 public void entryRemoved(IntentStateList value) {
740 // do nothing
741 }
Toshio Koide066506e2014-02-20 19:52:09 -0800742
Toshio Koidefdb75932014-06-16 17:59:24 -0700743 /**
744 * {@inheritDoc}
745 */
Ray Milkey149693c2014-05-20 14:58:53 -0700746 @SuppressWarnings("fallthrough")
Ray Milkey269ffb92014-04-03 14:43:30 -0700747 @Override
748 public void entryUpdated(IntentStateList value) {
749 // TODO draw state transition diagram in multiple ONOS instances and update this method
TeruU9e530662014-05-18 11:49:37 -0700750
Toshio Koide353a9e12014-06-09 21:03:40 -0700751 IntentOperationList opList = new IntentOperationList();
Ray Milkey269ffb92014-04-03 14:43:30 -0700752 lock.lock(); // TODO optimize locking using smaller steps
753 try {
TeruU9e530662014-05-18 11:49:37 -0700754 log.trace("lock entryUpdated, lock obj is already locked? {}", lock.isLocked());
Ray Milkey269ffb92014-04-03 14:43:30 -0700755 // reflect state changes of path-level intent into application-level intents
Ray Milkey269ffb92014-04-03 14:43:30 -0700756 IntentStateList highLevelIntentStates = new IntentStateList();
757 IntentStateList pathIntentStates = new IntentStateList();
758 for (Entry<String, IntentState> entry : value.entrySet()) {
Toshio Koide14dba902014-06-05 18:39:21 -0700759 String pathIntentId = entry.getKey();
760 IntentState nextPathIntentState = entry.getValue();
761 PathIntent pathIntent = (PathIntent) pathIntents.getIntent(pathIntentId);
Ray Milkeyb29e6262014-04-09 16:02:14 -0700762 if (pathIntent == null) {
763 continue;
764 }
Toshio Koide8315d7d2014-02-21 22:58:32 -0800765
Ray Milkey269ffb92014-04-03 14:43:30 -0700766 Intent parentIntent = pathIntent.getParentIntent();
767 if (parentIntent == null ||
Toshio Koide14dba902014-06-05 18:39:21 -0700768 !(parentIntent instanceof ShortestPathIntent)) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700769 continue;
Ray Milkeyb29e6262014-04-09 16:02:14 -0700770 }
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700771 String parentIntentId = parentIntent.getId();
Toshio Koide066506e2014-02-20 19:52:09 -0800772
Toshio Koide14dba902014-06-05 18:39:21 -0700773 boolean isChildIntent = ((ShortestPathIntent) parentIntent).getPathIntentId().equals(pathIntentId);
Toshio Koide353a9e12014-06-09 21:03:40 -0700774
775 // Check necessity for retrying the intent execution.
776 // When the PathIntent(=isChildIntent) transitioned to INST_{ACK/NACK}
777 // but was marked as stale (e.g., has been requested to reroute by Topology event),
778 // then immediately enqueue the re-computation of parent intent.
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700779 if (isChildIntent && staleIntents.containsKey(parentIntentId) && (
Toshio Koide353a9e12014-06-09 21:03:40 -0700780 nextPathIntentState.equals(IntentState.INST_ACK) ||
781 nextPathIntentState.equals(IntentState.INST_NACK))) {
782 opList.add(Operator.ADD, parentIntent);
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700783 staleIntents.remove(parentIntentId);
784 log.debug("retrying intent execution for intent ID:{}", parentIntentId);
Toshio Koide353a9e12014-06-09 21:03:40 -0700785 }
786
Toshio Koide14dba902014-06-05 18:39:21 -0700787 switch (nextPathIntentState) {
Ray Milkey269ffb92014-04-03 14:43:30 -0700788 case INST_ACK:
TeruUf9111652014-05-14 23:10:35 -0700789 Set<Long> installedDpids = calcInstalledDpids(pathIntent, value.domainSwitchDpids);
790 if (!isFlowInstalled(pathIntent, installedDpids)) {
791 break;
792 }
793 // FALLTHROUGH
Ray Milkey269ffb92014-04-03 14:43:30 -0700794 case INST_NACK:
TeruUf9111652014-05-14 23:10:35 -0700795 // FALLTHROUGH
Ray Milkey269ffb92014-04-03 14:43:30 -0700796 case DEL_PENDING:
Toshio Koide14dba902014-06-05 18:39:21 -0700797 if (isChildIntent) {
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700798 log.debug("put the state highLevelIntentStates ID {}, state {}",
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700799 parentIntentId, nextPathIntentState);
800 highLevelIntentStates.put(parentIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700801 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700802 log.debug("put the state pathIntentStates ID {}, state {}",
803 pathIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700804 pathIntentStates.put(pathIntentId, nextPathIntentState);
TeruU9e530662014-05-18 11:49:37 -0700805 break;
806 case DEL_ACK:
Toshio Koide14dba902014-06-05 18:39:21 -0700807 if (isChildIntent) {
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700808 if (intentInstalledMap.containsKey(pathIntentId)) {
809 intentInstalledMap.remove(pathIntentId);
Toshio Koide14dba902014-06-05 18:39:21 -0700810 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700811 log.debug("put the state highLevelIntentStates ID {}, state {}",
Toshio Koide4a58f0a2014-06-16 10:34:19 -0700812 parentIntentId, nextPathIntentState);
813 highLevelIntentStates.put(parentIntentId, nextPathIntentState);
TeruU9e530662014-05-18 11:49:37 -0700814 }
Jonathan Hartc00f5c22014-06-10 15:14:40 -0700815 log.debug("put the state pathIntentStates ID {}, state {}",
816 pathIntentId, nextPathIntentState);
Toshio Koide14dba902014-06-05 18:39:21 -0700817 pathIntentStates.put(pathIntentId, nextPathIntentState);
818 break;
819 case CREATED:
820 break;
821 case DEL_REQ:
822 break;
823 case INST_REQ:
824 break;
825 case REROUTE_REQ:
Ray Milkey269ffb92014-04-03 14:43:30 -0700826 break;
827 default:
828 break;
829 }
830 }
831 highLevelIntents.changeStates(highLevelIntentStates);
832 pathIntents.changeStates(pathIntentStates);
Ray Milkey269ffb92014-04-03 14:43:30 -0700833 } finally {
Ray Milkey269ffb92014-04-03 14:43:30 -0700834 lock.unlock();
TeruU9e530662014-05-18 11:49:37 -0700835 log.trace("unlock entryUpdated");
Ray Milkey269ffb92014-04-03 14:43:30 -0700836 }
Toshio Koide353a9e12014-06-09 21:03:40 -0700837 executeIntentOperations(opList);
Ray Milkey269ffb92014-04-03 14:43:30 -0700838 }
Toshio Koidea9078af2014-02-21 16:57:04 -0800839}