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.ListenableFuture;
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.LinkedList;
19 import java.util.List;
21 import java.util.Timer;
22 import java.util.TimerTask;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.concurrent.ConcurrentMap;
25 import java.util.concurrent.Future;
26 import java.util.stream.Collectors;
27 import javax.annotation.PostConstruct;
28 import javax.annotation.PreDestroy;
29 import javax.inject.Inject;
30 import javax.inject.Singleton;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
34 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
35 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
36 import org.opendaylight.genius.idmanager.ReleasedIdHolder.DelayedIdEntry;
37 import org.opendaylight.genius.idmanager.api.IdManagerMonitor;
38 import org.opendaylight.genius.idmanager.jobs.CleanUpJob;
39 import org.opendaylight.genius.idmanager.jobs.IdHolderSyncJob;
40 import org.opendaylight.genius.idmanager.jobs.LocalPoolCreateJob;
41 import org.opendaylight.genius.idmanager.jobs.LocalPoolDeleteJob;
42 import org.opendaylight.genius.idmanager.jobs.UpdateIdEntryJob;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdInput;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdOutputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeInput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.AllocateIdRangeOutputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.CreateIdPoolInput;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.DeleteIdPoolInput;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.ReleaseIdInput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.OperationFailedException;
67 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
70 import org.slf4j.Logger;
71 import org.slf4j.LoggerFactory;
74 public class IdManager implements IdManagerService, IdManagerMonitor {
76 private static final Logger LOG = LoggerFactory.getLogger(IdManager.class);
77 private static final long DEFAULT_IDLE_TIME = 24 * 60 * 60;
79 private final DataBroker broker;
80 private final SingleTransactionDataBroker singleTxDB;
81 private final LockManagerService lockManager;
82 private final IdUtils idUtils;
84 private final ConcurrentMap<String, IdLocalPool> localPool;
85 private final Timer cleanJobTimer = new Timer();
88 public IdManager(DataBroker db, LockManagerService lockManager, IdUtils idUtils) throws ReadFailedException {
90 this.singleTxDB = new SingleTransactionDataBroker(db);
91 this.lockManager = lockManager;
92 this.idUtils = idUtils;
93 this.localPool = new ConcurrentHashMap<>();
98 public Map<String, String> getLocalPoolsDetails() {
99 Map<String, String> map = new HashMap<>();
100 localPool.entrySet().stream().forEach(entry -> map.put(entry.getKey(), entry.getValue().toString()));
105 public void start() {
106 LOG.info("{} start", getClass().getSimpleName());
110 public void close() throws Exception {
111 LOG.info("{} close", getClass().getSimpleName());
114 private void populateCache() throws ReadFailedException {
115 // If IP changes during reboot, then there will be orphaned child pools.
116 InstanceIdentifier<IdPools> idPoolsInstance = idUtils.getIdPools();
117 Optional<IdPools> idPoolsOptional = singleTxDB.syncReadOptional(CONFIGURATION, idPoolsInstance);
118 if (!idPoolsOptional.isPresent()) {
121 IdPools idPools = idPoolsOptional.get();
122 List<IdPool> idPoolList = idPools.getIdPool();
125 .filter(idPool -> idPool.getParentPoolName() != null
126 && !idPool.getParentPoolName().isEmpty()
127 && idUtils.getLocalPoolName(idPool.getParentPoolName())
128 .equals(idPool.getPoolName()))
130 idPool -> updateLocalIdPoolCache(idPool,
131 idPool.getParentPoolName()));
134 public boolean updateLocalIdPoolCache(IdPool idPool, String parentPoolName) {
135 AvailableIdsHolder availableIdsHolder = idPool.getAvailableIdsHolder();
136 AvailableIdHolder availableIdHolder = new AvailableIdHolder(idUtils, availableIdsHolder.getStart(),
137 availableIdsHolder.getEnd());
138 availableIdHolder.setCur(availableIdsHolder.getCursor());
139 ReleasedIdsHolder releasedIdsHolder = idPool.getReleasedIdsHolder();
140 ReleasedIdHolder releasedIdHolder = new ReleasedIdHolder(idUtils, releasedIdsHolder.getDelayedTimeSec());
141 releasedIdHolder.setAvailableIdCount(releasedIdsHolder.getAvailableIdCount());
142 List<DelayedIdEntries> delayedEntries = releasedIdsHolder.getDelayedIdEntries();
143 List<DelayedIdEntry> delayedIdEntryInCache = new ArrayList<>();
144 if (delayedEntries != null) {
145 delayedIdEntryInCache = delayedEntries
147 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
148 .getId(), delayedIdEntry.getReadyTimeSec()))
149 .sorted((idEntry1, idEntry2) -> Long.compare(idEntry1.getReadyTimeSec(),
150 idEntry2.getReadyTimeSec())).collect(Collectors.toList());
152 releasedIdHolder.setDelayedEntries(delayedIdEntryInCache);
154 IdLocalPool idLocalPool = new IdLocalPool(idUtils, idPool.getPoolName());
155 idLocalPool.setAvailableIds(availableIdHolder);
156 idLocalPool.setReleasedIds(releasedIdHolder);
157 localPool.put(parentPoolName, idLocalPool);
158 if (LOG.isDebugEnabled()) {
159 LOG.debug("Populating cache for {} with {}", idLocalPool.getPoolName(), idLocalPool);
165 public Future<RpcResult<Void>> createIdPool(CreateIdPoolInput input) {
166 if (LOG.isDebugEnabled()) {
167 LOG.debug("createIdPool called with input {}", input);
169 String poolName = input.getPoolName();
170 long low = input.getLow();
171 long high = input.getHigh();
172 long blockSize = idUtils.computeBlockSize(low, high);
173 Future<RpcResult<Void>> futureResult;
175 idUtils.lockPool(lockManager, poolName);
176 WriteTransaction tx = broker.newWriteOnlyTransaction();
177 poolName = poolName.intern();
179 idPool = createGlobalPool(tx, poolName, low, high, blockSize);
180 String localPoolName = idUtils.getLocalPoolName(poolName);
181 IdLocalPool idLocalPool = localPool.get(poolName);
182 if (idLocalPool == null) {
183 createLocalPool(tx, localPoolName, idPool);
184 idUtils.updateChildPool(tx, idPool.getPoolName(), localPoolName);
186 tx.submit().checkedGet();
187 futureResult = RpcResultBuilder.<Void>success().buildFuture();
188 } catch (OperationFailedException | IdManagerException e) {
189 futureResult = buildFailedRpcResultFuture("createIdPool failed: " + input.toString(), e);
192 idUtils.unlockPool(lockManager, poolName);
193 } catch (IdManagerException e) {
194 futureResult = buildFailedRpcResultFuture("createIdPool unlockPool() failed: " + input.toString(), e);
201 public Future<RpcResult<AllocateIdOutput>> allocateId(AllocateIdInput input) {
202 if (LOG.isDebugEnabled()) {
203 LOG.debug("AllocateId called with input {}", input);
205 String idKey = input.getIdKey();
206 String poolName = input.getPoolName();
207 String localPoolName = idUtils.getLocalPoolName(poolName);
208 long newIdValue = -1;
209 AllocateIdOutputBuilder output = new AllocateIdOutputBuilder();
210 Future<RpcResult<AllocateIdOutput>> futureResult;
212 //allocateIdFromLocalPool method returns a list of IDs with one element. This element is obtained by get(0)
213 newIdValue = allocateIdFromLocalPool(poolName, localPoolName, idKey, 1).get(0);
214 output.setIdValue(newIdValue);
215 futureResult = RpcResultBuilder.<AllocateIdOutput>success().withResult(output.build()).buildFuture();
216 } catch (OperationFailedException | IdManagerException e) {
217 futureResult = buildFailedRpcResultFuture("allocateId failed: " + input.toString(), e);
223 public Future<RpcResult<AllocateIdRangeOutput>> allocateIdRange(AllocateIdRangeInput input) {
224 if (LOG.isDebugEnabled()) {
225 LOG.debug("AllocateIdRange called with input {}", input);
227 String idKey = input.getIdKey();
228 String poolName = input.getPoolName();
229 long size = input.getSize();
230 String localPoolName = idUtils.getLocalPoolName(poolName);
231 List<Long> newIdValuesList = new ArrayList<>();
232 AllocateIdRangeOutputBuilder output = new AllocateIdRangeOutputBuilder();
233 Future<RpcResult<AllocateIdRangeOutput>> futureResult;
235 newIdValuesList = allocateIdFromLocalPool(poolName, localPoolName, idKey, size);
236 Collections.sort(newIdValuesList);
237 output.setIdValues(newIdValuesList);
238 futureResult = RpcResultBuilder.<AllocateIdRangeOutput>success().withResult(output.build()).buildFuture();
239 } catch (OperationFailedException | IdManagerException e) {
240 futureResult = buildFailedRpcResultFuture("allocateIdRange failed: " + input.toString(), e);
246 public Future<RpcResult<Void>> deleteIdPool(DeleteIdPoolInput input) {
247 if (LOG.isDebugEnabled()) {
248 LOG.debug("DeleteIdPool called with input {}", input);
250 String poolName = input.getPoolName();
251 Future<RpcResult<Void>> futureResult;
253 InstanceIdentifier<IdPool> idPoolToBeDeleted = idUtils.getIdPoolInstance(poolName);
254 poolName = poolName.intern();
255 synchronized (poolName) {
256 IdPool idPool = singleTxDB.syncRead(CONFIGURATION, idPoolToBeDeleted);
257 List<ChildPools> childPoolList = idPool.getChildPools();
258 if (childPoolList != null) {
259 childPoolList.parallelStream().forEach(childPool -> deletePool(childPool.getChildPoolName()));
261 singleTxDB.syncDelete(CONFIGURATION, idPoolToBeDeleted);
262 if (LOG.isDebugEnabled()) {
263 LOG.debug("Deleted id pool {}", poolName);
266 futureResult = RpcResultBuilder.<Void>success().buildFuture();
267 } catch (OperationFailedException e) {
268 futureResult = buildFailedRpcResultFuture("deleteIdPool failed: " + input.toString(), e);
274 public Future<RpcResult<Void>> releaseId(ReleaseIdInput input) {
275 String poolName = input.getPoolName();
276 String idKey = input.getIdKey();
277 Future<RpcResult<Void>> futureResult;
279 releaseIdFromLocalPool(poolName, idUtils.getLocalPoolName(poolName), idKey);
280 futureResult = RpcResultBuilder.<Void>success().buildFuture();
281 } catch (ReadFailedException | IdManagerException e) {
282 futureResult = buildFailedRpcResultFuture("releaseId failed: " + input.toString(), e);
287 private <T> ListenableFuture<RpcResult<T>> buildFailedRpcResultFuture(String msg, Exception exception) {
288 LOG.error(msg, exception);
289 RpcResultBuilder<T> failedRpcResultBuilder = RpcResultBuilder.failed();
290 failedRpcResultBuilder.withError(ErrorType.APPLICATION, msg, exception);
291 if (exception instanceof OperationFailedException) {
292 failedRpcResultBuilder.withRpcErrors(((OperationFailedException) exception).getErrorList());
294 return failedRpcResultBuilder.buildFuture();
297 private List<Long> allocateIdFromLocalPool(String parentPoolName, String localPoolName, String idKey, long size)
298 throws OperationFailedException, IdManagerException {
299 if (LOG.isDebugEnabled()) {
300 LOG.debug("Allocating id from local pool {}. Parent pool {}. Idkey {}", localPoolName, parentPoolName,
303 long newIdValue = -1;
304 List<Long> newIdValuesList = new ArrayList<>();
305 localPoolName = localPoolName.intern();
306 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
307 InstanceIdentifier<IdEntries> existingId = idUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
308 Optional<IdEntries> existingIdEntry = singleTxDB.syncReadOptional(CONFIGURATION, existingId);
309 if (existingIdEntry.isPresent()) {
310 newIdValuesList = existingIdEntry.get().getIdValue();
311 if (LOG.isDebugEnabled()) {
312 LOG.debug("Existing ids {} for the key {} ", newIdValuesList, idKey);
314 return newIdValuesList;
316 IdLocalPool localIdPool = localPool.get(parentPoolName);
317 if (localIdPool == null) {
318 idUtils.lockPool(lockManager, parentPoolName);
320 WriteTransaction tx = broker.newWriteOnlyTransaction();
321 IdPool parentIdPool = singleTxDB.syncRead(CONFIGURATION, parentIdPoolInstanceIdentifier);
322 localIdPool = createLocalPool(tx, localPoolName, parentIdPool); // Return localIdPool.....
323 tx.submit().checkedGet();
325 idUtils.unlockPool(lockManager, parentPoolName);
328 if (LOG.isDebugEnabled()) {
329 LOG.debug("Got pool {}", localIdPool);
332 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
333 newIdValuesList.add(newIdValue);
335 IdPool parentIdPool = singleTxDB.syncRead(CONFIGURATION, parentIdPoolInstanceIdentifier);
336 long totalAvailableIdCount = localIdPool.getAvailableIds().getAvailableIdCount()
337 + localIdPool.getReleasedIds().getAvailableIdCount();
338 AvailableIdsHolderBuilder availableParentIds = idUtils.getAvailableIdsHolderBuilder(parentIdPool);
339 ReleasedIdsHolderBuilder releasedParentIds = idUtils.getReleaseIdsHolderBuilder(parentIdPool);
340 totalAvailableIdCount = totalAvailableIdCount + releasedParentIds.getAvailableIdCount()
341 + idUtils.getAvailableIdsCount(availableParentIds);
342 if (totalAvailableIdCount > size) {
345 newIdValue = getIdFromLocalPoolCache(localIdPool, parentPoolName);
346 } catch (OperationFailedException e) {
347 if (LOG.isDebugEnabled()) {
348 LOG.debug("Releasing IDs to pool {}", localPoolName);
350 // Releasing the IDs added in newIdValuesList since a null list would be returned now, as the
351 // requested size of list IDs exceeds the number of available IDs.
352 updateDelayedEntriesInLocalCache(newIdValuesList, parentPoolName, localIdPool);
354 newIdValuesList.add(newIdValue);
361 if (LOG.isDebugEnabled()) {
362 LOG.debug("The newIdValues {} for the idKey {}", newIdValuesList, idKey);
364 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, newIdValuesList, broker,
366 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
367 return newIdValuesList;
370 private Long getIdFromLocalPoolCache(IdLocalPool localIdPool, String parentPoolName)
371 throws OperationFailedException, IdManagerException {
373 IdHolder releasedIds = localIdPool.getReleasedIds();
374 Optional<Long> releasedId = releasedIds.allocateId();
375 if (releasedId.isPresent()) {
376 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), releasedIds, broker,
378 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob,
379 IdUtils.RETRY_COUNT);
380 return releasedId.get();
382 IdHolder availableIds = localIdPool.getAvailableIds();
383 if (availableIds != null) {
384 Optional<Long> availableId = availableIds.allocateId();
385 if (availableId.isPresent()) {
386 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localIdPool.getPoolName(), availableIds, broker,
388 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPool.getPoolName(), poolSyncJob,
389 IdUtils.RETRY_COUNT);
390 return availableId.get();
393 long idCount = getIdBlockFromParentPool(parentPoolName, localIdPool);
395 if (LOG.isDebugEnabled()) {
396 LOG.debug("Unable to allocate Id block from global pool");
398 throw new IdManagerException(String.format("Ids exhausted for pool : %s", parentPoolName));
404 * Changes made to availableIds and releasedIds will not be persisted to the datastore.
406 private long getIdBlockFromParentPool(String parentPoolName, IdLocalPool localIdPool)
407 throws OperationFailedException, IdManagerException {
408 if (LOG.isDebugEnabled()) {
409 LOG.debug("Allocating block of id from parent pool {}", parentPoolName);
411 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
412 parentPoolName = parentPoolName.intern();
413 idUtils.lockPool(lockManager, parentPoolName);
415 WriteTransaction tx = broker.newWriteOnlyTransaction();
416 IdPool parentIdPool = singleTxDB.syncRead(CONFIGURATION, idPoolInstanceIdentifier);
417 long idCount = allocateIdBlockFromParentPool(localIdPool, parentIdPool, tx);
418 tx.submit().checkedGet();
421 idUtils.unlockPool(lockManager, parentPoolName);
425 private long allocateIdBlockFromParentPool(IdLocalPool localPoolCache, IdPool parentIdPool, WriteTransaction tx)
426 throws OperationFailedException, IdManagerException {
428 ReleasedIdsHolderBuilder releasedIdsBuilderParent = idUtils.getReleaseIdsHolderBuilder(parentIdPool);
430 idCount = allocateIdBlockFromReleasedIdsHolder(localPoolCache, releasedIdsBuilderParent, parentIdPool, tx);
434 idCount = allocateIdBlockFromAvailableIdsHolder(localPoolCache, parentIdPool, tx);
438 idCount = getIdsFromOtherChildPools(releasedIdsBuilderParent, parentIdPool);
440 if (LOG.isDebugEnabled()) {
441 LOG.debug("Unable to allocate Id block from global pool");
443 throw new IdManagerException(String.format("Ids exhausted for pool : %s", parentIdPool.getPoolName()));
448 private long getIdsFromOtherChildPools(ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool)
449 throws OperationFailedException {
450 List<ChildPools> childPoolsList = parentIdPool.getChildPools();
451 // Sorting the child pools on last accessed time so that the pool that
452 // was not accessed for a long time comes first.
453 Collections.sort(childPoolsList,
454 (childPool1, childPool2) -> childPool1.getLastAccessTime().compareTo(childPool2.getLastAccessTime()));
455 long currentTime = System.currentTimeMillis() / 1000;
456 for (ChildPools childPools : childPoolsList) {
457 if (childPools.getLastAccessTime() + DEFAULT_IDLE_TIME > currentTime) {
460 if (!childPools.getChildPoolName().equals(idUtils.getLocalPoolName(parentIdPool.getPoolName()))) {
461 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils
462 .getIdPoolInstance(childPools.getChildPoolName());
463 IdPool otherChildPool = singleTxDB.syncRead(CONFIGURATION, idPoolInstanceIdentifier);
464 ReleasedIdsHolderBuilder releasedIds = idUtils.getReleaseIdsHolderBuilder(otherChildPool);
466 List<DelayedIdEntries> delayedIdEntriesChild = releasedIds.getDelayedIdEntries();
467 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
468 if (delayedIdEntriesParent == null) {
469 delayedIdEntriesParent = new LinkedList<>();
471 delayedIdEntriesParent.addAll(delayedIdEntriesChild);
472 delayedIdEntriesChild.removeAll(delayedIdEntriesChild);
474 AvailableIdsHolderBuilder availableIds = idUtils.getAvailableIdsHolderBuilder(otherChildPool);
475 while (idUtils.isIdAvailable(availableIds)) {
476 long cursor = availableIds.getCursor() + 1;
477 delayedIdEntriesParent.add(idUtils.createDelayedIdEntry(cursor, currentTime));
478 availableIds.setCursor(cursor);
481 long totalAvailableIdCount = releasedIds.getDelayedIdEntries().size()
482 + idUtils.getAvailableIdsCount(availableIds);
483 long count = releasedIdsBuilderParent.getAvailableIdCount() + totalAvailableIdCount;
484 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent).setAvailableIdCount(count);
485 singleTxDB.syncUpdate(CONFIGURATION, idPoolInstanceIdentifier,
486 new IdPoolBuilder().setKey(new IdPoolKey(otherChildPool.getPoolName()))
487 .setAvailableIdsHolder(availableIds.build()).setReleasedIdsHolder(releasedIds.build())
489 return totalAvailableIdCount;
495 private long allocateIdBlockFromReleasedIdsHolder(IdLocalPool localIdPool,
496 ReleasedIdsHolderBuilder releasedIdsBuilderParent, IdPool parentIdPool, WriteTransaction tx) {
497 if (releasedIdsBuilderParent.getAvailableIdCount() == 0) {
498 if (LOG.isDebugEnabled()) {
499 LOG.debug("Ids unavailable in releasedIds of parent pool {}", parentIdPool);
503 List<DelayedIdEntries> delayedIdEntriesParent = releasedIdsBuilderParent.getDelayedIdEntries();
504 int idCount = Math.min(delayedIdEntriesParent.size(), parentIdPool.getBlockSize());
505 List<DelayedIdEntries> idEntriesToBeRemoved = delayedIdEntriesParent.subList(0, idCount);
506 ReleasedIdHolder releasedIds = (ReleasedIdHolder) localIdPool.getReleasedIds();
507 List<DelayedIdEntry> delayedIdEntriesLocalCache = releasedIds.getDelayedEntries();
508 delayedIdEntriesLocalCache = idEntriesToBeRemoved
510 .map(delayedIdEntry -> new DelayedIdEntry(delayedIdEntry
511 .getId(), delayedIdEntry.getReadyTimeSec()))
512 .sorted((idEntry1, idEntry2) -> Long.compare(idEntry1.getReadyTimeSec(),
513 idEntry2.getReadyTimeSec())).collect(Collectors.toList());
514 releasedIds.setDelayedEntries(delayedIdEntriesLocalCache);
515 releasedIds.setAvailableIdCount(releasedIds.getAvailableIdCount() + idCount);
516 localIdPool.setReleasedIds(releasedIds);
517 delayedIdEntriesParent.removeAll(idEntriesToBeRemoved);
518 releasedIdsBuilderParent.setDelayedIdEntries(delayedIdEntriesParent);
519 InstanceIdentifier<ReleasedIdsHolder> releasedIdsHolderInstanceIdentifier = InstanceIdentifier
520 .builder(IdPools.class).child(IdPool.class,
521 new IdPoolKey(parentIdPool.getPoolName())).child(ReleasedIdsHolder.class).build();
522 releasedIdsBuilderParent.setAvailableIdCount(releasedIdsBuilderParent.getAvailableIdCount() - idCount);
523 if (LOG.isDebugEnabled()) {
524 LOG.debug("Allocated {} ids from releasedIds of parent pool {}", idCount, parentIdPool);
526 tx.merge(CONFIGURATION, releasedIdsHolderInstanceIdentifier,
527 releasedIdsBuilderParent.build(), true);
531 private long allocateIdBlockFromAvailableIdsHolder(IdLocalPool localIdPool, IdPool parentIdPool,
532 WriteTransaction tx) {
534 AvailableIdsHolderBuilder availableIdsBuilderParent = idUtils.getAvailableIdsHolderBuilder(parentIdPool);
535 long end = availableIdsBuilderParent.getEnd();
536 long cur = availableIdsBuilderParent.getCursor();
537 if (!idUtils.isIdAvailable(availableIdsBuilderParent)) {
538 if (LOG.isDebugEnabled()) {
539 LOG.debug("Ids exhausted in parent pool {}", parentIdPool);
543 // Update availableIdsHolder of Local Pool
544 idCount = Math.min(end - cur, parentIdPool.getBlockSize());
545 AvailableIdHolder availableIds = new AvailableIdHolder(idUtils, cur + 1, cur + idCount);
546 localIdPool.setAvailableIds(availableIds);
547 // Update availableIdsHolder of Global Pool
548 InstanceIdentifier<AvailableIdsHolder> availableIdsHolderInstanceIdentifier = InstanceIdentifier
549 .builder(IdPools.class).child(IdPool.class,
550 new IdPoolKey(parentIdPool.getPoolName())).child(AvailableIdsHolder.class).build();
551 availableIdsBuilderParent.setCursor(cur + idCount);
552 if (LOG.isDebugEnabled()) {
553 LOG.debug("Allocated {} ids from availableIds of global pool {}", idCount, parentIdPool);
555 tx.merge(CONFIGURATION, availableIdsHolderInstanceIdentifier,
556 availableIdsBuilderParent.build(), true);
560 private void releaseIdFromLocalPool(String parentPoolName, String localPoolName, String idKey)
561 throws ReadFailedException, IdManagerException {
562 localPoolName = localPoolName.intern();
563 InstanceIdentifier<IdPool> parentIdPoolInstanceIdentifier = idUtils.getIdPoolInstance(parentPoolName);
564 IdPool parentIdPool = singleTxDB.syncRead(CONFIGURATION, parentIdPoolInstanceIdentifier);
565 List<IdEntries> idEntries = parentIdPool.getIdEntries();
566 List<IdEntries> newIdEntries = idEntries;
567 if (idEntries == null) {
568 throw new IdManagerException("Id Entries does not exist");
570 InstanceIdentifier<IdEntries> existingId = idUtils.getIdEntry(parentIdPoolInstanceIdentifier, idKey);
571 Optional<IdEntries> existingIdEntryObject = singleTxDB.syncReadOptional(CONFIGURATION, existingId);
572 if (!existingIdEntryObject.isPresent()) {
573 throw new IdManagerException(
574 String.format("Specified Id key %s does not exist in id pool %s", idKey, parentPoolName));
576 IdEntries existingIdEntry = existingIdEntryObject.get();
577 List<Long> idValuesList = existingIdEntry.getIdValue();
578 IdLocalPool localIdPoolCache = localPool.get(parentPoolName);
579 boolean isRemoved = newIdEntries.remove(existingIdEntry);
580 if (LOG.isDebugEnabled()) {
581 LOG.debug("The entry {} is removed {}", existingIdEntry, isRemoved);
583 updateDelayedEntriesInLocalCache(idValuesList, parentPoolName, localIdPoolCache);
584 IdHolderSyncJob poolSyncJob = new IdHolderSyncJob(localPoolName, localIdPoolCache.getReleasedIds(), broker,
586 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, poolSyncJob, IdUtils.RETRY_COUNT);
587 scheduleCleanUpTask(localIdPoolCache, parentPoolName, parentIdPool.getBlockSize());
588 if (LOG.isDebugEnabled()) {
589 LOG.debug("Released id ({}, {}) from pool {}", idKey, idValuesList, localPoolName);
591 // Updating id entries in the parent pool. This will be used for restart scenario
592 UpdateIdEntryJob job = new UpdateIdEntryJob(parentPoolName, localPoolName, idKey, null, broker, idUtils);
593 DataStoreJobCoordinator.getInstance().enqueueJob(parentPoolName, job, IdUtils.RETRY_COUNT);
596 private void scheduleCleanUpTask(final IdLocalPool localIdPoolCache,
597 final String parentPoolName, final int blockSize) {
598 TimerTask scheduledTask = new TimerTask() {
601 CleanUpJob job = new CleanUpJob(localIdPoolCache, broker, parentPoolName, blockSize, lockManager,
603 DataStoreJobCoordinator.getInstance().enqueueJob(localIdPoolCache.getPoolName(), job,
604 IdUtils.RETRY_COUNT);
607 cleanJobTimer.schedule(scheduledTask, IdUtils.DEFAULT_DELAY_TIME * 1000);
610 private IdPool createGlobalPool(WriteTransaction tx, String poolName, long low, long high, long blockSize)
611 throws ReadFailedException {
613 InstanceIdentifier<IdPool> idPoolInstanceIdentifier = idUtils.getIdPoolInstance(poolName);
614 Optional<IdPool> existingIdPool = singleTxDB.syncReadOptional(CONFIGURATION, idPoolInstanceIdentifier);
615 if (!existingIdPool.isPresent()) {
616 if (LOG.isDebugEnabled()) {
617 LOG.debug("Creating new global pool {}", poolName);
619 idPool = idUtils.createGlobalPool(poolName, low, high, blockSize);
620 tx.put(CONFIGURATION, idPoolInstanceIdentifier, idPool, true);
622 idPool = existingIdPool.get();
623 if (LOG.isDebugEnabled()) {
624 LOG.debug("GlobalPool exists {}", idPool);
630 private IdLocalPool createLocalPool(WriteTransaction tx, String localPoolName, IdPool idPool)
631 throws OperationFailedException, IdManagerException {
632 localPoolName = localPoolName.intern();
633 IdLocalPool idLocalPool = new IdLocalPool(idUtils, localPoolName);
634 allocateIdBlockFromParentPool(idLocalPool, idPool, tx);
635 String parentPool = idPool.getPoolName();
636 localPool.put(parentPool, idLocalPool);
637 LocalPoolCreateJob job = new LocalPoolCreateJob(idLocalPool, broker, idPool.getPoolName(),
638 idPool.getBlockSize(), idUtils);
639 DataStoreJobCoordinator.getInstance().enqueueJob(localPoolName, job, IdUtils.RETRY_COUNT);
643 private void deletePool(String poolName) {
644 LocalPoolDeleteJob job = new LocalPoolDeleteJob(poolName, broker, idUtils);
645 DataStoreJobCoordinator.getInstance().enqueueJob(poolName, job, IdUtils.RETRY_COUNT);
648 public void poolDeleted(String parentPoolName, String poolName) {
649 IdLocalPool idLocalPool = localPool.get(parentPoolName);
650 if (idLocalPool != null) {
651 if (idLocalPool.getPoolName().equals(poolName)) {
652 localPool.remove(parentPoolName);
657 private void updateDelayedEntriesInLocalCache(List<Long> idsList, String parentPoolName,
658 IdLocalPool localPoolCache) {
659 for (long idValue : idsList) {
660 localPoolCache.getReleasedIds().addId(idValue);
662 localPool.put(parentPoolName, localPoolCache);