Package net.sf.cache4j.impl

Source Code of net.sf.cache4j.impl.BlockingCache$CacheInfoImpl

/* =========================================================================
* File: $Id: $BlockingCache.java,v$
*
* Copyright (c) 2006, Yuriy Stepovoy. All rights reserved.
* email: stepovoy@gmail.com
*
* =========================================================================
*/

package net.sf.cache4j.impl;

import net.sf.cache4j.CacheException;
import net.sf.cache4j.Cache;
import net.sf.cache4j.CacheConfig;
import net.sf.cache4j.CacheInfo;
import net.sf.cache4j.ManagedCache;

import java.util.Map;
import java.util.TreeMap;
import java.util.HashMap;
import java.io.IOException;

/**
* ����� BlockingCache ��� ���������� ���������� {@link net.sf.cache4j.Cache}
* � ������������� �� ������ ��������. ����� �������� ������ <code>get, put, remove</code>
* �������� � ���������� �������������� ������� � ����� � ������ ����������
* (� �������� ��������� ������). ���� ����� <code>get</code> ������ null ��
* ���������� � �������������� �� ���������. �����, ������� ������������
* �������������, ������ ��������� ������ � ��������� � ���, ������ ����� �����
* ���������� ����� ����� � ��� �������������� ������ ������ ���������� ������.
* ����� ��������� ��������� ���������(���������) ������, �������� ��� � ����,
* ������ � ����� ������.
* <br>
* ��������� ���������� ����:
* <pre>
*     Cache _personCache = CacheFactory.getInstance().getCache("Person");
* </pre>
* ���������\��������� �������:
* <pre>
*     Long id = ... ;
*     Person person = null;
*     try {
*         person = (Person)_personCache.get(id);
*     } catch (CacheException ce) {
*         //throw new Exception(ce);
*     }
*     if (person != null) {
*         return person;
*     }
*     try {
*         person = loadPersonFromDb(id);
*     } catch (Exception e) {
*         //throw new Exception(e);
*     } finally {
*         try {
*             _personCache.put(id, person);
*         } catch (CacheException ce) {
*             //throw new Exception(ce);
*         }
*     }
* </pre>
* �������� �������:
* <pre>
*     Person person = ... ;
*     Long id = person.getId();
*     removePersonFromDb(id);
*     try {
*         _personCache.remove(id);
*     } catch (CacheException ce) {
*         //throw new Exception(ce);
*     }
* </pre>
*
* @version $Revision: 1.0 $ $Date:$
* @author Yuriy Stepovoy. <a href="mailto:stepovoy@gmail.com">stepovoy@gmail.com</a>
**/

public class BlockingCache implements Cache, ManagedCache {
// ----------------------------------------------------------------------------- ���������
// ----------------------------------------------------------------------------- �������� ������
    /**
     * ����� � ����������� ���������
     */
    private Map _map;

    /**
     * ������ � ��������������� ������ ����\�������� � ����������� �� ��������� ��������
     */
    private TreeMap _tmap;

    /**
     * ������������ ����
     */
    private CacheConfigImpl _config;

    /**
     * ������ �������� ���� � ������
     */
    private long _memorySize;

    /**
     * ���������� � ����
     */
    private CacheInfoImpl _cacheInfo;

    /**
     * ThreadLocal ������������ ��� �������� CacheObject ����� ��������
     * get() - put()\remove(). ���� ����� get() ������ null, ������ CacheObject
     * � ��������� ��������������� ������� ����������� ������� ������� � ��� ���
     * ��������� �������.
     * ���� ����� �� ������ �� �������� ������������� deadlock.
     * ������:
     *   - �����1 ������� CacheObject1 c ������ 1, �����2 ��� ��������� ��
     *     CacheObject1 c ������ 1, �����3 ��� ��������� �� CacheObject1 c ������ 1.
     *   - �����1 ������ ������ CacheObject1 � ���� ���������. �����2 �������
     *     ��������� �� ������ CacheObject1 ����1 � ������� null ������ �������
     *     (������ ��� ������ �� ���������������� ������ �������)
     *   - �����2 �������� ������ � ������ 1 � �������� ��� � ���, �� ��� ���
     *     CacheObject1 ����1 ��� ����� �������1 �������� ����� ������
     *     CacheObject2 � ������ 1. � ����� CacheObject2
     *     ���������� ���������������� ������ � ��������� ���������.
     *   - �����3 ���������� ����� ������ ��������� � ������� ������� CacheObject1
     *     � ������� 1. �����3 ������� �� ��������. deadlock !!!
     */
    private ThreadLocal _tl = new ThreadLocal();

// ----------------------------------------------------------------------------- ����������� ����������
// ----------------------------------------------------------------------------- ������������
// ----------------------------------------------------------------------------- Public ������

    //-------------------------------------------------------------------------- Cache interface
    /**
     * �������� ������ � ���. ���� ����� ������� put() ��� ������ ����� get()
     * � �� ������ null �� � put() ����� �������� ����� �� objId ��� � � ����� get()
     * ����� ��������� CacheException.
     * @param objId ������������� �������
     * @param obj ������
     * @throws CacheException ���� �������� ��������, �������� ���������� ������� �������
     * @throws NullPointerException ���� objId==null
     */
    public void put(Object objId, Object obj) throws CacheException {
        if(objId==null) {
            throw new NullPointerException("objId is null");
        }

        //������ CacheObject �� �������� ������
        CacheObject tlCO = (CacheObject)_tl.get();
        CacheObject co = null;

        int objSize = 0;
        try {
            objSize = _config.getMaxMemorySize()>0 ? Utils.size(obj) : 0;
        } catch (IOException e) {
            throw new CacheException(e.getMessage());
        }

        //��������� �� ��������� �� ������������ ����
        checkOverflow(objSize);

        if (tlCO==null) {
            //���� � ������� ������ ��� CacheObject ������ ����� get() ����� ����
            //��� �� ��������� ��� ������ ������
            co = getCacheObject(objId);
        } else {
            //���� � ������� ������ ���� ������ ������ ����� ���� ����� get() ������ null

            //������������� �� �������� ������ � ������������� ����������� ������� ������ ����
            //�����������. ���� ��� �� ��� �� ��� ������ ������ get() ��� ������� ���� ����
            //� ��� ������ ������ put() ��� ������� ������ ����, � ��� �����������.
            if(tlCO.getObjectId().equals(objId)){
                //����� �� ��������� ����������� � ������ get() ������
                //����� ������ ���������� ������ ������������ ��� ���������� ���������
                co = tlCO;
                //������� ������ �� �������� ������ ����� ������ ����� �����������
                //������ ������ put()
                _tl.set(null);
            } else {
                tlCO.unlock();
                throw new CacheException("Cache:"+_config.getCacheId()+" wait for call put() with objId="+tlCO.getObjectId());
            }
        }

        co.lock();
        _cacheInfo.incPut();
        try {
            //��� ��������� � ������� ������������ ���������� co.reset()
            //� �������������� ���������� ���� � ������� ������ ��� ������� � _tmap
            //������� ������ ����� ������� �� _tmap
            //?:��� �������� ������� �� ���� � ���� ��� ������ ��������
            tmapRemove(co);

            //�������� CacheObject � ������������ �������� ����
            resetCacheObject(co);

            co.setObject(obj);
            co.setObjectSize(objSize);

            synchronized(this) {
                _memorySize = _memorySize + objSize;
            }

            tmapPut(co);
        } finally {
            co.unlock();
        }
    }

    /**
     * ���������� ������ �� ����. ���� ����� ������ null �� ���������� ������������
     * ������ � ���������� objId. ����� ����� � ��� ����� ��������� ������ �
     * ������� ����� objId ����� ��� ������ ������ ������ ����� ���������
     * CacheException.
     * @param objId ������������� �������
     * @return ������ ������������ ������ � ��� ������, ���� ������ ������
     * � ����� ����� ������� �� ����������� � �� ��������� ����� �����������.
     * @throws CacheException ���� �������� ��������
     * @throws NullPointerException ���� objId==null
     */
    public Object get(Object objId) throws CacheException {
        if(objId==null) {
            throw new NullPointerException("objId is null");
        }

        CacheObject tlCO = (CacheObject)_tl.get();
        if (tlCO!=null) {
            throw new CacheException("Cache:"+_config.getCacheId()+" wait for call put() with objId="+tlCO.getObjectId());
        }

        CacheObject co = getCacheObject(objId);
        co.lock();
        Object o = co.getObject();
        if(o!=null){
            tmapRemove(co);

            if(!valid(co)) {
                resetCacheObject(co);
                //�������� ������ � ������� �����
                _tl.set(co);

                _cacheInfo.incMisses();
                //������ �� �������� ������� ��������� �� �������
                return null;
            } else {
                co.updateStatistics();
                tmapPut(co);

                //������ ���������� � �� �������� ������� ������� ���������� � �������
                co.unlock();
                _cacheInfo.incHits();

                //?:return copy(o);
                return o;
            }
        } else {
            //�������� ������ � ������� ����� ����� ����� ������� � ������ put()
            _tl.set(co);
            _cacheInfo.incMisses();
            //���� ������� ��� �� ��������� �� �������
            return null;
        }
    }

    /**
     * ������� ������ �� ����.
     * @param objId ������������� �������
     * @throws CacheException ���� ����� ������� remove() ��� ������ ����� get()
     * � �� ������ null �� ��� ������ remove() ��������� CacheException.
     * @throws NullPointerException ���� objId==null
     */
    public void remove(Object objId) throws CacheException {
        if(objId==null) {
            throw new NullPointerException("objId is null");
        }

        //���� �� ������� ������� �������� ������ ������ ����� put() �� ��� ������
        //����� ���� ��� get() ������ null
        CacheObject tlCO = (CacheObject)_tl.get();
        if (tlCO!=null) {
            throw new CacheException("Cache:"+_config.getCacheId()+" wait for call put() with objId="+tlCO.getObjectId());
        }

        CacheObject co = null;//getCacheObject(objId);
        synchronized (this) {
            co = (CacheObject)_map.get(objId);
        }

        if (co==null) {
            return;
        }

        co.lock();
        _cacheInfo.incRemove();
        try {
            synchronized (this) {
                tmapRemove(co);

                //����� ��������� ��������� ������� ��� ����� �� ���� � ����
                //��� � ���� ����� ���� ������ ������ � ����� �� objId
                CacheObject co2 = (CacheObject)_map.get(co.getObjectId());
                if(co2!=null && co2==co){
                    _map.remove(co.getObjectId());
                    resetCacheObject(co);
                }
            }
        } finally {
            co.unlock();
        }
    }

    /**
     * ���������� ���������� �������� � ����
     */
    public int size() {
        return _map.size();
    }

    /**
     * ������� ��� ������� �� ����
     * @throws CacheException ���� ����� ������� clear() ��� ������ ����� get()
     * � �� ������ null �� ��� ������ clear() ����� ���������� CacheException.
     */
    public void clear() throws CacheException {
        Object[] objArr = null;
        synchronized (this) {
            objArr = _map.values().toArray();
        }

        //����� �� ������ deadlock ����� ������� �� �������� �� _map � ����� ����� remove()
        for (int i = 0, indx = objArr==null ? 0 : objArr.length; i<indx; i++) {
            remove(((CacheObject)objArr[i]).getObjectId());
        }
    }

    /**
     * ���������� ���������� � ����
     */
    public CacheInfo getCacheInfo() {
        return _cacheInfo;
    }

    /**
     * ���������� ����������� ����
     */
    public CacheConfig getCacheConfig() {
        return _config;
    }
    //-------------------------------------------------------------------------- Cache interface

    //-------------------------------------------------------------------------- ManagedCache interface

    /**
     * ������������� ������������ ����. ��� ��������� ������������ ��� �������
     * ���� ��������.
     * @param config ������������
     * @throws CacheException ���� �������� ��������
     * @throws NullPointerException ���� config==null
     */
    public synchronized void setCacheConfig(CacheConfig config) throws CacheException {
        if(config==null) {
            throw new NullPointerException("config is null");
        }

        _config = (CacheConfigImpl)config;

        _map = _config.getMaxSize()>1000 ? new HashMap(1024) : new HashMap();
        _memorySize = 0;
        _tmap = new TreeMap(_config.getAlgorithmComparator());
        _cacheInfo = new CacheInfoImpl();
        _tl.set(null);
    }

    /**
     * ��������� ������� ����. ��������� ������� � ������� ����������� �����
     * ����� ��� �������� ������ �������� ��� ���� ������ ����� null.
     * @throws CacheException ���� ����� ������� clean() ��� ������ ����� get()
     * � �� ������ null �� ��� ������ clean() ����� ���������� CacheException.
     */
    public void clean() throws CacheException {
        //������� �� ���� ����� ������� �� ������� ?
        if(_config.getTimeToLive()==0 && _config.getIdleTime()==0){
            return;
        }

        Object[] objArr = null;
        synchronized (this) {
            objArr = _map.values().toArray();
        }

        for (int i = 0, indx = objArr==null ? 0 : objArr.length; i<indx; i++) {
            CacheObject co = (CacheObject)objArr[i];
            //���� ������ �� �������� �� ������ ����� �������
            if ( !valid(co) ) {
                remove(co.getObjectId());
            }
        }
    }

    //-------------------------------------------------------------------------- ManagedCache interface

// ----------------------------------------------------------------------------- Package scope ������
// ----------------------------------------------------------------------------- Protected ������
// ----------------------------------------------------------------------------- Private ������

    /**
     * ���� ��� ����������, �� ���������� �������� ��� �� �������, ��
     * ��������� ���� ������ � ����������� � ���������� LFU, LRU, FIFO, ...
     */
    private void checkOverflow(int objSize) {
        synchronized(this) {
            //��������� ������������ �� ���������� ��� ������� ?
            //���� ��������� ������� ������ ��, ��������,  �� ���� ����� ������� ���������
            //�������� �������� ������� while
            while( (_config.getMaxSize() > 0 &&  _map.size()+1>_config.getMaxSize() ) ||
                    (_config.getMaxMemorySize()  > 0 && _memorySize+objSize > _config.getMaxMemorySize())  ) {

                //���� � tmap ��� �� ���� ������� ������ �������
                //��� ������ ���������� ��� ����� ����������� �������
                //��� LRU ��� ����� ����� ������ ������������� ������
                Object firstKey = _tmap.size()==0 ? null : _tmap.firstKey();
                CacheObject fco = firstKey==null ? null : (CacheObject)_tmap.remove(firstKey);

                if(fco!=null) {
                    //����� ��������� ��������� ������� ��� ����� �� ���� � ����
                    //��� � ���� ����� ���� ������ ������ � ����� �� objId
                    CacheObject co = (CacheObject)_map.get(fco.getObjectId());
                    if(co!=null && co==fco){
                        _map.remove(fco.getObjectId());
                        resetCacheObject(fco);
                    }
                }
            } //while
        }
    }
    /**
     * ������� ������ �� _tmap
     */
    private void tmapRemove(CacheObject co){
        synchronized(this) {
            _tmap.remove(co);
        }
    }
    /**
     * �������� ���������� ������ � _tmap
     * @param co ���������� ������
     */
    private void tmapPut(CacheObject co){
        synchronized(this) {
            //���� � ��������, ������� �������� _tmap, ������ ���� ���������
            //_tmap ����� ��������� ������ �� �������� ������� ���� � _map
            Object mapO = _map.get(co.getObjectId());
            if(mapO!=null && mapO==co){
                _tmap.put(co, co);
            }
        }
    }


    /**
     * ���������� ������ CacheObject ��� �������������� objId.
     * ���� ������� CacheObject ��� �� �� ��������.
     * @param objId ������������� �������
     */
    private CacheObject getCacheObject(Object objId) {
        synchronized (this) {
            CacheObject co = (CacheObject)_map.get(objId);
            if (co == null) {
                co = _config.newCacheObject(objId);
                _map.put(objId, co);
            }
            return co;
        }
    }
    /**
     * ���������� true ���� ������ ��������.
     * ����������� ����� ����� ������� � ����� ����������� �������
     * @param co ���������� ������
     */
    private boolean valid(CacheObject co){
        long curTime = System.currentTimeMillis();
        return  (_config.getTimeToLive()==0 || (co.getCreateTime()  + _config.getTimeToLive()) >= curTime) &&
                (_config.getIdleTime()==0 || (co.getLastAccessTime() + _config.getIdleTime()) >= curTime) &&
                //���� ������������ soft ������ �� �������� �������� ����� �������
                //������ CacheObject ����� ��� �� ����
                co.getObject()!=null;
    }
    /**
     *  ���� ������ ��� � ���� ��:
     *   - ������������� ������ ����
     *   - ������� ������ �� ������, �������� ������ �������, ���������� ����������
     * @param co ���������� ������
     */
    private void resetCacheObject(CacheObject co){
        synchronized(this) {
            _memorySize = _memorySize - co.getObjectSize();
        }
        co.reset();
    }
// ----------------------------------------------------------------------------- Inner ������
    private class CacheInfoImpl implements CacheInfo {
        private long _hit;
        private long _miss;
        private long _put;
        private long _remove;

        synchronized void incHits(){
            _hit++;
        }
        synchronized void incMisses(){
            _miss++;
        }
        synchronized void incPut(){
            _put++;
        }
        synchronized void incRemove(){
            _remove++;
        }
        public long getCacheHits(){
            return _hit;
        }
        public long getCacheMisses(){
            return _miss;
        }
        public long getTotalPuts() {
            return _put;
        }
        public long getTotalRemoves() {
            return _remove;
        }
        public synchronized void reset() {
            _hit = 0;
            _miss = 0;
            _put = 0;
            _remove = 0;
        }
        public long getMemorySize() {
            return _memorySize;
        }
        public String toString(){
            return "hit:"+_hit+" miss:"+_miss+" memorySize:"+_memorySize;
            //return "hit:"+_hit+" miss:"+_miss+" memorySize:"+_memorySize+" size:"+_map.size()+" tsize:"+_tmap.size();
        }
    }
}

/*
$Log: BlockingCache.java,v $
*/
 
TOP

Related Classes of net.sf.cache4j.impl.BlockingCache$CacheInfoImpl

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.