blob: bb9fd0412709559435df6bb5cce7a82f1e7c9f48 [file] [log] [blame]
Jian Li29986d82016-12-01 03:25:12 +09001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jian Li5e505c62016-12-05 02:44:24 +090016package org.onosproject.lisp.ctl.impl.map;
Jian Li29986d82016-12-01 03:25:12 +090017
18import org.slf4j.Logger;
19import org.slf4j.LoggerFactory;
20
Jian Lie5306902016-12-09 00:09:46 +090021import java.util.Collection;
22import java.util.Collections;
Jian Li29986d82016-12-01 03:25:12 +090023import java.util.Set;
24import java.util.Timer;
25import java.util.TimerTask;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ConcurrentMap;
28import java.util.concurrent.locks.Lock;
29import java.util.concurrent.locks.ReentrantLock;
30
31/**
32 * Default implementation of ExpireMap.
33 */
34public class ExpireHashMap<K, V> implements ExpireMap<K, V> {
35
36 private final Logger log = LoggerFactory.getLogger(getClass());
37
38 private static final long DEFAULT_TTL = 60000L;
39 private final ConcurrentMap<K, ExpiredObject<K, V>> map = new ConcurrentHashMap<>();
40 private final Lock writeLock = new ReentrantLock();
41 private final Timer timer = new Timer("ExpireMapTimer", true);
42
43 /**
44 * An expired object that associates with a TimerTask instance.
45 *
46 * @param <K1> key type K1
47 * @param <V1> value type V1
48 */
49 class ExpiredObject<K1, V1> {
50 private final V1 value;
51 private final ExpiryTask<K1> task;
52 private final long ttl;
53
54 public ExpiredObject(K1 key, V1 value) {
55 this(key, value, DEFAULT_TTL);
56 }
57
58 ExpiredObject(K1 key, V1 value, long ttl) {
59 this.value = value;
60 this.task = new ExpiryTask<>(key);
61 this.ttl = ttl;
62 timer.schedule(this.task, ttl);
63 }
64
65 ExpiryTask<K1> getTask() {
66 return task;
67 }
68
69 V1 getValue() {
70 return value;
71 }
72
73 long getTtl() {
74 return ttl;
75 }
76 }
77
78 /**
79 * A TimerTask that removes its associated map entry from the internal map.
80 *
81 * @param <K2> object key
82 */
83 class ExpiryTask<K2> extends TimerTask {
84 private final K2 key;
85
86 ExpiryTask(K2 key) {
87 this.key = key;
88 }
89
90 K2 getKey() {
91 return key;
92 }
93
94 @Override
95 public void run() {
96 log.info("Removing element with key [{}]", key);
97 try {
98 writeLock.lock();
99 if (map.containsKey(key)) {
100 map.remove(getKey());
101 }
102 } finally {
103 writeLock.unlock();
104 }
105 }
106 }
107
108 @Override
109 public void put(K key, V value, long expireMs) {
110 try {
111 writeLock.lock();
112
113 // if we have a value which is previously associated with the given
114 // key, we simply replace it with new value, and invalidate the
115 // previously associated value
116 final ExpiredObject<K, V> object =
117 map.putIfAbsent(key, new ExpiredObject<>(key, value, expireMs));
118
119 if (object != null) {
120 object.getTask().cancel();
121 }
122 } finally {
123 writeLock.unlock();
124 }
125 }
126
127 @Override
128 public void put(K key, V value) {
129 put(key, value, DEFAULT_TTL);
130 }
131
132 @Override
133 public V get(K key) {
134 return map.containsKey(key) ? map.get(key).getValue() : null;
135 }
136
137 @Override
138 public void clear() {
139 try {
140 writeLock.lock();
141 for (ExpiredObject<K, V> object : map.values()) {
142 object.getTask().cancel();
143 }
144 map.clear();
145 timer.purge();
146 } finally {
147 writeLock.unlock();
148 }
149 }
150
151 @Override
152 public boolean containsKey(K key) {
153 return map.containsKey(key);
154 }
155
156 @Override
157 public Set<K> keySet() {
158 return map.keySet();
159 }
160
161 @Override
Jian Lie5306902016-12-09 00:09:46 +0900162 public Collection<V> values() {
163 Collection<V> values = Collections.emptyList();
164 map.values().forEach(v -> values.add(v.getValue()));
165 return values;
166 }
167
168 @Override
Jian Li29986d82016-12-01 03:25:12 +0900169 public boolean isEmpty() {
170 return map.isEmpty();
171 }
172
173 @Override
174 public V remove(K key) {
175 final ExpiredObject<K, V> object;
176 try {
177 writeLock.lock();
178 object = map.remove(key);
179 if (object != null) {
180 object.getTask().cancel();
181 }
182 } finally {
183 writeLock.unlock();
184 }
185 return (object == null ? null : object.getValue());
186 }
187
188 @Override
189 public int size() {
190 return map.size();
191 }
192}