blob: 2835c152df67b0b0d2f042d51957c6e3ff20f7df [file] [log] [blame]
Brian O'Connor41718fc2014-10-30 16:57:21 -07001/*
Ray Milkey9a39eca2015-01-05 09:41:01 -08002 * Copyright 2014-2015 Open Networking Laboratory
Brian O'Connor41718fc2014-10-30 16:57:21 -07003 *
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;
Ray Milkey9a39eca2015-01-05 09:41:01 -080032import org.onlab.util.PositionalParameterStringFormatter;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.AnnotationKeys;
34import org.onosproject.net.Link;
35import org.onosproject.net.LinkKey;
36import org.onosproject.net.intent.IntentId;
37import org.onosproject.net.link.LinkService;
38import org.onosproject.net.resource.Bandwidth;
39import org.onosproject.net.resource.BandwidthResourceAllocation;
40import org.onosproject.net.resource.Lambda;
41import org.onosproject.net.resource.LambdaResourceAllocation;
42import org.onosproject.net.resource.LinkResourceAllocations;
43import org.onosproject.net.resource.LinkResourceEvent;
44import org.onosproject.net.resource.LinkResourceStore;
45import org.onosproject.net.resource.ResourceAllocation;
Ray Milkey9a39eca2015-01-05 09:41:01 -080046import org.onosproject.net.resource.ResourceAllocationException;
Brian O'Connorabafb502014-12-02 22:26:20 -080047import org.onosproject.net.resource.ResourceType;
48import org.onosproject.store.serializers.KryoSerializer;
49import org.onosproject.store.serializers.StoreSerializer;
50import org.onosproject.store.service.BatchWriteRequest;
51import org.onosproject.store.service.BatchWriteRequest.Builder;
52import org.onosproject.store.service.BatchWriteResult;
53import org.onosproject.store.service.DatabaseAdminService;
54import org.onosproject.store.service.DatabaseException;
55import org.onosproject.store.service.DatabaseService;
56import org.onosproject.store.service.VersionedValue;
57import org.onosproject.store.service.WriteRequest;
58import org.onosproject.store.service.WriteResult;
Brian O'Connor41718fc2014-10-30 16:57:21 -070059import org.slf4j.Logger;
60
Yuta HIGUCHI35242292014-11-12 18:53:15 -080061import com.google.common.base.Function;
62import com.google.common.collect.FluentIterable;
Ray Milkeye97ede92014-11-20 10:43:12 -080063import com.google.common.collect.ImmutableList;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080064import com.google.common.collect.ImmutableSet;
65import com.google.common.collect.Sets;
66
Yuta HIGUCHI35242292014-11-12 18:53:15 -080067import static com.google.common.base.Preconditions.checkArgument;
Brian O'Connor41718fc2014-10-30 16:57:21 -070068import static com.google.common.base.Preconditions.checkNotNull;
69import static com.google.common.base.Preconditions.checkState;
Yuta HIGUCHI35242292014-11-12 18:53:15 -080070import static com.google.common.base.Predicates.notNull;
71import static org.onlab.util.HexString.toHexString;
Brian O'Connor41718fc2014-10-30 16:57:21 -070072import static org.slf4j.LoggerFactory.getLogger;
73
74/**
Yuta HIGUCHI35242292014-11-12 18:53:15 -080075 * Manages link resources using database service.
Brian O'Connor41718fc2014-10-30 16:57:21 -070076 */
Yuta HIGUCHI9b108b32014-12-01 11:10:26 -080077@Component(immediate = true, enabled = false)
Brian O'Connor41718fc2014-10-30 16:57:21 -070078@Service
79public class DistributedLinkResourceStore implements LinkResourceStore {
Yuta HIGUCHI35242292014-11-12 18:53:15 -080080
Brian O'Connor41718fc2014-10-30 16:57:21 -070081 private final Logger log = getLogger(getClass());
Yuta HIGUCHI35242292014-11-12 18:53:15 -080082
Yuta HIGUCHI35242292014-11-12 18:53:15 -080083 private static final Bandwidth DEFAULT_BANDWIDTH = Bandwidth.valueOf(1_000);
84
85 // table to store current allocations
86 /** LinkKey -> List<LinkResourceAllocations>. */
87 private static final String LINK_RESOURCE_ALLOCATIONS = "LinkResourceAllocations";
88
89 /** IntentId -> LinkResourceAllocations. */
90 private static final String INTENT_ALLOCATIONS = "IntentAllocations";
91
92 private static final Bandwidth EMPTY_BW = Bandwidth.valueOf(0);
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DatabaseAdminService databaseAdminService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected DatabaseService databaseService;
99
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected LinkService linkService;
102
103 // Link annotation key name to use as bandwidth
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800104 private String bandwidthAnnotation = AnnotationKeys.BANDWIDTH;
Ray Milkeye97ede92014-11-20 10:43:12 -0800105 // Link annotation key name to use as max lambda
Yuta HIGUCHIbf366d52014-12-02 12:57:22 -0800106 private String wavesAnnotation = AnnotationKeys.OPTICAL_WAVES;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800107
108 private StoreSerializer serializer;
109
Brian O'Connor41718fc2014-10-30 16:57:21 -0700110
Yuta HIGUCHI45e5cd12014-11-24 14:57:13 -0800111 void createTable(String tableName) {
112 boolean tableReady = false;
113 do {
114 try {
115 if (!databaseAdminService.listTables().contains(tableName)) {
116 databaseAdminService.createTable(tableName);
117 }
118 tableReady = true;
119 } catch (DatabaseException e) {
120 log.debug("Failed creating table, retrying", e);
121 try {
122 Thread.sleep(200);
123 } catch (InterruptedException e1) {
124 throw new DatabaseException(e1);
125 }
126 }
127 } while (!tableReady);
128 }
129
Brian O'Connor41718fc2014-10-30 16:57:21 -0700130 @Activate
131 public void activate() {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800132
133 serializer = new KryoSerializer();
134
Yuta HIGUCHI45e5cd12014-11-24 14:57:13 -0800135 createTable(LINK_RESOURCE_ALLOCATIONS);
136 createTable(INTENT_ALLOCATIONS);
Yuta HIGUCHI2fe63342014-11-17 21:33:38 -0800137
Brian O'Connor41718fc2014-10-30 16:57:21 -0700138 log.info("Started");
139 }
140
141 @Deactivate
142 public void deactivate() {
143 log.info("Stopped");
144 }
145
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800146 private Set<? extends ResourceAllocation> getResourceCapacity(ResourceType type, Link link) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800147 if (type == ResourceType.BANDWIDTH) {
148 return ImmutableSet.of(getBandwidthResourceCapacity(link));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700149 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800150 if (type == ResourceType.LAMBDA) {
151 return getLambdaResourceCapacity(link);
152 }
153 return null;
154 }
155
156 private Set<LambdaResourceAllocation> getLambdaResourceCapacity(Link link) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800157 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 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800325 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();
Ray Milkey9a39eca2015-01-05 09:41:01 -0800389 BandwidthResourceAllocation bwReq = ((BandwidthResourceAllocation) req);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800390 if (bwLeft < 0) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800391 throw new ResourceAllocationException(
392 PositionalParameterStringFormatter.format(
393 "Unable to allocate bandwidth for link {} "
394 + " requested amount is {} current allocation is {}",
395 link,
396 bwReq.bandwidth().toDouble(),
397 bw));
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800398 }
399 } else if (req instanceof LambdaResourceAllocation) {
Ray Milkey9a39eca2015-01-05 09:41:01 -0800400 final LambdaResourceAllocation lambdaAllocation = (LambdaResourceAllocation) req;
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800401 // check if allocation should be accepted
402 if (!avail.contains(req)) {
403 // requested lambda was not available
Ray Milkey9a39eca2015-01-05 09:41:01 -0800404 throw new ResourceAllocationException(
405 PositionalParameterStringFormatter.format(
Sho SHIMIZU2b2e6812015-01-21 10:50:36 -0800406 "Unable to allocate lambda for link {} lambda is {}",
Ray Milkey9a39eca2015-01-05 09:41:01 -0800407 link,
408 lambdaAllocation.lambda().toInt()));
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800409 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700410 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700411 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800412 // all requests allocatable => add allocation
413 final List<LinkResourceAllocations> before = getAllocations(link);
414 List<LinkResourceAllocations> after = new ArrayList<>(before.size());
415 after.addAll(before);
416 after.add(allocations);
417 replaceLinkAllocations(builder, LinkKey.linkKey(link), before, after);
418 return builder;
419 }
420
421 private Builder replaceLinkAllocations(Builder builder, LinkKey linkKey,
422 List<LinkResourceAllocations> before,
423 List<LinkResourceAllocations> after) {
424
425 byte[] oldValue = encodeLinkAllocations(before);
426 byte[] newValue = encodeLinkAllocations(after);
427 builder.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, toLinkDbKey(linkKey), oldValue, newValue);
428 return builder;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700429 }
430
431 @Override
Ray Milkeye97ede92014-11-20 10:43:12 -0800432 public LinkResourceEvent releaseResources(LinkResourceAllocations allocations) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700433 checkNotNull(allocations);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800434
435 final IntentId intendId = allocations.intendId();
436 final String dbIntentId = toIntentDbKey(intendId);
437 final Collection<Link> links = allocations.links();
438
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800439 boolean success;
440 do {
441 Builder tx = BatchWriteRequest.newBuilder();
442
443 // TODO: Should IntentId -> Allocation be updated conditionally?
444 tx.remove(INTENT_ALLOCATIONS, dbIntentId);
445
446 for (Link link : links) {
447 final LinkKey linkId = LinkKey.linkKey(link);
448 final String dbLinkId = toLinkDbKey(linkId);
449 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbLinkId);
450 if (vv == null || vv.value() == null) {
451 // something is wrong, but it is already freed
452 log.warn("There was no resource left to release on {}", linkId);
453 continue;
454 }
455 List<LinkResourceAllocations> before = decodeLinkAllocations(vv.value());
456 List<LinkResourceAllocations> after = new ArrayList<>(before);
457 after.remove(allocations);
458 byte[] oldValue = encodeLinkAllocations(before);
459 byte[] newValue = encodeLinkAllocations(after);
460 tx.putIfValueMatches(LINK_RESOURCE_ALLOCATIONS, dbLinkId, oldValue, newValue);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700461 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800462
463 BatchWriteResult batchWrite = databaseService.batchWrite(tx.build());
464 success = batchWrite.isSuccessful();
465 } while (!success);
Ray Milkeye97ede92014-11-20 10:43:12 -0800466
467 // Issue events to force recompilation of intents.
468
469 final List<LinkResourceAllocations> releasedResources =
470 ImmutableList.of(allocations);
471 return new LinkResourceEvent(
472 LinkResourceEvent.Type.ADDITIONAL_RESOURCES_AVAILABLE,
473 releasedResources);
Brian O'Connor41718fc2014-10-30 16:57:21 -0700474 }
475
476 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800477 public LinkResourceAllocations getAllocations(IntentId intentId) {
Brian O'Connor41718fc2014-10-30 16:57:21 -0700478 checkNotNull(intentId);
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800479 VersionedValue vv = databaseService.get(INTENT_ALLOCATIONS, toIntentDbKey(intentId));
480 if (vv == null) {
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800481 return null;
Brian O'Connor41718fc2014-10-30 16:57:21 -0700482 }
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800483 LinkResourceAllocations allocations = decodeIntentAllocations(vv.value());
484 return allocations;
485 }
486
487 private String toLinkDbKey(LinkKey linkid) {
488 // introduce cache if necessary
489 return linkid.toString();
Yuta HIGUCHI65934892014-12-04 17:47:44 -0800490 // Note: Above is irreversible, if we need reverse conversion
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800491 // we may need something like below, due to String only limitation
492// byte[] bytes = serializer.encode(linkid);
493// StringBuilder builder = new StringBuilder(bytes.length * 4);
494// boolean isFirst = true;
495// for (byte b : bytes) {
496// if (!isFirst) {
497// builder.append(',');
498// }
499// builder.append(b);
500// isFirst = false;
501// }
502// return builder.toString();
503 }
504
505// private LinkKey toLinkKey(String linkKey) {
506// String[] bytes = linkKey.split(",");
507// ByteBuffer buf = ByteBuffer.allocate(bytes.length);
508// for (String bs : bytes) {
509// buf.put(Byte.parseByte(bs));
510// }
511// buf.flip();
512// return serializer.decode(buf);
513// }
514
515 private String toIntentDbKey(IntentId intentid) {
516 return intentid.toString();
517 }
518
519 private IntentId toIntentId(String intentid) {
520 checkArgument(intentid.startsWith("0x"));
521 return IntentId.valueOf(Long.parseLong(intentid.substring(2)));
522 }
523
524 private LinkResourceAllocations decodeIntentAllocations(byte[] bytes) {
525 return serializer.decode(bytes);
526 }
527
528 private byte[] encodeIntentAllocations(LinkResourceAllocations alloc) {
529 return serializer.encode(checkNotNull(alloc));
530 }
531
532 private List<LinkResourceAllocations> decodeLinkAllocations(byte[] bytes) {
533 return serializer.decode(bytes);
534 }
535
536 private byte[] encodeLinkAllocations(List<LinkResourceAllocations> alloc) {
537 return serializer.encode(checkNotNull(alloc));
Brian O'Connor41718fc2014-10-30 16:57:21 -0700538 }
539
540 @Override
Yuta HIGUCHI35242292014-11-12 18:53:15 -0800541 public List<LinkResourceAllocations> getAllocations(Link link) {
542 checkNotNull(link);
543 final LinkKey key = LinkKey.linkKey(link);
544 final String dbKey = toLinkDbKey(key);
545 VersionedValue vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
546 if (vv == null) {
547 // write empty so that all other update can be replace operation
548 byte[] emptyList = encodeLinkAllocations(new ArrayList<>());
549 boolean written = databaseService.putIfAbsent(LINK_RESOURCE_ALLOCATIONS, dbKey, emptyList);
550 log.trace("Empty allocation write success? {}", written);
551 vv = databaseService.get(LINK_RESOURCE_ALLOCATIONS, dbKey);
552 if (vv == null) {
553 log.error("Failed to re-read allocation for {}", dbKey);
554 // note: cannot be Collections.emptyList();
555 return new ArrayList<>();
556 }
557 }
558 List<LinkResourceAllocations> allocations = decodeLinkAllocations(vv.value());
559 return allocations;
560 }
561
562 @Override
563 public Iterable<LinkResourceAllocations> getAllocations() {
564 //IntentId -> LinkResourceAllocations
565 Map<String, VersionedValue> all = databaseService.getAll(INTENT_ALLOCATIONS);
566
567 return FluentIterable.from(all.values())
568 .transform(new Function<VersionedValue, LinkResourceAllocations>() {
569
570 @Override
571 public LinkResourceAllocations apply(VersionedValue input) {
572 if (input == null || input.value() == null) {
573 return null;
574 }
575 return decodeIntentAllocations(input.value());
576 }
577 })
578 .filter(notNull());
Brian O'Connor41718fc2014-10-30 16:57:21 -0700579 }
Brian O'Connor41718fc2014-10-30 16:57:21 -0700580}