mlruitemstatecache.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 323 行

JAVA
323
字号
/* * 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.core.state;import org.apache.commons.collections.map.LinkedMap;import org.apache.jackrabbit.core.ItemId;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Set;import java.util.Collections;import java.util.Collection;import java.util.ArrayList;import java.util.Iterator;/** * An <code>ItemStateCache</code> implementation that internally uses a * {@link LinkedMap} to maintain a cache of <code>ItemState</code> objects. The * cache uses a rough estimate of the memory consumption of the cached item * states for calculating the maximum number of entries. The oldest entries * are flushed once the cache size has exceeded a certain limit. * <p/> * TODO rename class to something more appropriate, e.g. FIFOItemSateCache since * it doesn't use a LRU eviction policy anymore. */public class MLRUItemStateCache implements ItemStateCache, Cache {    /** Logger instance */    private static Logger log = LoggerFactory.getLogger(MLRUItemStateCache.class);    /** default maximum memory to use */    public static final int DEFAULT_MAX_MEM = 4 * 1024 * 1024;    /** the amount of memory the entries use */    private long totalMem;    /** the maximum of memory the cache may use */    private long maxMem;    /** the number of writes */    private long numWrites = 0;    /** the access count */    private long accessCount = 0;    /** the cache access listeners */    private CacheAccessListener accessListener;    /**     * A cache for <code>ItemState</code> instances     */    private final LinkedMap cache = new LinkedMap();    /**     * Constructs a new, empty <code>ItemStateCache</code> with a maximum amount     * of memory of {@link #DEFAULT_MAX_MEM}.     */    public MLRUItemStateCache() {        this(DEFAULT_MAX_MEM);    }    /**     * Constructs a new, empty <code>ItemStateCache</code> with the specified     * maximum memory.     *     * @param maxMem the maximum amount of memory this cache may use.     */    private MLRUItemStateCache(int maxMem) {        this.maxMem = maxMem;    }    //-------------------------------------------------------< ItemStateCache >    /**     * {@inheritDoc}     */    public boolean isCached(ItemId id) {        synchronized (cache) {            return cache.containsKey(id);        }    }    /**     * {@inheritDoc}     */    public ItemState retrieve(ItemId id) {        touch();        synchronized (cache) {            Entry entry = (Entry) cache.remove(id);            if (entry != null) {                // 'touch' item, by adding at end of list                cache.put(id, entry);                return entry.state;            } else {                return null;            }        }    }    /**     * {@inheritDoc}     */    public void update(ItemId id) {        touch();        synchronized (cache) {            Entry entry = (Entry) cache.get(id);            if (entry != null) {                totalMem -= entry.size;                entry.recalc();                totalMem += entry.size;            }        }    }    /**     * {@inheritDoc}     */    public void cache(ItemState state) {        touch();        synchronized (cache) {            ItemId id = state.getId();            if (cache.containsKey(id)) {                log.warn("overwriting cached entry " + id);                evict(id);            }            Entry entry = new Entry(state);            cache.put(id, entry);            totalMem += entry.size;            shrinkIfRequired();            if (numWrites++ % 10000 == 0 && log.isDebugEnabled()) {                log.debug(this + " size=" + cache.size() + ", " + totalMem + "/" + maxMem);            }        }    }    private void shrinkIfRequired() {        // remove items, if too many        synchronized (cache) {            while (totalMem > maxMem) {                ItemId id = (ItemId) cache.firstKey();                Entry entry = (Entry) cache.remove(id);                totalMem -= entry.size;            }        }    }    /**     * {@inheritDoc}     */    public void evict(ItemId id) {        touch();        synchronized (cache) {            Entry entry = (Entry) cache.remove(id);            if (entry != null) {                totalMem -= entry.size;            }        }    }    /**     * {@inheritDoc}     */    public void evictAll() {        synchronized (cache) {            cache.clear();            totalMem = 0;        }    }    /**     * {@inheritDoc}     */    public boolean isEmpty() {        synchronized (cache) {            return cache.isEmpty();        }    }    /**     * {@inheritDoc}     */    public int size() {        synchronized (cache) {            return cache.size();        }    }    /**     * {@inheritDoc}     */    public Set keySet() {        synchronized (cache) {            return Collections.unmodifiableSet(cache.keySet());        }    }    /**     * {@inheritDoc}     */    public Collection values() {        synchronized (cache) {            ArrayList list = new ArrayList(cache.size());            Iterator iter = cache.values().iterator();            while (iter.hasNext()) {                Entry entry = (Entry) iter.next();                list.add(entry.state);            }            return list;        }    }    private void touch() {        accessCount++;        if ((accessCount % CacheAccessListener.ACCESS_INTERVAL) == 0) {            if (accessListener != null) {                accessListener.cacheAccessed();            }        }    }    /**     * {@inheritDoc}     */    public long getAccessCount() {        return accessCount;    }    /**     * {@inheritDoc}     */    public long getMaxMemorySize() {        return maxMem;    }    /**     * {@inheritDoc}     */    public long getMemoryUsed() {        synchronized (cache) {            totalMem = 0;            Iterator iter = cache.values().iterator();            while (iter.hasNext()) {                Entry entry = (Entry) iter.next();                entry.recalc();                totalMem += entry.size;            }        }        return totalMem;    }    /**     * {@inheritDoc}     */    public void resetAccessCount() {        synchronized (cache) {            accessCount = 0;        }    }    /**     * {@inheritDoc}     */    public void setMaxMemorySize(long size) {        synchronized (cache) {            this.maxMem = size;            shrinkIfRequired();        }    }    /**     * Set the cache access listener. Only one listener per cache is supported.     *     * @param listener the new listener     */    public void setAccessListener(CacheAccessListener listener) {        this.accessListener = listener;    }    /**     * {@inheritDoc}     */    public void dispose() {        synchronized (cache) {            if (accessListener != null) {                accessListener.disposeCache(this);            }        }    }    /**     * Internal cache entry.     */    private static class Entry {        private final ItemState state;        private long size;        public Entry(ItemState state) {            this.state = state;            this.size = 64 + state.calculateMemoryFootprint();        }        public void recalc() {            size = 64 + state.calculateMemoryFootprint();        }    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?