blob: b1cc6a81078fab6edbec62198413a5c3682d61ad [file] [log] [blame]
Brian O'Connor41718fc2014-10-30 16:57:21 -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 */
16package org.onlab.onos.store.resource.impl;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080021import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connor41718fc2014-10-30 16:57:21 -070023import org.apache.felix.scr.annotations.Service;
24import org.onlab.onos.net.Link;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080025import org.onlab.onos.net.LinkKey;
Brian O'Connor41718fc2014-10-30 16:57:21 -070026import org.onlab.onos.net.intent.IntentId;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080027import org.onlab.onos.net.link.LinkService;
Brian O'Connor41718fc2014-10-30 16:57:21 -070028import org.onlab.onos.net.resource.Bandwidth;
29import org.onlab.onos.net.resource.BandwidthResourceAllocation;
30import org.onlab.onos.net.resource.Lambda;
31import org.onlab.onos.net.resource.LambdaResourceAllocation;
32import org.onlab.onos.net.resource.LinkResourceAllocations;
33import org.onlab.onos.net.resource.LinkResourceStore;
34import org.onlab.onos.net.resource.ResourceAllocation;
35import org.onlab.onos.net.resource.ResourceType;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080036import org.onlab.onos.store.serializers.KryoSerializer;
37import org.onlab.onos.store.serializers.StoreSerializer;
38import org.onlab.onos.store.service.BatchWriteRequest;
39import org.onlab.onos.store.service.BatchWriteRequest.Builder;
40import org.onlab.onos.store.service.BatchWriteResult;
41import org.onlab.onos.store.service.DatabaseAdminService;
42import org.onlab.onos.store.service.DatabaseService;
43import org.onlab.onos.store.service.VersionedValue;
44import org.onlab.onos.store.service.WriteRequest;
45import org.onlab.onos.store.service.WriteResult;
Brian O'Connor41718fc2014-10-30 16:57:21 -070046import org.slf4j.Logger;
47
Yuta HIGUCHI35242292014-11-12 18:53:15 -080048import com.google.common.base.Function;
49import com.google.common.collect.FluentIterable;
50import com.google.common.collect.ImmutableSet;
51import com.google.common.collect.Sets;
52
53import java.util.ArrayList;
54import java.util.Collection;
Brian O'Connor41718fc2014-10-30 16:57:21 -070055import java.util.HashMap;
56import java.util.HashSet;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080057import java.util.List;
Brian O'Connor41718fc2014-10-30 16:57:21 -070058import java.util.Map;
59import java.util.Set;
60
Yuta HIGUCHI35242292014-11-12 18:53:15 -080061import static com.google.common.base.Preconditions.checkArgument;
Brian O'Connor41718fc2014-10-30 16:57:21 -070062import static com.google.common.base.Preconditions.checkNotNull;
63import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080064import static com.google.common.base.Predicates.notNull;
65import static org.onlab.util.HexString.toHexString;
Brian O'Connor41718fc2014-10-30 16:57:21 -070066import static org.slf4j.LoggerFactory.getLogger;
67
68/**
Yuta HIGUCHI35242292014-11-12 18:53:15 -080069 * Manages link resources using database service.
Brian O'Connor41718fc2014-10-30 16:57:21 -070070 */
71@Component(immediate = true)
72@Service
73public class DistributedLinkResourceStore implements LinkResourceStore {
Yuta HIGUCHI35242292014-11-12 18:53:15 -080074
Brian O'Connor41718fc2014-10-30 16:57:21 -070075 private final Logger log = getLogger(getClass());
Yuta HIGUCHI35242292014-11-12 18:53:15 -080076
77 // FIXME: what is the Bandwidth unit?
78 private static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.valueOf(1_000);
79
80 // table to store current allocations
81 /** LinkKey -> List<LinkResourceAllocations>. */
82 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
83
84 /** IntentId -> LinkResourceAllocations. */
85 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
86
87 private static final Bandwidth EMPTY_BW = Bandwidth.valueOf(0);
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected DatabaseAdminService databaseAdminService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DatabaseService databaseService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected LinkService linkService;
97
98 // Link annotation key name to use as bandwidth
99 private String bandwidthAnnotation = "bandwidth";
100 // Link annotation key name to use as max lamda
101 private String wavesAnnotation = "optical.waves";
102
103 private StoreSerializer serializer;
104
Brian O'Connor41718fc2014-10-30 16:57:21 -0700105
106 @Activate
107 public void activate() {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800108
109 serializer = new KryoSerializer();
110
111 Set<String> tables = databaseAdminService.listTables();
112 if (!tables.contains(LINK_RESOURCE_ALLOCATIONS)) {
113 databaseAdminService.createTable(LINK_RESOURCE_ALLOCATIONS);
114 }
115 if (!tables.contains(INTENT_ALLOCATIONS)) {
116 databaseAdminService.createTable(INTENT_ALLOCATIONS);
117 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700118
119 log.info("Started");
120 }
121
122 @Deactivate
123 public void deactivate() {
124 log.info("Stopped");
125 }
126
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800127 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
128 // TODO: plugin/provider mechanism to add resource type in the future?
129 if (type == ResourceType.BANDWIDTH) {
130 return ImmutableSet.of(getBandwidthResourceCapacity(link));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700131 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800132 if (type == ResourceType.LAMBDA) {
133 return getLambdaResourceCapacity(link);
134 }
135 return null;
136 }
137
138 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
139 // FIXME enumerate all the possible link/port lambdas
140 Set<LambdaResourceAllocation> allocations = new HashSet<>();
141 try {
142 final int waves = Integer.parseInt(link.annotations().value(wavesAnnotation));
143 for (int i = 1; i <= waves; i++) {
144 allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
145 }
146 } catch (NumberFormatException e) {
147 log.debug("No {} annotation on link %s", wavesAnnotation, link);
148 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700149 return allocations;
150 }
151
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800152 private BandwidthResourceAllocation getBandwidthResourceCapacity(Link link) {
153
154 // if Link annotation exist, use them
155 // if all fails, use DEFAULT_BANDWIDTH
156
157 Bandwidth bandwidth = null;
158 String strBw = link.annotations().value(bandwidthAnnotation);
159 if (strBw != null) {
160 try {
161 bandwidth = Bandwidth.valueOf(Double.parseDouble(strBw));
162 } catch (NumberFormatException e) {
163 // do nothings
164 bandwidth = null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700165 }
166 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800167
168 if (bandwidth == null) {
169 // fall back, use fixed default
170 bandwidth = DEFAULT_BANDWIDTH;
171 }
172 return new BandwidthResourceAllocation(bandwidth);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700173 }
174
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800175 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
176 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
177 for (ResourceType type : ResourceType.values()) {
178 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
179 if (cap != null) {
180 caps.put(type, cap);
181 }
182 }
183 return caps;
184 }
185
186 @Override
187 public Set<ResourceAllocation> getFreeResources(Link link) {
188 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(link);
189 Set<ResourceAllocation> allFree = new HashSet<>();
190 for (Set<? extends ResourceAllocation> r:freeResources.values()) {
191 allFree.addAll(r);
192 }
193 return allFree;
194 }
195
196 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(Link link) {
197 // returns capacity - allocated
198
Brian O'Connor41718fc2014-10-30 16:57:21 -0700199 checkNotNull(link);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800200 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
201 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
202 final Iterable<LinkResourceAllocations> allocations = getAllocations(link);
203
204 for (ResourceType type : ResourceType.values()) {
205 // there should be class/category of resources
206 switch (type) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700207 case BANDWIDTH:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800208 {
209 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
210 if (bw == null || bw.isEmpty()) {
211 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
212 }
213
214 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
215 double freeBw = cap.bandwidth().toDouble();
216
217 // enumerate current allocations, subtracting resources
218 for (LinkResourceAllocations alloc : allocations) {
219 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
220 for (ResourceAllocation a : types) {
221 if (a instanceof BandwidthResourceAllocation) {
222 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
223 freeBw -= bwA.bandwidth().toDouble();
224 }
225 }
226 }
227
228 free.put(type, Sets.newHashSet(new BandwidthResourceAllocation(Bandwidth.valueOf(freeBw))));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700229 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800230 }
231
Brian O'Connor41718fc2014-10-30 16:57:21 -0700232 case LAMBDA:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800233 {
234 Set<? extends ResourceAllocation> lmd = caps.get(type);
235 if (lmd == null || lmd.isEmpty()) {
236 // nothing left
237 break;
238 }
239 Set<LambdaResourceAllocation> freeL = new HashSet<>();
240 for (ResourceAllocation r : lmd) {
241 if (r instanceof LambdaResourceAllocation) {
242 freeL.add((LambdaResourceAllocation) r);
243 }
244 }
245
246 // enumerate current allocations, removing resources
247 for (LinkResourceAllocations alloc : allocations) {
248 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
249 for (ResourceAllocation a : types) {
250 if (a instanceof LambdaResourceAllocation) {
251 freeL.remove(a);
252 }
253 }
254 }
255
256 free.put(type, freeL);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700257 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800258 }
259
Brian O'Connor41718fc2014-10-30 16:57:21 -0700260 default:
261 break;
262 }
263 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800264 return free;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700265 }
266
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800267 private LinkResourceAllocations getIntentAllocations(IntentId id) {
268 VersionedValue vv
269 = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(checkNotNull(id)));
270 if (vv == null || vv.value() == null) {
271 return null;
272 }
273 return decodeIntentAllocations(vv.value());
274 }
275
276 private Builder putIntentAllocations(Builder ctx,
277 IntentId id,
278 LinkResourceAllocations alloc) {
279 return ctx.put(INTENT_ALLOCATIONS,
280 toIntentDbKey(id),
281 encodeIntentAllocations(alloc));
282 }
283
284
285 @Override
286 public void allocateResources(LinkResourceAllocations allocations) {
287 checkNotNull(allocations);
288
289 Builder tx = BatchWriteRequest.newBuilder();
290
291 // TODO: Should IntentId -> Allocation be updated conditionally?
292 putIntentAllocations(tx, allocations.intendId(), allocations);
293
294 for (Link link : allocations.links()) {
295 allocateLinkResource(tx, link, allocations);
296 }
297
298 BatchWriteRequest batch = tx.build();
299// log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
300// log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
301
302 BatchWriteResult result = databaseService.batchWrite(batch);
303 if (!result.isSuccessful()) {
304 log.error("Allocation Failed.");
305 if (log.isDebugEnabled()) {
306 logFailureDetail(batch, result);
307 }
308 // FIXME throw appropriate exception, with what failed.
309 checkState(result.isSuccessful(), "Allocation failed");
310 }
311 }
312
313 private void logFailureDetail(BatchWriteRequest batch,
314 BatchWriteResult result) {
315 for (int i = 0; i < batch.batchSize(); ++i) {
316 final WriteRequest req = batch.getAsList().get(i);
317 final WriteResult fail = result.getAsList().get(i);
318 switch (fail.status()) {
319 case ABORTED:
320 log.debug("ABORTED: {}@{}", req.key(), req.tableName());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700321 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800322 case PRECONDITION_VIOLATION:
323 switch (req.type()) {
324 case PUT_IF_ABSENT:
325 log.debug("{}: {}@{} : {}", req.type(),
326 req.key(), req.tableName(), fail.previousValue());
327 break;
328 case PUT_IF_VALUE:
329 case REMOVE_IF_VALUE:
330 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
331 req.key(), req.tableName(),
332 fail.previousValue(),
333 toHexString(req.oldValue()));
334 break;
335 case PUT_IF_VERSION:
336 case REMOVE_IF_VERSION:
337 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
338 req.key(), req.tableName(),
339 fail.previousValue().version(),
340 req.previousVersion());
341 break;
342 default:
343 log.error("Should never reach here.");
344 break;
345 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700346 break;
347 default:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800348 log.error("Should never reach here.");
Brian O'Connor41718fc2014-10-30 16:57:21 -0700349 break;
350 }
351 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700352 }
353
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800354 private Builder allocateLinkResource(Builder builder, Link link,
355 LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700356
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800357 // requested resources
358 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700359
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800360 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(link);
361 for (ResourceAllocation req : reqs) {
362 Set<? extends ResourceAllocation> avail = available.get(req.type());
363 if (req instanceof BandwidthResourceAllocation) {
364 // check if allocation should be accepted
365 if (avail.isEmpty()) {
366 checkState(!avail.isEmpty(),
367 "There's no Bandwidth resource on %s?",
368 link);
369 }
370 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
371 double bwLeft = bw.bandwidth().toDouble();
372 bwLeft -= ((BandwidthResourceAllocation) req).bandwidth().toDouble();
373 if (bwLeft < 0) {
374 // FIXME throw appropriate Exception
375 checkState(bwLeft >= 0,
376 "There's no Bandwidth left on %s. %s",
377 link, bwLeft);
378 }
379 } else if (req instanceof LambdaResourceAllocation) {
380
381 // check if allocation should be accepted
382 if (!avail.contains(req)) {
383 // requested lambda was not available
384 // FIXME throw appropriate exception
385 checkState(avail.contains(req),
386 "Allocating %s on %s failed",
387 req, link);
388 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700389 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700390 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800391 // all requests allocatable => add allocation
392 final List<LinkResourceAllocations> before = getAllocations(link);
393 List<LinkResourceAllocations> after = new ArrayList<>(before.size());
394 after.addAll(before);
395 after.add(allocations);
396 replaceLinkAllocations(builder, LinkKey.linkKey(link), before, after);
397 return builder;
398 }
399
400 private Builder replaceLinkAllocations(Builder builder, LinkKey linkKey,
401 List<LinkResourceAllocations> before,
402 List<LinkResourceAllocations> after) {
403
404 byte[] oldValue = encodeLinkAllocations(before);
405 byte[] newValue = encodeLinkAllocations(after);
406 builder.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, toLinkDbKey(linkKey), oldValue, newValue);
407 return builder;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700408 }
409
410 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800411 public void releaseResources(LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700412 checkNotNull(allocations);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800413
414 final IntentId intendId = allocations.intendId();
415 final String dbIntentId = toIntentDbKey(intendId);
416 final Collection<Link> links = allocations.links();
417
418 // TODO: does release must happen in a batch?
419 boolean success;
420 do {
421 Builder tx = BatchWriteRequest.newBuilder();
422
423 // TODO: Should IntentId -> Allocation be updated conditionally?
424 tx.remove(INTENT_ALLOCATIONS, dbIntentId);
425
426 for (Link link : links) {
427 final LinkKey linkId = LinkKey.linkKey(link);
428 final String dbLinkId = toLinkDbKey(linkId);
429 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbLinkId);
430 if (vv == null || vv.value() == null) {
431 // something is wrong, but it is already freed
432 log.warn("There was no resource left to release on {}", linkId);
433 continue;
434 }
435 List<LinkResourceAllocations> before = decodeLinkAllocations(vv.value());
436 List<LinkResourceAllocations> after = new ArrayList<>(before);
437 after.remove(allocations);
438 byte[] oldValue = encodeLinkAllocations(before);
439 byte[] newValue = encodeLinkAllocations(after);
440 tx.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, dbLinkId, oldValue, newValue);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700441 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800442
443 BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
444 success = batchWrite.isSuccessful();
445 } while (!success);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700446 }
447
448 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800449 public LinkResourceAllocations getAllocations(IntentId intentId) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700450 checkNotNull(intentId);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800451 VersionedValue vv = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(intentId));
452 if (vv == null) {
453 // FIXME: should we return null or LinkResourceAllocations with nothing allocated?
454 return null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700455 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800456 LinkResourceAllocations allocations = decodeIntentAllocations(vv.value());
457 return allocations;
458 }
459
460 private String toLinkDbKey(LinkKey linkid) {
461 // introduce cache if necessary
462 return linkid.toString();
463 // TODO: Above is irreversible, if we need reverse conversion
464 // we may need something like below, due to String only limitation
465// byte[] bytes = serializer.encode(linkid);
466// StringBuilder builder = new StringBuilder(bytes.length * 4);
467// boolean isFirst = true;
468// for (byte b : bytes) {
469// if (!isFirst) {
470// builder.append(',');
471// }
472// builder.append(b);
473// isFirst = false;
474// }
475// return builder.toString();
476 }
477
478// private LinkKey toLinkKey(String linkKey) {
479// String[] bytes = linkKey.split(",");
480// ByteBuffer buf = ByteBuffer.allocate(bytes.length);
481// for (String bs : bytes) {
482// buf.put(Byte.parseByte(bs));
483// }
484// buf.flip();
485// return serializer.decode(buf);
486// }
487
488 private String toIntentDbKey(IntentId intentid) {
489 return intentid.toString();
490 }
491
492 private IntentId toIntentId(String intentid) {
493 checkArgument(intentid.startsWith("0x"));
494 return IntentId.valueOf(Long.parseLong(intentid.substring(2)));
495 }
496
497 private LinkResourceAllocations decodeIntentAllocations(byte[] bytes) {
498 return serializer.decode(bytes);
499 }
500
501 private byte[] encodeIntentAllocations(LinkResourceAllocations alloc) {
502 return serializer.encode(checkNotNull(alloc));
503 }
504
505 private List<LinkResourceAllocations> decodeLinkAllocations(byte[] bytes) {
506 return serializer.decode(bytes);
507 }
508
509 private byte[] encodeLinkAllocations(List<LinkResourceAllocations> alloc) {
510 return serializer.encode(checkNotNull(alloc));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700511 }
512
513 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800514 public List<LinkResourceAllocations> getAllocations(Link link) {
515 checkNotNull(link);
516 final LinkKey key = LinkKey.linkKey(link);
517 final String dbKey = toLinkDbKey(key);
518 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
519 if (vv == null) {
520 // write empty so that all other update can be replace operation
521 byte[] emptyList = encodeLinkAllocations(new ArrayList<>());
522 boolean written = databaseService.putIfAbsent(LINK_RESOURCE_ALLOCATIONS, dbKey, emptyList);
523 log.trace("Empty allocation write success? {}", written);
524 vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
525 if (vv == null) {
526 log.error("Failed to re-read allocation for {}", dbKey);
527 // note: cannot be Collections.emptyList();
528 return new ArrayList<>();
529 }
530 }
531 List<LinkResourceAllocations> allocations = decodeLinkAllocations(vv.value());
532 return allocations;
533 }
534
535 @Override
536 public Iterable<LinkResourceAllocations> getAllocations() {
537 //IntentId -> LinkResourceAllocations
538 Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
539
540 return FluentIterable.from(all.values())
541 .transform(new Function<VersionedValue, LinkResourceAllocations>() {
542
543 @Override
544 public LinkResourceAllocations apply(VersionedValue input) {
545 if (input == null || input.value() == null) {
546 return null;
547 }
548 return decodeIntentAllocations(input.value());
549 }
550 })
551 .filter(notNull());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700552 }
553
554}