blob: 00141a2dbeb7fdebf7760732d6a28ab6bc6cd39f [file] [log] [blame]
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -08001/*
Ray Milkey9a39eca2015-01-05 09:41:01 -08002 * Copyright 2014-2015 Open Networking Laboratory
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -08003 *
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.resource.impl;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080017
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.Collections;
21import java.util.HashMap;
22import java.util.HashSet;
23import java.util.List;
24import java.util.Map;
25import java.util.Set;
26
27import org.apache.felix.scr.annotations.Activate;
28import org.apache.felix.scr.annotations.Component;
29import org.apache.felix.scr.annotations.Deactivate;
30import org.apache.felix.scr.annotations.Reference;
31import org.apache.felix.scr.annotations.ReferenceCardinality;
32import org.apache.felix.scr.annotations.Service;
Sho SHIMIZU6d01d3d2015-05-08 14:08:36 -070033import org.onlab.util.Bandwidth;
Ray Milkey9a39eca2015-01-05 09:41:01 -080034import org.onlab.util.PositionalParameterStringFormatter;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.AnnotationKeys;
36import org.onosproject.net.Link;
37import org.onosproject.net.LinkKey;
38import org.onosproject.net.intent.IntentId;
39import org.onosproject.net.link.LinkService;
Sho SHIMIZU63feca72015-05-07 10:44:25 -070040import org.onosproject.net.resource.BandwidthResource;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.resource.BandwidthResourceAllocation;
Sho SHIMIZU94b7ff42015-05-06 17:51:49 -070042import org.onosproject.net.resource.LambdaResource;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.resource.LambdaResourceAllocation;
44import org.onosproject.net.resource.LinkResourceAllocations;
45import org.onosproject.net.resource.LinkResourceEvent;
46import org.onosproject.net.resource.LinkResourceStore;
Michele Santuari4b6019e2014-12-19 11:31:45 +010047import org.onosproject.net.resource.MplsLabel;
48import org.onosproject.net.resource.MplsLabelResourceAllocation;
Brian O'Connorabafb502014-12-02 22:26:20 -080049import org.onosproject.net.resource.ResourceAllocation;
Ray Milkey9a39eca2015-01-05 09:41:01 -080050import org.onosproject.net.resource.ResourceAllocationException;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.resource.ResourceType;
52import org.onosproject.store.StoreDelegate;
53import org.onosproject.store.hz.AbstractHazelcastStore;
54import org.onosproject.store.hz.STxMap;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080055import org.slf4j.Logger;
56
57import com.google.common.collect.ImmutableList;
58import com.google.common.collect.ImmutableSet;
59import com.google.common.collect.Sets;
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080060import com.hazelcast.config.Config;
61import com.hazelcast.config.MapConfig;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080062import com.hazelcast.core.TransactionalMap;
63import com.hazelcast.transaction.TransactionContext;
64import com.hazelcast.transaction.TransactionException;
65import com.hazelcast.transaction.TransactionOptions;
66import com.hazelcast.transaction.TransactionOptions.TransactionType;
67
68import static com.google.common.base.Preconditions.checkNotNull;
69import static com.google.common.base.Preconditions.checkState;
70import static org.slf4j.LoggerFactory.getLogger;
71
72/**
73 * Manages link resources using Hazelcast.
74 */
Ayaka Koshibe474ef5f2015-05-01 15:24:51 -070075@Component(immediate = true, enabled = false)
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080076@Service
77public class HazelcastLinkResourceStore
78 extends AbstractHazelcastStore<LinkResourceEvent, StoreDelegate<LinkResourceEvent>>
79 implements LinkResourceStore {
80
81
82 private final Logger log = getLogger(getClass());
83
Sho SHIMIZU6d01d3d2015-05-08 14:08:36 -070084 private static final BandwidthResource DEFAULT_BANDWIDTH = new BandwidthResource(Bandwidth.mbps(1_000));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080085
Sho SHIMIZU6d01d3d2015-05-08 14:08:36 -070086 private static final BandwidthResource EMPTY_BW = new BandwidthResource(Bandwidth.bps(0));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080087
88 // table to store current allocations
89 /** LinkKey -> List<LinkResourceAllocations>. */
90 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
91
92 /** IntentId -> LinkResourceAllocations. */
93 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
94
95
96 // TODO make this configurable
97 // number of retries to attempt on allocation failure, due to
98 // concurrent update
99 private static int maxAllocateRetries = 5;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected LinkService linkService;
103
104 // Link annotation key name to use as bandwidth
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800105 private String bandwidthAnnotation = AnnotationKeys.BANDWIDTH;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800106 // Link annotation key name to use as max lambda
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800107 private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800108
Michele Santuari4b6019e2014-12-19 11:31:45 +0100109 // Max MPLS labels: 2^20 – 1
110 private int maxMplsLabel = 0xFFFFF;
111
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800112 @Override
113 @Activate
114 public void activate() {
115 super.activate();
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -0800116
117 final Config config = theInstance.getConfig();
118
119 MapConfig linkCfg = config.getMapConfig(LINK_RESOURCE_ALLOCATIONS);
120 linkCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - linkCfg.getBackupCount());
121
122 MapConfig intentCfg = config.getMapConfig(INTENT_ALLOCATIONS);
123 intentCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - intentCfg.getBackupCount());
124
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800125 log.info("Started");
126 }
127
128 @Deactivate
129 public void deactivate() {
130 log.info("Stopped");
131 }
132
133 private STxMap<IntentId, LinkResourceAllocations> getIntentAllocs(TransactionContext tx) {
134 TransactionalMap<byte[], byte[]> raw = tx.getMap(INTENT_ALLOCATIONS);
135 return new STxMap<>(raw, serializer);
136 }
137
138 private STxMap<LinkKey, List<LinkResourceAllocations>> getLinkAllocs(TransactionContext tx) {
139 TransactionalMap<byte[], byte[]> raw = tx.getMap(LINK_RESOURCE_ALLOCATIONS);
140 return new STxMap<>(raw, serializer);
141 }
142
143 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800144 if (type == ResourceType.BANDWIDTH) {
145 return ImmutableSet.of(getBandwidthResourceCapacity(link));
146 }
147 if (type == ResourceType.LAMBDA) {
148 return getLambdaResourceCapacity(link);
149 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100150 if (type == ResourceType.MPLS_LABEL) {
151 return getMplsResourceCapacity();
152 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800153 return null;
154 }
155
156 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800157 Set<LambdaResourceAllocation> allocations = new HashSet<>();
158 try {
159 final int waves = Integer.parseInt(link.annotations().value(wavesAnnotation));
160 for (int i = 1; i <= waves; i++) {
Sho SHIMIZU94b7ff42015-05-06 17:51:49 -0700161 allocations.add(new LambdaResourceAllocation(LambdaResource.valueOf(i)));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800162 }
163 } catch (NumberFormatException e) {
164 log.debug("No {} annotation on link %s", wavesAnnotation, link);
165 }
166 return allocations;
167 }
168
169 private BandwidthResourceAllocation getBandwidthResourceCapacity(Link link) {
170
171 // if Link annotation exist, use them
172 // if all fails, use DEFAULT_BANDWIDTH
173
Sho SHIMIZU63feca72015-05-07 10:44:25 -0700174 BandwidthResource bandwidth = null;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800175 String strBw = link.annotations().value(bandwidthAnnotation);
176 if (strBw != null) {
177 try {
Sho SHIMIZU6d01d3d2015-05-08 14:08:36 -0700178 bandwidth = new BandwidthResource(Bandwidth.mbps(Double.parseDouble(strBw)));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800179 } catch (NumberFormatException e) {
180 // do nothings
181 bandwidth = null;
182 }
183 }
184
185 if (bandwidth == null) {
186 // fall back, use fixed default
187 bandwidth = DEFAULT_BANDWIDTH;
188 }
189 return new BandwidthResourceAllocation(bandwidth);
190 }
191
Michele Santuari4b6019e2014-12-19 11:31:45 +0100192 private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
193 Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
194 //Ignoring reserved labels of 0 through 15
195 for (int i = 16; i <= maxMplsLabel; i++) {
196 allocations.add(new MplsLabelResourceAllocation(MplsLabel
197 .valueOf(i)));
198
199 }
200 return allocations;
201 }
202
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800203 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
204 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
205 for (ResourceType type : ResourceType.values()) {
206 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
207 if (cap != null) {
208 caps.put(type, cap);
209 }
210 }
211 return caps;
212 }
213
214 @Override
215 public Set<ResourceAllocation> getFreeResources(Link link) {
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800216 TransactionOptions opt = new TransactionOptions();
217 // read-only and will never be commited, thus does not need durability
218 opt.setTransactionType(TransactionType.LOCAL);
219 TransactionContext tx = theInstance.newTransactionContext(opt);
220 tx.beginTransaction();
221 try {
222 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link);
223 Set<ResourceAllocation> allFree = new HashSet<>();
224 for (Set<? extends ResourceAllocation> r : freeResources.values()) {
225 allFree.addAll(r);
226 }
227 return allFree;
228 } finally {
229 tx.rollbackTransaction();
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800230 }
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800231
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800232 }
233
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800234 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800235 // returns capacity - allocated
236
237 checkNotNull(link);
238 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
239 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800240 final Iterable<LinkResourceAllocations> allocations = getAllocations(tx, link);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800241
242 for (ResourceType type : ResourceType.values()) {
243 // there should be class/category of resources
244 switch (type) {
245 case BANDWIDTH:
246 {
247 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
248 if (bw == null || bw.isEmpty()) {
249 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
250 }
251
252 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
253 double freeBw = cap.bandwidth().toDouble();
254
255 // enumerate current allocations, subtracting resources
256 for (LinkResourceAllocations alloc : allocations) {
257 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
258 for (ResourceAllocation a : types) {
259 if (a instanceof BandwidthResourceAllocation) {
260 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
261 freeBw -= bwA.bandwidth().toDouble();
262 }
263 }
264 }
265
Sho SHIMIZU6d01d3d2015-05-08 14:08:36 -0700266 free.put(type, Sets.newHashSet(
267 new BandwidthResourceAllocation(new BandwidthResource(Bandwidth.bps(freeBw)))));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800268 break;
269 }
270
271 case LAMBDA:
272 {
273 Set<? extends ResourceAllocation> lmd = caps.get(type);
274 if (lmd == null || lmd.isEmpty()) {
275 // nothing left
276 break;
277 }
278 Set<LambdaResourceAllocation> freeL = new HashSet<>();
279 for (ResourceAllocation r : lmd) {
280 if (r instanceof LambdaResourceAllocation) {
281 freeL.add((LambdaResourceAllocation) r);
282 }
283 }
284
285 // enumerate current allocations, removing resources
286 for (LinkResourceAllocations alloc : allocations) {
287 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
288 for (ResourceAllocation a : types) {
289 if (a instanceof LambdaResourceAllocation) {
290 freeL.remove(a);
291 }
292 }
293 }
294
295 free.put(type, freeL);
296 break;
297 }
298
Michele Santuari4b6019e2014-12-19 11:31:45 +0100299 case MPLS_LABEL:
300 Set<? extends ResourceAllocation> mpls = caps.get(type);
301 if (mpls == null || mpls.isEmpty()) {
302 // nothing left
303 break;
304 }
305 Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
306 for (ResourceAllocation r : mpls) {
307 if (r instanceof MplsLabelResourceAllocation) {
308 freeLabel.add((MplsLabelResourceAllocation) r);
309 }
310 }
311
312 // enumerate current allocations, removing resources
313 for (LinkResourceAllocations alloc : allocations) {
314 Set<ResourceAllocation> types = alloc
315 .getResourceAllocation(link);
316 for (ResourceAllocation a : types) {
317 if (a instanceof MplsLabelResourceAllocation) {
318 freeLabel.remove(a);
319 }
320 }
321 }
322
323 free.put(type, freeLabel);
324 break;
325
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800326 default:
327 break;
328 }
329 }
330 return free;
331 }
332
333 @Override
334 public void allocateResources(LinkResourceAllocations allocations) {
335 checkNotNull(allocations);
336
337 for (int i = 0; i < maxAllocateRetries; ++i) {
338 TransactionContext tx = theInstance.newTransactionContext();
339 tx.beginTransaction();
340 try {
341
342 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
343 // should this be conditional write?
Ayaka Koshibee114f042015-05-01 11:43:00 -0700344 intentAllocs.put(allocations.intentId(), allocations);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800345
346 for (Link link : allocations.links()) {
347 allocateLinkResource(tx, link, allocations);
348 }
349
350 tx.commitTransaction();
351 return;
352 } catch (TransactionException e) {
353 log.debug("Failed to commit allocations for {}. [retry={}]",
Ayaka Koshibee114f042015-05-01 11:43:00 -0700354 allocations.intentId(), i);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800355 log.trace(" details {} ", allocations, e);
356 continue;
357 } catch (Exception e) {
358 log.error("Exception thrown, rolling back", e);
359 tx.rollbackTransaction();
360 throw e;
361 }
362 }
363 }
364
365 private void allocateLinkResource(TransactionContext tx, Link link,
366 LinkResourceAllocations allocations) {
367
368 // requested resources
369 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
370
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800371 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(tx, link);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800372 for (ResourceAllocation req : reqs) {
373 Set<? extends ResourceAllocation> avail = available.get(req.type());
374 if (req instanceof BandwidthResourceAllocation) {
375 // check if allocation should be accepted
376 if (avail.isEmpty()) {
377 checkState(!avail.isEmpty(),
378 "There's no Bandwidth resource on %s?",
379 link);
380 }
381 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
382 double bwLeft = bw.bandwidth().toDouble();
Ray Milkey9a39eca2015-01-05 09:41:01 -0800383 BandwidthResourceAllocation bwReq = ((BandwidthResourceAllocation) req);
384 bwLeft -= bwReq.bandwidth().toDouble();
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800385 if (bwLeft < 0) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800386 throw new ResourceAllocationException(
387 PositionalParameterStringFormatter.format(
388 "Unable to allocate bandwidth for link {} "
389 + " requested amount is {} current allocation is {}",
390 link,
391 bwReq.bandwidth().toDouble(),
392 bw));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800393 }
394 } else if (req instanceof LambdaResourceAllocation) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800395 LambdaResourceAllocation lambdaAllocation = (LambdaResourceAllocation) req;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800396 // check if allocation should be accepted
397 if (!avail.contains(req)) {
398 // requested lambda was not available
Ray Milkey9a39eca2015-01-05 09:41:01 -0800399 throw new ResourceAllocationException(
400 PositionalParameterStringFormatter.format(
Sho SHIMIZU2b2e6812015-01-21 10:50:36 -0800401 "Unable to allocate lambda for link {} lambda is {}",
Ray Milkey9a39eca2015-01-05 09:41:01 -0800402 link,
403 lambdaAllocation.lambda().toInt()));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800404 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100405 } else if (req instanceof MplsLabelResourceAllocation) {
406 MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
407 if (!avail.contains(req)) {
408 throw new ResourceAllocationException(
409 PositionalParameterStringFormatter
410 .format("Unable to allocate MPLS label for link "
411 + "{} MPLS label is {}",
412 link,
413 mplsAllocation
414 .mplsLabel()
415 .toString()));
416 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800417 }
418 }
419 // all requests allocatable => add allocation
420 final LinkKey linkKey = LinkKey.linkKey(link);
421 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800422 List<LinkResourceAllocations> before = linkAllocs.get(linkKey);
423 if (before == null) {
424 List<LinkResourceAllocations> after = new ArrayList<>();
425 after.add(allocations);
426 before = linkAllocs.putIfAbsent(linkKey, after);
427 if (before != null) {
428 // concurrent allocation detected, retry transaction
429 throw new TransactionException("Concurrent Allocation, retry");
430 }
Yuta HIGUCHI427a2142014-12-03 11:03:18 -0800431 } else {
432 List<LinkResourceAllocations> after = new ArrayList<>(before.size() + 1);
433 after.addAll(before);
434 after.add(allocations);
435 linkAllocs.replace(linkKey, before, after);
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800436 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800437 }
438
439 @Override
440 public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
441 checkNotNull(allocations);
442
Ayaka Koshibee114f042015-05-01 11:43:00 -0700443 final IntentId intendId = allocations.intentId();
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800444 final Collection<Link> links = allocations.links();
445
446 boolean success = false;
447 do {
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800448 // Note: might want to break it down into smaller tx unit
449 // to lower the chance of collisions.
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800450 TransactionContext tx = theInstance.newTransactionContext();
451 tx.beginTransaction();
452 try {
453 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
454 intentAllocs.remove(intendId);
455
456 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
457
458 for (Link link : links) {
459 final LinkKey linkId = LinkKey.linkKey(link);
460
461 List<LinkResourceAllocations> before = linkAllocs.get(linkId);
462 if (before == null || before.isEmpty()) {
463 // something is wrong, but it is already freed
464 log.warn("There was no resource left to release on {}", linkId);
465 continue;
466 }
467 List<LinkResourceAllocations> after = new ArrayList<>(before);
468 after.remove(allocations);
469 linkAllocs.replace(linkId, before, after);
470 }
471
472 tx.commitTransaction();
473 success = true;
474 } catch (TransactionException e) {
475 log.debug("Transaction failed, retrying");
476 } catch (Exception e) {
477 log.error("Exception thrown during releaseResource {}",
478 allocations, e);
479 tx.rollbackTransaction();
480 throw e;
481 }
482 } while (!success);
483
484 // Issue events to force recompilation of intents.
485 final List<LinkResourceAllocations> releasedResources =
486 ImmutableList.of(allocations);
487 return new LinkResourceEvent(
488 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
489 releasedResources);
490 }
491
492 @Override
493 public LinkResourceAllocations getAllocations(IntentId intentId) {
494 checkNotNull(intentId);
495 TransactionOptions opt = new TransactionOptions();
496 // read-only and will never be commited, thus does not need durability
497 opt.setTransactionType(TransactionType.LOCAL);
498 TransactionContext tx = theInstance.newTransactionContext(opt);
499 tx.beginTransaction();
500 try {
501 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
502 return intentAllocs.get(intentId);
503 } finally {
504 tx.rollbackTransaction();
505 }
506 }
507
508 @Override
509 public List<LinkResourceAllocations> getAllocations(Link link) {
510 checkNotNull(link);
511 final LinkKey key = LinkKey.linkKey(link);
512
513 TransactionOptions opt = new TransactionOptions();
514 // read-only and will never be commited, thus does not need durability
515 opt.setTransactionType(TransactionType.LOCAL);
516 TransactionContext tx = theInstance.newTransactionContext(opt);
517 tx.beginTransaction();
518 List<LinkResourceAllocations> res = null;
519 try {
520 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
521 res = linkAllocs.get(key);
522 } finally {
523 tx.rollbackTransaction();
524 }
525
526 if (res == null) {
527 // try to add empty list
528 TransactionContext tx2 = theInstance.newTransactionContext();
529 tx2.beginTransaction();
530 try {
531 res = getLinkAllocs(tx2).putIfAbsent(key, new ArrayList<>());
532 tx2.commitTransaction();
533 if (res == null) {
534 return Collections.emptyList();
535 } else {
536 return res;
537 }
538 } catch (TransactionException e) {
539 // concurrently added?
540 return getAllocations(link);
541 } catch (Exception e) {
542 tx.rollbackTransaction();
543 }
544 }
545 return res;
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800546 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800547
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800548 private Iterable<LinkResourceAllocations> getAllocations(TransactionContext tx,
549 Link link) {
550 checkNotNull(tx);
551 checkNotNull(link);
552 final LinkKey key = LinkKey.linkKey(link);
553
554 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
555 List<LinkResourceAllocations> res = null;
556 res = linkAllocs.get(key);
557 if (res == null) {
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800558 res = linkAllocs.putIfAbsent(key, new ArrayList<>());
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800559 if (res == null) {
560 return Collections.emptyList();
561 } else {
562 return res;
563 }
564 }
Yuta HIGUCHI81419e22014-12-03 16:54:16 -0800565 return res;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800566 }
567
568 @Override
569 public Iterable<LinkResourceAllocations> getAllocations() {
570 TransactionContext tx = theInstance.newTransactionContext();
571 tx.beginTransaction();
572 try {
573 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
574 return intentAllocs.values();
575 } finally {
576 tx.rollbackTransaction();
577 }
578 }
579}