head	1.10;
access;
symbols;
locks; strict;
comment	@# @;


1.10
date	2001.08.11.09.08.09;	author dlr;	state Exp;
branches;
next	1.9;

1.9
date	2001.06.18.22.12.21;	author leonardr;	state Exp;
branches;
next	1.8;

1.8
date	2001.06.16.00.25.47;	author leonardr;	state Exp;
branches;
next	1.7;

1.7
date	2001.06.16.00.22.58;	author leonardr;	state Exp;
branches;
next	1.6;

1.6
date	2001.06.15.21.23.35;	author leonardr;	state Exp;
branches;
next	1.5;

1.5
date	2001.06.15.18.28.35;	author leonardr;	state Exp;
branches;
next	1.4;

1.4
date	2001.06.15.17.11.19;	author leonardr;	state Exp;
branches;
next	1.3;

1.3
date	2001.06.14.21.15.22;	author leonardr;	state Exp;
branches;
next	1.2;

1.2
date	2001.06.11.17.50.35;	author leonardr;	state Exp;
branches;
next	1.1;

1.1
date	2001.06.08.20.53.38;	author leonardr;	state Exp;
branches;
next	;


desc
@@


1.10
log
@Upgrading to Turbine 3.0-dev, Fulcrum 1.0, and Torque 1.0.
@
text
@/* ================================================================
 * Copyright (c) 2001 CollabNet.  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 CollabNet (http://www.collab.net/)."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 * 
 * 5. Products derived from this software may not use the "Tigris" name
 * nor may "Tigris" appear in their names without prior written
 * permission of CollabNet.
 * 
 * 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 COLLABNET 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 CollabNet.
 */

package org.tigris.helm.tool.cache;

import org.apache.commons.util.BufferCache;
import org.apache.turbine.util.Log;

import org.tigris.helm.om.HelmPeer;
import org.tigris.helm.om.ProjectPeer;
import org.tigris.helm.om.Host;

/**
 * A BufferCache which is dynamically resized to always cache a certain
 * percentage of the entries in a database table.
 *
 * @@author <a href="mailto:leonard@@collab.net">Leonard Richardson</a>
 * @@version $Id: TableTrackingBufferCache.java,v 1.9 2001/06/18 22:12:21 leonardr Exp $ 
 */
public class TableTrackingBufferCache extends BufferCache
{
    /**
     * Whether or not to log debugging information;
     */
    public static final boolean DEBUG = true;

    /**
     * The number of invalidations which will pass between resizes of
     * the cache.  
     */
    private static final int INVALIDATIONS_BETWEEN_RESIZES = 20;

    /**
     * The name of the table this cache is to track.
     */ 
    private String tableName;    

    /**
     * The site attribute containing fractional size of the cache as
     * compared to the number of entries in the table tracked by the
     * cache.  
     */
    private String fractionalSizeAttribute;

    /**
     * The minimum size of the cache, to be adhered to no matter how
     * few entries there are in the corresponding table.
     */
    private Integer minimumSize;

    /**
     * The maximum size of the cache, to be adhered to no matter how
     * many entries it would be useful to contain. An Integer instead of
     * an int, because it can be null.
     */
    private Integer maximumSize;

    /**
     * A counter bumped up every invalidation and reset upon resize.
     */
    private int resizeCounter = 0;

    /**
     * A constructor which sets the table tracked by this cache and
     * the size of the cache in relation to the size of the table.
     */
    public TableTrackingBufferCache(String tableName, 
                                    String fractionalSizeAttribute)
        throws Exception
    {
        this(tableName, fractionalSizeAttribute, null, null);
    }

    /**
     * A constructor which sets the table tracked by this cache,
     * the size of the cache in relation to the size of the table,
     * and the minimum size of the cache.
     */
    public TableTrackingBufferCache(String tableName, 
                                    String fractionalSizeAttribute,
                                    int minimumSize)
        throws Exception
    {
        this(tableName, fractionalSizeAttribute, new Integer(minimumSize), null);
    }

    /**
     * A constructor which sets the table tracked by this cache,
     * the size of the cache in relation to the size of the table,
     * and minimum and maximum sizes for the cache.
     */
    public TableTrackingBufferCache(String tableName, 
                                    String fractionalSizeAttribute,
                                    int minimumSize, int maximumSize)
        throws Exception
    {
        this(tableName, fractionalSizeAttribute, new Integer(minimumSize),
             new Integer(maximumSize));
    }

    /**
     * A constructor which sets the table tracked by this cache,
     * the size of the cache in relation to the size of the table,
     * and minimum and maximum sizes for the cache.
     */
    public TableTrackingBufferCache(String tableName, 
                                    String fractionalSizeAttribute,
                                    Integer minimumSize, Integer maximumSize)
        throws Exception
    {
        this.tableName = tableName;
        this.minimumSize = minimumSize;
        this.maximumSize = maximumSize;
        this.fractionalSizeAttribute = fractionalSizeAttribute;
        resize();
    }

    /**
     * Describes the cache's parameters.
     */
    public String describeParameters()
    {
        int records = -1;
        double fractionalSize = -1;
        try
        {
            records = HelmPeer.numberOfRecords(tableName);
            fractionalSize = getFractionalSize(); 
        }
        catch (Exception ignore)
        {
        }

        StringBuffer buf = new StringBuffer("\nCurrent maximum cache size: ")
            .append(getMaxSize())
            .append("\n Minimum size ").append(minimumSize).append(", ");

        if (maximumSize != null)
        {
            buf.append("absolute maximum ").append(maximumSize).append(", ");
        }

        buf.append("tracking ").append(tableName)
            .append(" table at ").append(fractionalSize)
            .append(" of ").append(records).append(" record");
        if (records != 1)
        {
            buf.append("s");
        }
        buf.append(".\n Invalidations til next resize: ")
            .append(INVALIDATIONS_BETWEEN_RESIZES-resizeCounter)
            .append("\n\n");
        return buf.toString();
    }

    /**
     * Clears and resizes the cache.
     */
    public void invalidate()
        throws Exception
    {
        clear();
        if (++resizeCounter >= INVALIDATIONS_BETWEEN_RESIZES)
        {        
            resize();
        }
    }

    /**
     * Returns the current fractional size of this cache.
     */
    public double getFractionalSize()
        throws Exception
    {
        Host host = ProjectPeer.getHost();
        String attributeValue = host
            .getHostAttributeValue(fractionalSizeAttribute).getValue();
        return Double.parseDouble(attributeValue);
    }

    /**
     * Resize the cache depending on the number of records in the database
     * table. 
     */
    public void resize()
        throws Exception
    {        
        int oldSize = getMaxSize();
        int records = HelmPeer.numberOfRecords(tableName);
        double fractionalSize = getFractionalSize();
        int newSize = (int) (records * fractionalSize);

        //Scale the new size of the cache up or down depending on
        //specified minimum or maximum sizes.
        if (minimumSize != null)
        {
            int min = minimumSize.intValue();
            if (newSize < min)
            {
                newSize = min;
            }
        }

        if (maximumSize != null)
        {
            int max = maximumSize.intValue();
            if (newSize > max)
            {
                newSize = max;
            }
        }

        if (oldSize != newSize)
        {
            if (DEBUG)
            {
                Log.debug("Resizing " + tableName + "-tracking cache to " 
                          + newSize + " (was " + oldSize + ", minimum " 
                          + minimumSize + ", " + records + " records)");
            }
            resize(newSize);           
        }
        resizeCounter = 0;
    }

    //Copied in from Turbine; remove when we upgrade.

    /**
     * Changes the maximum size of the storage buffer.
     *
     * @@param newMaxSize The new maximum size of the storage buffer.
     */
    public synchronized void resize(int newMaxSize)
    {
        //If the cache is shrinking, we may currently be storing more
        //entries than will fit in a cache of the new size. If this is
        //so, then remove entries until we have as many as we can hold.
        if (newMaxSize > maxSize)
        {
            int actualSize = keySet().size();
            while (actualSize > newMaxSize)
            {
                remove(0);
                actualSize--;
            }        
        }
        maxSize = newMaxSize;
    }

    /**
     * Returns the current maximum size of the storage buffer.
     *
     * @@return The current maximum size of the storage buffer.
     */
    public int getMaxSize()
    {
        return maxSize;
    }

    /**
     * The size of the cache.  The newest elements in the sequence are kept
     * toward the end.
     */
    private int maxSize;
}
@


1.9
log
@Huge patch of the day: Got rid of redundant HELM_DOMAIN table. The project representation of the domain and the host is now the canonical one. Host and Domain now subclass ProjectGroup. The canonical representation of a project's membership in a domain group is now the corresponding mapping in HELM_PROJECT_PROJECTGROUP. Schema changes: No more HELM_DOMAIN table (obviously); no more DOMAIN_ID in HELM_PROJECT; HELM_USER and HELM_VC_VIEW now have foreign keys in HELM_PROJECT instead of HELM_DOMAIN.
@
text
@d49 1
a49 1
import org.apache.turbine.util.BufferCache;
d61 1
a61 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.8 2001/06/16 00:25:47 leonardr Exp $ 
@


1.8
log
@Consensus is enough that this cache is good enough. Removed promise of a better cache to come.
@
text
@d53 1
d61 1
a61 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.7 2001/06/16 00:22:58 leonardr Exp $ 
d218 1
a218 1
        Host host = new Host();
@


1.7
log
@TTBC-bearing RegisterableCaches now describe the behavior of their TTBCs.
@
text
@a58 7
 * A better cache would expand and contract upon insertion, depending
 * on the timestamp of the least-recently-used entry, so that huge
 * tables infrequently accessed would have smaller caches than small
 * tables in which every entry was used, without having to determine
 * and specify a percentage. However, I'm not sure which timestamps
 * would mean expand/contract.
 *
d60 1
a60 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.6 2001/06/15 21:23:35 leonardr Exp $ 
@


1.6
log
@TableTrackingBufferCache now watches the attribute containing its fractional size, rather than the fractional size itself.
@
text
@d67 1
a67 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.5 2001/06/15 18:28:35 leonardr Exp $ 
d168 38
d219 12
d239 1
a239 4
        Host host = new Host();
        String attributeValue = host
            .getHostAttributeValue(fractionalSizeAttribute).getValue();
        double fractionalSize = Double.parseDouble(attributeValue);
@


1.5
log
@Removed need for newer Turbine.
@
text
@d53 1
d67 1
a67 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.4 2001/06/15 17:11:19 leonardr Exp $ 
d88 3
a90 2
     * The fractional size of the cache as compared to the number of 
     * entries in the table tracked by the cache.
d92 1
a92 1
    private double fractionalSize;
d116 2
a117 1
    public TableTrackingBufferCache(String tableName, double fractionalSize)
d120 1
a120 1
        this(tableName, fractionalSize, null, null);
d128 2
a129 1
    public TableTrackingBufferCache(String tableName, double fractionalSize,
d133 1
a133 1
        this(tableName, fractionalSize, new Integer(minimumSize), null);
d141 2
a142 1
    public TableTrackingBufferCache(String tableName, double fractionalSize,
d146 1
a146 1
        this(tableName, fractionalSize, new Integer(minimumSize),
d155 2
a156 1
    public TableTrackingBufferCache(String tableName, double fractionalSize,
d163 2
a164 1
        setFractionalSize(fractionalSize);
a180 10
     * Sets the fractional size and resizes the cache appropriately.
     */
    public void setFractionalSize(double fractionalSize)
        throws Exception
    {
        this.fractionalSize = fractionalSize;
        resize();
    }

    /**
d189 4
@


1.4
log
@Added code to handle the default fractional size of TableTrackingBufferCaches as host attributes.
@
text
@d66 1
a66 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.3 2001/06/14 21:15:22 leonardr Exp $ 
d222 1
a222 1
            super.resize(newSize);           
@


1.3
log
@Put TableTrackingBufferCache into practice; hopefully I can soon replace it with something smarter.
@
text
@d66 1
a66 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.2 2001/06/11 17:50:35 leonardr Exp $ 
a154 1
        this.fractionalSize = fractionalSize;
d157 1
a157 1
        resize();
d171 10
@


1.2
log
@Commented out more code that assumes a newer Turbine JAR than we have.
@
text
@d55 1
a55 1
 * A BufferCache which is dynamically resized to cache a certain
d58 7
d66 2
a67 1
 * @@version $Id: TableTrackingBufferCache.java,v 1.1 2001/06/08 20:53:38 leonardr Exp $ */
d76 6
d96 13
a108 1
    private int minimumSize;
d117 1
a117 1
        this(tableName, fractionalSize, 0);
d129 25
d157 1
d162 13
d181 1
a181 3
        //This will have to wait until we're using a newer Turbine JAR.
        int oldSize = 0;
        //int oldSize = getMaxSize();
d184 4
a187 1
        if (newSize < minimumSize)
d189 14
a202 1
            newSize = minimumSize;
d213 25
a237 1
            //super.resize(newSize);           
d239 1
d241 16
@


1.1
log
@TableTrackingBufferCache is a cache which can be resized so that it
always has room for a set percentage of the records in a table.
@
text
@d59 1
a59 1
 * @@version $Id: RegisterableCache.java,v 1.16 2001/05/30 20:15:25 leonardr Exp $ */
d111 1
a111 1
     * table.
d116 3
a118 1
        int oldSize = getMaxSize();
a133 1
            //This will have to wait until the patch gets into Turbine.
@

