2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.genius.idmanager;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.Comparator;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.NoSuchElementException;
17 import java.util.Timer;
18 import java.util.TimerTask;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import java.util.stream.Collectors;
24 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
28 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
29 import org.opendaylight.genius.idmanager.ReleasedIdHolder.DelayedIdEntry;
30 import org.opendaylight.genius.idmanager.jobs.CleanUpJob;
31 import org.opendaylight.genius.idmanager.jobs.IdHolderSyncJob;
32 import org.opendaylight.genius.idmanager.jobs.LocalPoolCreateJob;
33 import org.opendaylight.genius.idmanager.jobs.LocalPoolDeleteJob;
34 import org.opendaylight.genius.idmanager.jobs.UpdateIdEntryJob;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.utils.cache.CacheUtil;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutputBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutputBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
61 import org.opendaylight.yangtools.yang.common.RpcResult;
62 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
66 import com.google.common.base.Optional;
67 import com.google.common.util.concurrent.CheckedFuture;
68 import com.google.common.util.concurrent.Futures;
70 public class IdManager implements IdManagerService, AutoCloseable {
71 private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
72 private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
73 private final DataBroker broker;
74 private LockManagerService lockManager;
75 private ConcurrentMap<String, IdLocalPool> localPool;
76 private Timer cleanJobTimer = new Timer();
79 public void close() throws Exception {
80 LOG.info("IDManager Closed");
83 public IdManager(DataBroker db, LockManagerService lockManager) {
85 this.lockManager = lockManager;
86 CacheUtil.createCache(IdUtils.ID_POOL_CACHE);
87 localPool = (ConcurrentMap<String, IdLocalPool>) CacheUtil.getCache(IdUtils.ID_POOL_CACHE);
91 private void populateCache() {
92 // If IP changes during reboot, then there will be orphaned child pools.
93 InstanceIdentifier<IdPools> idPoolsInstance = IdUtils.getIdPools();
94 Optional<IdPools> idPoolsOptional= MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolsInstance);
95 if (!idPoolsOptional.isPresent()) {
98 IdPools idPools = idPoolsOptional.get();
99 List<IdPool> idPoolList = idPools.getIdPool();
102 .filter(idPool -> idPool.getParentPoolName() != null
103 && !idPool.getParentPoolName().isEmpty()
104 && IdUtils.getLocalPoolName(idPool.getParentPoolName())
105 .equals(idPool.getPoolName()))
107 idPool -> updateLocalIdPoolCache(idPool,
108 idPool.getParentPoolName()));
111 public boolean updateLocalIdPoolCache(IdPool idPool, String parentPoolName) {
112 IdLocalPool idLocalPool = new IdLocalPool(idPool.getPoolName());
113 AvailableIdsHolder availableIdsHolder = idPool.getAvailableIdsHolder();
114 AvailableIdHolder availableIdHolder = new AvailableIdHolder(availableIdsHolder.getStart(), availableIdsHolder.getEnd());
115 availableIdHolder.setCur(availableIdsHolder.getCursor());
116 ReleasedIdsHolder releasedIdsHolder = idPool.getReleasedIdsHolder();
117 ReleasedIdHolder releasedIdHolder = new ReleasedIdHolder(releasedIdsHolder.getDelayedTimeSec());
118 releasedIdHolder.setAvailableIdCount(releasedIdsHolder.getAvailableIdCount());
119 List<DelayedIdEntries> delayedEntries = releasedIdsHolder.getDelayedIdEntries();
120 List<DelayedIdEntry> delayedIdEntryInCache = new ArrayList<>();
121 if (delayedEntries != null) {
122 delayedIdEntryInCache = delayedEntries
124 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
125 .getId(), delayedIdEntry.getReadyTimeSec()))
126 .sorted(new Comparator<DelayedIdEntry>() {
129 public int compare(DelayedIdEntry idEntry1,
130 DelayedIdEntry idEntry2) {
131 return Long.compare(idEntry1.getReadyTimeSec(),
132 idEntry2.getReadyTimeSec());
134 }).collect(Collectors.toList());
136 releasedIdHolder.setDelayedEntries(delayedIdEntryInCache);
137 idLocalPool.setAvailableIds(availableIdHolder);
138 idLocalPool.setReleasedIds(releasedIdHolder);
139 localPool.put(parentPoolName, idLocalPool);
140 if (LOG.isDebugEnabled()) {
141 LOG.debug("Populating cache for {} with {}", idLocalPool.getPoolName(), idLocalPool);
147 public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
148 if (LOG.isDebugEnabled()) {
149 LOG.debug("createIdPool called with input {}", input);
151 String poolName = input.getPoolName();
152 long low = input.getLow();
153 long high = input.getHigh();
154 long blockSize = IdUtils.computeBlockSize(low, high);
155 RpcResultBuilder<Void> createIdPoolRpcBuilder;
156 IdUtils.lockPool(lockManager, poolName);
158 WriteTransaction tx = broker.newWriteOnlyTransaction();
159 poolName = poolName.intern();
161 idPool = createGlobalPool(tx, poolName, low, high, blockSize);
162 String localPoolName = IdUtils.getLocalPoolName(poolName);
163 IdLocalPool idLocalPool = localPool.get(poolName);
164 if (idLocalPool == null) {
165 createLocalPool(tx, localPoolName, idPool);
166 IdUtils.updateChildPool(tx, idPool.getPoolName(), localPoolName);
168 submitTransaction(tx);
169 createIdPoolRpcBuilder = RpcResultBuilder.success();
170 } catch (Exception ex) {
171 LOG.error("Creation of Id Pool {} failed due to {}", poolName, ex);
172 createIdPoolRpcBuilder = RpcResultBuilder.failed();
173 createIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
175 IdUtils.unlockPool(lockManager, poolName);
177 return Futures.immediateFuture(createIdPoolRpcBuilder.build());
181 public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("AllocateId called with input {}", input);
185 String idKey = input.getIdKey();
186 String poolName = input.getPoolName();
187 String localPoolName = IdUtils.getLocalPoolName(poolName);
188 RpcResultBuilder<AllocateIdOutput> allocateIdRpcBuilder;
189 long newIdValue = -1;
190 AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
192 //allocateIdFromLocalPool method returns a list of IDs with one element. This element is obtatined by get(0)
193 newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey, 1).get(0);
194 output.setIdValue(newIdValue);
195 allocateIdRpcBuilder = RpcResultBuilder.success();
196 allocateIdRpcBuilder.withResult(output.build());
197 } catch (Exception ex) {
198 LOG.error("Allocate id in pool {} failed due to {}", poolName, ex);
199 allocateIdRpcBuilder = RpcResultBuilder.failed();
200 allocateIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
202 return Futures.immediateFuture(allocateIdRpcBuilder.build());
206 public Future<RpcResult<AllocateIdRangeOutput>> allocateIdRange(AllocateIdRangeInput input) {
207 if (LOG.isDebugEnabled()) {
208 LOG.debug("AllocateIdRange called with input {}", input);
210 String idKey = input.getIdKey();
211 String poolName = input.getPoolName();
212 long size = input.getSize();
213 String localPoolName = IdUtils.getLocalPoolName(poolName);
214 RpcResultBuilder<AllocateIdRangeOutput> allocateIdRangeRpcBuilder;
215 List<Long> newIdValuesList = new ArrayList<>();
216 AllocateIdRangeOutputBuilder output = new AllocateIdRangeOutputBuilder();
218 newIdValuesList = allocateIdFromLocalPool(poolName, localPoolName, idKey, size);
219 Collections.sort(newIdValuesList);
220 output.setIdValues(newIdValuesList);
221 allocateIdRangeRpcBuilder = RpcResultBuilder.success();
222 allocateIdRangeRpcBuilder.withResult(output.build());
223 } catch (NullPointerException e){
224 LOG.error("Not enough Ids available in the pool {} for requested size {}", poolName, size);
225 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
226 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, e.getMessage());
227 } catch (Exception ex) {
228 LOG.error("Allocate id range in pool {} failed due to {}", poolName, ex);
229 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
230 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
232 return Futures.immediateFuture(allocateIdRangeRpcBuilder.build());
236 public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
237 if (LOG.isDebugEnabled()) {
238 LOG.debug("DeleteIdPool called with input {}", input);
240 String poolName = input.getPoolName();
241 RpcResultBuilder<Void> deleteIdPoolRpcBuilder;
243 InstanceIdentifier<IdPool> idPoolToBeDeleted = IdUtils.getIdPoolInstance(poolName);
244 poolName = poolName.intern();
245 synchronized(poolName) {
246 IdPool idPool = getIdPool(idPoolToBeDeleted);
247 List<ChildPools> childPoolList = idPool.getChildPools();
248 if (childPoolList != null) {
249 childPoolList.parallelStream().forEach(childPool -> deletePool(childPool.getChildPoolName()));
251 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
252 if (LOG.isDebugEnabled()) {
253 LOG.debug("Deleted id pool {}", poolName);
256 deleteIdPoolRpcBuilder = RpcResultBuilder.success();
258 catch (Exception ex) {
259 LOG.error("Delete id in pool {} failed due to {}", poolName, ex);
260 deleteIdPoolRpcBuilder = RpcResultBuilder.failed();
261 deleteIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
263 return Futures.immediateFuture(deleteIdPoolRpcBuilder.build());
267 public Future<RpcResult<Void>> releaseId(ReleaseIdInput input) {
268 String poolName = input.getPoolName();
269 String idKey = input.getIdKey();
270 RpcResultBuilder<Void> releaseIdRpcBuilder;
272 releaseIdFromLocalPool(poolName, IdUtils.getLocalPoolName(poolName), idKey);
273 releaseIdRpcBuilder = RpcResultBuilder.success();
274 } catch (Exception ex) {
275 LOG.error("Release id {} from pool {} failed due to {}", idKey, poolName, ex);
276 releaseIdRpcBuilder = RpcResultBuilder.failed();
277 releaseIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
279 return Futures.immediateFuture(releaseIdRpcBuilder.build());
282 private List<Long> allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey, long size) {
283 if (LOG.isDebugEnabled()) {
284 LOG.debug("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName, idKey);
286 long newIdValue = -1;
287 List<Long> newIdValuesList = new ArrayList<>();
288 localPoolName = localPoolName.intern();
289 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
290 InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
291 Optional<IdEntries> existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
292 if (existingIdEntry.isPresent()) {
293 newIdValuesList = existingIdEntry.get().getIdValue();
294 if (LOG.isDebugEnabled()) {
295 LOG.debug("Existing ids {} for the key {} ", newIdValuesList, idKey);
297 return newIdValuesList;
299 IdLocalPool localIdPool = localPool.get(parentPoolName);
300 if (localIdPool == null) {
301 IdUtils.lockPool(lockManager, parentPoolName);
303 WriteTransaction tx = broker.newWriteOnlyTransaction();
304 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
305 localIdPool = createLocalPool(tx, localPoolName, parentIdPool); // Return localIdPool.....
306 submitTransaction(tx);
308 IdUtils.unlockPool(lockManager, parentPoolName);
311 if (LOG.isDebugEnabled()) {
312 LOG.debug("Got pool {}", localIdPool);
315 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
316 newIdValuesList.add(newIdValue);
318 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
319 long totalAvailableIdCount = localIdPool.getAvailableIds().getAvailableIdCount() + localIdPool.getReleasedIds().getAvailableIdCount();
320 AvailableIdsHolderBuilder availableParentIds = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
321 ReleasedIdsHolderBuilder releasedParentIds = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
322 totalAvailableIdCount = totalAvailableIdCount + releasedParentIds.getAvailableIdCount()
323 + IdUtils.getAvailableIdsCount(availableParentIds);
324 if (totalAvailableIdCount > size) {
327 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
328 } catch (RuntimeException e) {
329 if (LOG.isDebugEnabled()) {
330 LOG.debug("Releasing IDs to pool {}", localPoolName);
332 //Releasing the IDs added in newIdValuesList since a null list would be returned now, as the
333 //requested size of list IDs exceeds the number of available IDs.
334 updateDelayedEntriesInLocalCache(newIdValuesList, parentPoolName, localIdPool);
336 newIdValuesList.add(newIdValue);
343 if (LOG.isDebugEnabled()) {
344 LOG.debug("The newIdValues {} for the idKey {}", newIdValuesList, idKey);
346 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, newIdValuesList, broker);
347 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
348 return newIdValuesList;
351 private Long getIdFromLocalPoolCache(IdLocalPool localIdPool, String parentPoolName) {
353 IdHolder releasedIds = localIdPool.getReleasedIds();
354 Optional<Long> releasedId = releasedIds.allocateId();
355 if (releasedId.isPresent()) {
356 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), releasedIds, broker);
357 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob, IdUtils.RETRY_COUNT);
358 return releasedId.get();
360 IdHolder availableIds = localIdPool.getAvailableIds();
361 if (availableIds != null) {
362 Optional<Long> availableId = availableIds.allocateId();
363 if (availableId.isPresent()) {
364 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), availableIds, broker);
365 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob, IdUtils.RETRY_COUNT);
366 return availableId.get();
369 long idCount = getIdBlockFromParentPool(parentPoolName, localIdPool);
371 if (LOG.isDebugEnabled()) {
372 LOG.debug("Unable to allocate Id block from global pool");
374 throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentPoolName));
380 * Changes made to availableIds and releasedIds will not be persisted to the datastore
381 * @param parentPoolName
382 * @param availableIdsBuilder
383 * @param releasedIdsBuilder
386 private long getIdBlockFromParentPool(String parentPoolName, IdLocalPool localIdPool) {
387 if (LOG.isDebugEnabled()) {
388 LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
390 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
391 parentPoolName = parentPoolName.intern();
392 IdUtils.lockPool(lockManager, parentPoolName);
394 WriteTransaction tx = broker.newWriteOnlyTransaction();
395 IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier);
396 long idCount = allocateIdBlockFromParentPool(localIdPool, parentIdPool, tx);
397 submitTransaction(tx);
401 IdUtils.unlockPool(lockManager, parentPoolName);
405 private long allocateIdBlockFromParentPool(IdLocalPool localPoolCache, IdPool parentIdPool, WriteTransaction tx) {
407 ReleasedIdsHolderBuilder releasedIdsBuilderParent = IdUtils.getReleaseIdsHolderBuilder(parentIdPool);
409 idCount = allocateIdBlockFromReleasedIdsHolder(localPoolCache, releasedIdsBuilderParent, parentIdPool, tx);
413 idCount = allocateIdBlockFromAvailableIdsHolder(localPoolCache, parentIdPool, tx);
417 idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
419 if (LOG.isDebugEnabled()) {
420 LOG.debug("Unable to allocate Id block from global pool");
422 throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentIdPool.getPoolName()));
427 private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
428 List<ChildPools> childPoolsList = parentIdPool.getChildPools();
429 // Sorting the child pools on last accessed time so that the pool that was not accessed for a long time comes first.
430 Collections.sort(childPoolsList, new Comparator<ChildPools>() {
432 public int compare(ChildPools childPool1, ChildPools childPool2) {
433 return childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime());
436 long currentTime = System.currentTimeMillis() / 1000;
437 for (ChildPools childPools : childPoolsList) {
438 if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME > currentTime) {
441 if (!childPools.getChildPoolName().equals(IdUtils.getLocalPoolName(parentIdPool.getPoolName()))) {
442 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(childPools.getChildPoolName());
443 IdPool otherChildPool = getIdPool(idPoolInstanceIdentifier);
444 ReleasedIdsHolderBuilder releasedIds = IdUtils.getReleaseIdsHolderBuilder(otherChildPool);
445 AvailableIdsHolderBuilder availableIds = IdUtils.getAvailableIdsHolderBuilder(otherChildPool);
446 long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size() + IdUtils.getAvailableIdsCount(availableIds);
447 List<DelayedIdEntries> delayedIdEntriesChild = releasedIds.getDelayedIdEntries();
448 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
449 if (delayedIdEntriesParent == null) {
450 delayedIdEntriesParent = new LinkedList<>();
452 delayedIdEntriesParent.addAll(delayedIdEntriesChild);
453 delayedIdEntriesChild.removeAll(delayedIdEntriesChild);
454 while (IdUtils.isIdAvailable(availableIds)) {
455 long cursor = availableIds.getCursor() + 1;
456 delayedIdEntriesParent.add(IdUtils.createDelayedIdEntry(cursor, currentTime));
457 availableIds.setCursor(cursor);
459 long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount;
460 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count);
461 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier,
462 new IdPoolBuilder().setKey(new IdPoolKey(otherChildPool.getPoolName())).setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build()).build());
463 return totalAvailableIdCount;
469 private long allocateIdBlockFromReleasedIdsHolder(IdLocalPool localIdPool, ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool, WriteTransaction tx) {
470 if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
471 if (LOG.isDebugEnabled()) {
472 LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
476 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
477 int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize());
478 List<DelayedIdEntries> idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount);
479 ReleasedIdHolder releasedIds = (ReleasedIdHolder) localIdPool.getReleasedIds();
480 List<DelayedIdEntry> delayedIdEntriesLocalCache = releasedIds.getDelayedEntries();
481 delayedIdEntriesLocalCache = idEntriesToBeRemoved
483 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
484 .getId(), delayedIdEntry.getReadyTimeSec()))
485 .sorted(new Comparator<DelayedIdEntry>() {
487 public int compare(DelayedIdEntry idEntry1,
488 DelayedIdEntry idEntry2) {
489 return Long.compare(idEntry1.getReadyTimeSec(),
490 idEntry2.getReadyTimeSec());
492 }).collect(Collectors.toList());
493 releasedIds.setDelayedEntries(delayedIdEntriesLocalCache);
494 releasedIds.setAvailableIdCount(releasedIds.getAvailableIdCount() + idCount);
495 localIdPool.setReleasedIds(releasedIds);
496 delayedIdEntriesParent.removeAll(idEntriesToBeRemoved);
497 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent);
498 InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
499 .builder(IdPools.class).child(IdPool.class,
500 new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build();
501 releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount);
502 if (LOG.isDebugEnabled()) {
503 LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
505 tx.merge(LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier, releasedIdsBuilderParent.build(), true);
509 private long allocateIdBlockFromAvailableIdsHolder(IdLocalPool localIdPool, IdPool parentIdPool, WriteTransaction tx) {
511 AvailableIdsHolderBuilder availableIdsBuilderParent = IdUtils.getAvailableIdsHolderBuilder(parentIdPool);
512 long end = availableIdsBuilderParent.getEnd();
513 long cur = availableIdsBuilderParent.getCursor();
514 if (!IdUtils.isIdAvailable(availableIdsBuilderParent)) {
515 if (LOG.isDebugEnabled()) {
516 LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
520 // Update availableIdsHolder of Local Pool
521 idCount = Math.min(end - cur, parentIdPool.getBlockSize());
522 AvailableIdHolder availableIds = new AvailableIdHolder(cur + 1, cur + idCount);
523 localIdPool.setAvailableIds(availableIds);
524 // Update availableIdsHolder of Global Pool
525 InstanceIdentifier<AvailableIdsHolder> availableIdsHolderInstanceIdentifier = InstanceIdentifier
526 .builder(IdPools.class).child(IdPool.class,
527 new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build();
528 availableIdsBuilderParent.setCursor(cur + idCount);
529 if (LOG.isDebugEnabled()) {
530 LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
532 tx.merge(LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier, availableIdsBuilderParent.build(), true);
536 private void releaseIdFromLocalPool(String parentPoolName, String localPoolName, String idKey) {
537 localPoolName = localPoolName.intern();
538 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = IdUtils.getIdPoolInstance(parentPoolName);
539 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
540 List<IdEntries> idEntries = parentIdPool.getIdEntries();
541 List<IdEntries> newIdEntries = idEntries;
542 if (idEntries == null) {
543 throw new RuntimeException("Id Entries does not exist");
545 InstanceIdentifier<IdEntries> existingId = IdUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
546 Optional<IdEntries> existingIdEntryObject = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
547 if (!existingIdEntryObject.isPresent()) {
548 throw new RuntimeException(String.format("Specified Id key %s does not exist in id pool %s", idKey, parentPoolName));
550 IdEntries existingIdEntry = existingIdEntryObject.get();
551 List<Long> idValuesList = existingIdEntry.getIdValue();
552 IdLocalPool localIdPoolCache = localPool.get(parentPoolName);
553 boolean isRemoved = newIdEntries.remove(existingIdEntry);
554 if (LOG.isDebugEnabled()) {
555 LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved);
557 updateDelayedEntriesInLocalCache(idValuesList, parentPoolName, localIdPoolCache);
558 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localPoolName, localIdPoolCache.getReleasedIds(), broker);
559 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, poolSyncJob, IdUtils.RETRY_COUNT);
560 scheduleCleanUpTask(localIdPoolCache, parentPoolName, parentIdPool.getBlockSize());
561 if (LOG.isDebugEnabled()) {
562 LOG.debug("Released id ({}, {}) from pool {}", idKey, idValuesList, localPoolName);
564 //Updating id entries in the parent pool. This will be used for restart scenario
565 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, null, broker);
566 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
569 private void scheduleCleanUpTask(final IdLocalPool localIdPoolCache,
570 final String parentPoolName, final int blockSize) {
571 TimerTask scheduledTask = new TimerTask() {
574 CleanUpJob job = new CleanUpJob(localIdPoolCache, broker, parentPoolName, blockSize, lockManager);
575 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPoolCache.getPoolName(), job, IdUtils.RETRY_COUNT);
578 cleanJobTimer.schedule(scheduledTask, IdUtils.DEFAULT_DELAY_TIME * 1000);
581 private IdPool createGlobalPool(WriteTransaction tx, String poolName, long low, long high, long blockSize) {
583 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = IdUtils.getIdPoolInstance(poolName);
584 Optional<IdPool> existingIdPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
585 if (!existingIdPool.isPresent()) {
586 if (LOG.isDebugEnabled()) {
587 LOG.debug("Creating new global pool {}", poolName);
589 idPool = IdUtils.createGlobalPool(poolName, low, high, blockSize);
590 tx.put(LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool, true);
593 idPool = existingIdPool.get();
594 if (LOG.isDebugEnabled()) {
595 LOG.debug("GlobalPool exists {}", idPool);
601 IdLocalPool createLocalPool(WriteTransaction tx, String localPoolName, IdPool idPool) {
602 localPoolName = localPoolName.intern();
603 IdLocalPool idLocalPool = new IdLocalPool(localPoolName);
604 allocateIdBlockFromParentPool(idLocalPool, idPool, tx);
605 String parentPool = idPool.getPoolName();
606 localPool.put(parentPool, idLocalPool);
607 LocalPoolCreateJob job = new LocalPoolCreateJob(idLocalPool, broker, idPool.getPoolName(), idPool.getBlockSize());
608 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, job, IdUtils.RETRY_COUNT);
612 private void deletePool(String poolName) {
613 LocalPoolDeleteJob job = new LocalPoolDeleteJob(poolName, broker);
614 DataStoreJobCoordinator.getInstance().enqueueJob(poolName, job, IdUtils.RETRY_COUNT);
617 private IdPool getIdPool(InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
618 Optional<IdPool> idPool = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier);
619 if (!idPool.isPresent()) {
620 throw new NoSuchElementException(String.format("Specified pool %s does not exist" , idPool));
622 if (LOG.isDebugEnabled()) {
623 LOG.debug("GetIdPool : Read id pool {} ", idPool);
628 public void poolDeleted(String parentPoolName, String poolName) {
629 IdLocalPool idLocalPool = localPool.get(parentPoolName);
630 if (idLocalPool != null) {
631 if (idLocalPool.getPoolName().equals(poolName)) {
632 localPool.remove(parentPoolName);
637 private void submitTransaction(WriteTransaction tx) {
638 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
641 } catch (InterruptedException | ExecutionException e) {
642 LOG.error("Error writing to datastore tx", tx);
643 throw new RuntimeException(e.getMessage());
647 private void updateDelayedEntriesInLocalCache(List<Long> idsList, String parentPoolName, IdLocalPool localPoolCache) {
648 for(long idValue : idsList) {
649 localPoolCache.getReleasedIds().addId(idValue);
651 localPool.put(parentPoolName, localPoolCache);