Package org.fjank.jcache

Source Code of org.fjank.jcache.CacheSweeper

/*   Open Source Java Caching Service
*    Copyright (C) 2002 Frank Karlstr�m
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation; either
*    version 2.1 of the License, or (at your option) any later version.
*
*    This library is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*    Lesser General Public License for more details.
*
*    You should have received a copy of the GNU Lesser General Public
*    License along with this library; if not, write to the Free Software
*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*    The author can be contacted by email: fjankk@users.sourceforge.net
*/
package org.fjank.jcache;

import java.lang.ref.ReferenceQueue;
import java.util.Iterator;
import javax.util.jcache.Attributes;
import javax.util.jcache.CacheAttributes;
import javax.util.jcache.CacheException;
import javax.util.jcache.CacheNotAvailableException;
import javax.util.jcache.NullObjectException;




/**
* A Runnable class for Sweeping the cache for expired objects. Either they are
* serialized to disk, or they are removed from the cache depending on the
* attributes of the object.
*
* @author Frank Karlstr�m
*/
public class CacheSweeper implements Runnable {
    /** the singleton sweeper */
    private static CacheSweeper _singleton;
  /** a boolean indication wether this sweeper is active or not. */
    //2004-09-FB
    private boolean active = false;

    /**
     * Creates new CacheSweeper
     */
    private CacheSweeper() {
    }

    /**
     * sweeps the cache and removes invalid objects, waits for  cleanInterval
     * seconds, then sweeps again etc.
     */
    public void run() {
        CacheImpl cache = CacheImpl.getCache(true);
        CacheAttributes attribs = cache.getAttributes();

        while (active) {
            try {
              Thread.sleep(attribs.getCleanInterval() * 1000);
            } catch (InterruptedException e) {
                //normal
            }
            sweepCache();
        }
    }

    /**
     * checks the size of the objects in the cache,  and if the memory limit
     * is nearing its capacity,  somoe objects are saved to disk. The
     * algorithm for choosing these is in the method writeToDisk(). Then the
     * ReferenceQueue is checked, and all objects in this queue have been
     * swept by the GC. if they have expired, they are deleted from the cache.
     * If not, they are retained to the next cachesweep.
     */
    private void sweepCache() {
        CacheImpl cache = null;
        try {
            cache = CacheImpl.getCache(true);

            int maxSize = cache.getAttributes().getMemoryCacheSize();
            long maxBytes = maxSize * 1024 * 1024;
            if (getMemoryCacheSize() >= maxBytes) {
                writeToDisk();
            }
            /**sweeps the entire cache, and de-references the expired objects.
             * This will add them to the appropiate ReferenceQueue
             * when their referenceCount is zero. If no one uses the objects,
             * this will happen immediantely.
             * We also attempt to stimulate the gc to run. (Not neccessary perhaps?)
             *
             */

      CacheRegion reg = cache.getRegion();
      sweepGroup(reg);
      Iterator iter = cache.userRegionNames();
      while(iter.hasNext()) {
        Object key = iter.next();
        CacheRegion userReg = cache.getRegion(key);
        sweepGroup(userReg);
      }
      for(int i=0; i<3; i++) {
        System.runFinalization();
        System.gc();
        try {
          Thread.sleep(500);
        } catch (InterruptedException e1) {;}
      }

      /**now its up to the referencequeue to remove the
       * appropiate obects.
       */
      CacheObject cacheObj = null;
            ReferenceQueue q = cache.getReferenceQueue();
        while ((cacheObj = (CacheObject) q.poll()) != null) {
        cacheObj.resetRefCount();
        tryRemoval(cacheObj);
      }

    } catch (CacheException e) {
          e.printStackTrace();
            stopSweeper();
        } catch (java.lang.IncompatibleClassChangeError e) {
            //the cache has probably been reloaded/redeployed.
            //restart ourselves.
            if (cache != null) {
                cache.close();
                try {
                    cache.open();
                } catch (CacheNotAvailableException ee) {
                    stopSweeper();
                }
            }
        }
    }
  /**
   * Will sweep a group in search for an object which has expired.
   * any groups encountered will use this method as a recursive method
   * to further search for expired objects.
   * @todo there's no failsafe for groups containing themselves.
   * @param group the group to sweep.
   * @throws NullObjectException if a nullobject is encountered.
   */
    private void sweepGroup(CacheGroup group) throws NullObjectException {
      Iterator iter = group.weakReferenceObjects.keySet().iterator();
      while(iter.hasNext()) {
        Object key = iter.next();
        Object obj = group.weakReferenceObjects.get(key);
        if(obj instanceof CacheObject) {
          if(hasExpired((CacheObject) obj)) {
              group.removeObjectReference(key);
          }
        }else if(obj instanceof CacheGroup) {
          sweepGroup((CacheGroup) obj);
        }else {
          System.out.println("An unknown object ("+obj.getClass().getName()+") was discovered in the cache.");
          break;
        }
      }
    }

    /**
     * the actual remove routine.  if the object has been alive longer than the
     * timeToLive , its invalidated.
     * @todo Some of the code here is duplicated in tryRemoveHardReference.
     * @todo return value is never used.
     * @param cacheObj the CacheObject to try to remove.
     * @return an boolean indication wether the object was removed or not.
     */

    private boolean tryRemoval(final CacheObject cacheObj) throws NullObjectException {
        if (hasExpired(cacheObj)) {
            cacheObj.invalidate();
            return true;
        }
        return false;
    }
  private boolean hasExpired(CacheObject obj) throws NullObjectException {
    Attributes attributes = obj.getAttributes();
    if(attributes==null) throw new NullObjectException("A null attributes was detected.");
    /*-1 is the default for attributes, and the default is
     * non invalidation, so if the ttl is -1, the objects remains in the cache.
     */

    if(attributes.getTimeToLive()==-1) {
      return false;
    }
    if(attributes.getLoader()!=null) return false;
    long now = System.currentTimeMillis();
    long timealive = (now - attributes.getCreateTime()) / 1000;

    //only ttl is support for now. the rest of the params can be implemented later.
    if (timealive >= attributes.getTimeToLive()) {
      return true;
    }
    return false;
  }
    /**
     * Finds all objects wich are not in use, and determines wich one of them
     * is the best to flush to disk. LFU is a caching strategy that stands for
     * "least frequently used". In this strategy, elements are evicted based
     * when they were added, when they were last used, and how many times they
     * have been used.  Other strategies may be implemented later. Gets the
     * diskFile, fins an available position in the file, converts the
     * CacheObject to a CacheObjectDisk, and writes it to the disk file.
     *
     *@todo NOT IMPLEMENTED.
     */
    private void writeToDisk() {
    }

    /**
     * Gets the current size of all objects in the cache. Return the size of
     * the actuall object, not regarding the size of the attributes, or the
     * wrapper objects.
     *
     * @return long the current size of all objects in the cache.
     *
     *@todo NOT IMPLEMENTED.
     */
    private long getMemoryCacheSize() {
        return 0;
    }

  /**
   * activates this sweeper.
   */
  synchronized void startSweeper() {
    //2004/09-FB
    if (!_singleton.active){
      active=true;
      CacheThreadFactory fact = CacheThreadFactory.getInstance();
      fact.setName("Fjanks FKache - CacheSweeper");
      fact.setDaemon(true);
      fact.newThread(this).start();
     
    }
  }

    /**
     * deactivates this sweeper.
     */
  //2004/09-FB
  synchronized void stopSweeper() {
        active = false;
   
    }

  /**
   * create this sweeper instance.
   */
    public static synchronized CacheSweeper getInstance() {
        if (_singleton == null) {
            _singleton = new CacheSweeper();
            //2004/09-FB
            //_singleton.startSweeper();
     
        }
        return _singleton;
    }

  //2004/09-FB
  /**
   * remove this sweeper instance.
   */
  static synchronized void removeInstance() {
    if (_singleton != null) {
       if (_singleton.active){
        _singleton.stopSweeper();
       }
      _singleton = null;
     
    }
  }
}
TOP

Related Classes of org.fjank.jcache.CacheSweeper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.