You are viewing a plain text version of this content. The canonical link for it is here.
Posted to slide-dev@jakarta.apache.org by Martin Holz <ho...@fiz-chemie.de> on 2003/03/21 10:43:25 UTC

ObjectCache broken

Hello,

I tried to understand, how HashMapObjectCache and AbstractObjectCache 
work, but it makes no sense to me at all. 

At least, line 211 in  HashMapObjectCache.java rev.18
should be   "if (getSize() > maxSize)", not the 
other way. Currently the cache would grow forever
in some scenarios. However in most scenarios the
cache is pruned quite often without any need, even
if it holds only one object.

Aside from this obvious bug, I do not understand the
overal caching strategy. Why is the complete cache
cleared, if it is to successful? 

Replacing the current cache with the attached  LRU implementation
improved webdav overall performace 10 times. 

The LRUObjectCache reuses a cache from a different program and   
is not optimized. If someone has a better implementation, I would 
be happy. But it works reliable for me.



Re: ObjectCache broken

Posted by Martin Holz <ho...@fiz-chemie.de>.
Looks like the two attachments did not make it through the news-to-mail
gateway, so I embed them directly now.




----------------------------------------------------------------------
/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/util/ObjectCache.java,v 1.7 2002/04/25 21:30:16 jericho Exp $
 * $Revision: 1.7 $
 * $Date: 2002/04/25 21:30:16 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Slide", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */ 

package org.apache.slide.util;

/**
 * A LRU implementation of ObjectCache.
 * 
 * @author <a href="mailto:holz@fiz-chemie.de">Martin Holz</a>
 * @version $Revision: 1.7 $ $Date: 2002/04/25 21:30:16 $
 */
public class LRUObjectCache implements  ObjectCache {
    private CacheMap m_cache;  
    

    public LRUObjectCache(int size) {
	m_cache = new CacheMap(size);
    }

    
    /**
     * Get the object associated with the key.
     * 
     * @param key Object's key
     * @return Object null if there is no object associated with that key in 
     * the cache, or the object value otherwise
     */
    public synchronized Object get(Object key) {
	return m_cache.fetch(key);
    }
    
    
    /**
     * Add an object to the cache, or overwrite its value.
     * 
     * @param key Object's key
     * @param object Object's value
     */
    public synchronized void put(Object key, Object value) {
	m_cache.delete(key);
	m_cache.add(key,value);
    }
    
    
    /**
     * Remove object associated with the given key. Doesn't do anything if the 
     * key wasn't associated with any object.
     * 
     * @param key Object's key
     */
    public synchronized void remove(Object key) {
	m_cache.delete(key);
    }
    
    
    /**
     * Clear object cache.
     */
    public synchronized void clear() {
	m_cache.clear();
    }   
}

--------------------------------------------------------------------------------------------------

/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/util/ObjectCache.java,v 1.7 2002/04/25 21:30:16 jericho Exp $
 * $Revision: 1.7 $
 * $Date: 2002/04/25 21:30:16 $
 *
 * ====================================================================
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights 
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:  
 *       "This product includes software developed by the 
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Slide", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written 
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */ 

package org.apache.slide.util;


/**
 * CacheMap is a cache, which implements a "least recently
 * used" strategy.
 * It is not thread safe. A cache manager should synchronize
 * the concurrent access.
 *
 * @author   <a href="mailto:holz@fiz-chemie.de">Martin Holz</a>
 * @version  $Revision: 1.4 $ $Date: 2000/11/05 14:25:24 $ $State: Exp $
 *
 */

import java.util.HashMap;
import java.util.TreeSet;

class CacheMap {

    static final int DEFAULT_SIZE = 100;
    private int MAX_SIZE;
    private long _curNum = 0;

    private HashMap _dataMap;
    private TreeSet _usedSet;

    /**
     *  Create a CacheMap
     *
     * @param maxsize The maximum number of elements the cache can
     * hold. maxsize must be a positiv number.
     */
    CacheMap(int maxsize) {
	//assert maxsize > 0;
	MAX_SIZE = maxsize;
	_dataMap = new HashMap((int)(maxsize * 1.33));
	_usedSet = new TreeSet();
    }

   /**
    *  Create a CacheMap with a default size.
    */
    CacheMap() {
	this(DEFAULT_SIZE);
    }

    /**
     * Add a object to the cache. You must not call this
     * method, if the key allready exists in the cache.
     *
     * @throws IllegalStateException If the key is already in the map.
     *
     * @param key A key, which identifies the data.
     * @param data The data, you want to add to the cache.
     *
     * Neither <code>key</code> nor <code>data</code>
     * should be <code>null</code>.
     *
     */
    void add(Object key,Object data) {
	if (_dataMap.containsKey(key)) {
	    throw new IllegalStateException("You must not call add, if the key"
				       + " is already in the map.");
	}

	Bag bag = new Bag(key,data);
	_dataMap.put(key,bag);
	_usedSet.add(bag);

	shrink();
    }

    /**
     * Return object, with key <code>key</key>
     * or null, if it is not in the cache.
     */
    Object fetch(Object key) {
	Bag bag = (Bag)_dataMap.get(key);
	if (bag == null) {
	    return null;
	}

	Object data = bag.getData();
	Bag newBag = new Bag(key,data);

	boolean success = _usedSet.remove(bag);
        // assert success;
	_usedSet.add(newBag);
        _dataMap.put(key,newBag);

	return data;
    }

    /**
     * Remove a key from cache, if present.
     */
    void delete(Object key) {
	Bag bag = (Bag)_dataMap.remove(key);
	if (bag == null) {
	    return;
	}
	boolean success = _usedSet.remove(bag);
        //assert success;
    }

    /**
     * Resizes the cache map.
     *
     * @throws IllegalArgumentException If the maxsize is smaller
     * than 1.
     */
    synchronized void resize(int maxsize) {
	if (maxsize < 1) {
	    throw new IllegalArgumentException(
		"Cache size must be a positiv number.");
	}
	MAX_SIZE = maxsize;
	shrink();
    }


    /**
     * Remove old entries until cache size fits.
     */
    synchronized protected void shrink() {
	while (_usedSet.size() > MAX_SIZE) {
	    Bag oldBag = (Bag)_usedSet.last();
	    //System.err.println("Remove " + oldBag.getData());
	    _usedSet.remove(oldBag);
	    _dataMap.remove(oldBag.getKey());
	}
    }

    /**
     * Remove all entries from cache.
     */
    synchronized void clear() {
	_usedSet.clear();
	_dataMap.clear();
    }

    /**
     * The number of elements, the cache can hold.
     */
    public int size() {
	return MAX_SIZE;
    }

    /**
     * Number of elements in cache.
     */
    public int numElements() {
	System.err.println("DataMap " + _dataMap.size());
	System.err.println("UsedSet " + _usedSet.size());
	return _dataMap.size();
    }

    /**
     * Bag is a tuple (timestamp,key,data).
     */
    protected class Bag implements Comparable {
	private Object key;
	private Object data;
	private long myNum;
	private Long myNumber;

	public Bag(Object key, Object data) {
	    this.key = key;
	    this.data = data;
	    myNum = _curNum++;
	    myNumber = new Long(myNum);
	}

	// The smallest object is the most recently used one.
	public int compareTo(Object o) throws ClassCastException {
	    Bag other = (Bag)o;
	    return (-1) * myNumber.compareTo(other.myNumber);
	}

	public boolean equals(Object o) {
	    if (o instanceof Bag) {
		return myNumber.equals(((Bag)o).myNumber);
	    } else {
		return false;
	    }
	}
	public Object getKey() { return key; }

	public Object getData() { return data; }
    }
}


---------------------------------------------------------------------
To unsubscribe, e-mail: slide-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: slide-dev-help@jakarta.apache.org