blob: c45b3d36d65e5d8b2ea54966ba211846f6dcd99c [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
Ray Milkeye97ede92014-11-20 10:43:12 -080018import java.util.ArrayList;
19import java.util.Collection;
20import java.util.HashMap;
21import java.util.HashSet;
22import java.util.List;
23import java.util.Map;
24import java.util.Set;
25
Brian O'Connor41718fc2014-10-30 16:57:21 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connor41718fc2014-10-30 16:57:21 -070031import org.apache.felix.scr.annotations.Service;
32import org.onlab.onos.net.Link;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080033import org.onlab.onos.net.LinkKey;
Brian O'Connor41718fc2014-10-30 16:57:21 -070034import org.onlab.onos.net.intent.IntentId;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080035import org.onlab.onos.net.link.LinkService;
Brian O'Connor41718fc2014-10-30 16:57:21 -070036import org.onlab.onos.net.resource.Bandwidth;
37import org.onlab.onos.net.resource.BandwidthResourceAllocation;
38import org.onlab.onos.net.resource.Lambda;
39import org.onlab.onos.net.resource.LambdaResourceAllocation;
40import org.onlab.onos.net.resource.LinkResourceAllocations;
Ray Milkeye97ede92014-11-20 10:43:12 -080041import org.onlab.onos.net.resource.LinkResourceEvent;
Brian O'Connor41718fc2014-10-30 16:57:21 -070042import org.onlab.onos.net.resource.LinkResourceStore;
43import org.onlab.onos.net.resource.ResourceAllocation;
44import org.onlab.onos.net.resource.ResourceType;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080045import org.onlab.onos.store.serializers.KryoSerializer;
46import org.onlab.onos.store.serializers.StoreSerializer;
47import org.onlab.onos.store.service.BatchWriteRequest;
48import org.onlab.onos.store.service.BatchWriteRequest.Builder;
49import org.onlab.onos.store.service.BatchWriteResult;
50import org.onlab.onos.store.service.DatabaseAdminService;
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -080051import org.onlab.onos.store.service.DatabaseException;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080052import org.onlab.onos.store.service.DatabaseService;
53import org.onlab.onos.store.service.VersionedValue;
54import org.onlab.onos.store.service.WriteRequest;
55import org.onlab.onos.store.service.WriteResult;
Brian O'Connor41718fc2014-10-30 16:57:21 -070056import org.slf4j.Logger;
57
Yuta HIGUCHI35242292014-11-12 18:53:15 -080058import com.google.common.base.Function;
59import com.google.common.collect.FluentIterable;
Ray Milkeye97ede92014-11-20 10:43:12 -080060import com.google.common.collect.ImmutableList;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080061import com.google.common.collect.ImmutableSet;
62import com.google.common.collect.Sets;
63
Yuta HIGUCHI35242292014-11-12 18:53:15 -080064import static com.google.common.base.Preconditions.checkArgument;
Brian O'Connor41718fc2014-10-30 16:57:21 -070065import static com.google.common.base.Preconditions.checkNotNull;
66import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080067import static com.google.common.base.Predicates.notNull;
68import static org.onlab.util.HexString.toHexString;
Brian O'Connor41718fc2014-10-30 16:57:21 -070069import static org.slf4j.LoggerFactory.getLogger;
70
71/**
Yuta HIGUCHI35242292014-11-12 18:53:15 -080072 * Manages link resources using database service.
Brian O'Connor41718fc2014-10-30 16:57:21 -070073 */
74@Component(immediate = true)
75@Service
76public class DistributedLinkResourceStore implements LinkResourceStore {
Yuta HIGUCHI35242292014-11-12 18:53:15 -080077
Brian O'Connor41718fc2014-10-30 16:57:21 -070078 private final Logger log = getLogger(getClass());
Yuta HIGUCHI35242292014-11-12 18:53:15 -080079
80 // FIXME: what is the Bandwidth unit?
81 private static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.valueOf(1_000);
82
83 // table to store current allocations
84 /** LinkKey -> List<LinkResourceAllocations>. */
85 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
86
87 /** IntentId -> LinkResourceAllocations. */
88 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
89
90 private static final Bandwidth EMPTY_BW = Bandwidth.valueOf(0);
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DatabaseAdminService databaseAdminService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected DatabaseService databaseService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected LinkService linkService;
100
101 // Link annotation key name to use as bandwidth
102 private String bandwidthAnnotation = "bandwidth";
Ray Milkeye97ede92014-11-20 10:43:12 -0800103 // Link annotation key name to use as max lambda
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800104 private String wavesAnnotation = "optical.waves";
105
106 private StoreSerializer serializer;
107
Brian O'Connor41718fc2014-10-30 16:57:21 -0700108
Yuta HIGUCHI45e5cd12014-11-24 14:57:13 -0800109 void createTable(String tableName) {
110 boolean tableReady = false;
111 do {
112 try {
113 if (!databaseAdminService.listTables().contains(tableName)) {
114 databaseAdminService.createTable(tableName);
115 }
116 tableReady = true;
117 } catch (DatabaseException e) {
118 log.debug("Failed creating table, retrying", e);
119 try {
120 Thread.sleep(200);
121 } catch (InterruptedException e1) {
122 throw new DatabaseException(e1);
123 }
124 }
125 } while (!tableReady);
126 }
127
Brian O'Connor41718fc2014-10-30 16:57:21 -0700128 @Activate
129 public void activate() {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800130
131 serializer = new KryoSerializer();
132
Yuta HIGUCHI45e5cd12014-11-24 14:57:13 -0800133 createTable(LINK_RESOURCE_ALLOCATIONS);
134 createTable(INTENT_ALLOCATIONS);
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -0800135
Brian O'Connor41718fc2014-10-30 16:57:21 -0700136 log.info("Started");
137 }
138
139 @Deactivate
140 public void deactivate() {
141 log.info("Stopped");
142 }
143
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800144 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
145 // TODO: plugin/provider mechanism to add resource type in the future?
146 if (type == ResourceType.BANDWIDTH) {
147 return ImmutableSet.of(getBandwidthResourceCapacity(link));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700148 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800149 if (type == ResourceType.LAMBDA) {
150 return getLambdaResourceCapacity(link);
151 }
152 return null;
153 }
154
155 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
156 // FIXME enumerate all the possible link/port lambdas
157 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++) {
161 allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
162 }
163 } catch (NumberFormatException e) {
164 log.debug("No {} annotation on link %s", wavesAnnotation, link);
165 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700166 return allocations;
167 }
168
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800169 private BandwidthResourceAllocation getBandwidthResourceCapacity(Link link) {
170
171 // if Link annotation exist, use them
172 // if all fails, use DEFAULT_BANDWIDTH
173
174 Bandwidth bandwidth = null;
175 String strBw = link.annotations().value(bandwidthAnnotation);
176 if (strBw != null) {
177 try {
178 bandwidth = Bandwidth.valueOf(Double.parseDouble(strBw));
179 } catch (NumberFormatException e) {
180 // do nothings
181 bandwidth = null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700182 }
183 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800184
185 if (bandwidth == null) {
186 // fall back, use fixed default
187 bandwidth = DEFAULT_BANDWIDTH;
188 }
189 return new BandwidthResourceAllocation(bandwidth);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700190 }
191
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800192 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
193 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
194 for (ResourceType type : ResourceType.values()) {
195 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
196 if (cap != null) {
197 caps.put(type, cap);
198 }
199 }
200 return caps;
201 }
202
203 @Override
204 public Set<ResourceAllocation> getFreeResources(Link link) {
205 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(link);
206 Set<ResourceAllocation> allFree = new HashSet<>();
207 for (Set<? extends ResourceAllocation> r:freeResources.values()) {
208 allFree.addAll(r);
209 }
210 return allFree;
211 }
212
213 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(Link link) {
214 // returns capacity - allocated
215
Brian O'Connor41718fc2014-10-30 16:57:21 -0700216 checkNotNull(link);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800217 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
218 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
219 final Iterable<LinkResourceAllocations> allocations = getAllocations(link);
220
221 for (ResourceType type : ResourceType.values()) {
222 // there should be class/category of resources
223 switch (type) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700224 case BANDWIDTH:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800225 {
226 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
227 if (bw == null || bw.isEmpty()) {
228 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
229 }
230
231 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
232 double freeBw = cap.bandwidth().toDouble();
233
234 // enumerate current allocations, subtracting resources
235 for (LinkResourceAllocations alloc : allocations) {
236 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
237 for (ResourceAllocation a : types) {
238 if (a instanceof BandwidthResourceAllocation) {
239 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
240 freeBw -= bwA.bandwidth().toDouble();
241 }
242 }
243 }
244
245 free.put(type, Sets.newHashSet(new BandwidthResourceAllocation(Bandwidth.valueOf(freeBw))));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700246 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800247 }
248
Brian O'Connor41718fc2014-10-30 16:57:21 -0700249 case LAMBDA:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800250 {
251 Set<? extends ResourceAllocation> lmd = caps.get(type);
252 if (lmd == null || lmd.isEmpty()) {
253 // nothing left
254 break;
255 }
256 Set<LambdaResourceAllocation> freeL = new HashSet<>();
257 for (ResourceAllocation r : lmd) {
258 if (r instanceof LambdaResourceAllocation) {
259 freeL.add((LambdaResourceAllocation) r);
260 }
261 }
262
263 // enumerate current allocations, removing resources
264 for (LinkResourceAllocations alloc : allocations) {
265 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
266 for (ResourceAllocation a : types) {
267 if (a instanceof LambdaResourceAllocation) {
268 freeL.remove(a);
269 }
270 }
271 }
272
273 free.put(type, freeL);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700274 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800275 }
276
Brian O'Connor41718fc2014-10-30 16:57:21 -0700277 default:
278 break;
279 }
280 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800281 return free;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700282 }
283
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800284 private LinkResourceAllocations getIntentAllocations(IntentId id) {
285 VersionedValue vv
286 = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(checkNotNull(id)));
287 if (vv == null || vv.value() == null) {
288 return null;
289 }
290 return decodeIntentAllocations(vv.value());
291 }
292
293 private Builder putIntentAllocations(Builder ctx,
294 IntentId id,
295 LinkResourceAllocations alloc) {
296 return ctx.put(INTENT_ALLOCATIONS,
297 toIntentDbKey(id),
298 encodeIntentAllocations(alloc));
299 }
300
301
302 @Override
303 public void allocateResources(LinkResourceAllocations allocations) {
304 checkNotNull(allocations);
305
306 Builder tx = BatchWriteRequest.newBuilder();
307
308 // TODO: Should IntentId -> Allocation be updated conditionally?
309 putIntentAllocations(tx, allocations.intendId(), allocations);
310
311 for (Link link : allocations.links()) {
312 allocateLinkResource(tx, link, allocations);
313 }
314
315 BatchWriteRequest batch = tx.build();
316// log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
317// log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
318
319 BatchWriteResult result = databaseService.batchWrite(batch);
320 if (!result.isSuccessful()) {
321 log.error("Allocation Failed.");
322 if (log.isDebugEnabled()) {
323 logFailureDetail(batch, result);
324 }
325 // FIXME throw appropriate exception, with what failed.
326 checkState(result.isSuccessful(), "Allocation failed");
327 }
328 }
329
330 private void logFailureDetail(BatchWriteRequest batch,
331 BatchWriteResult result) {
332 for (int i = 0; i < batch.batchSize(); ++i) {
333 final WriteRequest req = batch.getAsList().get(i);
334 final WriteResult fail = result.getAsList().get(i);
335 switch (fail.status()) {
336 case ABORTED:
337 log.debug("ABORTED: {}@{}", req.key(), req.tableName());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700338 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800339 case PRECONDITION_VIOLATION:
340 switch (req.type()) {
341 case PUT_IF_ABSENT:
342 log.debug("{}: {}@{} : {}", req.type(),
343 req.key(), req.tableName(), fail.previousValue());
344 break;
345 case PUT_IF_VALUE:
346 case REMOVE_IF_VALUE:
347 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
348 req.key(), req.tableName(),
349 fail.previousValue(),
350 toHexString(req.oldValue()));
351 break;
352 case PUT_IF_VERSION:
353 case REMOVE_IF_VERSION:
354 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
355 req.key(), req.tableName(),
356 fail.previousValue().version(),
357 req.previousVersion());
358 break;
359 default:
360 log.error("Should never reach here.");
361 break;
362 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700363 break;
364 default:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800365 log.error("Should never reach here.");
Brian O'Connor41718fc2014-10-30 16:57:21 -0700366 break;
367 }
368 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700369 }
370
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800371 private Builder allocateLinkResource(Builder builder, Link link,
372 LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700373
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800374 // requested resources
375 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700376
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800377 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(link);
378 for (ResourceAllocation req : reqs) {
379 Set<? extends ResourceAllocation> avail = available.get(req.type());
380 if (req instanceof BandwidthResourceAllocation) {
381 // check if allocation should be accepted
382 if (avail.isEmpty()) {
383 checkState(!avail.isEmpty(),
384 "There's no Bandwidth resource on %s?",
385 link);
386 }
387 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
388 double bwLeft = bw.bandwidth().toDouble();
389 bwLeft -= ((BandwidthResourceAllocation) req).bandwidth().toDouble();
390 if (bwLeft < 0) {
391 // FIXME throw appropriate Exception
392 checkState(bwLeft >= 0,
393 "There's no Bandwidth left on %s. %s",
394 link, bwLeft);
395 }
396 } else if (req instanceof LambdaResourceAllocation) {
397
398 // check if allocation should be accepted
399 if (!avail.contains(req)) {
400 // requested lambda was not available
401 // FIXME throw appropriate exception
402 checkState(avail.contains(req),
403 "Allocating %s on %s failed",
404 req, link);
405 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700406 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700407 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800408 // all requests allocatable => add allocation
409 final List<LinkResourceAllocations> before = getAllocations(link);
410 List<LinkResourceAllocations> after = new ArrayList<>(before.size());
411 after.addAll(before);
412 after.add(allocations);
413 replaceLinkAllocations(builder, LinkKey.linkKey(link), before, after);
414 return builder;
415 }
416
417 private Builder replaceLinkAllocations(Builder builder, LinkKey linkKey,
418 List<LinkResourceAllocations> before,
419 List<LinkResourceAllocations> after) {
420
421 byte[] oldValue = encodeLinkAllocations(before);
422 byte[] newValue = encodeLinkAllocations(after);
423 builder.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, toLinkDbKey(linkKey), oldValue, newValue);
424 return builder;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700425 }
426
427 @Override
Ray Milkeye97ede92014-11-20 10:43:12 -0800428 public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700429 checkNotNull(allocations);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800430
431 final IntentId intendId = allocations.intendId();
432 final String dbIntentId = toIntentDbKey(intendId);
433 final Collection<Link> links = allocations.links();
434
435 // TODO: does release must happen in a batch?
436 boolean success;
437 do {
438 Builder tx = BatchWriteRequest.newBuilder();
439
440 // TODO: Should IntentId -> Allocation be updated conditionally?
441 tx.remove(INTENT_ALLOCATIONS, dbIntentId);
442
443 for (Link link : links) {
444 final LinkKey linkId = LinkKey.linkKey(link);
445 final String dbLinkId = toLinkDbKey(linkId);
446 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbLinkId);
447 if (vv == null || vv.value() == null) {
448 // something is wrong, but it is already freed
449 log.warn("There was no resource left to release on {}", linkId);
450 continue;
451 }
452 List<LinkResourceAllocations> before = decodeLinkAllocations(vv.value());
453 List<LinkResourceAllocations> after = new ArrayList<>(before);
454 after.remove(allocations);
455 byte[] oldValue = encodeLinkAllocations(before);
456 byte[] newValue = encodeLinkAllocations(after);
457 tx.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, dbLinkId, oldValue, newValue);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700458 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800459
460 BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
461 success = batchWrite.isSuccessful();
462 } while (!success);
Ray Milkeye97ede92014-11-20 10:43:12 -0800463
464 // Issue events to force recompilation of intents.
465
466 final List<LinkResourceAllocations> releasedResources =
467 ImmutableList.of(allocations);
468 return new LinkResourceEvent(
469 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
470 releasedResources);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700471 }
472
473 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800474 public LinkResourceAllocations getAllocations(IntentId intentId) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700475 checkNotNull(intentId);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800476 VersionedValue vv = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(intentId));
477 if (vv == null) {
478 // FIXME: should we return null or LinkResourceAllocations with nothing allocated?
479 return null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700480 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800481 LinkResourceAllocations allocations = decodeIntentAllocations(vv.value());
482 return allocations;
483 }
484
485 private String toLinkDbKey(LinkKey linkid) {
486 // introduce cache if necessary
487 return linkid.toString();
488 // TODO: Above is irreversible, if we need reverse conversion
489 // we may need something like below, due to String only limitation
490// byte[] bytes = serializer.encode(linkid);
491// StringBuilder builder = new StringBuilder(bytes.length * 4);
492// boolean isFirst = true;
493// for (byte b : bytes) {
494// if (!isFirst) {
495// builder.append(',');
496// }
497// builder.append(b);
498// isFirst = false;
499// }
500// return builder.toString();
501 }
502
503// private LinkKey toLinkKey(String linkKey) {
504// String[] bytes = linkKey.split(",");
505// ByteBuffer buf = ByteBuffer.allocate(bytes.length);
506// for (String bs : bytes) {
507// buf.put(Byte.parseByte(bs));
508// }
509// buf.flip();
510// return serializer.decode(buf);
511// }
512
513 private String toIntentDbKey(IntentId intentid) {
514 return intentid.toString();
515 }
516
517 private IntentId toIntentId(String intentid) {
518 checkArgument(intentid.startsWith("0x"));
519 return IntentId.valueOf(Long.parseLong(intentid.substring(2)));
520 }
521
522 private LinkResourceAllocations decodeIntentAllocations(byte[] bytes) {
523 return serializer.decode(bytes);
524 }
525
526 private byte[] encodeIntentAllocations(LinkResourceAllocations alloc) {
527 return serializer.encode(checkNotNull(alloc));
528 }
529
530 private List<LinkResourceAllocations> decodeLinkAllocations(byte[] bytes) {
531 return serializer.decode(bytes);
532 }
533
534 private byte[] encodeLinkAllocations(List<LinkResourceAllocations> alloc) {
535 return serializer.encode(checkNotNull(alloc));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700536 }
537
538 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800539 public List<LinkResourceAllocations> getAllocations(Link link) {
540 checkNotNull(link);
541 final LinkKey key = LinkKey.linkKey(link);
542 final String dbKey = toLinkDbKey(key);
543 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
544 if (vv == null) {
545 // write empty so that all other update can be replace operation
546 byte[] emptyList = encodeLinkAllocations(new ArrayList<>());
547 boolean written = databaseService.putIfAbsent(LINK_RESOURCE_ALLOCATIONS, dbKey, emptyList);
548 log.trace("Empty allocation write success? {}", written);
549 vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
550 if (vv == null) {
551 log.error("Failed to re-read allocation for {}", dbKey);
552 // note: cannot be Collections.emptyList();
553 return new ArrayList<>();
554 }
555 }
556 List<LinkResourceAllocations> allocations = decodeLinkAllocations(vv.value());
557 return allocations;
558 }
559
560 @Override
561 public Iterable<LinkResourceAllocations> getAllocations() {
562 //IntentId -> LinkResourceAllocations
563 Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
564
565 return FluentIterable.from(all.values())
566 .transform(new Function<VersionedValue, LinkResourceAllocations>() {
567
568 @Override
569 public LinkResourceAllocations apply(VersionedValue input) {
570 if (input == null || input.value() == null) {
571 return null;
572 }
573 return decodeIntentAllocations(input.value());
574 }
575 })
576 .filter(notNull());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700577 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700578}