Fix checkstyle
[lispflowmapping.git] / mappingservice / implementation / src / main / java / org / opendaylight / lispflowmapping / implementation / timebucket / containers / TimeBucketWheel.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc.  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.lispflowmapping.implementation.timebucket.containers;
9
10 import java.util.ArrayList;
11 import java.util.List;
12 import org.opendaylight.lispflowmapping.implementation.MappingSystem;
13 import org.opendaylight.lispflowmapping.lisp.type.MappingData;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.eid.container.Eid;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 /**
19  * Created by Shakib Ahmed on 12/1/16.
20  */
21 public class TimeBucketWheel {
22     private static final Logger LOG = LoggerFactory.getLogger(TimeBucketWheel.class);
23
24     private int currentBucketId;
25     private int numberOfBuckets;
26     private long lastRotationTimestamp;
27
28     private List<TimeBucket> bucketList;
29
30     private long timeFrame;
31
32     public TimeBucketWheel(int numberOfBuckets, long mappingRecordValidityInMilis, MappingSystem mappingSystem) {
33
34         if (numberOfBuckets <= 1) {
35             throw new IllegalArgumentException("Expected number of buckets "
36                     + "in TimeBucketMappingContainer to be more 1");
37         }
38
39         this.numberOfBuckets = numberOfBuckets;
40
41         initializeBucketList(mappingSystem);
42         timeFrame = (long) Math.ceil(1.0 * mappingRecordValidityInMilis / (numberOfBuckets - 1));
43         lastRotationTimestamp = System.currentTimeMillis();
44         currentBucketId = 0;
45     }
46
47     private void initializeBucketList(MappingSystem mappingSystem) {
48         bucketList = new ArrayList<>();
49         for (int i = 0; i < numberOfBuckets; i++) {
50             bucketList.add(new TimeBucket(mappingSystem));
51         }
52     }
53
54     public int add(Eid key, MappingData mappingData, long timestamp) {
55         clearExpiredMappingAndRotate(timestamp);
56         int timeBucketId = getProperBucketId(timestamp);
57
58         TimeBucket properTimeBucket = getBucket(timeBucketId);
59         properTimeBucket.add(key, mappingData);
60         return timeBucketId;
61     }
62
63     public int refreshMappping(Eid key, MappingData newMappingData, long timestamp, int bucketId) {
64         TimeBucket timeBucket = getBucket(bucketId);
65         timeBucket.removeFromBucketOnly(key);
66         return add(key, newMappingData, timestamp);
67     }
68
69     public void removeMapping(Eid key, int bucketId) {
70         TimeBucket timeBucket = getBucket(bucketId);
71         timeBucket.removeFromBucketOnly(key);
72     }
73
74     private int getLastBucketId() {
75         return (currentBucketId - 1 + numberOfBuckets) % numberOfBuckets;
76     }
77
78     private int getProperBucketId(long timestamp) {
79         if (timestamp > lastRotationTimestamp) {
80             //after rotation we are at current
81             return currentBucketId;
82         }
83
84         int relativeBucketId = (int) ((lastRotationTimestamp - timestamp) / timeFrame);
85         if (relativeBucketId >= numberOfBuckets) {
86             //too old scenario
87             LOG.error("The mapping that is being added is too old! This should not happen.");
88             return getLastBucketId();
89         }
90
91         return (this.currentBucketId + relativeBucketId) % numberOfBuckets;
92     }
93
94     private TimeBucket getBucket(int bucketId) {
95         return bucketList.get(bucketId);
96     }
97
98     public void clearExpiredMappingAndRotate() {
99         clearExpiredMappingAndRotate(System.currentTimeMillis());
100     }
101
102     public void clearExpiredMappingAndRotate(long currentStamp) {
103         int numberOfRotationToPerform = getNumberOfRotationsToPerform(currentStamp);
104
105         long timeForwarded = 0;
106
107         while (numberOfRotationToPerform > 0) {
108             clearExpiredBucket();
109             rotate();
110             numberOfRotationToPerform--;
111             timeForwarded += timeFrame;
112         }
113
114         lastRotationTimestamp = lastRotationTimestamp + timeForwarded;
115     }
116
117     private int getNumberOfRotationsToPerform(long currentStamp) {
118         if (currentStamp < lastRotationTimestamp) {
119             return 0;
120         }
121
122         long durationInMillis = (currentStamp - lastRotationTimestamp);
123
124         int numberOfRotationToPerform = (int) (1.0 * durationInMillis / timeFrame);
125         numberOfRotationToPerform = Math.min(numberOfRotationToPerform, numberOfBuckets);
126
127         return numberOfRotationToPerform;
128     }
129
130     private void clearExpiredBucket() {
131         int timeoutBucketId = getLastBucketId();
132         clearSpecificBucket(timeoutBucketId);
133     }
134
135     private void clearSpecificBucket(int bucketId) {
136         TimeBucket bucket = getBucket(bucketId);
137         bucket.clearBucket();
138     }
139
140     private void rotate() {
141         currentBucketId = getLastBucketId();
142     }
143 }