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