Merge "Load config system files in etc/opendaylight/karaf"
[genius.git] / idmanager / idmanager-impl / src / main / java / org / opendaylight / genius / idmanager / IdManager.java
index 0d114c8b939426a07c2255a929735b65bff6a3d3..a5cc46eda6e62d8e61030a280513b905cb40865c 100644 (file)
@@ -8,17 +8,41 @@
 
 package org.opendaylight.genius.idmanager;
 
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.ExecutionException;
+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.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.genius.mdsalutil.MDSALUtil;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.*;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntriesBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
@@ -30,16 +54,14 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.Future;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
 
 public class IdManager implements IdManagerService, AutoCloseable{
     private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
 
-       private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
+    private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
 
     private ListenerRegistration<DataChangeListener> listenerRegistration;
     private final DataBroker broker;
@@ -68,7 +90,9 @@ public class IdManager implements IdManagerService, AutoCloseable{
 
     @Override
     public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
-        LOG.debug("createIdPool called with input {}", input);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("createIdPool called with input {}", input);
+        }
         String poolName = input.getPoolName();
         long low = input.getLow();
         long high = input.getHigh();
@@ -76,15 +100,13 @@ public class IdManager implements IdManagerService, AutoCloseable{
         RpcResultBuilder<Void> createIdPoolRpcBuilder;
         IdUtils.lockPool(lockManager, poolName);
         try {
-            InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
             poolName = poolName.intern();
             IdPool idPool;
-            idPool = createGlobalPool(poolName, low, high, blockSize, idPoolInstanceIdentifier);
+            idPool = createGlobalPool(tx, poolName, low, high, blockSize);
             String localPoolName = IdUtils.getLocalPoolName(poolName);
-            if (createLocalPool(localPoolName, idPool)) {
-                LOG.debug("Updating global id pool {} with childPool {}", poolName, localPoolName);
-                updateChildPool(poolName, localPoolName);
-            }
+            createLocalPool(tx, localPoolName, idPool);
+            submitTransaction(tx);
             createIdPoolRpcBuilder = RpcResultBuilder.success();
         } catch (Exception ex) {
             LOG.error("Creation of Id Pool {} failed due to {}", poolName, ex);
@@ -98,7 +120,9 @@ public class IdManager implements IdManagerService, AutoCloseable{
 
     @Override
     public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
-        LOG.debug("AllocateId called with input {}", input);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("AllocateId called with input {}", input);
+        }
         String idKey = input.getIdKey();
         String poolName = input.getPoolName();
         String localPoolName = IdUtils.getLocalPoolName(poolName);
@@ -106,7 +130,8 @@ public class IdManager implements IdManagerService, AutoCloseable{
         long newIdValue = -1;
         AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
         try {
-            newIdValue = allocateIdFromLocalPool(localPoolName, idKey);
+            //allocateIdFromLocalPool method returns a list of IDs with one element. This element is obtatined by get(0)
+            newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey, 1).get(0);
             output.setIdValue(newIdValue);
             allocateIdRpcBuilder = RpcResultBuilder.success();
             allocateIdRpcBuilder.withResult(output.build());
@@ -118,9 +143,41 @@ public class IdManager implements IdManagerService, AutoCloseable{
         return Futures.immediateFuture(allocateIdRpcBuilder.build());
     }
 
+    @Override
+    public Future<RpcResult<AllocateIdRangeOutput>> allocateIdRange(AllocateIdRangeInput input) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("AllocateIdRange called with input {}", input);
+        }
+        String idKey = input.getIdKey();
+        String poolName = input.getPoolName();
+        long size = input.getSize();
+        String localPoolName = IdUtils.getLocalPoolName(poolName);
+        RpcResultBuilder<AllocateIdRangeOutput> allocateIdRangeRpcBuilder;
+        List<Long> newIdValuesList = new ArrayList<>();
+        AllocateIdRangeOutputBuilder output = new AllocateIdRangeOutputBuilder();
+        try {
+            newIdValuesList = allocateIdFromLocalPool(poolName, localPoolName, idKey, size);
+            Collections.sort(newIdValuesList);
+            output.setIdValues(newIdValuesList);
+            allocateIdRangeRpcBuilder = RpcResultBuilder.success();
+            allocateIdRangeRpcBuilder.withResult(output.build());
+        } catch (NullPointerException e){
+            LOG.error("Not enough Ids available in the pool {} for requested size {}", poolName, size);
+            allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
+            allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, e.getMessage());
+        } catch (Exception ex) {
+            LOG.error("Allocate id range in pool {} failed due to {}", poolName, ex);
+            allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
+            allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
+        }
+        return Futures.immediateFuture(allocateIdRangeRpcBuilder.build());
+    }
+
     @Override
     public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
-        LOG.debug("DeleteIdPool called with input {}", input);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("DeleteIdPool called with input {}", input);
+        }
         String poolName = input.getPoolName();
         RpcResultBuilder<Void> deleteIdPoolRpcBuilder;
         try {
@@ -135,7 +192,9 @@ public class IdManager implements IdManagerService, AutoCloseable{
                     }
                 }
                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
-                LOG.debug("Deleted id pool {}", poolName);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Deleted id pool {}", poolName);
+                }
             }
             deleteIdPoolRpcBuilder = RpcResultBuilder.success();
         }
@@ -163,42 +222,120 @@ public class IdManager implements IdManagerService, AutoCloseable{
         return Futures.immediateFuture(releaseIdRpcBuilder.build());
     }
 
-    private long allocateIdFromLocalPool(String localPoolName, String idKey) {
+    private List<Long> allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey, long size) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName, idKey);
+        }
         long newIdValue = -1;
-        InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
+        List<Long> newIdValuesList = new ArrayList<>();
+        InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
         localPoolName = localPoolName.intern();
         synchronized (localPoolName) {
-            IdEntries newIdEntry;
-            IdPool pool = getIdPool(idPoolInstanceIdentifier);
-            List<IdEntries> idEntries = pool.getIdEntries();
-
-            AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(pool);
-            ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(pool);
-            //Calling cleanupExcessIds since there could be excessive ids.
-            cleanupExcessIds(availableIds, releasedIds, pool.getParentPoolName(), pool.getBlockSize());
+            InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
+            IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
+            List<IdEntries> idEntries = parentIdPool.getIdEntries();
             if (idEntries == null) {
                 idEntries = new LinkedList<IdEntries>();
             } else {
-                InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(idPoolInstanceIdentifier, idKey);
+                InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
                 Optional<IdEntries> existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
                 if (existingIdEntry.isPresent()) {
-                    newIdValue = existingIdEntry.get().getIdValue();
-                    LOG.debug("Existing id {} for the key {} ", idKey, newIdValue);
-                    InstanceIdentifier<ReleasedIdsHolder> 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;
+                    newIdValuesList = existingIdEntry.get().getIdValue();
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("Existing ids {} for the key {} ", newIdValuesList, idKey);
+                    }
+                    return newIdValuesList;
+                }
+            }
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
+            IdPool localPool = null;
+            try {
+                localPool = getIdPool(localIdPoolInstanceIdentifier);
+            } catch (NoSuchElementException e) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Creating local pool {} since it was not present", localPoolName);
                 }
+                localPool = IdUtils.createLocalIdPool(localPoolName, parentIdPool);
+                updateChildPool(tx, localPool.getParentPoolName(), localPoolName);
             }
-            newIdValue = getIdFromPool(pool, availableIds, releasedIds);
-            newIdEntry = IdUtils.createIdEntries(idKey, newIdValue);
+            IdEntries newIdEntry;
+            AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool);
+            ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool);
+            //Calling cleanupExcessIds since there could be excessive ids.
+            cleanupExcessIds(availableIds, releasedIds, parentPoolName, localPool.getBlockSize());
+
+            long totalAvailableIdCount = releasedIds.getAvailableIdCount() + IdUtils.getAvailableIdsCount(availableIds);
+            AvailableIdsHolderBuilder availableParentIds = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
+            ReleasedIdsHolderBuilder releasedParentIds = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
+            totalAvailableIdCount = totalAvailableIdCount + releasedParentIds.getAvailableIdCount()
+                    + IdUtils.getAvailableIdsCount(availableParentIds);
+            if (totalAvailableIdCount > size) {
+                while (size > 0) {
+                    try {
+                        newIdValue = getIdFromPool(localPool, availableIds, releasedIds);
+                    } catch (RuntimeException e) {
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Releasing IDs to pool {}", localPoolName);
+                        }
+                        //Releasing the IDs added in newIdValuesList since a null list would be returned now, as the
+                        //requested size of list IDs exceeds the number of available IDs.
+                        updateDelayedEntries(availableIds, releasedIds, newIdValuesList, parentPoolName,
+                                localPool, localIdPoolInstanceIdentifier, tx);
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Released ids ({}, {}) from local pool {}", idKey, newIdValuesList, localPoolName);
+                        }
+                        submitTransaction(tx);
+                        return null;
+                    }
+                    newIdValuesList.add(newIdValue);
+                    size--;
+                }
+            } else {
+                return null;
+            }
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("The newIdValues {} for the idKey {}", newIdValuesList, idKey);
+            }
+            newIdEntry = IdUtils.createIdEntries(idKey, newIdValuesList);
             idEntries.add(newIdEntry);
-            pool = new IdPoolBuilder(pool).setIdEntries(idEntries)
-                   .setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, pool);
-            updateChildPool(pool.getParentPoolName(), localPoolName);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("The availablelIds are {}", availableIds.build());
+            }
+            localPool = new IdPoolBuilder(localPool).setAvailableIdsHolder(availableIds.build())
+                    .setReleasedIdsHolder(releasedIds.build()).build();
+            tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool, true);
+            updateChildPool(tx, localPool.getParentPoolName(), localPoolName);
+            //Updating id entries in the parent pool. This will be used for restart scenario
+            tx.merge(LogicalDatastoreType.CONFIGURATION, IdUtils.getIdEntriesInstanceIdentifier(parentPoolName, idKey), newIdEntry);
+            submitTransaction(tx);
+        }
+        return newIdValuesList;
+    }
+
+    private void updateDelayedEntries(AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds,
+                                      List<Long> idsList, String parentPoolName, IdPool localPool,
+                                      InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier, WriteTransaction tx){
+        long delayTime = System.currentTimeMillis() / 1000 + releasedIds.getDelayedTimeSec();
+        List<DelayedIdEntries> delayedIdEntries = releasedIds.getDelayedIdEntries();
+        if (delayedIdEntries == null) {
+            delayedIdEntries = new LinkedList<DelayedIdEntries>();
+        }
+        for(long idValue : idsList) {
+            DelayedIdEntries delayedIdEntry = IdUtils.createDelayedIdEntry(idValue, delayTime);
+            delayedIdEntries.add(delayedIdEntry);
         }
-        return newIdValue;
+
+        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();
+        tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, localPool, true);
     }
 
     private long getIdFromPool(IdPool pool, AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds) {
@@ -206,17 +343,23 @@ public class IdManager implements IdManagerService, AutoCloseable{
         while (true) {
             newIdValue = IdUtils.getIdFromReleaseIdsIfAvailable(releasedIds);
             if (newIdValue != -1) {
-                LOG.debug("Retrieved id value {} from released id holder", newIdValue);
+                if (LOG.isDebugEnabled()) {
+                    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());
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Creating a new id {} for the pool: {} ", newIdValue, pool.getPoolName());
+                }
                 return newIdValue;
             }
-            long idCount = allocateIdBlockFromParentPool(pool.getParentPoolName(), availableIds, releasedIds);
+            long idCount = getIdBlockFromParentPool(pool.getParentPoolName(), availableIds, releasedIds);
             if (idCount <= 0) {
-                LOG.debug("Unable to allocate Id block from global pool");
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Unable to allocate Id block from global pool");
+                }
                 throw new RuntimeException(String.format("Ids exhausted for pool : %s", pool.getPoolName()));
             }
         }
@@ -244,7 +387,9 @@ public class IdManager implements IdManagerService, AutoCloseable{
                     return;
                 }
                 releasedIdsParent = new ReleasedIdsHolderBuilder(releasedIdsHolder.get());
-                LOG.debug("Releasing excesss Ids from local pool");
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Releasing excesss Ids from local pool");
+                }
                 IdUtils.freeExcessAvailableIds(releasedIds, releasedIdsParent, blockSize);
                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier, releasedIdsParent.build());
             } finally {
@@ -260,37 +405,56 @@ public class IdManager implements IdManagerService, AutoCloseable{
      * @param releasedIdsBuilder
      * @return
      */
-    private long allocateIdBlockFromParentPool(String parentPoolName,
+    private long getIdBlockFromParentPool(String parentPoolName,
             AvailableIdsHolderBuilder availableIdsBuilder, ReleasedIdsHolderBuilder releasedIdsBuilder) {
-        LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
+        }
         InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
         parentPoolName = parentPoolName.intern();
-        long idCount = -1;
         IdUtils.lockPool(lockManager, parentPoolName);
         try {
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
             IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier);
-            ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
-            while (true) {
-                idCount = allocateIdBlockFromReleasedIdsHolder(releasedIdsBuilder, releasedIdsBuilderParent, parentIdPool);
-                if (idCount > 0) {
-                    return idCount;
-                }
-                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));
-                }
-            }
+            long idCount = allocateIdBlockFromParentPool(availableIdsBuilder, releasedIdsBuilder, parentIdPool, tx);
+            submitTransaction(tx);
+            return idCount;
         }
         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(AvailableIdsHolderBuilder availableIdsBuilder,
+            ReleasedIdsHolderBuilder releasedIdsBuilder, IdPool parentIdPool, WriteTransaction tx) {
+        long idCount = -1;
+        ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
+        while (true) {
+            idCount = allocateIdBlockFromReleasedIdsHolder(releasedIdsBuilder, releasedIdsBuilderParent, parentIdPool, tx);
+            if (idCount > 0) {
+                return idCount;
+            }
+            idCount = allocateIdBlockFromAvailableIdsHolder(availableIdsBuilder, parentIdPool, tx);
+            if (idCount > 0) {
+                return idCount;
+            }
+            idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
+            if (idCount <= 0) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Unable to allocate Id block from global pool");
+                }
+                throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentIdPool.getPoolName()));
+            }
+        }
+    }
+
     private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
         List<ChildPools> 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.
@@ -333,9 +497,11 @@ public class IdManager implements IdManagerService, AutoCloseable{
         return 0;
     }
 
-       private long allocateIdBlockFromReleasedIdsHolder(ReleasedIdsHolderBuilder releasedIdsBuilderChild, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
+    private long allocateIdBlockFromReleasedIdsHolder(ReleasedIdsHolderBuilder releasedIdsBuilderChild, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool, WriteTransaction tx) {
         if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
-            LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
+            }
             return 0;
         }
         List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
@@ -354,18 +520,22 @@ public class IdManager implements IdManagerService, AutoCloseable{
                 .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());
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
+        }
+        tx.merge(LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIdsBuilderParent.build(), true);
         return idCount;
     }
 
-    private long allocateIdBlockFromAvailableIdsHolder(AvailableIdsHolderBuilder availableIdsBuilder, IdPool parentIdPool) {
+    private long allocateIdBlockFromAvailableIdsHolder(AvailableIdsHolderBuilder availableIdsBuilder, IdPool parentIdPool, WriteTransaction tx) {
         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);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
+            }
             return idCount;
         }
         // Update availableIdsHolder of Local Pool
@@ -378,79 +548,92 @@ public class IdManager implements IdManagerService, AutoCloseable{
                 .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());
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
+        }
+        tx.merge(LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier, availableIdsBuilderParent.build(), true);
         return idCount;
     }
 
     private void releaseIdFromLocalPool(String poolName, String idKey) {
-        InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
+        InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
         poolName = poolName.intern();
         synchronized (poolName) {
-            IdPool pool = getIdPool(idPoolInstanceIdentifier);
-            List<IdEntries> idEntries = pool.getIdEntries();
+            IdPool localPool = getIdPool(localIdPoolInstanceIdentifier);
+            String parentPoolName = localPool.getParentPoolName();
+            InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
+            IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
+            List<IdEntries> idEntries = parentIdPool.getIdEntries();
             List<IdEntries> newIdEntries = idEntries;
             if (idEntries == null) {
                 throw new RuntimeException("Id Entries does not exist");
             }
-            InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(idPoolInstanceIdentifier, idKey);
+            InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
             Optional<IdEntries> 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();
-            newIdEntries.remove(existingIdEntry);
-            ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(pool);
-            AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(pool);
-            long delayTime = System.currentTimeMillis() / 1000 + releasedIds.getDelayedTimeSec();
-            DelayedIdEntries delayedIdEntry = IdUtils.createDelayedIdEntry(idValue, delayTime);
-            List<DelayedIdEntries> delayedIdEntries = releasedIds.getDelayedIdEntries();
-            if (delayedIdEntries == null) {
-                delayedIdEntries = new LinkedList<DelayedIdEntries>();
+            List<Long> idValuesList = existingIdEntry.getIdValue();
+            boolean isRemoved = newIdEntries.remove(existingIdEntry);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved);
             }
-            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, pool.getParentPoolName(), pool.getBlockSize());
-            pool = new IdPoolBuilder(pool).setIdEntries(newIdEntries)
-                    .setAvailableIdsHolder(availableIds.build())
-                    .setReleasedIdsHolder(releasedIds.build()).build();
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, pool);
-            LOG.debug("Released id ({}, {}) from pool {}", idKey, idValue, poolName);
+            ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(localPool);
+            AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(localPool);
+            WriteTransaction tx = broker.newWriteOnlyTransaction();
+            updateDelayedEntries(availableIds, releasedIds, idValuesList, parentPoolName,
+                    localPool, localIdPoolInstanceIdentifier, tx);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Released ids ({}, {}) from pool {}", idKey, idValuesList, poolName);
+            }
+            //Updating id entries in the parent pool. This will be used for restart scenario
+            tx.delete(LogicalDatastoreType.CONFIGURATION, IdUtils.getIdEntriesInstanceIdentifier(parentPoolName, idKey));
+            submitTransaction(tx);
         }
     }
 
-    private IdPool createGlobalPool(String poolName, long low, long high,
-            long blockSize, InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
+    private IdPool createGlobalPool(WriteTransaction tx, String poolName, long low, long high,
+                                    long blockSize) {
         IdPool idPool;
+        InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
         Optional<IdPool> existingIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
         if (!existingIdPool.isPresent()) {
-            LOG.debug("Creating new global pool {}", poolName);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Creating new global pool {}", poolName);
+            }
             idPool = IdUtils.createGlobalPool(poolName, low, high, blockSize);
-            MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool);
+            tx.put(LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool, true);
         }
         else {
             idPool = existingIdPool.get();
-            LOG.debug("GlobalPool exists {}", idPool);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("GlobalPool exists {}", idPool);
+            }
         }
         return idPool;
     }
 
-    private boolean createLocalPool(String localPoolName, IdPool idPool) {
+    private boolean createLocalPool(WriteTransaction tx, String localPoolName, IdPool idPool) {
         localPoolName = localPoolName.intern();
         synchronized (localPoolName) {
             InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
             Optional<IdPool> localIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier);
             if (!localIdPool.isPresent()) {
-                LOG.debug("Creating new local pool");
+                if (LOG.isDebugEnabled()) {
+                    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);
+                ReleasedIdsHolderBuilder releasedIdsBuilder = IdUtils.getReleaseIdsHolderBuilder(newLocalIdPool);
+                AvailableIdsHolderBuilder availableIdsBuilder = IdUtils.getAvailableIdsHolderBuilder(newLocalIdPool);
+                allocateIdBlockFromParentPool(availableIdsBuilder, releasedIdsBuilder, idPool, tx);
+                newLocalIdPool = new IdPoolBuilder(newLocalIdPool).setAvailableIdsHolder(availableIdsBuilder.build())
+                        .setReleasedIdsHolder(releasedIdsBuilder.build()).build();
+                tx.put(LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, newLocalIdPool, true);
+                updateChildPool(tx, idPool.getPoolName(), localPoolName);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Local pool created {}", newLocalIdPool);
+                }
                 return true;
             }
         }
@@ -463,7 +646,9 @@ public class IdManager implements IdManagerService, AutoCloseable{
             Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
             if (idPool.isPresent()) {
                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
-                LOG.debug("Deleted local pool {}", poolName);
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("Deleted local pool {}", poolName);
+                }
             }
         }
     }
@@ -471,14 +656,28 @@ public class IdManager implements IdManagerService, AutoCloseable{
     private IdPool getIdPool(InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
         Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
         if (!idPool.isPresent()) {
-            throw new RuntimeException(String.format("Specified pool %s does not exist" , idPool));
+            throw new NoSuchElementException(String.format("Specified pool %s does not exist" , idPool));
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("GetIdPool : Read id pool {} ", idPool);
         }
         return idPool.get();
     }
 
-    private void updateChildPool(String poolName, String localPoolName) {
+    private void updateChildPool(WriteTransaction tx, String poolName, String localPoolName) {
         ChildPools childPool = IdUtils.createChildPool(localPoolName);
         InstanceIdentifier<ChildPools> childPoolInstanceIdentifier = IdUtils.getChildPoolsInstanceIdentifier(poolName, localPoolName);
-        MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, childPoolInstanceIdentifier, childPool);
+        tx.merge(LogicalDatastoreType.CONFIGURATION, childPoolInstanceIdentifier, childPool, true);
+    }
+
+
+    private void submitTransaction(WriteTransaction tx) {
+        CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
+        try {
+            futures.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error writing to datastore tx", tx);
+            throw new RuntimeException(e.getMessage());
+        }
     }
 }