Migrate idmanager to use mdsal-binding-util
[genius.git] / idmanager / idmanager-impl / src / main / java / org / opendaylight / genius / idmanager / IdUtils.java
1 /*
2  * Copyright (c) 2016, 2017 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 package org.opendaylight.genius.idmanager;
9
10 import com.google.common.net.InetAddresses;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.ArrayList;
14 import java.util.LinkedList;
15 import java.util.List;
16 import java.util.Optional;
17 import java.util.concurrent.CompletableFuture;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.CountDownLatch;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.atomic.AtomicInteger;
23 import javax.inject.Singleton;
24 import org.opendaylight.genius.idmanager.ReleasedIdHolder.DelayedIdEntry;
25 import org.opendaylight.mdsal.binding.util.Datastore.Configuration;
26 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdPools;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPool;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.IdPoolKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.AvailableIdsHolderBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPools;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ChildPoolsKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntries;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.IdEntriesKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.id.pools.id.pool.ReleasedIdsHolderBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntries;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.released.ids.DelayedIdEntriesBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.LockManagerService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInput;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockInputBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.TryLockOutput;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockInputBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.lockmanager.rev160413.UnlockOutput;
50 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
51 import org.opendaylight.yangtools.yang.common.RpcResult;
52 import org.opendaylight.yangtools.yang.common.Uint32;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 @Singleton
57 public class IdUtils {
58     private static final Logger LOG = LoggerFactory.getLogger(IdUtils.class);
59
60     public static final long DEFAULT_DELAY_TIME = 30;
61     private static final long DEFAULT_AVAILABLE_ID_COUNT = 0;
62     private static final int DEFAULT_BLOCK_SIZE_DIFF = 10;
63     public static final int RETRY_COUNT = 6;
64
65     private final ConcurrentHashMap<String, CompletableFuture<List<Uint32>>> allocatedIdMap = new ConcurrentHashMap<>();
66     private final ConcurrentHashMap<String, CountDownLatch> releaseIdLatchMap = new ConcurrentHashMap<>();
67     private final ConcurrentHashMap<String, AtomicInteger> poolUpdatedMap = new ConcurrentHashMap<>();
68
69     private final int bladeId;
70
71     public IdUtils() throws UnknownHostException {
72         bladeId = InetAddresses.coerceToInteger(InetAddress.getLocalHost());
73     }
74
75     public CompletableFuture<List<Uint32>> removeAllocatedIds(String uniqueIdKey) {
76         return allocatedIdMap.remove(uniqueIdKey);
77     }
78
79     public CompletableFuture<List<Uint32>> putAllocatedIdsIfAbsent(String uniqueIdKey,
80             CompletableFuture<List<Uint32>> futureIdValues) {
81         return allocatedIdMap.putIfAbsent(uniqueIdKey, futureIdValues);
82     }
83
84     public void putReleaseIdLatch(String uniqueIdKey, CountDownLatch latch) {
85         releaseIdLatchMap.put(uniqueIdKey, latch);
86     }
87
88     public CountDownLatch getReleaseIdLatch(String uniqueIdKey) {
89         return releaseIdLatchMap.get(uniqueIdKey);
90     }
91
92     public CountDownLatch removeReleaseIdLatch(String uniqueIdKey) {
93         return releaseIdLatchMap.remove(uniqueIdKey);
94     }
95
96     public InstanceIdentifier<IdEntries> getIdEntry(InstanceIdentifier<IdPool> poolName, String idKey) {
97         InstanceIdentifier.InstanceIdentifierBuilder<IdEntries> idEntriesBuilder = poolName
98                 .builder().child(IdEntries.class, new IdEntriesKey(idKey));
99         return idEntriesBuilder.build();
100     }
101
102     public IdEntries createIdEntries(String idKey, List<Uint32> newIdVals) {
103         return new IdEntriesBuilder().withKey(new IdEntriesKey(idKey))
104                 .setIdKey(idKey).setIdValue(newIdVals).build();
105     }
106
107     public DelayedIdEntries createDelayedIdEntry(long idValue, long delayTime) {
108         return new DelayedIdEntriesBuilder()
109                 .setId(idValue)
110                 .setReadyTimeSec(delayTime).build();
111     }
112
113     protected IdPool createGlobalPool(String poolName, long low, long high, long blockSize) {
114         AvailableIdsHolder availableIdsHolder = createAvailableIdsHolder(low, high, low - 1);
115         ReleasedIdsHolder releasedIdsHolder = createReleasedIdsHolder(DEFAULT_AVAILABLE_ID_COUNT, 0);
116         int size = (int) blockSize;
117         return new IdPoolBuilder().withKey(new IdPoolKey(poolName))
118                 .setBlockSize(size).setPoolName(poolName)
119                 .setAvailableIdsHolder(availableIdsHolder)
120                 .setReleasedIdsHolder(releasedIdsHolder).build();
121     }
122
123     public AvailableIdsHolder createAvailableIdsHolder(long low, long high, long cursor) {
124         return new AvailableIdsHolderBuilder()
125                 .setStart(low).setEnd(high).setCursor(cursor).build();
126     }
127
128     protected ReleasedIdsHolder createReleasedIdsHolder(long availableIdCount, long delayTime) {
129         return new ReleasedIdsHolderBuilder()
130                 .setAvailableIdCount(availableIdCount)
131                 .setDelayedTimeSec(delayTime).build();
132     }
133
134     public InstanceIdentifier<IdPool> getIdPoolInstance(String poolName) {
135         InstanceIdentifier.InstanceIdentifierBuilder<IdPool> idPoolBuilder = InstanceIdentifier
136                 .builder(IdPools.class).child(IdPool.class,
137                         new IdPoolKey(poolName));
138         return idPoolBuilder.build();
139     }
140
141     public InstanceIdentifier<ReleasedIdsHolder> getReleasedIdsHolderInstance(String poolName) {
142         InstanceIdentifier.InstanceIdentifierBuilder<ReleasedIdsHolder> releasedIdsHolder = InstanceIdentifier
143                 .builder(IdPools.class).child(IdPool.class,
144                         new IdPoolKey(poolName)).child(ReleasedIdsHolder.class);
145         return releasedIdsHolder.build();
146     }
147
148     protected boolean isIdAvailable(AvailableIdsHolderBuilder availableIds) {
149         if (availableIds.getCursor() != null && availableIds.getEnd() != null) {
150             return availableIds.getCursor() < availableIds.getEnd().toJava();
151         }
152         return false;
153     }
154
155     // public only to re-use this from IdManagerTest
156     public String getLocalPoolName(String poolName) {
157         return poolName + "." + bladeId;
158     }
159
160     protected ChildPools createChildPool(String childPoolName) {
161         return new ChildPoolsBuilder().withKey(new ChildPoolsKey(childPoolName)).setChildPoolName(childPoolName)
162                 .setLastAccessTime(System.currentTimeMillis() / 1000).build();
163     }
164
165     protected AvailableIdsHolderBuilder getAvailableIdsHolderBuilder(IdPool pool) {
166         AvailableIdsHolder availableIds = pool.getAvailableIdsHolder();
167         if (availableIds != null) {
168             return new AvailableIdsHolderBuilder(availableIds);
169         }
170         return new AvailableIdsHolderBuilder();
171     }
172
173     protected static ReleasedIdsHolderBuilder getReleaseIdsHolderBuilder(IdPool pool) {
174         ReleasedIdsHolder releasedIds = pool.getReleasedIdsHolder();
175         if (releasedIds != null) {
176             return new ReleasedIdsHolderBuilder(releasedIds);
177         }
178         return new ReleasedIdsHolderBuilder();
179     }
180
181     /**
182      * Changes made to the parameters passed are not persisted to the Datastore.
183      * Method invoking should ensure that these gets persisted.
184      */
185     public void freeExcessAvailableIds(ReleasedIdHolder releasedIdHolder,
186         ReleasedIdsHolderBuilder releasedIdsParent, long idCountToBeFreed) {
187         List<DelayedIdEntries> existingDelayedIdEntriesInParent = releasedIdsParent.getDelayedIdEntries();
188         long availableIdCountChild = releasedIdHolder.getAvailableIdCount();
189         if (existingDelayedIdEntriesInParent == null) {
190             existingDelayedIdEntriesInParent = new LinkedList<>();
191         }
192         idCountToBeFreed = Math.min(idCountToBeFreed, availableIdCountChild);
193         for (int index = 0; index < idCountToBeFreed; index++) {
194             Optional<Long> idValueOptional = releasedIdHolder.allocateId();
195             if (!idValueOptional.isPresent()) {
196                 break;
197             }
198             long idValue = idValueOptional.get();
199             DelayedIdEntries delayedIdEntries = new DelayedIdEntriesBuilder().setId(idValue)
200                     .setReadyTimeSec(System.currentTimeMillis() / 1000).build();
201             existingDelayedIdEntriesInParent.add(delayedIdEntries);
202         }
203         long availableIdCountParent = releasedIdsParent.getAvailableIdCount().toJava();
204         releasedIdsParent.setDelayedIdEntries(existingDelayedIdEntriesInParent)
205                 .setAvailableIdCount(availableIdCountParent + idCountToBeFreed);
206     }
207
208     public InstanceIdentifier<IdEntries> getIdEntriesInstanceIdentifier(String poolName, String idKey) {
209         return InstanceIdentifier
210                 .builder(IdPools.class).child(IdPool.class,
211                         new IdPoolKey(poolName)).child(IdEntries.class, new IdEntriesKey(idKey)).build();
212     }
213
214     protected InstanceIdentifier<ChildPools> getChildPoolsInstanceIdentifier(String poolName, String localPoolName) {
215         return InstanceIdentifier
216                 .builder(IdPools.class)
217                 .child(IdPool.class, new IdPoolKey(poolName))
218                 .child(ChildPools.class, new ChildPoolsKey(localPoolName)).build();
219     }
220
221     public long computeBlockSize(long low, long high) {
222         long blockSize;
223
224         long diff = high - low;
225         if (diff > DEFAULT_BLOCK_SIZE_DIFF) {
226             blockSize = diff / DEFAULT_BLOCK_SIZE_DIFF;
227         } else {
228             blockSize = 1;
229         }
230         return blockSize;
231     }
232
233     public long getAvailableIdsCount(AvailableIdsHolderBuilder availableIds) {
234         if (availableIds != null && isIdAvailable(availableIds)) {
235             return availableIds.getEnd().toJava() - availableIds.getCursor();
236         }
237         return 0;
238     }
239
240     public void lock(LockManagerService lockManager, String poolName) throws IdManagerException {
241         TryLockInput input = new TryLockInputBuilder().setLockName(poolName).build();
242         Future<RpcResult<TryLockOutput>> result = lockManager.tryLock(input);
243         try {
244             if (result != null && result.get().isSuccessful()) {
245                 if (LOG.isDebugEnabled()) {
246                     LOG.debug("Acquired lock {}", poolName);
247                 }
248             } else {
249                 throw new IdManagerException(String.format("Unable to getLock for pool %s", poolName));
250             }
251         } catch (InterruptedException | ExecutionException e) {
252             LOG.error("Unable to getLock for pool {}", poolName, e);
253             throw new RuntimeException(String.format("Unable to getLock for pool %s", poolName), e);
254         }
255     }
256
257     public void unlock(LockManagerService lockManager, String poolName) {
258         UnlockInput input = new UnlockInputBuilder().setLockName(poolName).build();
259         Future<RpcResult<UnlockOutput>> result = lockManager.unlock(input);
260         try {
261             if (result != null && result.get().isSuccessful()) {
262                 if (LOG.isDebugEnabled()) {
263                     LOG.debug("Unlocked {}", poolName);
264                 }
265             } else {
266                 if (LOG.isDebugEnabled()) {
267                     LOG.debug("Unable to unlock pool {}", poolName);
268                 }
269             }
270         } catch (InterruptedException | ExecutionException e) {
271             LOG.error("Unable to unlock for pool {}", poolName, e);
272             throw new RuntimeException(String.format("Unable to unlock pool %s", poolName), e);
273         }
274     }
275
276     public InstanceIdentifier<IdPools> getIdPools() {
277         return InstanceIdentifier.builder(IdPools.class).build();
278     }
279
280     public void syncReleaseIdHolder(ReleasedIdHolder releasedIdHolder, IdPoolBuilder idPool) {
281         long delayTime = releasedIdHolder.getTimeDelaySec();
282         ReleasedIdsHolderBuilder releasedIdsBuilder = new ReleasedIdsHolderBuilder();
283         List<DelayedIdEntries> delayedIdEntriesList = new ArrayList<>();
284         List<DelayedIdEntry> delayList = releasedIdHolder.getDelayedEntries();
285         for (DelayedIdEntry delayedId : delayList) {
286             DelayedIdEntries delayedIdEntry = createDelayedIdEntry(delayedId.getId(), delayedId.getReadyTimeSec());
287             delayedIdEntriesList.add(delayedIdEntry);
288         }
289         releasedIdsBuilder.setAvailableIdCount((long) delayedIdEntriesList.size()).setDelayedTimeSec(delayTime)
290                 .setDelayedIdEntries(delayedIdEntriesList);
291         idPool.setReleasedIdsHolder(releasedIdsBuilder.build());
292     }
293
294     public void syncAvailableIdHolder(AvailableIdHolder availableIdHolder, IdPoolBuilder idPool) {
295         long cur = availableIdHolder.getCur().get();
296         long low = availableIdHolder.getLow();
297         long high = availableIdHolder.getHigh();
298         AvailableIdsHolder availableIdsHolder = createAvailableIdsHolder(low, high, cur);
299         idPool.setAvailableIdsHolder(availableIdsHolder);
300     }
301
302     public void updateChildPool(TypedWriteTransaction<Configuration> tx, String poolName, String localPoolName) {
303         ChildPools childPool = createChildPool(localPoolName);
304         InstanceIdentifier<ChildPools> childPoolInstanceIdentifier =
305                 getChildPoolsInstanceIdentifier(poolName, localPoolName);
306         tx.mergeParentStructureMerge(childPoolInstanceIdentifier, childPool);
307     }
308
309     public void incrementPoolUpdatedMap(String localPoolName) {
310         AtomicInteger value = poolUpdatedMap.putIfAbsent(localPoolName, new AtomicInteger(0));
311         if (value == null) {
312             value = poolUpdatedMap.get(localPoolName);
313         }
314         value.incrementAndGet();
315     }
316
317     public void decrementPoolUpdatedMap(String localPoolName) {
318         AtomicInteger value = poolUpdatedMap.get(localPoolName);
319         if (value != null && value.get() >= 1) {
320             value.decrementAndGet();
321         }
322     }
323
324     public boolean getPoolUpdatedMap(String localPoolName) {
325         AtomicInteger value = poolUpdatedMap.get(localPoolName);
326         return value != null && value.get() > 0;
327     }
328
329     public void removeFromPoolUpdatedMap(String localPoolName) {
330         poolUpdatedMap.remove(localPoolName);
331     }
332
333     public String getUniqueKey(String parentPoolName, String idKey) {
334         return parentPoolName + idKey;
335     }
336 }