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 static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
13 import com.google.common.base.Optional;
14 import com.google.common.util.concurrent.CheckedFuture;
15 import com.google.common.util.concurrent.Futures;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.List;
22 import java.util.NoSuchElementException;
23 import java.util.Timer;
24 import java.util.TimerTask;
25 import java.util.concurrent.ConcurrentHashMap;
26 import java.util.concurrent.ConcurrentMap;
27 import java.util.concurrent.ExecutionException;
28 import java.util.concurrent.Future;
29 import java.util.stream.Collectors;
30 import javax.annotation.PostConstruct;
31 import javax.annotation.PreDestroy;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
34 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
35 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
38 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
39 import org.opendaylight.genius.idmanager.ReleasedIdHolder.DelayedIdEntry;
40 import org.opendaylight.genius.idmanager.api.IdManagerMonitor;
41 import org.opendaylight.genius.idmanager.jobs.CleanUpJob;
42 import org.opendaylight.genius.idmanager.jobs.IdHolderSyncJob;
43 import org.opendaylight.genius.idmanager.jobs.LocalPoolCreateJob;
44 import org.opendaylight.genius.idmanager.jobs.LocalPoolDeleteJob;
45 import org.opendaylight.genius.idmanager.jobs.UpdateIdEntryJob;
46 import org.opendaylight.genius.mdsalutil.MDSALUtil;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutputBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutputBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
71 import org.opendaylight.yangtools.yang.common.RpcResult;
72 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
77 public class IdManager implements IdManagerService, IdManagerMonitor {
79 private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
80 private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
82 private final DataBroker broker;
83 private final LockManagerService lockManager;
84 private final IdUtils idUtils;
86 private final ConcurrentMap<String, IdLocalPool> localPool;
87 private final Timer cleanJobTimer = new Timer();
90 public IdManager(DataBroker db, LockManagerService lockManager, IdUtils idUtils) {
92 this.lockManager = lockManager;
93 this.idUtils = idUtils;
94 this.localPool = new ConcurrentHashMap<>();
99 public Map<String, String> getLocalPoolsDetails() {
100 Map<String, String> map = new HashMap<>();
101 localPool.entrySet().stream().forEach(entry -> map.put(entry.getKey(), entry.getValue().toString()));
106 public void start() {
107 LOG.info("{} start", getClass().getSimpleName());
111 public void close() throws Exception {
112 LOG.info("{} close", getClass().getSimpleName());
115 private void populateCache() {
116 // If IP changes during reboot, then there will be orphaned child pools.
117 InstanceIdentifier<IdPools> idPoolsInstance = idUtils.getIdPools();
118 Optional<IdPools> idPoolsOptional = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, idPoolsInstance);
119 if (!idPoolsOptional.isPresent()) {
122 IdPools idPools = idPoolsOptional.get();
123 List<IdPool> idPoolList = idPools.getIdPool();
126 .filter(idPool -> idPool.getParentPoolName() != null
127 && !idPool.getParentPoolName().isEmpty()
128 && idUtils.getLocalPoolName(idPool.getParentPoolName())
129 .equals(idPool.getPoolName()))
131 idPool -> updateLocalIdPoolCache(idPool,
132 idPool.getParentPoolName()));
135 public boolean updateLocalIdPoolCache(IdPool idPool, String parentPoolName) {
136 AvailableIdsHolder availableIdsHolder = idPool.getAvailableIdsHolder();
137 AvailableIdHolder availableIdHolder = new AvailableIdHolder(idUtils, availableIdsHolder.getStart(),
138 availableIdsHolder.getEnd());
139 availableIdHolder.setCur(availableIdsHolder.getCursor());
140 ReleasedIdsHolder releasedIdsHolder = idPool.getReleasedIdsHolder();
141 ReleasedIdHolder releasedIdHolder = new ReleasedIdHolder(idUtils, releasedIdsHolder.getDelayedTimeSec());
142 releasedIdHolder.setAvailableIdCount(releasedIdsHolder.getAvailableIdCount());
143 List<DelayedIdEntries> delayedEntries = releasedIdsHolder.getDelayedIdEntries();
144 List<DelayedIdEntry> delayedIdEntryInCache = new ArrayList<>();
145 if (delayedEntries != null) {
146 delayedIdEntryInCache = delayedEntries
148 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
149 .getId(), delayedIdEntry.getReadyTimeSec()))
150 .sorted((idEntry1, idEntry2) -> Long.compare(idEntry1.getReadyTimeSec(),
151 idEntry2.getReadyTimeSec())).collect(Collectors.toList());
153 releasedIdHolder.setDelayedEntries(delayedIdEntryInCache);
155 IdLocalPool idLocalPool = new IdLocalPool(idUtils, idPool.getPoolName());
156 idLocalPool.setAvailableIds(availableIdHolder);
157 idLocalPool.setReleasedIds(releasedIdHolder);
158 localPool.put(parentPoolName, idLocalPool);
159 if (LOG.isDebugEnabled()) {
160 LOG.debug("Populating cache for {} with {}", idLocalPool.getPoolName(), idLocalPool);
166 public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
167 if (LOG.isDebugEnabled()) {
168 LOG.debug("createIdPool called with input {}", input);
170 String poolName = input.getPoolName();
171 long low = input.getLow();
172 long high = input.getHigh();
173 long blockSize = idUtils.computeBlockSize(low, high);
174 RpcResultBuilder<Void> createIdPoolRpcBuilder;
175 idUtils.lockPool(lockManager, poolName);
177 WriteTransaction tx = broker.newWriteOnlyTransaction();
178 poolName = poolName.intern();
180 idPool = createGlobalPool(tx, poolName, low, high, blockSize);
181 String localPoolName = idUtils.getLocalPoolName(poolName);
182 IdLocalPool idLocalPool = localPool.get(poolName);
183 if (idLocalPool == null) {
184 createLocalPool(tx, localPoolName, idPool);
185 idUtils.updateChildPool(tx, idPool.getPoolName(), localPoolName);
187 submitTransaction(tx);
188 createIdPoolRpcBuilder = RpcResultBuilder.success();
189 } catch (Exception ex) {
190 LOG.error("Creation of Id Pool {} failed", poolName, ex);
191 createIdPoolRpcBuilder = RpcResultBuilder.failed();
192 createIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
194 idUtils.unlockPool(lockManager, poolName);
196 return Futures.immediateFuture(createIdPoolRpcBuilder.build());
200 public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
201 if (LOG.isDebugEnabled()) {
202 LOG.debug("AllocateId called with input {}", input);
204 String idKey = input.getIdKey();
205 String poolName = input.getPoolName();
206 String localPoolName = idUtils.getLocalPoolName(poolName);
207 RpcResultBuilder<AllocateIdOutput> allocateIdRpcBuilder;
208 long newIdValue = -1;
209 AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
211 //allocateIdFromLocalPool method returns a list of IDs with one element. This element is obtatined by get(0)
212 newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey, 1).get(0);
213 output.setIdValue(newIdValue);
214 allocateIdRpcBuilder = RpcResultBuilder.success();
215 allocateIdRpcBuilder.withResult(output.build());
216 } catch (Exception ex) {
217 LOG.error("Allocate id in pool {} failed", poolName, ex);
218 allocateIdRpcBuilder = RpcResultBuilder.failed();
219 allocateIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
221 return Futures.immediateFuture(allocateIdRpcBuilder.build());
225 public Future<RpcResult<AllocateIdRangeOutput>> allocateIdRange(AllocateIdRangeInput input) {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("AllocateIdRange called with input {}", input);
229 String idKey = input.getIdKey();
230 String poolName = input.getPoolName();
231 long size = input.getSize();
232 String localPoolName = idUtils.getLocalPoolName(poolName);
233 RpcResultBuilder<AllocateIdRangeOutput> allocateIdRangeRpcBuilder;
234 List<Long> newIdValuesList = new ArrayList<>();
235 AllocateIdRangeOutputBuilder output = new AllocateIdRangeOutputBuilder();
237 newIdValuesList = allocateIdFromLocalPool(poolName, localPoolName, idKey, size);
238 Collections.sort(newIdValuesList);
239 output.setIdValues(newIdValuesList);
240 allocateIdRangeRpcBuilder = RpcResultBuilder.success();
241 allocateIdRangeRpcBuilder.withResult(output.build());
242 } catch (NullPointerException e) {
243 LOG.error("Not enough Ids available in the pool {} for requested size {}", poolName, size);
244 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
245 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, e.getMessage());
246 } catch (Exception ex) {
247 LOG.error("Allocate id range in pool {} failed due to {}", poolName, ex);
248 allocateIdRangeRpcBuilder = RpcResultBuilder.failed();
249 allocateIdRangeRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
251 return Futures.immediateFuture(allocateIdRangeRpcBuilder.build());
255 public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
256 if (LOG.isDebugEnabled()) {
257 LOG.debug("DeleteIdPool called with input {}", input);
259 String poolName = input.getPoolName();
260 RpcResultBuilder<Void> deleteIdPoolRpcBuilder;
262 InstanceIdentifier<IdPool> idPoolToBeDeleted = idUtils.getIdPoolInstance(poolName);
263 poolName = poolName.intern();
264 synchronized (poolName) {
265 IdPool idPool = getIdPool(idPoolToBeDeleted);
266 List<ChildPools> childPoolList = idPool.getChildPools();
267 if (childPoolList != null) {
268 childPoolList.parallelStream().forEach(childPool -> deletePool(childPool.getChildPoolName()));
270 MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, idPoolToBeDeleted);
271 if (LOG.isDebugEnabled()) {
272 LOG.debug("Deleted id pool {}", poolName);
275 deleteIdPoolRpcBuilder = RpcResultBuilder.success();
276 } catch (Exception ex) {
277 LOG.error("Delete id in pool {} failed", poolName, ex);
278 deleteIdPoolRpcBuilder = RpcResultBuilder.failed();
279 deleteIdPoolRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
281 return Futures.immediateFuture(deleteIdPoolRpcBuilder.build());
285 public Future<RpcResult<Void>> releaseId(ReleaseIdInput input) {
286 String poolName = input.getPoolName();
287 String idKey = input.getIdKey();
288 RpcResultBuilder<Void> releaseIdRpcBuilder;
290 releaseIdFromLocalPool(poolName, idUtils.getLocalPoolName(poolName), idKey);
291 releaseIdRpcBuilder = RpcResultBuilder.success();
292 } catch (Exception ex) {
293 LOG.error("Release id {} from pool {} failed", idKey, poolName, ex);
294 releaseIdRpcBuilder = RpcResultBuilder.failed();
295 releaseIdRpcBuilder.withError(ErrorType.APPLICATION, ex.getMessage());
297 return Futures.immediateFuture(releaseIdRpcBuilder.build());
300 private List<Long> allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey, long size) {
301 if (LOG.isDebugEnabled()) {
302 LOG.debug("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName,
305 long newIdValue = -1;
306 List<Long> newIdValuesList = new ArrayList<>();
307 localPoolName = localPoolName.intern();
308 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
309 InstanceIdentifier<IdEntries> existingId = idUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
310 Optional<IdEntries> existingIdEntry = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
311 if (existingIdEntry.isPresent()) {
312 newIdValuesList = existingIdEntry.get().getIdValue();
313 if (LOG.isDebugEnabled()) {
314 LOG.debug("Existing ids {} for the key {} ", newIdValuesList, idKey);
316 return newIdValuesList;
318 IdLocalPool localIdPool = localPool.get(parentPoolName);
319 if (localIdPool == null) {
320 idUtils.lockPool(lockManager, parentPoolName);
322 WriteTransaction tx = broker.newWriteOnlyTransaction();
323 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
324 localIdPool = createLocalPool(tx, localPoolName, parentIdPool); // Return localIdPool.....
325 submitTransaction(tx);
327 idUtils.unlockPool(lockManager, parentPoolName);
330 if (LOG.isDebugEnabled()) {
331 LOG.debug("Got pool {}", localIdPool);
334 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
335 newIdValuesList.add(newIdValue);
337 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
338 long totalAvailableIdCount = localIdPool.getAvailableIds().getAvailableIdCount()
339 + localIdPool.getReleasedIds().getAvailableIdCount();
340 AvailableIdsHolderBuilder availableParentIds = idUtils.getAvailableIdsHolderBuilder(parentIdPool);
341 ReleasedIdsHolderBuilder releasedParentIds = idUtils.getReleaseIdsHolderBuilder(parentIdPool);
342 totalAvailableIdCount = totalAvailableIdCount + releasedParentIds.getAvailableIdCount()
343 + idUtils.getAvailableIdsCount(availableParentIds);
344 if (totalAvailableIdCount > size) {
347 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
348 } catch (RuntimeException e) {
349 if (LOG.isDebugEnabled()) {
350 LOG.debug("Releasing IDs to pool {}", localPoolName);
352 // Releasing the IDs added in newIdValuesList since a null list would be returned now, as the
353 // requested size of list IDs exceeds the number of available IDs.
354 updateDelayedEntriesInLocalCache(newIdValuesList, parentPoolName, localIdPool);
356 newIdValuesList.add(newIdValue);
363 if (LOG.isDebugEnabled()) {
364 LOG.debug("The newIdValues {} for the idKey {}", newIdValuesList, idKey);
366 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, newIdValuesList, broker, idUtils);
367 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
368 return newIdValuesList;
371 private Long getIdFromLocalPoolCache(IdLocalPool localIdPool, String parentPoolName) {
373 IdHolder releasedIds = localIdPool.getReleasedIds();
374 Optional<Long> releasedId = releasedIds.allocateId();
375 if (releasedId.isPresent()) {
376 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), releasedIds, broker, idUtils);
377 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob, IdUtils.RETRY_COUNT);
378 return releasedId.get();
380 IdHolder availableIds = localIdPool.getAvailableIds();
381 if (availableIds != null) {
382 Optional<Long> availableId = availableIds.allocateId();
383 if (availableId.isPresent()) {
384 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), availableIds, broker, idUtils);
385 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob, IdUtils.RETRY_COUNT);
386 return availableId.get();
389 long idCount = getIdBlockFromParentPool(parentPoolName, localIdPool);
391 if (LOG.isDebugEnabled()) {
392 LOG.debug("Unable to allocate Id block from global pool");
394 throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentPoolName));
400 * Changes made to availableIds and releasedIds will not be persisted to the datastore.
402 private long getIdBlockFromParentPool(String parentPoolName, IdLocalPool localIdPool) {
403 if (LOG.isDebugEnabled()) {
404 LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
406 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
407 parentPoolName = parentPoolName.intern();
408 idUtils.lockPool(lockManager, parentPoolName);
410 WriteTransaction tx = broker.newWriteOnlyTransaction();
411 IdPool parentIdPool = getIdPool(idPoolInstanceIdentifier);
412 long idCount = allocateIdBlockFromParentPool(localIdPool, parentIdPool, tx);
413 submitTransaction(tx);
416 idUtils.unlockPool(lockManager, parentPoolName);
420 private long allocateIdBlockFromParentPool(IdLocalPool localPoolCache, IdPool parentIdPool, WriteTransaction tx) {
422 ReleasedIdsHolderBuilder releasedIdsBuilderParent = idUtils.getReleaseIdsHolderBuilder(parentIdPool);
424 idCount = allocateIdBlockFromReleasedIdsHolder(localPoolCache, releasedIdsBuilderParent, parentIdPool, tx);
428 idCount = allocateIdBlockFromAvailableIdsHolder(localPoolCache, parentIdPool, tx);
432 idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
434 if (LOG.isDebugEnabled()) {
435 LOG.debug("Unable to allocate Id block from global pool");
437 throw new RuntimeException(String.format("Ids exhausted for pool : %s", parentIdPool.getPoolName()));
442 private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool) {
443 List<ChildPools> childPoolsList = parentIdPool.getChildPools();
444 // Sorting the child pools on last accessed time so that the pool that
445 // was not accessed for a long time comes first.
446 Collections.sort(childPoolsList,
447 (childPool1, childPool2) -> childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime()));
448 long currentTime = System.currentTimeMillis() / 1000;
449 for (ChildPools childPools : childPoolsList) {
450 if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME > currentTime) {
453 if (!childPools.getChildPoolName().equals(idUtils.getLocalPoolName(parentIdPool.getPoolName()))) {
454 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils.getIdPoolInstance(childPools.getChildPoolName());
455 IdPool otherChildPool = getIdPool(idPoolInstanceIdentifier);
456 ReleasedIdsHolderBuilder releasedIds = idUtils.getReleaseIdsHolderBuilder(otherChildPool);
457 AvailableIdsHolderBuilder availableIds = idUtils.getAvailableIdsHolderBuilder(otherChildPool);
458 long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size() + idUtils.getAvailableIdsCount(availableIds);
459 List<DelayedIdEntries> delayedIdEntriesChild = releasedIds.getDelayedIdEntries();
460 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
461 if (delayedIdEntriesParent == null) {
462 delayedIdEntriesParent = new LinkedList<>();
464 delayedIdEntriesParent.addAll(delayedIdEntriesChild);
465 delayedIdEntriesChild.removeAll(delayedIdEntriesChild);
466 while (idUtils.isIdAvailable(availableIds)) {
467 long cursor = availableIds.getCursor() + 1;
468 delayedIdEntriesParent.add(idUtils.createDelayedIdEntry(cursor, currentTime));
469 availableIds.setCursor(cursor);
471 long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount;
472 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count);
473 MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier,
474 new IdPoolBuilder().setKey(new IdPoolKey(otherChildPool.getPoolName()))
475 .setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build())
477 return totalAvailableIdCount;
483 private long allocateIdBlockFromReleasedIdsHolder(IdLocalPool localIdPool,
484 ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool, WriteTransaction tx) {
485 if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
486 if (LOG.isDebugEnabled()) {
487 LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
491 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
492 int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize());
493 List<DelayedIdEntries> idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount);
494 ReleasedIdHolder releasedIds = (ReleasedIdHolder) localIdPool.getReleasedIds();
495 List<DelayedIdEntry> delayedIdEntriesLocalCache = releasedIds.getDelayedEntries();
496 delayedIdEntriesLocalCache = idEntriesToBeRemoved
498 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
499 .getId(), delayedIdEntry.getReadyTimeSec()))
500 .sorted((idEntry1, idEntry2) -> Long.compare(idEntry1.getReadyTimeSec(),
501 idEntry2.getReadyTimeSec())).collect(Collectors.toList());
502 releasedIds.setDelayedEntries(delayedIdEntriesLocalCache);
503 releasedIds.setAvailableIdCount(releasedIds.getAvailableIdCount() + idCount);
504 localIdPool.setReleasedIds(releasedIds);
505 delayedIdEntriesParent.removeAll(idEntriesToBeRemoved);
506 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent);
507 InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
508 .builder(IdPools.class).child(IdPool.class,
509 new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build();
510 releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount);
511 if (LOG.isDebugEnabled()) {
512 LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
514 tx.merge(LogicalDatastoreType.CONFIGURATION, releasedIdsHolderInstanceIdentifier,
515 releasedIdsBuilderParent.build(), true);
519 private long allocateIdBlockFromAvailableIdsHolder(IdLocalPool localIdPool, IdPool parentIdPool,
520 WriteTransaction tx) {
522 AvailableIdsHolderBuilder availableIdsBuilderParent = idUtils.getAvailableIdsHolderBuilder(parentIdPool);
523 long end = availableIdsBuilderParent.getEnd();
524 long cur = availableIdsBuilderParent.getCursor();
525 if (!idUtils.isIdAvailable(availableIdsBuilderParent)) {
526 if (LOG.isDebugEnabled()) {
527 LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
531 // Update availableIdsHolder of Local Pool
532 idCount = Math.min(end - cur, parentIdPool.getBlockSize());
533 AvailableIdHolder availableIds = new AvailableIdHolder(idUtils, cur + 1, cur + idCount);
534 localIdPool.setAvailableIds(availableIds);
535 // Update availableIdsHolder of Global Pool
536 InstanceIdentifier<AvailableIdsHolder> availableIdsHolderInstanceIdentifier = InstanceIdentifier
537 .builder(IdPools.class).child(IdPool.class,
538 new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build();
539 availableIdsBuilderParent.setCursor(cur + idCount);
540 if (LOG.isDebugEnabled()) {
541 LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
543 tx.merge(LogicalDatastoreType.CONFIGURATION, availableIdsHolderInstanceIdentifier,
544 availableIdsBuilderParent.build(), true);
548 private void releaseIdFromLocalPool(String parentPoolName, String localPoolName, String idKey) {
549 localPoolName = localPoolName.intern();
550 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
551 IdPool parentIdPool = getIdPool(parentIdPoolInstanceIdentifier);
552 List<IdEntries> idEntries = parentIdPool.getIdEntries();
553 List<IdEntries> newIdEntries = idEntries;
554 if (idEntries == null) {
555 throw new RuntimeException("Id Entries does not exist");
557 InstanceIdentifier<IdEntries> existingId = idUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
558 Optional<IdEntries> existingIdEntryObject = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, existingId);
559 if (!existingIdEntryObject.isPresent()) {
560 throw new RuntimeException(
561 String.format("Specified Id key %s does not exist in id pool %s", idKey, parentPoolName));
563 IdEntries existingIdEntry = existingIdEntryObject.get();
564 List<Long> idValuesList = existingIdEntry.getIdValue();
565 IdLocalPool localIdPoolCache = localPool.get(parentPoolName);
566 boolean isRemoved = newIdEntries.remove(existingIdEntry);
567 if (LOG.isDebugEnabled()) {
568 LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved);
570 updateDelayedEntriesInLocalCache(idValuesList, parentPoolName, localIdPoolCache);
571 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localPoolName, localIdPoolCache.getReleasedIds(), broker, idUtils);
572 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, poolSyncJob, IdUtils.RETRY_COUNT);
573 scheduleCleanUpTask(localIdPoolCache, parentPoolName, parentIdPool.getBlockSize());
574 if (LOG.isDebugEnabled()) {
575 LOG.debug("Released id ({}, {}) from pool {}", idKey, idValuesList, localPoolName);
577 //Updating id entries in the parent pool. This will be used for restart scenario
578 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, null, broker, idUtils);
579 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
582 private void scheduleCleanUpTask(final IdLocalPool localIdPoolCache,
583 final String parentPoolName, final int blockSize) {
584 TimerTask scheduledTask = new TimerTask() {
587 CleanUpJob job = new CleanUpJob(localIdPoolCache, broker, parentPoolName, blockSize, lockManager, idUtils);
588 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPoolCache.getPoolName(), job, IdUtils.RETRY_COUNT);
591 cleanJobTimer.schedule(scheduledTask, IdUtils.DEFAULT_DELAY_TIME * 1000);
594 private IdPool createGlobalPool(WriteTransaction tx, String poolName, long low, long high, long blockSize) {
596 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils.getIdPoolInstance(poolName);
597 Optional<IdPool> existingIdPool = MDSALUtil.read(broker, CONFIGURATION, idPoolInstanceIdentifier);
598 if (!existingIdPool.isPresent()) {
599 if (LOG.isDebugEnabled()) {
600 LOG.debug("Creating new global pool {}", poolName);
602 idPool = idUtils.createGlobalPool(poolName, low, high, blockSize);
603 tx.put(LogicalDatastoreType.CONFIGURATION, idPoolInstanceIdentifier, idPool, true);
605 idPool = existingIdPool.get();
606 if (LOG.isDebugEnabled()) {
607 LOG.debug("GlobalPool exists {}", idPool);
613 IdLocalPool createLocalPool(WriteTransaction tx, String localPoolName, IdPool idPool) {
614 localPoolName = localPoolName.intern();
615 IdLocalPool idLocalPool = new IdLocalPool(idUtils, localPoolName);
616 allocateIdBlockFromParentPool(idLocalPool, idPool, tx);
617 String parentPool = idPool.getPoolName();
618 localPool.put(parentPool, idLocalPool);
619 LocalPoolCreateJob job = new LocalPoolCreateJob(idLocalPool, broker, idPool.getPoolName(),
620 idPool.getBlockSize(), idUtils);
621 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, job, IdUtils.RETRY_COUNT);
625 private void deletePool(String poolName) {
626 LocalPoolDeleteJob job = new LocalPoolDeleteJob(poolName, broker, idUtils);
627 DataStoreJobCoordinator.getInstance().enqueueJob(poolName, job, IdUtils.RETRY_COUNT);
630 private IdPool getIdPool(InstanceIdentifier<IdPool> idPoolInstanceIdentifier) {
631 Optional<IdPool> idPool = MDSALUtil.read(broker, CONFIGURATION, idPoolInstanceIdentifier);
632 if (!idPool.isPresent()) {
633 throw new NoSuchElementException(String.format("Specified pool %s does not exist" , idPool));
635 if (LOG.isDebugEnabled()) {
636 LOG.debug("GetIdPool : Read id pool {} ", idPool);
641 public void poolDeleted(String parentPoolName, String poolName) {
642 IdLocalPool idLocalPool = localPool.get(parentPoolName);
643 if (idLocalPool != null) {
644 if (idLocalPool.getPoolName().equals(poolName)) {
645 localPool.remove(parentPoolName);
650 private void submitTransaction(WriteTransaction tx) {
651 CheckedFuture<Void, TransactionCommitFailedException> futures = tx.submit();
654 } catch (InterruptedException | ExecutionException e) {
655 LOG.error("Error writing to datastore tx", tx);
656 throw new RuntimeException(e.getMessage());
660 private void updateDelayedEntriesInLocalCache(List<Long> idsList, String parentPoolName,
661 IdLocalPool localPoolCache) {
662 for (long idValue : idsList) {
663 localPoolCache.getReleasedIds().addId(idValue);
665 localPool.put(parentPoolName, localPoolCache);