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