blob: ab167be6f50b57fd3ec6e0e1104a21e291a6d86f [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;
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -080042import org.onlab.onos.store.service.DatabaseException;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080043import org.onlab.onos.store.service.DatabaseService;
44import org.onlab.onos.store.service.VersionedValue;
45import org.onlab.onos.store.service.WriteRequest;
46import org.onlab.onos.store.service.WriteResult;
Brian O'Connor41718fc2014-10-30 16:57:21 -070047import org.slf4j.Logger;
48
Yuta HIGUCHI35242292014-11-12 18:53:15 -080049import com.google.common.base.Function;
50import com.google.common.collect.FluentIterable;
51import com.google.common.collect.ImmutableSet;
52import com.google.common.collect.Sets;
53
54import java.util.ArrayList;
55import java.util.Collection;
Brian O'Connor41718fc2014-10-30 16:57:21 -070056import java.util.HashMap;
57import java.util.HashSet;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080058import java.util.List;
Brian O'Connor41718fc2014-10-30 16:57:21 -070059import java.util.Map;
60import java.util.Set;
61
Yuta HIGUCHI35242292014-11-12 18:53:15 -080062import static com.google.common.base.Preconditions.checkArgument;
Brian O'Connor41718fc2014-10-30 16:57:21 -070063import static com.google.common.base.Preconditions.checkNotNull;
64import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080065import static com.google.common.base.Predicates.notNull;
66import static org.onlab.util.HexString.toHexString;
Brian O'Connor41718fc2014-10-30 16:57:21 -070067import static org.slf4j.LoggerFactory.getLogger;
68
69/**
Yuta HIGUCHI35242292014-11-12 18:53:15 -080070 * Manages link resources using database service.
Brian O'Connor41718fc2014-10-30 16:57:21 -070071 */
72@Component(immediate = true)
73@Service
74public class DistributedLinkResourceStore implements LinkResourceStore {
Yuta HIGUCHI35242292014-11-12 18:53:15 -080075
Brian O'Connor41718fc2014-10-30 16:57:21 -070076 private final Logger log = getLogger(getClass());
Yuta HIGUCHI35242292014-11-12 18:53:15 -080077
78 // FIXME: what is the Bandwidth unit?
79 private static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.valueOf(1_000);
80
81 // table to store current allocations
82 /** LinkKey -> List<LinkResourceAllocations>. */
83 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
84
85 /** IntentId -> LinkResourceAllocations. */
86 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
87
88 private static final Bandwidth EMPTY_BW = Bandwidth.valueOf(0);
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected DatabaseAdminService databaseAdminService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DatabaseService databaseService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected LinkService linkService;
98
99 // Link annotation key name to use as bandwidth
100 private String bandwidthAnnotation = "bandwidth";
101 // Link annotation key name to use as max lamda
102 private String wavesAnnotation = "optical.waves";
103
104 private StoreSerializer serializer;
105
Brian O'Connor41718fc2014-10-30 16:57:21 -0700106
107 @Activate
108 public void activate() {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800109
110 serializer = new KryoSerializer();
111
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -0800112 Set<String> tables = null;
113 int retries = 0;
114 do {
115 try {
116 tables = databaseAdminService.listTables();
117 } catch (DatabaseException e) {
118 log.debug("DatabaseException", e);
119 retries++;
120 if (retries > 10) {
121 log.error("Failed to list tables, moving on", e);
122 tables = new HashSet<>();
123 }
124 }
125 } while (tables == null);
126
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800127 if (!tables.contains(LINK_RESOURCE_ALLOCATIONS)) {
128 databaseAdminService.createTable(LINK_RESOURCE_ALLOCATIONS);
129 }
130 if (!tables.contains(INTENT_ALLOCATIONS)) {
131 databaseAdminService.createTable(INTENT_ALLOCATIONS);
132 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700133
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -0800134
Brian O'Connor41718fc2014-10-30 16:57:21 -0700135 log.info("Started");
136 }
137
138 @Deactivate
139 public void deactivate() {
140 log.info("Stopped");
141 }
142
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800143 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
144 // TODO: plugin/provider mechanism to add resource type in the future?
145 if (type == ResourceType.BANDWIDTH) {
146 return ImmutableSet.of(getBandwidthResourceCapacity(link));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700147 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800148 if (type == ResourceType.LAMBDA) {
149 return getLambdaResourceCapacity(link);
150 }
151 return null;
152 }
153
154 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
155 // FIXME enumerate all the possible link/port lambdas
156 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 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700165 return allocations;
166 }
167
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800168 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 {
177 bandwidth = Bandwidth.valueOf(Double.parseDouble(strBw));
178 } catch (NumberFormatException e) {
179 // do nothings
180 bandwidth = null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700181 }
182 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800183
184 if (bandwidth == null) {
185 // fall back, use fixed default
186 bandwidth = DEFAULT_BANDWIDTH;
187 }
188 return new BandwidthResourceAllocation(bandwidth);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700189 }
190
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800191 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
192 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
193 for (ResourceType type : ResourceType.values()) {
194 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
195 if (cap != null) {
196 caps.put(type, cap);
197 }
198 }
199 return caps;
200 }
201
202 @Override
203 public Set<ResourceAllocation> getFreeResources(Link link) {
204 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(link);
205 Set<ResourceAllocation> allFree = new HashSet<>();
206 for (Set<? extends ResourceAllocation> r:freeResources.values()) {
207 allFree.addAll(r);
208 }
209 return allFree;
210 }
211
212 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(Link link) {
213 // returns capacity - allocated
214
Brian O'Connor41718fc2014-10-30 16:57:21 -0700215 checkNotNull(link);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800216 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
217 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
218 final Iterable<LinkResourceAllocations> allocations = getAllocations(link);
219
220 for (ResourceType type : ResourceType.values()) {
221 // there should be class/category of resources
222 switch (type) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700223 case BANDWIDTH:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800224 {
225 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
226 if (bw == null || bw.isEmpty()) {
227 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
228 }
229
230 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
231 double freeBw = cap.bandwidth().toDouble();
232
233 // enumerate current allocations, subtracting resources
234 for (LinkResourceAllocations alloc : allocations) {
235 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
236 for (ResourceAllocation a : types) {
237 if (a instanceof BandwidthResourceAllocation) {
238 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
239 freeBw -= bwA.bandwidth().toDouble();
240 }
241 }
242 }
243
244 free.put(type, Sets.newHashSet(new BandwidthResourceAllocation(Bandwidth.valueOf(freeBw))));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700245 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800246 }
247
Brian O'Connor41718fc2014-10-30 16:57:21 -0700248 case LAMBDA:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800249 {
250 Set<? extends ResourceAllocation> lmd = caps.get(type);
251 if (lmd == null || lmd.isEmpty()) {
252 // nothing left
253 break;
254 }
255 Set<LambdaResourceAllocation> freeL = new HashSet<>();
256 for (ResourceAllocation r : lmd) {
257 if (r instanceof LambdaResourceAllocation) {
258 freeL.add((LambdaResourceAllocation) r);
259 }
260 }
261
262 // enumerate current allocations, removing resources
263 for (LinkResourceAllocations alloc : allocations) {
264 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
265 for (ResourceAllocation a : types) {
266 if (a instanceof LambdaResourceAllocation) {
267 freeL.remove(a);
268 }
269 }
270 }
271
272 free.put(type, freeL);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700273 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800274 }
275
Brian O'Connor41718fc2014-10-30 16:57:21 -0700276 default:
277 break;
278 }
279 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800280 return free;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700281 }
282
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800283 private LinkResourceAllocations getIntentAllocations(IntentId id) {
284 VersionedValue vv
285 = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(checkNotNull(id)));
286 if (vv == null || vv.value() == null) {
287 return null;
288 }
289 return decodeIntentAllocations(vv.value());
290 }
291
292 private Builder putIntentAllocations(Builder ctx,
293 IntentId id,
294 LinkResourceAllocations alloc) {
295 return ctx.put(INTENT_ALLOCATIONS,
296 toIntentDbKey(id),
297 encodeIntentAllocations(alloc));
298 }
299
300
301 @Override
302 public void allocateResources(LinkResourceAllocations allocations) {
303 checkNotNull(allocations);
304
305 Builder tx = BatchWriteRequest.newBuilder();
306
307 // TODO: Should IntentId -> Allocation be updated conditionally?
308 putIntentAllocations(tx, allocations.intendId(), allocations);
309
310 for (Link link : allocations.links()) {
311 allocateLinkResource(tx, link, allocations);
312 }
313
314 BatchWriteRequest batch = tx.build();
315// log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
316// log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
317
318 BatchWriteResult result = databaseService.batchWrite(batch);
319 if (!result.isSuccessful()) {
320 log.error("Allocation Failed.");
321 if (log.isDebugEnabled()) {
322 logFailureDetail(batch, result);
323 }
324 // FIXME throw appropriate exception, with what failed.
325 checkState(result.isSuccessful(), "Allocation failed");
326 }
327 }
328
329 private void logFailureDetail(BatchWriteRequest batch,
330 BatchWriteResult result) {
331 for (int i = 0; i < batch.batchSize(); ++i) {
332 final WriteRequest req = batch.getAsList().get(i);
333 final WriteResult fail = result.getAsList().get(i);
334 switch (fail.status()) {
335 case ABORTED:
336 log.debug("ABORTED: {}@{}", req.key(), req.tableName());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700337 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800338 case PRECONDITION_VIOLATION:
339 switch (req.type()) {
340 case PUT_IF_ABSENT:
341 log.debug("{}: {}@{} : {}", req.type(),
342 req.key(), req.tableName(), fail.previousValue());
343 break;
344 case PUT_IF_VALUE:
345 case REMOVE_IF_VALUE:
346 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
347 req.key(), req.tableName(),
348 fail.previousValue(),
349 toHexString(req.oldValue()));
350 break;
351 case PUT_IF_VERSION:
352 case REMOVE_IF_VERSION:
353 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
354 req.key(), req.tableName(),
355 fail.previousValue().version(),
356 req.previousVersion());
357 break;
358 default:
359 log.error("Should never reach here.");
360 break;
361 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700362 break;
363 default:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800364 log.error("Should never reach here.");
Brian O'Connor41718fc2014-10-30 16:57:21 -0700365 break;
366 }
367 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700368 }
369
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800370 private Builder allocateLinkResource(Builder builder, Link link,
371 LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700372
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800373 // requested resources
374 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700375
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800376 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(link);
377 for (ResourceAllocation req : reqs) {
378 Set<? extends ResourceAllocation> avail = available.get(req.type());
379 if (req instanceof BandwidthResourceAllocation) {
380 // check if allocation should be accepted
381 if (avail.isEmpty()) {
382 checkState(!avail.isEmpty(),
383 "There's no Bandwidth resource on %s?",
384 link);
385 }
386 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
387 double bwLeft = bw.bandwidth().toDouble();
388 bwLeft -= ((BandwidthResourceAllocation) req).bandwidth().toDouble();
389 if (bwLeft < 0) {
390 // FIXME throw appropriate Exception
391 checkState(bwLeft >= 0,
392 "There's no Bandwidth left on %s. %s",
393 link, bwLeft);
394 }
395 } else if (req instanceof LambdaResourceAllocation) {
396
397 // check if allocation should be accepted
398 if (!avail.contains(req)) {
399 // requested lambda was not available
400 // FIXME throw appropriate exception
401 checkState(avail.contains(req),
402 "Allocating %s on %s failed",
403 req, link);
404 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700405 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700406 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800407 // all requests allocatable => add allocation
408 final List<LinkResourceAllocations> before = getAllocations(link);
409 List<LinkResourceAllocations> after = new ArrayList<>(before.size());
410 after.addAll(before);
411 after.add(allocations);
412 replaceLinkAllocations(builder, LinkKey.linkKey(link), before, after);
413 return builder;
414 }
415
416 private Builder replaceLinkAllocations(Builder builder, LinkKey linkKey,
417 List<LinkResourceAllocations> before,
418 List<LinkResourceAllocations> after) {
419
420 byte[] oldValue = encodeLinkAllocations(before);
421 byte[] newValue = encodeLinkAllocations(after);
422 builder.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, toLinkDbKey(linkKey), oldValue, newValue);
423 return builder;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700424 }
425
426 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800427 public void releaseResources(LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700428 checkNotNull(allocations);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800429
430 final IntentId intendId = allocations.intendId();
431 final String dbIntentId = toIntentDbKey(intendId);
432 final Collection<Link> links = allocations.links();
433
434 // TODO: does release must happen in a batch?
435 boolean success;
436 do {
437 Builder tx = BatchWriteRequest.newBuilder();
438
439 // TODO: Should IntentId -> Allocation be updated conditionally?
440 tx.remove(INTENT_ALLOCATIONS, dbIntentId);
441
442 for (Link link : links) {
443 final LinkKey linkId = LinkKey.linkKey(link);
444 final String dbLinkId = toLinkDbKey(linkId);
445 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbLinkId);
446 if (vv == null || vv.value() == null) {
447 // something is wrong, but it is already freed
448 log.warn("There was no resource left to release on {}", linkId);
449 continue;
450 }
451 List<LinkResourceAllocations> before = decodeLinkAllocations(vv.value());
452 List<LinkResourceAllocations> after = new ArrayList<>(before);
453 after.remove(allocations);
454 byte[] oldValue = encodeLinkAllocations(before);
455 byte[] newValue = encodeLinkAllocations(after);
456 tx.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, dbLinkId, oldValue, newValue);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700457 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800458
459 BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
460 success = batchWrite.isSuccessful();
461 } while (!success);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700462 }
463
464 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800465 public LinkResourceAllocations getAllocations(IntentId intentId) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700466 checkNotNull(intentId);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800467 VersionedValue vv = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(intentId));
468 if (vv == null) {
469 // FIXME: should we return null or LinkResourceAllocations with nothing allocated?
470 return null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700471 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800472 LinkResourceAllocations allocations = decodeIntentAllocations(vv.value());
473 return allocations;
474 }
475
476 private String toLinkDbKey(LinkKey linkid) {
477 // introduce cache if necessary
478 return linkid.toString();
479 // TODO: Above is irreversible, if we need reverse conversion
480 // we may need something like below, due to String only limitation
481// byte[] bytes = serializer.encode(linkid);
482// StringBuilder builder = new StringBuilder(bytes.length * 4);
483// boolean isFirst = true;
484// for (byte b : bytes) {
485// if (!isFirst) {
486// builder.append(',');
487// }
488// builder.append(b);
489// isFirst = false;
490// }
491// return builder.toString();
492 }
493
494// private LinkKey toLinkKey(String linkKey) {
495// String[] bytes = linkKey.split(",");
496// ByteBuffer buf = ByteBuffer.allocate(bytes.length);
497// for (String bs : bytes) {
498// buf.put(Byte.parseByte(bs));
499// }
500// buf.flip();
501// return serializer.decode(buf);
502// }
503
504 private String toIntentDbKey(IntentId intentid) {
505 return intentid.toString();
506 }
507
508 private IntentId toIntentId(String intentid) {
509 checkArgument(intentid.startsWith("0x"));
510 return IntentId.valueOf(Long.parseLong(intentid.substring(2)));
511 }
512
513 private LinkResourceAllocations decodeIntentAllocations(byte[] bytes) {
514 return serializer.decode(bytes);
515 }
516
517 private byte[] encodeIntentAllocations(LinkResourceAllocations alloc) {
518 return serializer.encode(checkNotNull(alloc));
519 }
520
521 private List<LinkResourceAllocations> decodeLinkAllocations(byte[] bytes) {
522 return serializer.decode(bytes);
523 }
524
525 private byte[] encodeLinkAllocations(List<LinkResourceAllocations> alloc) {
526 return serializer.encode(checkNotNull(alloc));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700527 }
528
529 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800530 public List<LinkResourceAllocations> getAllocations(Link link) {
531 checkNotNull(link);
532 final LinkKey key = LinkKey.linkKey(link);
533 final String dbKey = toLinkDbKey(key);
534 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
535 if (vv == null) {
536 // write empty so that all other update can be replace operation
537 byte[] emptyList = encodeLinkAllocations(new ArrayList<>());
538 boolean written = databaseService.putIfAbsent(LINK_RESOURCE_ALLOCATIONS, dbKey, emptyList);
539 log.trace("Empty allocation write success? {}", written);
540 vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
541 if (vv == null) {
542 log.error("Failed to re-read allocation for {}", dbKey);
543 // note: cannot be Collections.emptyList();
544 return new ArrayList<>();
545 }
546 }
547 List<LinkResourceAllocations> allocations = decodeLinkAllocations(vv.value());
548 return allocations;
549 }
550
551 @Override
552 public Iterable<LinkResourceAllocations> getAllocations() {
553 //IntentId -> LinkResourceAllocations
554 Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
555
556 return FluentIterable.from(all.values())
557 .transform(new Function<VersionedValue, LinkResourceAllocations>() {
558
559 @Override
560 public LinkResourceAllocations apply(VersionedValue input) {
561 if (input == null || input.value() == null) {
562 return null;
563 }
564 return decodeIntentAllocations(input.value());
565 }
566 })
567 .filter(notNull());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700568 }
569
570}