/*
* Copyright 2015 Evgeny Dolganov (evgenij.dolganov@gmail.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package och.comp.cache.impl;
import static och.util.concurrent.DoneFuture.*;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import och.comp.cache.Cache;
public class CacheImpl implements Cache {
//private Log log = getLog(getClass());
private long removeOldDeltaTime;
private ConcurrentHashMap<Object, CacheItem> map = new ConcurrentHashMap<>();
private Timer cleanDeadItemsTimer;
public CacheImpl(long removeOldDeltaTime) {
this.removeOldDeltaTime = removeOldDeltaTime;
}
public void run(){
cleanDeadItemsTimer = new Timer("CacheImpl-cleanDeadItemsTimer", false);
cleanDeadItemsTimer.scheduleAtFixedRate(new TimerTask(){
@Override
public void run() {
cleanDeadItems();
}
}, removeOldDeltaTime, removeOldDeltaTime);
}
public void shutdown(){
cleanDeadItemsTimer.cancel();
}
public void putObjVal(Object key, Object val, int liveTime) {
map.put(key, new CacheItem(key, val, liveTime));
}
public Object getObjVal(Object key) {
CacheItem item = map.get(key);
if(item == null) return null;
if(item.isNeedRemove()){
map.remove(key);
return null;
}
return item.val;
}
public Object removeObjVal(Object key) {
CacheItem item = map.remove(key);
if(item == null) return null;
return item.val;
}
public Integer getItemLivetime(Object key){
CacheItem cacheItem = map.get(key);
return cacheItem == null? null : cacheItem.liveTime;
}
private void cleanDeadItems(){
LinkedList<Object> toDelete = new LinkedList<>();
Set<Entry<Object, CacheItem>> entrySet = map.entrySet();
for (Entry<Object, CacheItem> entry : entrySet) {
if(entry.getValue().isNeedRemove()) toDelete.add(entry.getKey());
}
if(toDelete.size() == 0) return;
//log.info("Found items to delete: "+toDelete.size());
for (Object key : toDelete) {
map.remove(key);
}
}
@Override
public Future<?> putCacheAsync(String key, String val) {
putObjVal(key, val, 0);
return EMPTY_DONE_FUTURE;
}
@Override
public Future<?> putCacheAsync(String key, String val, int liveTime) {
putObjVal(key, val, liveTime);
return EMPTY_DONE_FUTURE;
}
@Override
public void tryPutCache(String key, String val) {
putObjVal(key, val, 0);
}
@Override
public void tryPutCache(String key, String val, int liveTime) {
putObjVal(key, val, liveTime);
}
@Override
public void putCache(String key, String val) throws IOException {
putObjVal(key, val, 0);
}
@Override
public void putCache(String key, String val, int liveTime) throws IOException {
putObjVal(key, val, liveTime);
}
@Override
public String tryGetVal(String key) {
return (String)getObjVal(key);
}
@Override
public String tryGetVal(String key, String defaultVal) {
String out = tryGetVal(key);
if(out == null) return defaultVal;
return out;
}
@Override
public String getVal(String key) throws IOException {
return tryGetVal(key);
}
@Override
public String tryRemoveCache(String key) {
return (String)removeObjVal(key);
}
@Override
public String removeCache(String key) throws IOException {
return tryRemoveCache(key);
}
@Override
public Future<?> removeCacheAsync(String key) {
tryRemoveCache(key);
return EMPTY_DONE_FUTURE;
}
}