X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=idmanager%2Fidmanager-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fidmanager%2FIdManager.java;h=f3251e38477c710b48fcf72e40a6846fd93e563d;hb=HEAD;hp=a57086a42cab68bf2dbe15c6c5061c7414b09ac5;hpb=42c322817cb799810b82212370b23ee92d866294;p=vpnservice.git diff --git a/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java b/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java index a57086a4..f3251e38 100644 --- a/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java +++ b/idmanager/idmanager-impl/src/main/java/org/opendaylight/idmanager/IdManager.java @@ -8,37 +8,56 @@ package org.opendaylight.idmanager; -import com.google.common.base.Optional; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.concurrent.Future; + import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; -import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; -import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.mdsalutil.MDSALUtil; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.DeleteIdPoolInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.AvailableIdsHolder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.AvailableIdsHolderBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ChildPools; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.IdEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ReleasedIdsHolder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ReleasedIdsHolderBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.released.ids.DelayedIdEntries; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.released.ids.DelayedIdEntriesBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService; import org.opendaylight.yangtools.concepts.ListenerRegistration; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcError.ErrorType; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.*; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.pools.*; -import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.pools.id.pool.*; - -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.Future; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; public class IdManager implements IdManagerService, AutoCloseable{ private static final Logger LOG = LoggerFactory.getLogger(IdManager.class); - private ListenerRegistration listenerRegistration; - private final DataBroker broker; + private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60; + private ListenerRegistration listenerRegistration; + private final DataBroker broker; + private LockManagerService lockManager; @Override public void close() throws Exception { @@ -57,146 +76,468 @@ public class IdManager implements IdManagerService, AutoCloseable{ broker = db; } - private Optional read(LogicalDatastoreType datastoreType, - InstanceIdentifier path) { - - ReadOnlyTransaction tx = broker.newReadOnlyTransaction(); + public void setLockManager(LockManagerService lockManager) { + this.lockManager = lockManager; + } - Optional result = Optional.absent(); + @Override + public Future> createIdPool(CreateIdPoolInput input) { + LOG.debug("createIdPool called with input {}", input); + String poolName = input.getPoolName(); + long low = input.getLow(); + long high = input.getHigh(); + long blockSize = IdUtils.computeBlockSize(low, high); + RpcResultBuilder createIdPoolRpcBuilder; + IdUtils.lockPool(lockManager, poolName); try { - result = tx.read(datastoreType, path).get(); - } catch (Exception e) { - throw new RuntimeException(e); + InstanceIdentifier idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName); + poolName = poolName.intern(); + IdPool idPool; + idPool = createGlobalPool(poolName, low, high, blockSize, idPoolInstanceIdentifier); + String localPoolName = IdUtils.getLocalPoolName(poolName); + if (createLocalPool(localPoolName, idPool)) { + LOG.debug("Updating global id pool {} with childPool {}", poolName, localPoolName); + updateChildPool(poolName, localPoolName); + } + createIdPoolRpcBuilder = RpcResultBuilder.success(); + } catch (Exception ex) { + LOG.error("Creation of Id Pool {} failed due to {}", poolName, ex); + createIdPoolRpcBuilder = RpcResultBuilder.failed(); + createIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage()); + } finally { + IdUtils.unlockPool(lockManager, poolName); } - - return result; + return Futures.immediateFuture(createIdPoolRpcBuilder.build()); } - protected void asyncWrite(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.put(datastoreType, path, data, true); - Futures.addCallback(tx.submit(), callback); - } - - protected void asyncUpdate(LogicalDatastoreType datastoreType, - InstanceIdentifier path, T data, FutureCallback callback) { - WriteTransaction tx = broker.newWriteOnlyTransaction(); - tx.merge(datastoreType, path, data, true); - Futures.addCallback(tx.submit(), callback); + @Override + public Future> allocateId(AllocateIdInput input) { + LOG.debug("AllocateId called with input {}", input); + String idKey = input.getIdKey(); + String poolName = input.getPoolName(); + String localPoolName = IdUtils.getLocalPoolName(poolName); + RpcResultBuilder allocateIdRpcBuilder; + long newIdValue = -1; + AllocateIdOutputBuilder output = new AllocateIdOutputBuilder(); + try { + newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey); + output.setIdValue(newIdValue); + allocateIdRpcBuilder = RpcResultBuilder.success(); + allocateIdRpcBuilder.withResult(output.build()); + } catch (Exception ex) { + LOG.error("Allocate id in pool {} failed due to {}", poolName, ex); + allocateIdRpcBuilder = RpcResultBuilder.failed(); + allocateIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage()); + } + return Futures.immediateFuture(allocateIdRpcBuilder.build()); } @Override - public Future> createIdPool(CreateIdPoolInput input) - { - + public Future> deleteIdPool(DeleteIdPoolInput input) { + LOG.debug("DeleteIdPool called with input {}", input); String poolName = input.getPoolName(); - long startIndx = input.getIdStart(); - long poolSize = input.getPoolSize().longValue(); - RpcResultBuilder rpcResultBuilder; - - LOG.debug("poolName: {}, startIndx: {} , poolSize: {} ", poolName, startIndx, poolSize); - + RpcResultBuilder deleteIdPoolRpcBuilder; try { - InstanceIdentifier.InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(Pools.class).child(IdPool.class, new IdPoolKey(poolName)); - InstanceIdentifier id = idBuilder.build(); - Optional pool = read(LogicalDatastoreType.OPERATIONAL, id); - if (!pool.isPresent()) { - LOG.debug("Creating a new global pool: {} ", poolName); - IdPool newPool = getPoolInterface(poolName, startIndx, poolSize); - LOG.debug("NewPool: {}", newPool); - asyncWrite(LogicalDatastoreType.OPERATIONAL, id, newPool, DEFAULT_CALLBACK); - + InstanceIdentifier idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName); + poolName = poolName.intern(); + synchronized(poolName) { + IdPool idPool = getIdPool(idPoolToBeDeleted); + List childPoolList = idPool.getChildPools(); + if (childPoolList != null) { + for (ChildPools childPoolName : childPoolList) { + deletePool(childPoolName.getChildPoolName()); + } + } + MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted); + LOG.debug("Deleted id pool {}", poolName); } - - rpcResultBuilder = RpcResultBuilder.success(); + deleteIdPoolRpcBuilder = RpcResultBuilder.success(); } - catch(Exception e){ - LOG.error("Creation of global pool {} failed due to {}" ,poolName, e); - rpcResultBuilder = RpcResultBuilder.failed(); + catch (Exception ex) { + LOG.error("Delete id in pool {} failed due to {}", poolName, ex); + deleteIdPoolRpcBuilder = RpcResultBuilder.failed(); + deleteIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage()); } - - return Futures.immediateFuture(rpcResultBuilder.build()); + return Futures.immediateFuture(deleteIdPoolRpcBuilder.build()); } - @Override - public Future> getUniqueId(GetUniqueIdInput input){ - + public Future> releaseId(ReleaseIdInput input) { String poolName = input.getPoolName(); String idKey = input.getIdKey(); + RpcResultBuilder releaseIdRpcBuilder; + try { + releaseIdFromLocalPool(IdUtils.getLocalPoolName(poolName), idKey); + releaseIdRpcBuilder = RpcResultBuilder.success(); + } catch (Exception ex) { + LOG.error("Release id {} from pool {} failed due to {}", idKey, poolName, ex); + releaseIdRpcBuilder = RpcResultBuilder.failed(); + releaseIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage()); + } + return Futures.immediateFuture(releaseIdRpcBuilder.build()); + } + + private long allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey) { + LOG.trace("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName, idKey); + long newIdValue = -1; + InstanceIdentifier localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName); + localPoolName = localPoolName.intern(); + synchronized (localPoolName) { + InstanceIdentifier parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName); + IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier); + IdPool localPool = null; + try { + localPool = getIdPool(localIdPoolInstanceIdentifier); + } catch (NoSuchElementException e){ + LOG.trace("Creating local pool {} since it was not present", localPoolName); + localPool = IdUtils.createLocalIdPool(localPoolName, parentIdPool); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool); + IdUtils.lockPool(lockManager, parentPoolName); + try { + updateChildPool(parentPoolName, localPoolName); + } finally { + IdUtils.unlockPool(lockManager, parentPoolName); + } + LOG.debug("Updating global id pool {} with childPool {}", parentPoolName, localPoolName); + } + IdEntries newIdEntry; + List idEntries = parentIdPool.getIdEntries(); + AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool); + ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool); + //Calling cleanupExcessIds since there could be excessive ids. + cleanupExcessIds(availableIds, releasedIds, parentPoolName, localPool.getBlockSize()); + if (idEntries == null) { + idEntries = new LinkedList(); + } else { + InstanceIdentifier existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey); + Optional existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId); + if (existingIdEntry.isPresent()) { + newIdValue = existingIdEntry.get().getIdValue(); + LOG.debug("Existing id {} for the key {} ", idKey, newIdValue); + InstanceIdentifier releasedIdsHolderInstanceIdentifier = InstanceIdentifier + .builder(IdPools.class).child(IdPool.class, new IdPoolKey(localPoolName)).child(ReleasedIdsHolder.class).build(); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIds.build()); + return newIdValue; + } + } + newIdValue = getIdFromPool(localPool, availableIds, releasedIds); + LOG.debug("The newIdValue {} for the idKey {}", newIdValue, idKey); + newIdEntry = IdUtils.createIdEntries(idKey, newIdValue); + idEntries.add(newIdEntry); + LOG.debug("The availablelIds are {}", availableIds.build()); + localPool = new IdPoolBuilder(localPool).setAvailableIdsHolder(availableIds.build()) + .setReleasedIdsHolder(releasedIds.build()).build(); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool); + updateChildPool(localPool.getParentPoolName(), localPoolName); + //Updating id entries in the parent pool. This will be used for restart scenario + IdUtils.lockPool(lockManager, parentPoolName); + try { + parentIdPool = getIdPool(parentIdPoolInstanceIdentifier); + IdPool parentPool = new IdPoolBuilder(parentIdPool).setIdEntries(idEntries).build(); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, parentIdPoolInstanceIdentifier, parentPool); + } catch (Exception ex) { + LOG.error("Saving of Id entries to parent pool {} failed due to {}", parentPoolName, ex); + } finally { + IdUtils.unlockPool(lockManager, parentPoolName); + } + } + return newIdValue; + } - LOG.debug("poolName: {} ,idKey: {}", poolName, idKey); - RpcResultBuilder rpcResultBuilder; + private long getIdFromPool(IdPool pool, AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds) { + long newIdValue = -1; + while (true) { + newIdValue = IdUtils.getIdFromReleaseIdsIfAvailable(releasedIds); + if (newIdValue != -1) { + LOG.debug("Retrieved id value {} from released id holder", newIdValue); + return newIdValue; + } + newIdValue = IdUtils.getIdFromAvailableIds(availableIds); + if (newIdValue != -1) { + LOG.debug("Creating a new id {} for the pool: {} ", newIdValue, pool.getPoolName()); + return newIdValue; + } + long idCount = allocateIdBlockFromParentPool(pool.getParentPoolName(), availableIds, releasedIds); + if (idCount <= 0) { + LOG.debug("Unable to allocate Id block from global pool"); + throw new RuntimeException(String.format("Ids exhausted for pool : %s", pool.getPoolName())); + } + } + } + /** + * Changes made to releaseIds and AvailableIds are not persisted. + * @param availableIds + * @param releasedIds + * @param parentPoolName + * @param blockSize + */ + private void cleanupExcessIds(AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds, String parentPoolName, int blockSize) { + IdUtils.processDelayList(releasedIds); + long totalAvailableIdCount = releasedIds.getAvailableIdCount() + IdUtils.getAvailableIdsCount(availableIds); + if (totalAvailableIdCount > blockSize * 2) { + parentPoolName = parentPoolName.intern(); + InstanceIdentifier releasedIdInstanceIdentifier = IdUtils.getReleasedIdsHolderInstance(parentPoolName); + IdUtils.lockPool(lockManager, parentPoolName); + try { + Optional releasedIdsHolder = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier); + ReleasedIdsHolderBuilder releasedIdsParent; + if (!releasedIdsHolder.isPresent()) { + LOG.error("ReleasedIds not present in parent pool. Unable to cleanup excess ids"); + return; + } + releasedIdsParent = new ReleasedIdsHolderBuilder(releasedIdsHolder.get()); + LOG.debug("Releasing excesss Ids from local pool"); + IdUtils.freeExcessAvailableIds(releasedIds, releasedIdsParent, blockSize); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier, releasedIdsParent.build()); + } finally { + IdUtils.unlockPool(lockManager, parentPoolName); + } + } + } + + /** + * Changes made to availableIds and releasedIds will not be persisted to the datastore + * @param parentPoolName + * @param availableIdsBuilder + * @param releasedIdsBuilder + * @return + */ + private long allocateIdBlockFromParentPool(String parentPoolName, + AvailableIdsHolderBuilder availableIdsBuilder, ReleasedIdsHolderBuilder releasedIdsBuilder) { + LOG.debug("Allocating block of id from parent pool {}", parentPoolName); + InstanceIdentifier idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName); + parentPoolName = parentPoolName.intern(); + long idCount = -1; + IdUtils.lockPool(lockManager, parentPoolName); try { - InstanceIdentifier.InstanceIdentifierBuilder idBuilder = - InstanceIdentifier.builder(Pools.class).child(IdPool.class, new IdPoolKey(poolName)); - InstanceIdentifier id = idBuilder.build(); - Optional globalPool = read(LogicalDatastoreType.OPERATIONAL, id); - GetUniqueIdOutputBuilder output = new GetUniqueIdOutputBuilder(); - Long newIdValue = null; - GeneratedIds newGenId = null; - if (globalPool.isPresent()) { - IdPool pool = globalPool.get(); - List generatedIds = pool.getGeneratedIds(); - - if (generatedIds == null) { - generatedIds = new ArrayList(); + IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier); + ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool); + while (true) { + idCount = allocateIdBlockFromReleasedIdsHolder(releasedIdsBuilder, releasedIdsBuilderParent, parentIdPool); + if (idCount > 0) { + return idCount; } - if (!generatedIds.isEmpty()) { - for (GeneratedIds genId : generatedIds) { - if (genId.getIdKey().equals(idKey)) { - newIdValue = genId.getIdValue(); - LOG.debug("Existing id {} for the key {} ", idKey, newIdValue); - } + idCount = allocateIdBlockFromAvailableIdsHolder(availableIdsBuilder, parentIdPool); + if (idCount > 0) { + return idCount; + } + idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool); + if (idCount <= 0) { + LOG.debug("Unable to allocate Id block from global pool"); + throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentPoolName)); + } + } + } + finally { + IdUtils.unlockPool(lockManager, parentPoolName); + } + } - } + private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) { + List childPoolsList = parentIdPool.getChildPools(); + // Sorting the child pools on last accessed time so that the pool that was not accessed for a long time comes first. + Collections.sort(childPoolsList, new Comparator() { + @Override + public int compare(ChildPools childPool1, ChildPools childPool2) { + return childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime()); + } + }); + long currentTime = System.currentTimeMillis() / 1000; + for (ChildPools childPools : childPoolsList) { + if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME < currentTime) { + break; + } + if (!childPools.getChildPoolName().equals(IdUtils.getLocalPoolName(parentIdPool.getPoolName()))) { + InstanceIdentifier idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(childPools.getChildPoolName()); + IdPool otherChildPool = getIdPool(idPoolInstanceIdentifier); + ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(otherChildPool); + AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(otherChildPool); + long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size() + IdUtils.getAvailableIdsCount(availableIds); + List delayedIdEntriesChild = releasedIds.getDelayedIdEntries(); + List delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries(); + if (delayedIdEntriesParent == null) { + delayedIdEntriesParent = new LinkedList<>(); } - synchronized (this) { - if (newIdValue == null) { - newIdValue = (long) generatedIds.size() + 1; - LOG.debug("Creating a new id {} for the pool: {} ", newIdValue, poolName); - newGenId = getIdsInterface(idKey, newIdValue); - generatedIds.add(newGenId); - pool = new IdPoolBuilder(pool).setGeneratedIds(generatedIds).build(); - asyncUpdate(LogicalDatastoreType.OPERATIONAL, id, pool, DEFAULT_CALLBACK); - } + delayedIdEntriesParent.addAll(delayedIdEntriesChild); + delayedIdEntriesChild.removeAll(delayedIdEntriesChild); + while (IdUtils.isIdAvailable(availableIds)) { + long cursor = availableIds.getCursor() + 1; + delayedIdEntriesParent.add(new DelayedIdEntriesBuilder().setId(cursor).setReadyTimeSec(System.currentTimeMillis()).build()); + availableIds.setCursor(cursor); } - output.setIdValue(newIdValue); + long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount; + releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, + new IdPoolBuilder(otherChildPool).setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build()); + return totalAvailableIdCount; } + } + return 0; + } - rpcResultBuilder = RpcResultBuilder.success(); - rpcResultBuilder.withResult(output.build()); + private long allocateIdBlockFromReleasedIdsHolder(ReleasedIdsHolderBuilder releasedIdsBuilderChild, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) { + if (releasedIdsBuilderParent.getAvailableIdCount() == 0) { + LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool); + return 0; } - catch(Exception e){ - LOG.error("Creation of id for the key {} , global pool {} failed due to {}" ,idKey, poolName, e); - rpcResultBuilder = RpcResultBuilder.failed(); + List delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries(); + List delayedIdEntriesChild = releasedIdsBuilderChild.getDelayedIdEntries(); + if (delayedIdEntriesChild == null) { + delayedIdEntriesChild = new LinkedList(); } - return Futures.immediateFuture(rpcResultBuilder.build()); + int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize()); + List idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount); + delayedIdEntriesChild.addAll(0, idEntriesToBeRemoved); + delayedIdEntriesParent.removeAll(idEntriesToBeRemoved); + releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent); + releasedIdsBuilderChild.setDelayedIdEntries(delayedIdEntriesChild); + releasedIdsBuilderChild.setAvailableIdCount(releasedIdsBuilderChild.getAvailableIdCount() + idCount); + InstanceIdentifier releasedIdsHolderInstanceIdentifier = InstanceIdentifier + .builder(IdPools.class).child(IdPool.class, + new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build(); + releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount); + LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool); + MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIdsBuilderParent.build()); + return idCount; } + private long allocateIdBlockFromAvailableIdsHolder(AvailableIdsHolderBuilder availableIdsBuilder, IdPool parentIdPool) { + long idCount = 0; + AvailableIdsHolderBuilder availableIdsBuilderParent = IdUtils.getAvailableIdsHolderBuilder(parentIdPool); + long end = availableIdsBuilderParent.getEnd(); + long cur = availableIdsBuilderParent.getCursor(); + if (!IdUtils.isIdAvailable(availableIdsBuilderParent)) { + LOG.debug("Ids exhausted in parent pool {}", parentIdPool); + return idCount; + } + // Update availableIdsHolder of Local Pool + availableIdsBuilder.setStart(cur + 1); + idCount = Math.min(end - cur, parentIdPool.getBlockSize()); + availableIdsBuilder.setEnd(cur + idCount); + availableIdsBuilder.setCursor(cur); + // Update availableIdsHolder of Global Pool + InstanceIdentifier availableIdsHolderInstanceIdentifier = InstanceIdentifier + .builder(IdPools.class).child(IdPool.class, + new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build(); + availableIdsBuilderParent.setCursor(cur + idCount); + LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool); + MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier, availableIdsBuilderParent.build()); + return idCount; + } - private IdPool getPoolInterface(String poolName, long startIndx, long poolSize) { - BigInteger size = BigInteger.valueOf(poolSize); - return new IdPoolBuilder().setKey(new IdPoolKey(poolName)).setPoolName(poolName).setIdStart(startIndx) - .setPoolSize(size).build(); + private void releaseIdFromLocalPool(String poolName, String idKey) { + InstanceIdentifier localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName); + poolName = poolName.intern(); + synchronized (poolName) { + IdPool localPool = getIdPool(localIdPoolInstanceIdentifier); + String parentPoolName = localPool.getParentPoolName(); + InstanceIdentifier parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName); + IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier); + List idEntries = parentIdPool.getIdEntries(); + List newIdEntries = idEntries; + if (idEntries == null) { + throw new RuntimeException("Id Entries does not exist"); + } + InstanceIdentifier existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey); + Optional existingIdEntryObject = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId); + if (!existingIdEntryObject.isPresent()) { + throw new RuntimeException(String.format("Specified Id key %s does not exist in id pool %s", idKey, poolName)); + } + IdEntries existingIdEntry = existingIdEntryObject.get(); + long idValue = existingIdEntry.getIdValue(); + boolean isRemoved = newIdEntries.remove(existingIdEntry); + LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved); + ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool); + AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool); + long delayTime = System.currentTimeMillis() / 1000 + releasedIds.getDelayedTimeSec(); + DelayedIdEntries delayedIdEntry = IdUtils.createDelayedIdEntry(idValue, delayTime); + List delayedIdEntries = releasedIds.getDelayedIdEntries(); + if (delayedIdEntries == null) { + delayedIdEntries = new LinkedList(); + } + delayedIdEntries.add(delayedIdEntry); + long availableIdCount = releasedIds + .getAvailableIdCount() == null ? 0 + : releasedIds.getAvailableIdCount(); + releasedIds.setDelayedIdEntries(delayedIdEntries); + releasedIds.setAvailableIdCount(availableIdCount); + //Calling cleanupExcessIds since there could be excessive ids. + cleanupExcessIds(availableIds, releasedIds, parentPoolName, localPool.getBlockSize()); + localPool = new IdPoolBuilder(localPool) + .setAvailableIdsHolder(availableIds.build()) + .setReleasedIdsHolder(releasedIds.build()).build(); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool); + LOG.debug("Released id ({}, {}) from pool {}", idKey, idValue, poolName); + //Updating id entries in the parent pool. This will be used for restart scenario + IdUtils.lockPool(lockManager, parentPoolName); + try { + parentIdPool = getIdPool(parentIdPoolInstanceIdentifier); + IdPool parentPool = new IdPoolBuilder(parentIdPool).setIdEntries(newIdEntries).build(); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, parentIdPoolInstanceIdentifier, parentPool); + } catch (Exception ex) { + LOG.error("Saving of Id entries to parent pool {} failed due to {}", parentPoolName, ex); + } finally { + IdUtils.unlockPool(lockManager, parentPoolName); + } + } } - private GeneratedIds getIdsInterface(String idKey, long newIdVal) { - return new GeneratedIdsBuilder().setKey(new GeneratedIdsKey(idKey)).setIdKey(idKey) - .setIdValue(newIdVal).build(); + private IdPool createGlobalPool(String poolName, long low, long high, + long blockSize, InstanceIdentifier idPoolInstanceIdentifier) { + IdPool idPool; + Optional existingIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier); + if (!existingIdPool.isPresent()) { + LOG.debug("Creating new global pool {}", poolName); + idPool = IdUtils.createGlobalPool(poolName, low, high, blockSize); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool); + } + else { + idPool = existingIdPool.get(); + LOG.debug("GlobalPool exists {}", idPool); + } + return idPool; } - private static final FutureCallback DEFAULT_CALLBACK = - new FutureCallback() { - public void onSuccess(Void result) { - LOG.debug("Success in Datastore write operation"); + private boolean createLocalPool(String localPoolName, IdPool idPool) { + localPoolName = localPoolName.intern(); + synchronized (localPoolName) { + InstanceIdentifier localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName); + Optional localIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier); + if (!localIdPool.isPresent()) { + LOG.debug("Creating new local pool"); + IdPool newLocalIdPool = IdUtils.createLocalIdPool(localPoolName, idPool); + MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, newLocalIdPool); + LOG.debug("Local pool created {}", newLocalIdPool); + return true; } + } + return false; + } - public void onFailure(Throwable error) { - LOG.error("Error in Datastore write operation", error); + private void deletePool(String poolName) { + InstanceIdentifier idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName); + synchronized (poolName) { + Optional idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted); + if (idPool.isPresent()) { + MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted); + LOG.debug("Deleted local pool {}", poolName); } - }; + } + } + + private IdPool getIdPool(InstanceIdentifier idPoolInstanceIdentifier) { + Optional idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier); + if (!idPool.isPresent()) { + throw new NoSuchElementException(String.format("Specified pool %s does not exist" , idPool)); + } + LOG.trace("GetIdPool : Read id pool {} ", idPool); + return idPool.get(); + } + + private void updateChildPool(String poolName, String localPoolName) { + ChildPools childPool = IdUtils.createChildPool(localPoolName); + InstanceIdentifier childPoolInstanceIdentifier = IdUtils.getChildPoolsInstanceIdentifier(poolName, localPoolName); + MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, childPoolInstanceIdentifier, childPool); + } }