2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.genius.idmanager;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.NoSuchElementException;
17 import java.util.concurrent.ExecutionException;
18 import java.util.concurrent.Future;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutputBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutputBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntriesBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import com.google.common.base.Optional;
58 import com.google.common.util.concurrent.CheckedFuture;
59 import com.google.common.util.concurrent.Futures;
61 public class IdManager implements IdManagerService, AutoCloseable{
62 private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
64 private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
66 private ListenerRegistration<DataChangeListener> listenerRegistration;
67 private final DataBroker broker;
68 private LockManagerService lockManager;
71 public void close() throws Exception {
72 if (listenerRegistration != null) {
74 listenerRegistration.close();
75 } catch (final Exception e) {
76 LOG.error("Error when cleaning up DataChangeListener.", e);
78 listenerRegistration = null;
80 LOG.info("IDManager Closed");
83 public IdManager(final DataBroker db) {
87 public void setLockManager(LockManagerService lockManager) {
88 this.lockManager = lockManager;
92 public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
93 if (LOG.isDebugEnabled()) {
94 LOG.debug("createIdPool called with input {}", input);
96 String poolName = input.getPoolName();
97 long low = input.getLow();
98 long high = input.getHigh();
99 long blockSize = IdUtils.computeBlockSize(low, high);
100 RpcResultBuilder<Void> createIdPoolRpcBuilder;
101 IdUtils.lockPool(lockManager, poolName);
103 WriteTransaction tx = broker.newWriteOnlyTransaction();
104 poolName = poolName.intern();
106 idPool = createGlobalPool(tx, poolName, low, high, blockSize);
107 String localPoolName = IdUtils.getLocalPoolName(poolName);
108 createLocalPool(tx, localPoolName, idPool);
109 submitTransaction(tx);
110 createIdPoolRpcBuilder = RpcResultBuilder.success();
111 } catch (Exception ex) {
112 LOG.error("Creation of Id Pool {} failed due to {}", poolName, ex);
113 createIdPoolRpcBuilder = RpcResultBuilder.failed();
114 createIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
116 IdUtils.unlockPool(lockManager, poolName);
118 return Futures.immediateFuture(createIdPoolRpcBuilder.build());
122 public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
123 if (LOG.isDebugEnabled()) {
124 LOG.debug("AllocateId called with input {}", input);
126 String idKey = input.getIdKey();
127 String poolName = input.getPoolName();
128 String localPoolName = IdUtils.getLocalPoolName(poolName);
129 RpcResultBuilder<AllocateIdOutput> allocateIdRpcBuilder;
130 long newIdValue = -1;
131 AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
133 //allocateIdFromLocalPool method returns a list of IDs with one element. This element is obtatined by get(0)
134 newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey, 1).get(0);
135 output.setIdValue(newIdValue);
136 allocateIdRpcBuilder = RpcResultBuilder.success();
137 allocateIdRpcBuilder.withResult(output.build());
138 } catch (Exception ex) {
139 LOG.error("Allocate id in pool {} failed due to {}", poolName, ex);
140 allocateIdRpcBuilder = RpcResultBuilder.failed();
141 allocateIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
143 return Futures.immediateFuture(allocateIdRpcBuilder.build());
147 public Future<RpcResult<AllocateIdRangeOutput>> allocateIdRange(AllocateIdRangeInput input) {
148 if (LOG.isDebugEnabled()) {
149 LOG.debug("AllocateIdRange called with input {}", input);
151 String idKey = input.getIdKey();
152 String poolName = input.getPoolName();
153 long size = input.getSize();
154 String localPoolName = IdUtils.getLocalPoolName(poolName);
155 RpcResultBuilder<AllocateIdRangeOutput> allocateIdRangeRpcBuilder;
156 List<Long> newIdValuesList = new ArrayList<>();
157 AllocateIdRangeOutputBuilder output = new AllocateIdRangeOutputBuilder();
159 newIdValuesList = allocateIdFromLocalPool(poolName, localPoolName, idKey, size);
160 Collections.sort(newIdValuesList);
161 output.setIdValues(newIdValuesList);
162 allocateIdRangeRpcBuilder = RpcResultBuilder.success();
163 allocateIdRangeRpcBuilder.withResult(output.build());
164 } catch (NullPointerException e){
165 LOG.error("Not enough Ids available in the pool {} for requested size {}", poolName, size);
166 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
167 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, e.getMessage());
168 } catch (Exception ex) {
169 LOG.error("Allocate id range in pool {} failed due to {}", poolName, ex);
170 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
171 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
173 return Futures.immediateFuture(allocateIdRangeRpcBuilder.build());
177 public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
178 if (LOG.isDebugEnabled()) {
179 LOG.debug("DeleteIdPool called with input {}", input);
181 String poolName = input.getPoolName();
182 RpcResultBuilder<Void> deleteIdPoolRpcBuilder;
184 InstanceIdentifier<IdPool> idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName);
185 poolName = poolName.intern();
186 synchronized(poolName) {
187 IdPool idPool = getIdPool(idPoolToBeDeleted);
188 List<ChildPools> childPoolList = idPool.getChildPools();
189 if (childPoolList != null) {
190 for (ChildPools childPoolName : childPoolList) {
191 deletePool(childPoolName.getChildPoolName());
194 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
195 if (LOG.isDebugEnabled()) {
196 LOG.debug("Deleted id pool {}", poolName);
199 deleteIdPoolRpcBuilder = RpcResultBuilder.success();
201 catch (Exception ex) {
202 LOG.error("Delete id in pool {} failed due to {}", poolName, ex);
203 deleteIdPoolRpcBuilder = RpcResultBuilder.failed();
204 deleteIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
206 return Futures.immediateFuture(deleteIdPoolRpcBuilder.build());
210 public Future<RpcResult<Void>> releaseId(ReleaseIdInput input) {
211 String poolName = input.getPoolName();
212 String idKey = input.getIdKey();
213 RpcResultBuilder<Void> releaseIdRpcBuilder;
215 releaseIdFromLocalPool(IdUtils.getLocalPoolName(poolName), idKey);
216 releaseIdRpcBuilder = RpcResultBuilder.success();
217 } catch (Exception ex) {
218 LOG.error("Release id {} from pool {} failed due to {}", idKey, poolName, ex);
219 releaseIdRpcBuilder = RpcResultBuilder.failed();
220 releaseIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
222 return Futures.immediateFuture(releaseIdRpcBuilder.build());
225 private List<Long> allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey, long size) {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName, idKey);
229 long newIdValue = -1;
230 List<Long> newIdValuesList = new ArrayList<>();
231 InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
232 localPoolName = localPoolName.intern();
233 synchronized (localPoolName) {
234 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
235 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
236 List<IdEntries> idEntries = parentIdPool.getIdEntries();
237 if (idEntries == null) {
238 idEntries = new LinkedList<IdEntries>();
240 InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
241 Optional<IdEntries> existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
242 if (existingIdEntry.isPresent()) {
243 newIdValuesList = existingIdEntry.get().getIdValue();
244 if (LOG.isDebugEnabled()) {
245 LOG.debug("Existing ids {} for the key {} ", newIdValuesList, idKey);
247 return newIdValuesList;
250 WriteTransaction tx = broker.newWriteOnlyTransaction();
251 IdPool localPool = null;
253 localPool = getIdPool(localIdPoolInstanceIdentifier);
254 } catch (NoSuchElementException e) {
255 if (LOG.isDebugEnabled()) {
256 LOG.debug("Creating local pool {} since it was not present", localPoolName);
258 localPool = IdUtils.createLocalIdPool(localPoolName, parentIdPool);
259 updateChildPool(tx, localPool.getParentPoolName(), localPoolName);
261 IdEntries newIdEntry;
262 AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool);
263 ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool);
264 //Calling cleanupExcessIds since there could be excessive ids.
265 cleanupExcessIds(availableIds, releasedIds, parentPoolName, localPool.getBlockSize());
267 long totalAvailableIdCount = releasedIds.getAvailableIdCount() + IdUtils.getAvailableIdsCount(availableIds);
268 AvailableIdsHolderBuilder availableParentIds = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
269 ReleasedIdsHolderBuilder releasedParentIds = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
270 totalAvailableIdCount = totalAvailableIdCount + releasedParentIds.getAvailableIdCount()
271 + IdUtils.getAvailableIdsCount(availableParentIds);
272 if (totalAvailableIdCount > size) {
275 newIdValue = getIdFromPool(localPool, availableIds, releasedIds);
276 } catch (RuntimeException e) {
277 if (LOG.isDebugEnabled()) {
278 LOG.debug("Releasing IDs to pool {}", localPoolName);
280 //Releasing the IDs added in newIdValuesList since a null list would be returned now, as the
281 //requested size of list IDs exceeds the number of available IDs.
282 updateDelayedEntries(availableIds, releasedIds, newIdValuesList, parentPoolName,
283 localPool, localIdPoolInstanceIdentifier, tx);
284 if (LOG.isDebugEnabled()) {
285 LOG.debug("Released ids ({}, {}) from local pool {}", idKey, newIdValuesList, localPoolName);
287 submitTransaction(tx);
290 newIdValuesList.add(newIdValue);
296 if (LOG.isDebugEnabled()) {
297 LOG.debug("The newIdValues {} for the idKey {}", newIdValuesList, idKey);
299 newIdEntry = IdUtils.createIdEntries(idKey, newIdValuesList);
300 idEntries.add(newIdEntry);
301 if (LOG.isDebugEnabled()) {
302 LOG.debug("The availablelIds are {}", availableIds.build());
304 localPool = new IdPoolBuilder(localPool).setAvailableIdsHolder(availableIds.build())
305 .setReleasedIdsHolder(releasedIds.build()).build();
306 tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool, true);
307 updateChildPool(tx, localPool.getParentPoolName(), localPoolName);
308 //Updating id entries in the parent pool. This will be used for restart scenario
309 tx.merge(LogicalDatastoreType.CONFIGURATION, IdUtils.getIdEntriesInstanceIdentifier(parentPoolName, idKey), newIdEntry);
310 submitTransaction(tx);
312 return newIdValuesList;
315 private void updateDelayedEntries(AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds,
316 List<Long> idsList, String parentPoolName, IdPool localPool,
317 InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier, WriteTransaction tx){
318 long delayTime = System.currentTimeMillis() / 1000 + releasedIds.getDelayedTimeSec();
319 List<DelayedIdEntries> delayedIdEntries = releasedIds.getDelayedIdEntries();
320 if (delayedIdEntries == null) {
321 delayedIdEntries = new LinkedList<DelayedIdEntries>();
323 for(long idValue : idsList) {
324 DelayedIdEntries delayedIdEntry = IdUtils.createDelayedIdEntry(idValue, delayTime);
325 delayedIdEntries.add(delayedIdEntry);
328 long availableIdCount = releasedIds
329 .getAvailableIdCount() == null ? 0
330 : releasedIds.getAvailableIdCount();
331 releasedIds.setDelayedIdEntries(delayedIdEntries);
332 releasedIds.setAvailableIdCount(availableIdCount);
333 //Calling cleanupExcessIds since there could be excessive ids.
334 cleanupExcessIds(availableIds, releasedIds, parentPoolName, localPool.getBlockSize());
335 localPool = new IdPoolBuilder(localPool)
336 .setAvailableIdsHolder(availableIds.build())
337 .setReleasedIdsHolder(releasedIds.build()).build();
338 tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool, true);
341 private long getIdFromPool(IdPool pool, AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds) {
342 long newIdValue = -1;
344 newIdValue = IdUtils.getIdFromReleaseIdsIfAvailable(releasedIds);
345 if (newIdValue != -1) {
346 if (LOG.isDebugEnabled()) {
347 LOG.debug("Retrieved id value {} from released id holder", newIdValue);
351 newIdValue = IdUtils.getIdFromAvailableIds(availableIds);
352 if (newIdValue != -1) {
353 if (LOG.isDebugEnabled()) {
354 LOG.debug("Creating a new id {} for the pool: {} ", newIdValue, pool.getPoolName());
358 long idCount = getIdBlockFromParentPool(pool.getParentPoolName(), availableIds, releasedIds);
360 if (LOG.isDebugEnabled()) {
361 LOG.debug("Unable to allocate Id block from global pool");
363 throw new RuntimeException(String.format("Ids exhausted for pool : %s", pool.getPoolName()));
369 * Changes made to releaseIds and AvailableIds are not persisted.
370 * @param availableIds
372 * @param parentPoolName
375 private void cleanupExcessIds(AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds, String parentPoolName, int blockSize) {
376 IdUtils.processDelayList(releasedIds);
377 long totalAvailableIdCount = releasedIds.getAvailableIdCount() + IdUtils.getAvailableIdsCount(availableIds);
378 if (totalAvailableIdCount > blockSize * 2) {
379 parentPoolName = parentPoolName.intern();
380 InstanceIdentifier<ReleasedIdsHolder> releasedIdInstanceIdentifier = IdUtils.getReleasedIdsHolderInstance(parentPoolName);
381 IdUtils.lockPool(lockManager, parentPoolName);
383 Optional<ReleasedIdsHolder> releasedIdsHolder = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier);
384 ReleasedIdsHolderBuilder releasedIdsParent;
385 if (!releasedIdsHolder.isPresent()) {
386 LOG.error("ReleasedIds not present in parent pool. Unable to cleanup excess ids");
389 releasedIdsParent = new ReleasedIdsHolderBuilder(releasedIdsHolder.get());
390 if (LOG.isDebugEnabled()) {
391 LOG.debug("Releasing excesss Ids from local pool");
393 IdUtils.freeExcessAvailableIds(releasedIds, releasedIdsParent, blockSize);
394 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier, releasedIdsParent.build());
396 IdUtils.unlockPool(lockManager, parentPoolName);
402 * Changes made to availableIds and releasedIds will not be persisted to the datastore
403 * @param parentPoolName
404 * @param availableIdsBuilder
405 * @param releasedIdsBuilder
408 private long getIdBlockFromParentPool(String parentPoolName,
409 AvailableIdsHolderBuilder availableIdsBuilder, ReleasedIdsHolderBuilder releasedIdsBuilder) {
410 if (LOG.isDebugEnabled()) {
411 LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
413 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
414 parentPoolName = parentPoolName.intern();
415 IdUtils.lockPool(lockManager, parentPoolName);
417 WriteTransaction tx = broker.newWriteOnlyTransaction();
418 IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier);
419 long idCount = allocateIdBlockFromParentPool(availableIdsBuilder, releasedIdsBuilder, parentIdPool, tx);
420 submitTransaction(tx);
424 IdUtils.unlockPool(lockManager, parentPoolName);
429 * Changes made to availableIds and releasedIds will not be persisted to the datastore
430 * @param parentPoolName
431 * @param availableIdsBuilder
432 * @param releasedIdsBuilder
435 private long allocateIdBlockFromParentPool(AvailableIdsHolderBuilder availableIdsBuilder,
436 ReleasedIdsHolderBuilder releasedIdsBuilder, IdPool parentIdPool, WriteTransaction tx) {
438 ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
440 idCount = allocateIdBlockFromReleasedIdsHolder(releasedIdsBuilder, releasedIdsBuilderParent, parentIdPool, tx);
444 idCount = allocateIdBlockFromAvailableIdsHolder(availableIdsBuilder, parentIdPool, tx);
448 idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
450 if (LOG.isDebugEnabled()) {
451 LOG.debug("Unable to allocate Id block from global pool");
453 throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentIdPool.getPoolName()));
458 private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
459 List<ChildPools> childPoolsList = parentIdPool.getChildPools();
460 // Sorting the child pools on last accessed time so that the pool that was not accessed for a long time comes first.
461 Collections.sort(childPoolsList, new Comparator<ChildPools>() {
463 public int compare(ChildPools childPool1, ChildPools childPool2) {
464 return childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime());
467 long currentTime = System.currentTimeMillis() / 1000;
468 for (ChildPools childPools : childPoolsList) {
469 if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME < currentTime) {
472 if (!childPools.getChildPoolName().equals(IdUtils.getLocalPoolName(parentIdPool.getPoolName()))) {
473 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(childPools.getChildPoolName());
474 IdPool otherChildPool = getIdPool(idPoolInstanceIdentifier);
475 ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(otherChildPool);
476 AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(otherChildPool);
477 long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size() + IdUtils.getAvailableIdsCount(availableIds);
478 List<DelayedIdEntries> delayedIdEntriesChild = releasedIds.getDelayedIdEntries();
479 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
480 if (delayedIdEntriesParent == null) {
481 delayedIdEntriesParent = new LinkedList<>();
483 delayedIdEntriesParent.addAll(delayedIdEntriesChild);
484 delayedIdEntriesChild.removeAll(delayedIdEntriesChild);
485 while (IdUtils.isIdAvailable(availableIds)) {
486 long cursor = availableIds.getCursor() + 1;
487 delayedIdEntriesParent.add(new DelayedIdEntriesBuilder().setId(cursor).setReadyTimeSec(System.currentTimeMillis()).build());
488 availableIds.setCursor(cursor);
490 long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount;
491 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count);
492 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier,
493 new IdPoolBuilder(otherChildPool).setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build());
494 return totalAvailableIdCount;
500 private long allocateIdBlockFromReleasedIdsHolder(ReleasedIdsHolderBuilder releasedIdsBuilderChild, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool, WriteTransaction tx) {
501 if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
502 if (LOG.isDebugEnabled()) {
503 LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
507 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
508 List<DelayedIdEntries> delayedIdEntriesChild = releasedIdsBuilderChild.getDelayedIdEntries();
509 if (delayedIdEntriesChild == null) {
510 delayedIdEntriesChild = new LinkedList<DelayedIdEntries>();
512 int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize());
513 List<DelayedIdEntries> idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount);
514 delayedIdEntriesChild.addAll(0, idEntriesToBeRemoved);
515 delayedIdEntriesParent.removeAll(idEntriesToBeRemoved);
516 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent);
517 releasedIdsBuilderChild.setDelayedIdEntries(delayedIdEntriesChild);
518 releasedIdsBuilderChild.setAvailableIdCount(releasedIdsBuilderChild.getAvailableIdCount() + idCount);
519 InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
520 .builder(IdPools.class).child(IdPool.class,
521 new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build();
522 releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount);
523 if (LOG.isDebugEnabled()) {
524 LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
526 tx.merge(LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIdsBuilderParent.build(), true);
530 private long allocateIdBlockFromAvailableIdsHolder(AvailableIdsHolderBuilder availableIdsBuilder, IdPool parentIdPool, WriteTransaction tx) {
532 AvailableIdsHolderBuilder availableIdsBuilderParent = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
533 long end = availableIdsBuilderParent.getEnd();
534 long cur = availableIdsBuilderParent.getCursor();
535 if (!IdUtils.isIdAvailable(availableIdsBuilderParent)) {
536 if (LOG.isDebugEnabled()) {
537 LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
541 // Update availableIdsHolder of Local Pool
542 availableIdsBuilder.setStart(cur + 1);
543 idCount = Math.min(end - cur, parentIdPool.getBlockSize());
544 availableIdsBuilder.setEnd(cur + idCount);
545 availableIdsBuilder.setCursor(cur);
546 // Update availableIdsHolder of Global Pool
547 InstanceIdentifier<AvailableIdsHolder> availableIdsHolderInstanceIdentifier = InstanceIdentifier
548 .builder(IdPools.class).child(IdPool.class,
549 new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build();
550 availableIdsBuilderParent.setCursor(cur + idCount);
551 if (LOG.isDebugEnabled()) {
552 LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
554 tx.merge(LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier, availableIdsBuilderParent.build(), true);
558 private void releaseIdFromLocalPool(String poolName, String idKey) {
559 InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
560 poolName = poolName.intern();
561 synchronized (poolName) {
562 IdPool localPool = getIdPool(localIdPoolInstanceIdentifier);
563 String parentPoolName = localPool.getParentPoolName();
564 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
565 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
566 List<IdEntries> idEntries = parentIdPool.getIdEntries();
567 List<IdEntries> newIdEntries = idEntries;
568 if (idEntries == null) {
569 throw new RuntimeException("Id Entries does not exist");
571 InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
572 Optional<IdEntries> existingIdEntryObject = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
573 if (!existingIdEntryObject.isPresent()) {
574 throw new RuntimeException(String.format("Specified Id key %s does not exist in id pool %s", idKey, poolName));
576 IdEntries existingIdEntry = existingIdEntryObject.get();
577 List<Long> idValuesList = existingIdEntry.getIdValue();
578 boolean isRemoved = newIdEntries.remove(existingIdEntry);
579 if (LOG.isDebugEnabled()) {
580 LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved);
582 ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool);
583 AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool);
584 WriteTransaction tx = broker.newWriteOnlyTransaction();
585 updateDelayedEntries(availableIds, releasedIds, idValuesList, parentPoolName,
586 localPool, localIdPoolInstanceIdentifier, tx);
587 if (LOG.isDebugEnabled()) {
588 LOG.debug("Released ids ({}, {}) from pool {}", idKey, idValuesList, poolName);
590 //Updating id entries in the parent pool. This will be used for restart scenario
591 tx.delete(LogicalDatastoreType.CONFIGURATION, IdUtils.getIdEntriesInstanceIdentifier(parentPoolName, idKey));
592 submitTransaction(tx);
596 private IdPool createGlobalPool(WriteTransaction tx, String poolName, long low, long high,
599 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
600 Optional<IdPool> existingIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
601 if (!existingIdPool.isPresent()) {
602 if (LOG.isDebugEnabled()) {
603 LOG.debug("Creating new global pool {}", poolName);
605 idPool = IdUtils.createGlobalPool(poolName, low, high, blockSize);
606 tx.put(LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool, true);
609 idPool = existingIdPool.get();
610 if (LOG.isDebugEnabled()) {
611 LOG.debug("GlobalPool exists {}", idPool);
617 private boolean createLocalPool(WriteTransaction tx, String localPoolName, IdPool idPool) {
618 localPoolName = localPoolName.intern();
619 synchronized (localPoolName) {
620 InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
621 Optional<IdPool> localIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier);
622 if (!localIdPool.isPresent()) {
623 if (LOG.isDebugEnabled()) {
624 LOG.debug("Creating new local pool");
626 IdPool newLocalIdPool = IdUtils.createLocalIdPool(localPoolName, idPool);
627 ReleasedIdsHolderBuilder releasedIdsBuilder = IdUtils.getReleaseIdsHolderBuilder(newLocalIdPool);
628 AvailableIdsHolderBuilder availableIdsBuilder = IdUtils.getAvailableIdsHolderBuilder(newLocalIdPool);
629 allocateIdBlockFromParentPool(availableIdsBuilder, releasedIdsBuilder, idPool, tx);
630 newLocalIdPool = new IdPoolBuilder(newLocalIdPool).setAvailableIdsHolder(availableIdsBuilder.build())
631 .setReleasedIdsHolder(releasedIdsBuilder.build()).build();
632 tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, newLocalIdPool, true);
633 updateChildPool(tx, idPool.getPoolName(), localPoolName);
634 if (LOG.isDebugEnabled()) {
635 LOG.debug("Local pool created {}", newLocalIdPool);
643 private void deletePool(String poolName) {
644 InstanceIdentifier<IdPool> idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName);
645 synchronized (poolName) {
646 Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
647 if (idPool.isPresent()) {
648 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
649 if (LOG.isDebugEnabled()) {
650 LOG.debug("Deleted local pool {}", poolName);
656 private IdPool getIdPool(InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
657 Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
658 if (!idPool.isPresent()) {
659 throw new NoSuchElementException(String.format("Specified pool %s does not exist" , idPool));
661 if (LOG.isDebugEnabled()) {
662 LOG.debug("GetIdPool : Read id pool {} ", idPool);
667 private void updateChildPool(WriteTransaction tx, String poolName, String localPoolName) {
668 ChildPools childPool = IdUtils.createChildPool(localPoolName);
669 InstanceIdentifier<ChildPools> childPoolInstanceIdentifier = IdUtils.getChildPoolsInstanceIdentifier(poolName, localPoolName);
670 tx.merge(LogicalDatastoreType.CONFIGURATION, childPoolInstanceIdentifier, childPool, true);
674 private void submitTransaction(WriteTransaction tx) {
675 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
678 } catch (InterruptedException | ExecutionException e) {
679 LOG.error("Error writing to datastore tx", tx);
680 throw new RuntimeException(e.getMessage());