/*
* INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa
* Copyright 2013 INESC-ID and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3.0 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.container;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.container.versioning.EntryVersion;
import org.infinispan.eviction.EvictionManager;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionThreadPolicy;
import org.infinispan.eviction.PassivationManager;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.util.Immutables;
import org.infinispan.util.concurrent.BoundedConcurrentHashMap;
import org.infinispan.util.concurrent.ConcurrentMapFactory;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
* // TODO: Document this
*
* @author Pedro Ruivo
* @since 5.2
*/
public abstract class AbstractDataContainer<T> implements DataContainer {
protected final ConcurrentMap<Object, T> entries;
protected InternalEntryFactory entryFactory;
private EvictionManager evictionManager;
private PassivationManager passivator;
protected AbstractDataContainer(int concurrencyLevel) {
entries = ConcurrentMapFactory.makeConcurrentMap(128, concurrencyLevel);
}
protected AbstractDataContainer(int concurrencyLevel, int maxEntries, EvictionStrategy strategy, EvictionThreadPolicy policy) {
// translate eviction policy and strategy
BoundedConcurrentHashMap.EvictionListener<Object, T> evictionListener;
switch (policy) {
case PIGGYBACK:
case DEFAULT:
evictionListener = new DefaultEvictionListener();
break;
default:
throw new IllegalArgumentException("No such eviction thread policy " + strategy);
}
BoundedConcurrentHashMap.Eviction eviction;
switch (strategy) {
case FIFO:
case UNORDERED:
case LRU:
eviction = BoundedConcurrentHashMap.Eviction.LRU;
break;
case LIRS:
eviction = BoundedConcurrentHashMap.Eviction.LIRS;
break;
default:
throw new IllegalArgumentException("No such eviction strategy " + strategy);
}
entries = new BoundedConcurrentHashMap<Object, T>(maxEntries, concurrencyLevel, eviction, evictionListener);
}
@Inject
public void initialize(EvictionManager evictionManager, PassivationManager passivator,
InternalEntryFactory entryFactory) {
this.evictionManager = evictionManager;
this.passivator = passivator;
this.entryFactory = entryFactory;
}
@Override
public Set<Object> keySet(EntryVersion version) {
return Collections.unmodifiableSet(entries.keySet());
}
@Override
public Collection<Object> values(EntryVersion version) {
return new Values(version);
}
@Override
public Set<InternalCacheEntry> entrySet(EntryVersion version) {
return new EntrySet(version);
}
@Override
public Iterator<InternalCacheEntry> iterator() {
return createEntryIterator(null);
}
protected abstract Map<Object, InternalCacheEntry> getCacheEntries(Map<Object, T> evicted);
protected abstract InternalCacheEntry getCacheEntry(T evicted);
protected abstract InternalCacheEntry getCacheEntry(T entry, EntryVersion version);
protected abstract EntryIterator createEntryIterator(EntryVersion version);
private final class DefaultEvictionListener implements BoundedConcurrentHashMap.EvictionListener<Object, T> {
@Override
public void onEntryEviction(Map<Object, T> evicted) {
evictionManager.onEntryEviction(getCacheEntries(evicted));
}
@Override
public void onEntryChosenForEviction(T entry) {
passivator.passivate(getCacheEntry(entry));
}
}
protected abstract static class EntryIterator implements Iterator<InternalCacheEntry> {}
private class ImmutableEntryIterator implements Iterator<InternalCacheEntry> {
private final EntryIterator entryIterator;
ImmutableEntryIterator(EntryIterator entryIterator){
this.entryIterator = entryIterator;
}
@Override
public boolean hasNext() {
return entryIterator.hasNext();
}
@Override
public InternalCacheEntry next() {
return Immutables.immutableInternalCacheEntry(entryIterator.next());
}
@Override
public void remove() {
entryIterator.remove();
}
}
/**
* Minimal implementation needed for unmodifiable Set
*
*/
public class EntrySet extends AbstractSet<InternalCacheEntry> {
private final EntryVersion version;
public EntrySet(EntryVersion version) {
this.version = version;
}
@Override
public boolean contains(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry) o;
InternalCacheEntry ice = getCacheEntry(entries.get(e.getKey()), version);
return ice != null && ice.getValue().equals(e.getValue());
}
@Override
public Iterator<InternalCacheEntry> iterator() {
return new ImmutableEntryIterator(createEntryIterator(version));
}
@Override
public int size() {
return AbstractDataContainer.this.size(version);
}
}
/**
* Minimal implementation needed for unmodifiable Collection
*
*/
private class Values extends AbstractCollection<Object> {
private final EntryVersion version;
private Values(EntryVersion version) {
this.version = version;
}
@Override
public Iterator<Object> iterator() {
return new ValueIterator(createEntryIterator(version));
}
@Override
public int size() {
return AbstractDataContainer.this.size(version);
}
}
private class ValueIterator implements Iterator<Object> {
private final EntryIterator currentIterator;
private ValueIterator(EntryIterator it) {
currentIterator = it;
}
@Override
public boolean hasNext() {
return currentIterator.hasNext();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Object next() {
return currentIterator.next().getValue();
}
}
}