All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jackrabbit.spi.commons.conversion.GenerationalCache Maven / Gradle / Ivy

There is a newer version: 2.23.1-beta
Show newest version
/*
 * 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:
     * 
    *
  1. The union of the two cache generations is calculated
  2. *
  3. The union is added to the long term name cache
  4. *
  5. If the cache size exceeds the maximum, only the union is kept
  6. *
  7. A new cache generation is started
  8. *
* * @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