blob: 02f1a5c97161cd9e6761bacbf8aa0636e1ae2133 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.mnemonic;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
/**
*
* This class inherited from abstract CachePool class that implemented all
* inherited abstract methods. it specialized to cache MemBufferHolder objects
* that is backed by native memory pool.
*
*/
public class MemBufferHolderCachePool<KeyT> extends CachePool<KeyT, MemBufferHolder<?>> {
private static final long serialVersionUID = 684275993324558070L;
private AtomicLong currentMemory = new AtomicLong(0L);
private long maxStoreCapacity = 0L;
/**
* Constructs an empty cache pool with specified capacity.
*
* @param maxCapacity
* the capacity of this cache pool
*
*/
public MemBufferHolderCachePool(long maxCapacity) {
super(512, 0.75f);
maxStoreCapacity = maxCapacity;
}
/**
* @see CachePool#freeCapacity()
*/
@Override
public long freeCapacity() {
return maxStoreCapacity - currentMemory.get();
}
/**
* @see CachePool#usedCapacity()
*/
@Override
public long usedCapacity() {
return currentMemory.get();
}
/**
* @see Map#remove(Object)
*/
@Override
public synchronized MemBufferHolder<?> remove(Object k) {
MemBufferHolder<?> ret = super.remove(k);
if (null != ret) {
currentMemory.getAndAdd(-ret.getSize());
}
return ret;
}
/**
* Associates the specified value with the specified key in this map (optional
* operation). If the map previously contained a mapping for the key, the old
* value is replaced by the specified value. (A map m is said to contain a
* mapping for a key k if and only if m.containsKey(k) would return true.)
*
* @param k
* key with which the specified value is to be associated
*
* @param v
* MemBufferHolder value to be associated with the specified key
*
* @return the previous value associated with key, or null if there was no
* mapping for key. (A null return can also indicate that the map
* previously associated null with key, if the implementation supports
* null values.)
*/
@Override
public MemBufferHolder<?> put(KeyT k, MemBufferHolder<?> v) {
return put(k, v, null, null);
}
/**
* @see CachePool#put(Object, Object, DropEvent, EvictFilter)
*/
@Override
public MemBufferHolder<?> put(KeyT k, MemBufferHolder<?> v, DropEvent<KeyT, MemBufferHolder<?>> fsop,
EvictFilter<KeyT, MemBufferHolder<?>> dfilter) {
MemBufferHolder<?> ret = null;
long sz = v.getSize();
if (containsKey(k)) {
sz -= get(k).getSize();
}
if (sz <= maxStoreCapacity && ensureFreeSpace(sz, fsop, dfilter)) {
currentMemory.addAndGet(sz);
ret = super.put(k, v);
} else {
throw new ContainerOverflowException("Out of capacity of MemBufferHolderCachePool.");
}
return ret;
}
/**
* @see Map#putAll(Map)
*/
@Override
public void putAll(Map<? extends KeyT, ? extends MemBufferHolder<?>> m) {
putAll(m, null, null);
}
/**
* @see CachePool#putAll(Map, DropEvent, EvictFilter)
*/
@Override
public void putAll(Map<? extends KeyT, ? extends MemBufferHolder<?>> m, DropEvent<KeyT, MemBufferHolder<?>> fsop,
EvictFilter<KeyT, MemBufferHolder<?>> dfilter) {
long reqsz = 0;
for (KeyT k : m.keySet()) {
reqsz += m.get(k).getSize();
}
if (reqsz <= maxStoreCapacity && ensureFreeSpace(reqsz, fsop, dfilter)) {
currentMemory.addAndGet(reqsz);
super.putAll(m);
} else {
throw new ContainerOverflowException("Out of capacity of MemBufferHolderCachePool.");
}
}
/**
* @see CachePool#hotKeySet(int)
*/
@Override
public Set<KeyT> hotKeySet(int n) {
Set<KeyT> ret = new HashSet<KeyT>();
ArrayList<KeyT> keys = new ArrayList<KeyT>(keySet());
int endindex = keys.size() > n ? keys.size() - n : 0;
for (int i = keys.size(); i > endindex; i--) {
ret.add(keys.get(i - 1));
}
return ret;
}
/**
* @see CachePool#ensureFreeSpace(long)
*/
@Override
public boolean ensureFreeSpace(long freesz) {
return ensureFreeSpace(freesz, null, null);
}
/**
* @see CachePool#removeFirstEntry(DropEvent, EvictFilter)
*/
@Override
public boolean removeFirstEntry(DropEvent<KeyT, MemBufferHolder<?>> fsop,
EvictFilter<KeyT, MemBufferHolder<?>> dfilter) {
boolean ret = false;
boolean delible = true;
for (Map.Entry<KeyT, MemBufferHolder<?>> entry : entrySet()) {
if (null != dfilter) {
delible = dfilter.validate(this, entry.getKey(), entry.getValue());
}
if (delible) {
KeyT k = entry.getKey();
MemBufferHolder<?> v = remove(k);
if (null != fsop) {
fsop.drop(this, k, v);
}
ret = true;
break;
}
}
return ret;
}
/**
* @see CachePool#ensureFreeSpace(long, DropEvent, EvictFilter)
*/
@Override
public boolean ensureFreeSpace(long freesz, DropEvent<KeyT, MemBufferHolder<?>> fsop,
EvictFilter<KeyT, MemBufferHolder<?>> dfilter) {
boolean ret = false;
if (freesz <= freeCapacity()) {
return true;
}
if (freesz > maxStoreCapacity) {
return false;
}
long selectedMemory = 0L;
Set<KeyT> selected = new HashSet<KeyT>();
boolean delible = true;
for (Map.Entry<KeyT, MemBufferHolder<?>> entry : entrySet()) {
if (null != dfilter) {
delible = dfilter.validate(this, entry.getKey(), entry.getValue());
}
if (delible) {
selectedMemory += entry.getValue().getSize();
selected.add(entry.getKey());
if (freesz <= freeCapacity() + selectedMemory) {
ret = true;
break;
}
}
}
if (ret) {
for (KeyT k : selected) {
MemBufferHolder<?> mbh = remove(k);
if (null != fsop) {
fsop.drop(this, k, mbh);
}
}
}
return ret;
}
}