07f0e3c69a4e678eab99e3c66b3445f5c68abe15
[vpnservice.git] / idmanager / idmanager-impl / src / main / java / org / opendaylight / idmanager / IdManager.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.idmanager;
10
11 import java.util.Collections;
12 import java.util.Comparator;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.concurrent.ExecutionException;
16 import java.util.concurrent.Future;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdInput;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutput;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.AllocateIdOutputBuilder;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.CreateIdPoolInput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.DeleteIdPoolInput;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdManagerService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.IdPools;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.ReleaseIdInput;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPool;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.IdPoolKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.AvailableIdsHolder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.AvailableIdsHolderBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ChildPools;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.IdEntries;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ReleasedIdsHolder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.id.pools.id.pool.ReleasedIdsHolderBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.released.ids.DelayedIdEntries;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.idmanager.rev150403.released.ids.DelayedIdEntriesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.lockmanager.rev150819.LockManagerService;
45 import org.opendaylight.yangtools.concepts.ListenerRegistration;
46 import org.opendaylight.yangtools.yang.binding.DataObject;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Optional;
55 import com.google.common.util.concurrent.CheckedFuture;
56 import com.google.common.util.concurrent.Futures;
57
58 public class IdManager implements IdManagerService, AutoCloseable{
59     private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
60
61         private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
62
63     private ListenerRegistration<DataChangeListener> listenerRegistration;
64     private final DataBroker broker;
65     private LockManagerService lockManager;
66
67     @Override
68     public void close() throws Exception {
69         if (listenerRegistration != null) {
70             try {
71                 listenerRegistration.close();
72             } catch (final Exception e) {
73                 LOG.error("Error when cleaning up DataChangeListener.", e);
74             }
75             listenerRegistration = null;
76         }
77         LOG.info("IDManager Closed");
78     }
79
80     public IdManager(final DataBroker db) {
81         broker = db;
82     }
83
84     public void setLockManager(LockManagerService lockManager) {
85         this.lockManager = lockManager;
86     }
87
88     @Override
89     public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
90         LOG.debug("createIdPool called with input {}", input);
91         String poolName = input.getPoolName();
92         long low = input.getLow();
93         long high = input.getHigh();
94         long blockSize = IdUtils.computeBlockSize(low, high);
95         RpcResultBuilder<Void> createIdPoolRpcBuilder;
96         IdUtils.lockPool(lockManager, poolName);
97         try {
98             InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
99             poolName = poolName.intern();
100             IdPool idPool;
101             idPool = createGlobalPool(poolName, low, high, blockSize, idPoolInstanceIdentifier);
102             String localPoolName = IdUtils.getLocalPoolName(poolName);
103             if (createLocalPool(localPoolName, idPool)) {
104                 LOG.debug("Updating global id pool {} with childPool {}", poolName, localPoolName);
105                 updateChildPool(poolName, localPoolName);
106             }
107             createIdPoolRpcBuilder = RpcResultBuilder.success();
108         } catch (Exception ex) {
109             LOG.error("Creation of Id Pool {} failed due to {}", poolName, ex);
110             createIdPoolRpcBuilder = RpcResultBuilder.failed();
111             createIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
112         } finally {
113             IdUtils.unlockPool(lockManager, poolName);
114         }
115         return Futures.immediateFuture(createIdPoolRpcBuilder.build());
116     }
117
118     @Override
119     public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
120         LOG.debug("AllocateId called with input {}", input);
121         String idKey = input.getIdKey();
122         String poolName = input.getPoolName();
123         String localPoolName = IdUtils.getLocalPoolName(poolName);
124         RpcResultBuilder<AllocateIdOutput> allocateIdRpcBuilder;
125         long newIdValue = -1;
126         AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
127         try {
128             newIdValue = allocateIdFromLocalPool(localPoolName, idKey);
129             output.setIdValue(newIdValue);
130             allocateIdRpcBuilder = RpcResultBuilder.success();
131             allocateIdRpcBuilder.withResult(output.build());
132         } catch (Exception ex) {
133             LOG.error("Allocate id in pool {} failed due to {}", poolName, ex);
134             allocateIdRpcBuilder = RpcResultBuilder.failed();
135             allocateIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
136         }
137         return Futures.immediateFuture(allocateIdRpcBuilder.build());
138     }
139
140     @Override
141     public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
142         LOG.debug("DeleteIdPool called with input {}", input);
143         String poolName = input.getPoolName();
144         RpcResultBuilder<Void> deleteIdPoolRpcBuilder;
145         try {
146             InstanceIdentifier<IdPool> idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName);
147             poolName = poolName.intern();
148             synchronized(poolName) {
149                 IdPool idPool = getIdPool(idPoolToBeDeleted);
150                 List<ChildPools> childPoolList = idPool.getChildPools();
151                 if (childPoolList != null) {
152                     for (ChildPools childPoolName : childPoolList) {
153                         deletePool(childPoolName.getChildPoolName());
154                     }
155                 }
156                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
157                 LOG.debug("Deleted id pool {}", poolName);
158             }
159             deleteIdPoolRpcBuilder = RpcResultBuilder.success();
160         }
161         catch (Exception ex) {
162             LOG.error("Delete id in pool {} failed due to {}", poolName, ex);
163             deleteIdPoolRpcBuilder = RpcResultBuilder.failed();
164             deleteIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
165         }
166         return Futures.immediateFuture(deleteIdPoolRpcBuilder.build());
167     }
168
169     @Override
170     public Future<RpcResult<Void>> releaseId(ReleaseIdInput input) {
171         String poolName = input.getPoolName();
172         String idKey = input.getIdKey();
173         RpcResultBuilder<Void> releaseIdRpcBuilder;
174         try {
175             releaseIdFromLocalPool(IdUtils.getLocalPoolName(poolName), idKey);
176             releaseIdRpcBuilder = RpcResultBuilder.success();
177         } catch (Exception ex) {
178             LOG.error("Release id {} from pool {} failed due to {}", idKey, poolName, ex);
179             releaseIdRpcBuilder = RpcResultBuilder.failed();
180             releaseIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
181         }
182         return Futures.immediateFuture(releaseIdRpcBuilder.build());
183     }
184
185     private long allocateIdFromLocalPool(String localPoolName, String idKey) {
186         long newIdValue = -1;
187         InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
188         localPoolName = localPoolName.intern();
189         synchronized (localPoolName) {
190             IdEntries newIdEntry;
191             IdPool pool = getIdPool(idPoolInstanceIdentifier);
192             List<IdEntries> idEntries = pool.getIdEntries();
193
194             AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(pool);
195             ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(pool);
196             //Calling cleanupExcessIds since there could be excessive ids.
197             cleanupExcessIds(availableIds, releasedIds, pool.getParentPoolName(), pool.getBlockSize());
198             if (idEntries == null) {
199                 idEntries = new LinkedList<IdEntries>();
200             } else {
201                 InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(idPoolInstanceIdentifier, idKey);
202                 Optional<IdEntries> existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
203                 if (existingIdEntry.isPresent()) {
204                     newIdValue = existingIdEntry.get().getIdValue();
205                     LOG.debug("Existing id {} for the key {} ", idKey, newIdValue);
206                     InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
207                                 .builder(IdPools.class).child(IdPool.class, new IdPoolKey(localPoolName)).child(ReleasedIdsHolder.class).build();
208                         MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIds.build());
209                     return newIdValue;
210                 }
211             }
212             newIdValue = getIdFromPool(pool, availableIds, releasedIds);
213             newIdEntry = IdUtils.createIdEntries(idKey, newIdValue);
214             idEntries.add(newIdEntry);
215             pool = new IdPoolBuilder(pool).setIdEntries(idEntries)
216                    .setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build();
217             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, pool);
218             updateChildPool(pool.getParentPoolName(), localPoolName);
219         }
220         return newIdValue;
221     }
222
223     private long getIdFromPool(IdPool pool, AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds) {
224         long newIdValue = -1;
225         while (true) {
226             newIdValue = IdUtils.getIdFromReleaseIdsIfAvailable(releasedIds);
227             if (newIdValue != -1) {
228                 LOG.debug("Retrieved id value {} from released id holder", newIdValue);
229                 return newIdValue;
230             }
231             newIdValue = IdUtils.getIdFromAvailableIds(availableIds);
232             if (newIdValue != -1) {
233                 LOG.debug("Creating a new id {} for the pool: {} ", newIdValue, pool.getPoolName());
234                 return newIdValue;
235             }
236             long idCount = allocateIdBlockFromParentPool(pool.getParentPoolName(), availableIds, releasedIds);
237             if (idCount <= 0) {
238                 LOG.debug("Unable to allocate Id block from global pool");
239                 throw new RuntimeException(String.format("Ids exhausted for pool : %s", pool.getPoolName()));
240             }
241         }
242     }
243
244     /**
245      * Changes made to releaseIds and AvailableIds are not persisted.
246      * @param availableIds
247      * @param releasedIds
248      * @param parentPoolName
249      * @param blockSize
250      */
251     private void cleanupExcessIds(AvailableIdsHolderBuilder availableIds, ReleasedIdsHolderBuilder releasedIds, String parentPoolName, int blockSize) {
252         IdUtils.processDelayList(releasedIds);
253         long totalAvailableIdCount = releasedIds.getAvailableIdCount() + IdUtils.getAvailableIdsCount(availableIds);
254         if (totalAvailableIdCount > blockSize * 2) {
255             parentPoolName = parentPoolName.intern();
256             InstanceIdentifier<ReleasedIdsHolder> releasedIdInstanceIdentifier = IdUtils.getReleasedIdsHolderInstance(parentPoolName);
257             IdUtils.lockPool(lockManager, parentPoolName);
258             try {
259                 Optional<ReleasedIdsHolder> releasedIdsHolder = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier);
260                 ReleasedIdsHolderBuilder releasedIdsParent;
261                 if (!releasedIdsHolder.isPresent()) {
262                     LOG.error("ReleasedIds not present in parent pool. Unable to cleanup excess ids");
263                     return;
264                 }
265                 releasedIdsParent = new ReleasedIdsHolderBuilder(releasedIdsHolder.get());
266                 LOG.debug("Releasing excesss Ids from local pool");
267                 IdUtils.freeExcessAvailableIds(releasedIds, releasedIdsParent, blockSize);
268                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, releasedIdInstanceIdentifier, releasedIdsParent.build());
269             } finally {
270                 IdUtils.unlockPool(lockManager, parentPoolName);
271             }
272         }
273     }
274
275     /**
276      * Changes made to availableIds and releasedIds will not be persisted to the datastore
277      * @param parentPoolName
278      * @param availableIdsBuilder
279      * @param releasedIdsBuilder
280      * @return
281      */
282     private long allocateIdBlockFromParentPool(String parentPoolName,
283             AvailableIdsHolderBuilder availableIdsBuilder, ReleasedIdsHolderBuilder releasedIdsBuilder) {
284         LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
285         InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
286         parentPoolName = parentPoolName.intern();
287         long idCount = -1;
288         IdUtils.lockPool(lockManager, parentPoolName);
289         try {
290             IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier);
291             ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
292             while (true) {
293                 idCount = allocateIdBlockFromReleasedIdsHolder(releasedIdsBuilder, releasedIdsBuilderParent, parentIdPool);
294                 if (idCount > 0) {
295                     return idCount;
296                 }
297                 idCount = allocateIdBlockFromAvailableIdsHolder(availableIdsBuilder, parentIdPool);
298                 if (idCount > 0) {
299                     return idCount;
300                 }
301                 idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
302                 if (idCount <= 0) {
303                     LOG.debug("Unable to allocate Id block from global pool");
304                     throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentPoolName));
305                 }
306             }
307         }
308         finally {
309             IdUtils.unlockPool(lockManager, parentPoolName);
310         }
311     }
312
313     private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
314         List<ChildPools> childPoolsList = parentIdPool.getChildPools();
315         // Sorting the child pools on last accessed time so that the pool that was not accessed for a long time comes first.
316         Collections.sort(childPoolsList, new Comparator<ChildPools>() {
317             @Override
318             public int compare(ChildPools childPool1, ChildPools childPool2) {
319                 return childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime());
320             }
321         });
322         long currentTime = System.currentTimeMillis() / 1000;
323         for (ChildPools childPools : childPoolsList) {
324             if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME < currentTime) {
325                 break;
326             }
327             if (!childPools.getChildPoolName().equals(IdUtils.getLocalPoolName(parentIdPool.getPoolName()))) {
328                 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(childPools.getChildPoolName());
329                 IdPool otherChildPool = getIdPool(idPoolInstanceIdentifier);
330                 ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(otherChildPool);
331                 AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(otherChildPool);
332                 long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size() + IdUtils.getAvailableIdsCount(availableIds);
333                 List<DelayedIdEntries> delayedIdEntriesChild = releasedIds.getDelayedIdEntries();
334                 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
335                 if (delayedIdEntriesParent == null) {
336                     delayedIdEntriesParent = new LinkedList<>();
337                 }
338                 delayedIdEntriesParent.addAll(delayedIdEntriesChild);
339                 delayedIdEntriesChild.removeAll(delayedIdEntriesChild);
340                 while (IdUtils.isIdAvailable(availableIds)) {
341                     long cursor = availableIds.getCursor() + 1;
342                     delayedIdEntriesParent.add(new DelayedIdEntriesBuilder().setId(cursor).setReadyTimeSec(System.currentTimeMillis()).build());
343                     availableIds.setCursor(cursor);
344                 }
345                 long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount;
346                 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count);
347                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier,
348                         new IdPoolBuilder(otherChildPool).setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build());
349                 return totalAvailableIdCount;
350             }
351         }
352         return 0;
353     }
354
355         private long allocateIdBlockFromReleasedIdsHolder(ReleasedIdsHolderBuilder releasedIdsBuilderChild, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
356         if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
357             LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
358             return 0;
359         }
360         List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
361         List<DelayedIdEntries> delayedIdEntriesChild = releasedIdsBuilderChild.getDelayedIdEntries();
362         if (delayedIdEntriesChild == null) {
363             delayedIdEntriesChild = new LinkedList<DelayedIdEntries>();
364         }
365         int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize());
366         List<DelayedIdEntries> idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount);
367         delayedIdEntriesChild.addAll(0, idEntriesToBeRemoved);
368         delayedIdEntriesParent.removeAll(idEntriesToBeRemoved);
369         releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent);
370         releasedIdsBuilderChild.setDelayedIdEntries(delayedIdEntriesChild);
371         releasedIdsBuilderChild.setAvailableIdCount(releasedIdsBuilderChild.getAvailableIdCount() + idCount);
372         InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
373                 .builder(IdPools.class).child(IdPool.class,
374                         new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build();
375         releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount);
376         LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
377         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIdsBuilderParent.build());
378         return idCount;
379     }
380
381     private long allocateIdBlockFromAvailableIdsHolder(AvailableIdsHolderBuilder availableIdsBuilder, IdPool parentIdPool) {
382         long idCount = 0;
383         AvailableIdsHolderBuilder availableIdsBuilderParent = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
384         long end = availableIdsBuilderParent.getEnd();
385         long cur = availableIdsBuilderParent.getCursor();
386         if (!IdUtils.isIdAvailable(availableIdsBuilderParent)) {
387             LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
388             return idCount;
389         }
390         // Update availableIdsHolder of Local Pool
391         availableIdsBuilder.setStart(cur + 1);
392         idCount = Math.min(end - cur, parentIdPool.getBlockSize());
393         availableIdsBuilder.setEnd(cur + idCount);
394         availableIdsBuilder.setCursor(cur);
395         // Update availableIdsHolder of Global Pool
396         InstanceIdentifier<AvailableIdsHolder> availableIdsHolderInstanceIdentifier = InstanceIdentifier
397                 .builder(IdPools.class).child(IdPool.class,
398                         new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build();
399         availableIdsBuilderParent.setCursor(cur + idCount);
400         LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
401         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier, availableIdsBuilderParent.build());
402         return idCount;
403     }
404
405     private void releaseIdFromLocalPool(String poolName, String idKey) {
406         InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
407         poolName = poolName.intern();
408         synchronized (poolName) {
409             IdPool pool = getIdPool(idPoolInstanceIdentifier);
410             List<IdEntries> idEntries = pool.getIdEntries();
411             List<IdEntries> newIdEntries = idEntries;
412             if (idEntries == null) {
413                 throw new RuntimeException("Id Entries does not exist");
414             }
415             InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(idPoolInstanceIdentifier, idKey);
416             Optional<IdEntries> existingIdEntryObject = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
417             if (!existingIdEntryObject.isPresent()) {
418                 throw new RuntimeException(String.format("Specified Id key %s does not exist in id pool %s", idKey, poolName));
419             }
420             IdEntries existingIdEntry = existingIdEntryObject.get();
421             long idValue = existingIdEntry.getIdValue();
422             newIdEntries.remove(existingIdEntry);
423             ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(pool);
424             AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(pool);
425             long delayTime = System.currentTimeMillis() / 1000 + releasedIds.getDelayedTimeSec();
426             DelayedIdEntries delayedIdEntry = IdUtils.createDelayedIdEntry(idValue, delayTime);
427             List<DelayedIdEntries> delayedIdEntries = releasedIds.getDelayedIdEntries();
428             if (delayedIdEntries == null) {
429                 delayedIdEntries = new LinkedList<DelayedIdEntries>();
430             }
431             delayedIdEntries.add(delayedIdEntry);
432             long availableIdCount = releasedIds
433                     .getAvailableIdCount() == null ? 0
434                             : releasedIds.getAvailableIdCount();
435             releasedIds.setDelayedIdEntries(delayedIdEntries);
436             releasedIds.setAvailableIdCount(availableIdCount);
437             //Calling cleanupExcessIds since there could be excessive ids.
438             cleanupExcessIds(availableIds, releasedIds, pool.getParentPoolName(), pool.getBlockSize());
439             pool = new IdPoolBuilder(pool).setIdEntries(newIdEntries)
440                     .setAvailableIdsHolder(availableIds.build())
441                     .setReleasedIdsHolder(releasedIds.build()).build();
442             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, pool);
443             LOG.debug("Released id ({}, {}) from pool {}", idKey, idValue, poolName);
444         }
445     }
446
447     private IdPool createGlobalPool(String poolName, long low, long high,
448             long blockSize, InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
449         IdPool idPool;
450         Optional<IdPool> existingIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
451         if (!existingIdPool.isPresent()) {
452             LOG.debug("Creating new global pool {}", poolName);
453             idPool = IdUtils.createGlobalPool(poolName, low, high, blockSize);
454             MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool);
455         }
456         else {
457             idPool = existingIdPool.get();
458             LOG.debug("GlobalPool exists {}", idPool);
459         }
460         return idPool;
461     }
462
463     private boolean createLocalPool(String localPoolName, IdPool idPool) {
464         localPoolName = localPoolName.intern();
465         synchronized (localPoolName) {
466             InstanceIdentifier<IdPool> localIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(localPoolName);
467             Optional<IdPool> localIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier);
468             if (!localIdPool.isPresent()) {
469                 LOG.debug("Creating new local pool");
470                 IdPool newLocalIdPool = IdUtils.createLocalIdPool(localPoolName, idPool);
471                 MDSALUtil.syncWrite(broker, LogicalDatastoreType.CONFIGURATION, localIdPoolInstanceIdentifier, newLocalIdPool);
472                 LOG.debug("Local pool created {}", newLocalIdPool);
473                 return true;
474             }
475         }
476         return false;
477     }
478
479     private void deletePool(String poolName) {
480         InstanceIdentifier<IdPool> idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName);
481         synchronized (poolName) {
482             Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
483             if (idPool.isPresent()) {
484                 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
485                 LOG.debug("Deleted local pool {}", poolName);
486             }
487         }
488     }
489
490     private IdPool getIdPool(InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
491         Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
492         if (!idPool.isPresent()) {
493             throw new RuntimeException(String.format("Specified pool %s does not exist" , idPool));
494         }
495         return idPool.get();
496     }
497
498     private void updateChildPool(String poolName, String localPoolName) {
499         ChildPools childPool = IdUtils.createChildPool(localPoolName);
500         InstanceIdentifier<ChildPools> childPoolInstanceIdentifier = IdUtils.getChildPoolsInstanceIdentifier(poolName, localPoolName);
501         MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, childPoolInstanceIdentifier, childPool);
502     }
503 }