blob: 2e7dfa13c81b3d48fad94bd96e60718d48a3fd05 [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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.store.resource.impl;
Brian O'Connor41718fc2014-10-30 16:57:21 -070017
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;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.AnnotationKeys;
33import org.onosproject.net.Link;
34import org.onosproject.net.LinkKey;
35import org.onosproject.net.intent.IntentId;
36import org.onosproject.net.link.LinkService;
37import org.onosproject.net.resource.Bandwidth;
38import org.onosproject.net.resource.BandwidthResourceAllocation;
39import org.onosproject.net.resource.Lambda;
40import org.onosproject.net.resource.LambdaResourceAllocation;
41import org.onosproject.net.resource.LinkResourceAllocations;
42import org.onosproject.net.resource.LinkResourceEvent;
43import org.onosproject.net.resource.LinkResourceStore;
44import org.onosproject.net.resource.ResourceAllocation;
45import org.onosproject.net.resource.ResourceType;
46import org.onosproject.store.serializers.KryoSerializer;
47import org.onosproject.store.serializers.StoreSerializer;
48import org.onosproject.store.service.BatchWriteRequest;
49import org.onosproject.store.service.BatchWriteRequest.Builder;
50import org.onosproject.store.service.BatchWriteResult;
51import org.onosproject.store.service.DatabaseAdminService;
52import org.onosproject.store.service.DatabaseException;
53import org.onosproject.store.service.DatabaseService;
54import org.onosproject.store.service.VersionedValue;
55import org.onosproject.store.service.WriteRequest;
56import org.onosproject.store.service.WriteResult;
Brian O'Connor41718fc2014-10-30 16:57:21 -070057import org.slf4j.Logger;
58
Yuta HIGUCHI35242292014-11-12 18:53:15 -080059import com.google.common.base.Function;
60import com.google.common.collect.FluentIterable;
Ray Milkeye97ede92014-11-20 10:43:12 -080061import com.google.common.collect.ImmutableList;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080062import com.google.common.collect.ImmutableSet;
63import com.google.common.collect.Sets;
64
Yuta HIGUCHI35242292014-11-12 18:53:15 -080065import static com.google.common.base.Preconditions.checkArgument;
Brian O'Connor41718fc2014-10-30 16:57:21 -070066import static com.google.common.base.Preconditions.checkNotNull;
67import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080068import static com.google.common.base.Predicates.notNull;
69import static org.onlab.util.HexString.toHexString;
Brian O'Connor41718fc2014-10-30 16:57:21 -070070import static org.slf4j.LoggerFactory.getLogger;
71
72/**
Yuta HIGUCHI35242292014-11-12 18:53:15 -080073 * Manages link resources using database service.
Brian O'Connor41718fc2014-10-30 16:57:21 -070074 */
Yuta HIGUCHI9b108b32014-12-01 11:10:26 -080075@Component(immediate = true, enabled = false)
Brian O'Connor41718fc2014-10-30 16:57:21 -070076@Service
77public class DistributedLinkResourceStore implements LinkResourceStore {
Yuta HIGUCHI35242292014-11-12 18:53:15 -080078
Brian O'Connor41718fc2014-10-30 16:57:21 -070079 private final Logger log = getLogger(getClass());
Yuta HIGUCHI35242292014-11-12 18:53:15 -080080
Yuta HIGUCHI35242292014-11-12 18:53:15 -080081 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
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800102 private String bandwidthAnnotation = AnnotationKeys.BANDWIDTH;
Ray Milkeye97ede92014-11-20 10:43:12 -0800103 // Link annotation key name to use as max lambda
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800104 private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800105
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) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800145 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) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800155 Set<LambdaResourceAllocation> allocations = new HashSet<>();
156 try {
157 final int waves = Integer.parseInt(link.annotations().value(wavesAnnotation));
158 for (int i = 1; i <= waves; i++) {
159 allocations.add(new LambdaResourceAllocation(Lambda.valueOf(i)));
160 }
161 } catch (NumberFormatException e) {
162 log.debug("No {} annotation on link %s", wavesAnnotation, link);
163 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700164 return allocations;
165 }
166
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800167 private BandwidthResourceAllocation getBandwidthResourceCapacity(Link link) {
168
169 // if Link annotation exist, use them
170 // if all fails, use DEFAULT_BANDWIDTH
171
172 Bandwidth bandwidth = null;
173 String strBw = link.annotations().value(bandwidthAnnotation);
174 if (strBw != null) {
175 try {
176 bandwidth = Bandwidth.valueOf(Double.parseDouble(strBw));
177 } catch (NumberFormatException e) {
178 // do nothings
179 bandwidth = null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700180 }
181 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800182
183 if (bandwidth == null) {
184 // fall back, use fixed default
185 bandwidth = DEFAULT_BANDWIDTH;
186 }
187 return new BandwidthResourceAllocation(bandwidth);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700188 }
189
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800190 private Map<ResourceType, Set<? extends ResourceAllocation>> getResourceCapacity(Link link) {
191 Map<ResourceType, Set<? extends ResourceAllocation>> caps = new HashMap<>();
192 for (ResourceType type : ResourceType.values()) {
193 Set<? extends ResourceAllocation> cap = getResourceCapacity(type, link);
194 if (cap != null) {
195 caps.put(type, cap);
196 }
197 }
198 return caps;
199 }
200
201 @Override
202 public Set<ResourceAllocation> getFreeResources(Link link) {
203 Map<ResourceType, Set<? extends ResourceAllocation>> freeResources = getFreeResourcesEx(link);
204 Set<ResourceAllocation> allFree = new HashSet<>();
205 for (Set<? extends ResourceAllocation> r:freeResources.values()) {
206 allFree.addAll(r);
207 }
208 return allFree;
209 }
210
211 private Map<ResourceType, Set<? extends ResourceAllocation>> getFreeResourcesEx(Link link) {
212 // returns capacity - allocated
213
Brian O'Connor41718fc2014-10-30 16:57:21 -0700214 checkNotNull(link);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800215 Map<ResourceType, Set<? extends ResourceAllocation>> free = new HashMap<>();
216 final Map<ResourceType, Set<? extends ResourceAllocation>> caps = getResourceCapacity(link);
217 final Iterable<LinkResourceAllocations> allocations = getAllocations(link);
218
219 for (ResourceType type : ResourceType.values()) {
220 // there should be class/category of resources
221 switch (type) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700222 case BANDWIDTH:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800223 {
224 Set<? extends ResourceAllocation> bw = caps.get(ResourceType.BANDWIDTH);
225 if (bw == null || bw.isEmpty()) {
226 bw = Sets.newHashSet(new BandwidthResourceAllocation(EMPTY_BW));
227 }
228
229 BandwidthResourceAllocation cap = (BandwidthResourceAllocation) bw.iterator().next();
230 double freeBw = cap.bandwidth().toDouble();
231
232 // enumerate current allocations, subtracting resources
233 for (LinkResourceAllocations alloc : allocations) {
234 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
235 for (ResourceAllocation a : types) {
236 if (a instanceof BandwidthResourceAllocation) {
237 BandwidthResourceAllocation bwA = (BandwidthResourceAllocation) a;
238 freeBw -= bwA.bandwidth().toDouble();
239 }
240 }
241 }
242
243 free.put(type, Sets.newHashSet(new BandwidthResourceAllocation(Bandwidth.valueOf(freeBw))));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700244 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800245 }
246
Brian O'Connor41718fc2014-10-30 16:57:21 -0700247 case LAMBDA:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800248 {
249 Set<? extends ResourceAllocation> lmd = caps.get(type);
250 if (lmd == null || lmd.isEmpty()) {
251 // nothing left
252 break;
253 }
254 Set<LambdaResourceAllocation> freeL = new HashSet<>();
255 for (ResourceAllocation r : lmd) {
256 if (r instanceof LambdaResourceAllocation) {
257 freeL.add((LambdaResourceAllocation) r);
258 }
259 }
260
261 // enumerate current allocations, removing resources
262 for (LinkResourceAllocations alloc : allocations) {
263 Set<ResourceAllocation> types = alloc.getResourceAllocation(link);
264 for (ResourceAllocation a : types) {
265 if (a instanceof LambdaResourceAllocation) {
266 freeL.remove(a);
267 }
268 }
269 }
270
271 free.put(type, freeL);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700272 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800273 }
274
Brian O'Connor41718fc2014-10-30 16:57:21 -0700275 default:
276 break;
277 }
278 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800279 return free;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700280 }
281
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800282 private LinkResourceAllocations getIntentAllocations(IntentId id) {
283 VersionedValue vv
284 = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(checkNotNull(id)));
285 if (vv == null || vv.value() == null) {
286 return null;
287 }
288 return decodeIntentAllocations(vv.value());
289 }
290
291 private Builder putIntentAllocations(Builder ctx,
292 IntentId id,
293 LinkResourceAllocations alloc) {
294 return ctx.put(INTENT_ALLOCATIONS,
295 toIntentDbKey(id),
296 encodeIntentAllocations(alloc));
297 }
298
299
300 @Override
301 public void allocateResources(LinkResourceAllocations allocations) {
302 checkNotNull(allocations);
303
304 Builder tx = BatchWriteRequest.newBuilder();
305
306 // TODO: Should IntentId -> Allocation be updated conditionally?
307 putIntentAllocations(tx, allocations.intendId(), allocations);
308
309 for (Link link : allocations.links()) {
310 allocateLinkResource(tx, link, allocations);
311 }
312
313 BatchWriteRequest batch = tx.build();
314// log.info("Intent: {}", databaseService.getAll(INTENT_ALLOCATIONS));
315// log.info("Link: {}", databaseService.getAll(LINK_RESOURCE_ALLOCATIONS));
316
317 BatchWriteResult result = databaseService.batchWrite(batch);
318 if (!result.isSuccessful()) {
319 log.error("Allocation Failed.");
320 if (log.isDebugEnabled()) {
321 logFailureDetail(batch, result);
322 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800323 checkState(result.isSuccessful(), "Allocation failed");
324 }
325 }
326
327 private void logFailureDetail(BatchWriteRequest batch,
328 BatchWriteResult result) {
329 for (int i = 0; i < batch.batchSize(); ++i) {
330 final WriteRequest req = batch.getAsList().get(i);
331 final WriteResult fail = result.getAsList().get(i);
332 switch (fail.status()) {
333 case ABORTED:
334 log.debug("ABORTED: {}@{}", req.key(), req.tableName());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700335 break;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800336 case PRECONDITION_VIOLATION:
337 switch (req.type()) {
338 case PUT_IF_ABSENT:
339 log.debug("{}: {}@{} : {}", req.type(),
340 req.key(), req.tableName(), fail.previousValue());
341 break;
342 case PUT_IF_VALUE:
343 case REMOVE_IF_VALUE:
344 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
345 req.key(), req.tableName(),
346 fail.previousValue(),
347 toHexString(req.oldValue()));
348 break;
349 case PUT_IF_VERSION:
350 case REMOVE_IF_VERSION:
351 log.debug("{}: {}@{} : was {}, expected {}", req.type(),
352 req.key(), req.tableName(),
353 fail.previousValue().version(),
354 req.previousVersion());
355 break;
356 default:
357 log.error("Should never reach here.");
358 break;
359 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700360 break;
361 default:
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800362 log.error("Should never reach here.");
Brian O'Connor41718fc2014-10-30 16:57:21 -0700363 break;
364 }
365 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700366 }
367
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800368 private Builder allocateLinkResource(Builder builder, Link link,
369 LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700370
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800371 // requested resources
372 Set<ResourceAllocation> reqs = allocations.getResourceAllocation(link);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700373
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800374 Map<ResourceType, Set<? extends ResourceAllocation>> available = getFreeResourcesEx(link);
375 for (ResourceAllocation req : reqs) {
376 Set<? extends ResourceAllocation> avail = available.get(req.type());
377 if (req instanceof BandwidthResourceAllocation) {
378 // check if allocation should be accepted
379 if (avail.isEmpty()) {
380 checkState(!avail.isEmpty(),
381 "There's no Bandwidth resource on %s?",
382 link);
383 }
384 BandwidthResourceAllocation bw = (BandwidthResourceAllocation) avail.iterator().next();
385 double bwLeft = bw.bandwidth().toDouble();
386 bwLeft -= ((BandwidthResourceAllocation) req).bandwidth().toDouble();
387 if (bwLeft < 0) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800388 checkState(bwLeft >= 0,
389 "There's no Bandwidth left on %s. %s",
390 link, bwLeft);
391 }
392 } else if (req instanceof LambdaResourceAllocation) {
393
394 // check if allocation should be accepted
395 if (!avail.contains(req)) {
396 // requested lambda was not available
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800397 checkState(avail.contains(req),
398 "Allocating %s on %s failed",
399 req, link);
400 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700401 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700402 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800403 // all requests allocatable => add allocation
404 final List<LinkResourceAllocations> before = getAllocations(link);
405 List<LinkResourceAllocations> after = new ArrayList<>(before.size());
406 after.addAll(before);
407 after.add(allocations);
408 replaceLinkAllocations(builder, LinkKey.linkKey(link), before, after);
409 return builder;
410 }
411
412 private Builder replaceLinkAllocations(Builder builder, LinkKey linkKey,
413 List<LinkResourceAllocations> before,
414 List<LinkResourceAllocations> after) {
415
416 byte[] oldValue = encodeLinkAllocations(before);
417 byte[] newValue = encodeLinkAllocations(after);
418 builder.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, toLinkDbKey(linkKey), oldValue, newValue);
419 return builder;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700420 }
421
422 @Override
Ray Milkeye97ede92014-11-20 10:43:12 -0800423 public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700424 checkNotNull(allocations);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800425
426 final IntentId intendId = allocations.intendId();
427 final String dbIntentId = toIntentDbKey(intendId);
428 final Collection<Link> links = allocations.links();
429
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800430 boolean success;
431 do {
432 Builder tx = BatchWriteRequest.newBuilder();
433
434 // TODO: Should IntentId -> Allocation be updated conditionally?
435 tx.remove(INTENT_ALLOCATIONS, dbIntentId);
436
437 for (Link link : links) {
438 final LinkKey linkId = LinkKey.linkKey(link);
439 final String dbLinkId = toLinkDbKey(linkId);
440 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbLinkId);
441 if (vv == null || vv.value() == null) {
442 // something is wrong, but it is already freed
443 log.warn("There was no resource left to release on {}", linkId);
444 continue;
445 }
446 List<LinkResourceAllocations> before = decodeLinkAllocations(vv.value());
447 List<LinkResourceAllocations> after = new ArrayList<>(before);
448 after.remove(allocations);
449 byte[] oldValue = encodeLinkAllocations(before);
450 byte[] newValue = encodeLinkAllocations(after);
451 tx.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, dbLinkId, oldValue, newValue);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700452 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800453
454 BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
455 success = batchWrite.isSuccessful();
456 } while (!success);
Ray Milkeye97ede92014-11-20 10:43:12 -0800457
458 // Issue events to force recompilation of intents.
459
460 final List<LinkResourceAllocations> releasedResources =
461 ImmutableList.of(allocations);
462 return new LinkResourceEvent(
463 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
464 releasedResources);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700465 }
466
467 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800468 public LinkResourceAllocations getAllocations(IntentId intentId) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700469 checkNotNull(intentId);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800470 VersionedValue vv = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(intentId));
471 if (vv == null) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800472 return null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700473 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800474 LinkResourceAllocations allocations = decodeIntentAllocations(vv.value());
475 return allocations;
476 }
477
478 private String toLinkDbKey(LinkKey linkid) {
479 // introduce cache if necessary
480 return linkid.toString();
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800481 // Note: Above is irreversible, if we need reverse conversion
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800482 // we may need something like below, due to String only limitation
483// byte[] bytes = serializer.encode(linkid);
484// StringBuilder builder = new StringBuilder(bytes.length * 4);
485// boolean isFirst = true;
486// for (byte b : bytes) {
487// if (!isFirst) {
488// builder.append(',');
489// }
490// builder.append(b);
491// isFirst = false;
492// }
493// return builder.toString();
494 }
495
496// private LinkKey toLinkKey(String linkKey) {
497// String[] bytes = linkKey.split(",");
498// ByteBuffer buf = ByteBuffer.allocate(bytes.length);
499// for (String bs : bytes) {
500// buf.put(Byte.parseByte(bs));
501// }
502// buf.flip();
503// return serializer.decode(buf);
504// }
505
506 private String toIntentDbKey(IntentId intentid) {
507 return intentid.toString();
508 }
509
510 private IntentId toIntentId(String intentid) {
511 checkArgument(intentid.startsWith("0x"));
512 return IntentId.valueOf(Long.parseLong(intentid.substring(2)));
513 }
514
515 private LinkResourceAllocations decodeIntentAllocations(byte[] bytes) {
516 return serializer.decode(bytes);
517 }
518
519 private byte[] encodeIntentAllocations(LinkResourceAllocations alloc) {
520 return serializer.encode(checkNotNull(alloc));
521 }
522
523 private List<LinkResourceAllocations> decodeLinkAllocations(byte[] bytes) {
524 return serializer.decode(bytes);
525 }
526
527 private byte[] encodeLinkAllocations(List<LinkResourceAllocations> alloc) {
528 return serializer.encode(checkNotNull(alloc));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700529 }
530
531 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800532 public List<LinkResourceAllocations> getAllocations(Link link) {
533 checkNotNull(link);
534 final LinkKey key = LinkKey.linkKey(link);
535 final String dbKey = toLinkDbKey(key);
536 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
537 if (vv == null) {
538 // write empty so that all other update can be replace operation
539 byte[] emptyList = encodeLinkAllocations(new ArrayList<>());
540 boolean written = databaseService.putIfAbsent(LINK_RESOURCE_ALLOCATIONS, dbKey, emptyList);
541 log.trace("Empty allocation write success? {}", written);
542 vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
543 if (vv == null) {
544 log.error("Failed to re-read allocation for {}", dbKey);
545 // note: cannot be Collections.emptyList();
546 return new ArrayList<>();
547 }
548 }
549 List<LinkResourceAllocations> allocations = decodeLinkAllocations(vv.value());
550 return allocations;
551 }
552
553 @Override
554 public Iterable<LinkResourceAllocations> getAllocations() {
555 //IntentId -> LinkResourceAllocations
556 Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
557
558 return FluentIterable.from(all.values())
559 .transform(new Function<VersionedValue, LinkResourceAllocations>() {
560
561 @Override
562 public LinkResourceAllocations apply(VersionedValue input) {
563 if (input == null || input.value() == null) {
564 return null;
565 }
566 return decodeIntentAllocations(input.value());
567 }
568 })
569 .filter(notNull());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700570 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700571}