blob: 52494ddeb2e24b431dc83233582aac3e847758ee [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;
Ray Milkey9a39eca2015-01-05 09:41:01 -080033import org.onlab.util.PositionalParameterStringFormatter;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.AnnotationKeys;
35import org.onosproject.net.Link;
36import org.onosproject.net.LinkKey;
37import org.onosproject.net.intent.IntentId;
38import org.onosproject.net.link.LinkService;
39import org.onosproject.net.resource.Bandwidth;
40import org.onosproject.net.resource.BandwidthResourceAllocation;
41import org.onosproject.net.resource.Lambda;
42import org.onosproject.net.resource.LambdaResourceAllocation;
43import org.onosproject.net.resource.LinkResourceAllocations;
44import org.onosproject.net.resource.LinkResourceEvent;
45import org.onosproject.net.resource.LinkResourceStore;
Michele Santuari4b6019e2014-12-19 11:31:45 +010046import org.onosproject.net.resource.MplsLabel;
47import org.onosproject.net.resource.MplsLabelResourceAllocation;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.resource.ResourceAllocation;
Ray Milkey9a39eca2015-01-05 09:41:01 -080049import org.onosproject.net.resource.ResourceAllocationException;
Brian O'Connorabafb502014-12-02 22:26:20 -080050import org.onosproject.net.resource.ResourceType;
51import org.onosproject.store.StoreDelegate;
52import org.onosproject.store.hz.AbstractHazelcastStore;
53import org.onosproject.store.hz.STxMap;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080054import org.slf4j.Logger;
55
56import com.google.common.collect.ImmutableList;
57import com.google.common.collect.ImmutableSet;
58import com.google.common.collect.Sets;
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -080059import com.hazelcast.config.Config;
60import com.hazelcast.config.MapConfig;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080061import com.hazelcast.core.TransactionalMap;
62import com.hazelcast.transaction.TransactionContext;
63import com.hazelcast.transaction.TransactionException;
64import com.hazelcast.transaction.TransactionOptions;
65import com.hazelcast.transaction.TransactionOptions.TransactionType;
66
67import static com.google.common.base.Preconditions.checkNotNull;
68import static com.google.common.base.Preconditions.checkState;
69import static org.slf4j.LoggerFactory.getLogger;
70
71/**
72 * Manages link resources using Hazelcast.
73 */
Yuta HIGUCHI9b108b32014-12-01 11:10:26 -080074@Component(immediate = true, enabled = true)
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080075@Service
76public class HazelcastLinkResourceStore
77 extends AbstractHazelcastStore<LinkResourceEvent, StoreDelegate<LinkResourceEvent>>
78 implements LinkResourceStore {
79
80
81 private final Logger log = getLogger(getClass());
82
Sho SHIMIZU0ce220a2015-01-23 15:54:47 -080083 private static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.mbps(1_000);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080084
Sho SHIMIZU0ce220a2015-01-23 15:54:47 -080085 private static final Bandwidth EMPTY_BW = Bandwidth.bps(0);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -080086
87 // table to store current allocations
88 /** LinkKey -> List<LinkResourceAllocations>. */
89 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
90
91 /** IntentId -> LinkResourceAllocations. */
92 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
93
94
95 // TODO make this configurable
96 // number of retries to attempt on allocation failure, due to
97 // concurrent update
98 private static int maxAllocateRetries = 5;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected LinkService linkService;
102
103 // Link annotation key name to use as bandwidth
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800104 private String bandwidthAnnotation = AnnotationKeys.BANDWIDTH;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800105 // Link annotation key name to use as max lambda
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800106 private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800107
Michele Santuari4b6019e2014-12-19 11:31:45 +0100108 // Max MPLS labels: 2^20 – 1
109 private int maxMplsLabel = 0xFFFFF;
110
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800111 @Override
112 @Activate
113 public void activate() {
114 super.activate();
Yuta HIGUCHId36a58e2014-12-02 12:46:33 -0800115
116 final Config config = theInstance.getConfig();
117
118 MapConfig linkCfg = config.getMapConfig(LINK_RESOURCE_ALLOCATIONS);
119 linkCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - linkCfg.getBackupCount());
120
121 MapConfig intentCfg = config.getMapConfig(INTENT_ALLOCATIONS);
122 intentCfg.setAsyncBackupCount(MapConfig.MAX_BACKUP_COUNT - intentCfg.getBackupCount());
123
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800124 log.info("Started");
125 }
126
127 @Deactivate
128 public void deactivate() {
129 log.info("Stopped");
130 }
131
132 private STxMap<IntentId, LinkResourceAllocations> getIntentAllocs(TransactionContext tx) {
133 TransactionalMap<byte[], byte[]> raw = tx.getMap(INTENT_ALLOCATIONS);
134 return new STxMap<>(raw, serializer);
135 }
136
137 private STxMap<LinkKey, List<LinkResourceAllocations>> getLinkAllocs(TransactionContext tx) {
138 TransactionalMap<byte[], byte[]> raw = tx.getMap(LINK_RESOURCE_ALLOCATIONS);
139 return new STxMap<>(raw, serializer);
140 }
141
142 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800143 if (type == ResourceType.BANDWIDTH) {
144 return ImmutableSet.of(getBandwidthResourceCapacity(link));
145 }
146 if (type == ResourceType.LAMBDA) {
147 return getLambdaResourceCapacity(link);
148 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100149 if (type == ResourceType.MPLS_LABEL) {
150 return getMplsResourceCapacity();
151 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800152 return null;
153 }
154
155 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800156 Set<LambdaResourceAllocation> allocations = new HashSet<>();
157 try {
158 final int waves = Integer.parseInt(link.annotations().value(wavesAnnotation));
159 for (int i = 1; i <= waves; i++) {
160 allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
161 }
162 } catch (NumberFormatException e) {
163 log.debug("No {} annotation on link %s", wavesAnnotation, link);
164 }
165 return allocations;
166 }
167
168 private BandwidthResourceAllocation getBandwidthResourceCapacity(Link link) {
169
170 // if Link annotation exist, use them
171 // if all fails, use DEFAULT_BANDWIDTH
172
173 Bandwidth bandwidth = null;
174 String strBw = link.annotations().value(bandwidthAnnotation);
175 if (strBw != null) {
176 try {
Sho SHIMIZU0ce220a2015-01-23 15:54:47 -0800177 bandwidth = Bandwidth.mbps(Double.parseDouble(strBw));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800178 } catch (NumberFormatException e) {
179 // do nothings
180 bandwidth = null;
181 }
182 }
183
184 if (bandwidth == null) {
185 // fall back, use fixed default
186 bandwidth = DEFAULT_BANDWIDTH;
187 }
188 return new BandwidthResourceAllocation(bandwidth);
189 }
190
Michele Santuari4b6019e2014-12-19 11:31:45 +0100191 private Set<MplsLabelResourceAllocation> getMplsResourceCapacity() {
192 Set<MplsLabelResourceAllocation> allocations = new HashSet<>();
193 //Ignoring reserved labels of 0 through 15
194 for (int i = 16; i <= maxMplsLabel; i++) {
195 allocations.add(new MplsLabelResourceAllocation(MplsLabel
196 .valueOf(i)));
197
198 }
199 return allocations;
200 }
201
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800202 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
203 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
204 for (ResourceType type : ResourceType.values()) {
205 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
206 if (cap != null) {
207 caps.put(type, cap);
208 }
209 }
210 return caps;
211 }
212
213 @Override
214 public Set<ResourceAllocation> getFreeResources(Link link) {
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800215 TransactionOptions opt = new TransactionOptions();
216 // read-only and will never be commited, thus does not need durability
217 opt.setTransactionType(TransactionType.LOCAL);
218 TransactionContext tx = theInstance.newTransactionContext(opt);
219 tx.beginTransaction();
220 try {
221 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(tx, link);
222 Set<ResourceAllocation> allFree = new HashSet<>();
223 for (Set<? extends ResourceAllocation> r : freeResources.values()) {
224 allFree.addAll(r);
225 }
226 return allFree;
227 } finally {
228 tx.rollbackTransaction();
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800229 }
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800230
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800231 }
232
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800233 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(TransactionContext tx, Link link) {
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800234 // returns capacity - allocated
235
236 checkNotNull(link);
237 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
238 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800239 final Iterable<LinkResourceAllocations> allocations = getAllocations(tx, link);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800240
241 for (ResourceType type : ResourceType.values()) {
242 // there should be class/category of resources
243 switch (type) {
244 case BANDWIDTH:
245 {
246 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
247 if (bw == null || bw.isEmpty()) {
248 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
249 }
250
251 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
252 double freeBw = cap.bandwidth().toDouble();
253
254 // enumerate current allocations, subtracting resources
255 for (LinkResourceAllocations alloc : allocations) {
256 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
257 for (ResourceAllocation a : types) {
258 if (a instanceof BandwidthResourceAllocation) {
259 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
260 freeBw -= bwA.bandwidth().toDouble();
261 }
262 }
263 }
264
Sho SHIMIZU0ce220a2015-01-23 15:54:47 -0800265 free.put(type, Sets.newHashSet(new BandwidthResourceAllocation(Bandwidth.bps(freeBw))));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800266 break;
267 }
268
269 case LAMBDA:
270 {
271 Set<? extends ResourceAllocation> lmd = caps.get(type);
272 if (lmd == null || lmd.isEmpty()) {
273 // nothing left
274 break;
275 }
276 Set<LambdaResourceAllocation> freeL = new HashSet<>();
277 for (ResourceAllocation r : lmd) {
278 if (r instanceof LambdaResourceAllocation) {
279 freeL.add((LambdaResourceAllocation) r);
280 }
281 }
282
283 // enumerate current allocations, removing resources
284 for (LinkResourceAllocations alloc : allocations) {
285 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
286 for (ResourceAllocation a : types) {
287 if (a instanceof LambdaResourceAllocation) {
288 freeL.remove(a);
289 }
290 }
291 }
292
293 free.put(type, freeL);
294 break;
295 }
296
Michele Santuari4b6019e2014-12-19 11:31:45 +0100297 case MPLS_LABEL:
298 Set<? extends ResourceAllocation> mpls = caps.get(type);
299 if (mpls == null || mpls.isEmpty()) {
300 // nothing left
301 break;
302 }
303 Set<MplsLabelResourceAllocation> freeLabel = new HashSet<>();
304 for (ResourceAllocation r : mpls) {
305 if (r instanceof MplsLabelResourceAllocation) {
306 freeLabel.add((MplsLabelResourceAllocation) r);
307 }
308 }
309
310 // enumerate current allocations, removing resources
311 for (LinkResourceAllocations alloc : allocations) {
312 Set<ResourceAllocation> types = alloc
313 .getResourceAllocation(link);
314 for (ResourceAllocation a : types) {
315 if (a instanceof MplsLabelResourceAllocation) {
316 freeLabel.remove(a);
317 }
318 }
319 }
320
321 free.put(type, freeLabel);
322 break;
323
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800324 default:
325 break;
326 }
327 }
328 return free;
329 }
330
331 @Override
332 public void allocateResources(LinkResourceAllocations allocations) {
333 checkNotNull(allocations);
334
335 for (int i = 0; i < maxAllocateRetries; ++i) {
336 TransactionContext tx = theInstance.newTransactionContext();
337 tx.beginTransaction();
338 try {
339
340 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
341 // should this be conditional write?
342 intentAllocs.put(allocations.intendId(), allocations);
343
344 for (Link link : allocations.links()) {
345 allocateLinkResource(tx, link, allocations);
346 }
347
348 tx.commitTransaction();
349 return;
350 } catch (TransactionException e) {
351 log.debug("Failed to commit allocations for {}. [retry={}]",
352 allocations.intendId(), i);
353 log.trace(" details {} ", allocations, e);
354 continue;
355 } catch (Exception e) {
356 log.error("Exception thrown, rolling back", e);
357 tx.rollbackTransaction();
358 throw e;
359 }
360 }
361 }
362
363 private void allocateLinkResource(TransactionContext tx, Link link,
364 LinkResourceAllocations allocations) {
365
366 // requested resources
367 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
368
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800369 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(tx, link);
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800370 for (ResourceAllocation req : reqs) {
371 Set<? extends ResourceAllocation> avail = available.get(req.type());
372 if (req instanceof BandwidthResourceAllocation) {
373 // check if allocation should be accepted
374 if (avail.isEmpty()) {
375 checkState(!avail.isEmpty(),
376 "There's no Bandwidth resource on %s?",
377 link);
378 }
379 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
380 double bwLeft = bw.bandwidth().toDouble();
Ray Milkey9a39eca2015-01-05 09:41:01 -0800381 BandwidthResourceAllocation bwReq = ((BandwidthResourceAllocation) req);
382 bwLeft -= bwReq.bandwidth().toDouble();
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800383 if (bwLeft < 0) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800384 throw new ResourceAllocationException(
385 PositionalParameterStringFormatter.format(
386 "Unable to allocate bandwidth for link {} "
387 + " requested amount is {} current allocation is {}",
388 link,
389 bwReq.bandwidth().toDouble(),
390 bw));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800391 }
392 } else if (req instanceof LambdaResourceAllocation) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800393 LambdaResourceAllocation lambdaAllocation = (LambdaResourceAllocation) req;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800394 // check if allocation should be accepted
395 if (!avail.contains(req)) {
396 // requested lambda was not available
Ray Milkey9a39eca2015-01-05 09:41:01 -0800397 throw new ResourceAllocationException(
398 PositionalParameterStringFormatter.format(
Sho SHIMIZU2b2e6812015-01-21 10:50:36 -0800399 "Unable to allocate lambda for link {} lambda is {}",
Ray Milkey9a39eca2015-01-05 09:41:01 -0800400 link,
401 lambdaAllocation.lambda().toInt()));
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800402 }
Michele Santuari4b6019e2014-12-19 11:31:45 +0100403 } else if (req instanceof MplsLabelResourceAllocation) {
404 MplsLabelResourceAllocation mplsAllocation = (MplsLabelResourceAllocation) req;
405 if (!avail.contains(req)) {
406 throw new ResourceAllocationException(
407 PositionalParameterStringFormatter
408 .format("Unable to allocate MPLS label for link "
409 + "{} MPLS label is {}",
410 link,
411 mplsAllocation
412 .mplsLabel()
413 .toString()));
414 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800415 }
416 }
417 // all requests allocatable => add allocation
418 final LinkKey linkKey = LinkKey.linkKey(link);
419 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800420 List<LinkResourceAllocations> before = linkAllocs.get(linkKey);
421 if (before == null) {
422 List<LinkResourceAllocations> after = new ArrayList<>();
423 after.add(allocations);
424 before = linkAllocs.putIfAbsent(linkKey, after);
425 if (before != null) {
426 // concurrent allocation detected, retry transaction
427 throw new TransactionException("Concurrent Allocation, retry");
428 }
Yuta HIGUCHI427a2142014-12-03 11:03:18 -0800429 } else {
430 List<LinkResourceAllocations> after = new ArrayList<>(before.size() + 1);
431 after.addAll(before);
432 after.add(allocations);
433 linkAllocs.replace(linkKey, before, after);
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800434 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800435 }
436
437 @Override
438 public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
439 checkNotNull(allocations);
440
441 final IntentId intendId = allocations.intendId();
442 final Collection<Link> links = allocations.links();
443
444 boolean success = false;
445 do {
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800446 // Note: might want to break it down into smaller tx unit
447 // to lower the chance of collisions.
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800448 TransactionContext tx = theInstance.newTransactionContext();
449 tx.beginTransaction();
450 try {
451 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
452 intentAllocs.remove(intendId);
453
454 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
455
456 for (Link link : links) {
457 final LinkKey linkId = LinkKey.linkKey(link);
458
459 List<LinkResourceAllocations> before = linkAllocs.get(linkId);
460 if (before == null || before.isEmpty()) {
461 // something is wrong, but it is already freed
462 log.warn("There was no resource left to release on {}", linkId);
463 continue;
464 }
465 List<LinkResourceAllocations> after = new ArrayList<>(before);
466 after.remove(allocations);
467 linkAllocs.replace(linkId, before, after);
468 }
469
470 tx.commitTransaction();
471 success = true;
472 } catch (TransactionException e) {
473 log.debug("Transaction failed, retrying");
474 } catch (Exception e) {
475 log.error("Exception thrown during releaseResource {}",
476 allocations, e);
477 tx.rollbackTransaction();
478 throw e;
479 }
480 } while (!success);
481
482 // Issue events to force recompilation of intents.
483 final List<LinkResourceAllocations> releasedResources =
484 ImmutableList.of(allocations);
485 return new LinkResourceEvent(
486 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
487 releasedResources);
488 }
489
490 @Override
491 public LinkResourceAllocations getAllocations(IntentId intentId) {
492 checkNotNull(intentId);
493 TransactionOptions opt = new TransactionOptions();
494 // read-only and will never be commited, thus does not need durability
495 opt.setTransactionType(TransactionType.LOCAL);
496 TransactionContext tx = theInstance.newTransactionContext(opt);
497 tx.beginTransaction();
498 try {
499 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
500 return intentAllocs.get(intentId);
501 } finally {
502 tx.rollbackTransaction();
503 }
504 }
505
506 @Override
507 public List<LinkResourceAllocations> getAllocations(Link link) {
508 checkNotNull(link);
509 final LinkKey key = LinkKey.linkKey(link);
510
511 TransactionOptions opt = new TransactionOptions();
512 // read-only and will never be commited, thus does not need durability
513 opt.setTransactionType(TransactionType.LOCAL);
514 TransactionContext tx = theInstance.newTransactionContext(opt);
515 tx.beginTransaction();
516 List<LinkResourceAllocations> res = null;
517 try {
518 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
519 res = linkAllocs.get(key);
520 } finally {
521 tx.rollbackTransaction();
522 }
523
524 if (res == null) {
525 // try to add empty list
526 TransactionContext tx2 = theInstance.newTransactionContext();
527 tx2.beginTransaction();
528 try {
529 res = getLinkAllocs(tx2).putIfAbsent(key, new ArrayList<>());
530 tx2.commitTransaction();
531 if (res == null) {
532 return Collections.emptyList();
533 } else {
534 return res;
535 }
536 } catch (TransactionException e) {
537 // concurrently added?
538 return getAllocations(link);
539 } catch (Exception e) {
540 tx.rollbackTransaction();
541 }
542 }
543 return res;
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800544 }
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800545
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800546 private Iterable<LinkResourceAllocations> getAllocations(TransactionContext tx,
547 Link link) {
548 checkNotNull(tx);
549 checkNotNull(link);
550 final LinkKey key = LinkKey.linkKey(link);
551
552 STxMap<LinkKey, List<LinkResourceAllocations>> linkAllocs = getLinkAllocs(tx);
553 List<LinkResourceAllocations> res = null;
554 res = linkAllocs.get(key);
555 if (res == null) {
Yuta HIGUCHIacdec312014-12-02 21:01:16 -0800556 res = linkAllocs.putIfAbsent(key, new ArrayList<>());
Yuta HIGUCHIbd1aee12014-12-01 20:05:47 -0800557 if (res == null) {
558 return Collections.emptyList();
559 } else {
560 return res;
561 }
562 }
Yuta HIGUCHI81419e22014-12-03 16:54:16 -0800563 return res;
Yuta HIGUCHI3cc4d9b2014-11-29 18:17:17 -0800564 }
565
566 @Override
567 public Iterable<LinkResourceAllocations> getAllocations() {
568 TransactionContext tx = theInstance.newTransactionContext();
569 tx.beginTransaction();
570 try {
571 STxMap<IntentId, LinkResourceAllocations> intentAllocs = getIntentAllocs(tx);
572 return intentAllocs.values();
573 } finally {
574 tx.rollbackTransaction();
575 }
576 }
577}