
org.apache.jackrabbit.spi.commons.conversion.GenerationalCache Maven / Gradle / Ivy
/*
* 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.jackrabbit.spi.commons.conversion;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
/**
* Generational cache. The cache implemented by this class consists of three
* parts: a long term cache and two generations of recent entries. The two
* generations are used to collect recent new entries, and those entries that
* are used within two successive generations get promoted to the long term
* cache. The entries within the long term cache are discarded only when the
* size of the cache exceeds the given maximum cache size.
*/
class GenerationalCache {
/**
* Default maximum cache size.
*/
private static final int DEFAULT_CACHE_SIZE = 1000;
/**
* Divisor used to determine the default generation age from the
* maximum cache size.
*/
private static final int DEFAULT_SIZE_AGE_RATIO = 10;
/**
* Maximum size of the name cache.
*/
private final int maxSize;
/**
* Maximum age of a cache generation.
*/
private final int maxAge;
/**
* Long term cache. Read only.
*/
private Map cache = new HashMap();
/**
* Old cache generation.
*/
private Map old = new HashMap();
/**
* Young cache generation.
*/
private Map young = new HashMap();
/**
* Age of the young cache generation.
*/
private int age = 0;
/**
* Creates a caching resolver.
*
* @param maxSize maximum size of the long term cache
* @param maxAge maximum age of a cache generation
*/
public GenerationalCache(int maxSize, int maxAge) {
this.maxSize = maxSize;
this.maxAge = maxAge;
}
/**
* Creates a caching resolver using the default generation age for
* the given cache size.
*
* @param maxSize maximum size of the long term cache
*/
public GenerationalCache(int maxSize) {
this(maxSize, maxSize / DEFAULT_SIZE_AGE_RATIO);
}
/**
* Creates a caching resolver using the default size and generation age.
*/
public GenerationalCache() {
this(DEFAULT_CACHE_SIZE);
}
/**
* Returns the cached value (if any) for the given key. The value is
* looked up both from the long term cache and the old cache generation.
* If the value is only found in the old cache generation, it gets added
* to the young generation via a call to {@link #put(Object, Object)}.
*
* @param key key of the cache entry
* @return value of the cache entry, or null
*/
public Object get(Object key) {
Object value = cache.get(key);
if (value == null) {
value = old.get(key);
if (value != null) {
put(key, value);
}
}
return value;
}
/**
* Caches the given key-value pair and increases the age of the current
* cache generation. When the maximum age of a generation is reached,
* the following steps are taken:
*
* - The union of the two cache generations is calculated
* - The union is added to the long term name cache
* - If the cache size exceeds the maximum, only the union is kept
* - A new cache generation is started
*
*
* @param key key of the cache entry
* @param value value of the cache entry
*/
public synchronized void put(Object key, Object value) {
young.put(key, value);
if (++age == maxAge) {
Map union = new HashMap();
Iterator iterator = old.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
if (young.containsKey(entry.getKey())) {
union.put(entry.getKey(), entry.getValue());
}
}
if (!union.isEmpty()) {
if (cache.size() + union.size() <= maxSize) {
union.putAll(cache);
}
cache = union;
}
old = young;
young = new HashMap();
age = 0;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy