abstractconcurrentreadcache.java

来自「oscache-2.4.1-full」· Java 代码 · 共 1,858 行 · 第 1/5 页

JAVA
1,858
字号
            groupEntries = (Set) getGroupForReading(groupName);
        }

        if (groupEntries == null) {
            // Not in the map, try the persistence layer
            groupEntries = persistRetrieveGroup(groupName);
        }

        return groupEntries;
    }

    /**
     * Set the cache capacity
     */
    public void setMaxEntries(int newLimit) {
        if (newLimit > 0) {
            maxEntries = newLimit;

            synchronized (this) { // because remove() isn't synchronized

                while (size() > maxEntries) {
                    remove(removeItem(), false, false);
                }
            }
        } else {
            // Capacity must be at least 1
            throw new IllegalArgumentException("Cache maximum number of entries must be at least 1");
        }
    }

    /**
     * Retrieve the cache capacity (number of entries).
     */
    public int getMaxEntries() {
        return maxEntries;
    }

    /**
     * Sets the memory caching flag.
     */
    public void setMemoryCaching(boolean memoryCaching) {
        this.memoryCaching = memoryCaching;
    }

    /**
     * Check if memory caching is used.
     */
    public boolean isMemoryCaching() {
        return memoryCaching;
    }

    /**
     * Set the persistence listener to use.
     */
    public void setPersistenceListener(PersistenceListener listener) {
        this.persistenceListener = listener;
    }

    /**
     * Get the persistence listener.
     */
    public PersistenceListener getPersistenceListener() {
        return persistenceListener;
    }

    /**
     * Sets the unlimited disk caching flag.
     */
    public void setUnlimitedDiskCache(boolean unlimitedDiskCache) {
        this.unlimitedDiskCache = unlimitedDiskCache;
    }

    /**
     * Check if we use unlimited disk cache.
     */
    public boolean isUnlimitedDiskCache() {
        return unlimitedDiskCache;
    }

    /**
     * Check if we use overflowPersistence
     *
     * @return Returns the overflowPersistence.
     */
    public boolean isOverflowPersistence() {
        return this.overflowPersistence;
    }

    /**
     * Sets the overflowPersistence flag
     *
     * @param overflowPersistence The overflowPersistence to set.
     */
    public void setOverflowPersistence(boolean overflowPersistence) {
        this.overflowPersistence = overflowPersistence;
    }

    /**
     * Return the number of slots in this table.
     **/
    public synchronized int capacity() {
        return table.length;
    }

    /**
     * Removes all mappings from this map.
     */
    public synchronized void clear() {
        Entry[] tab = table;

        for (int i = 0; i < tab.length; ++i) {
            // must invalidate all to force concurrent get's to wait and then retry
            for (Entry e = tab[i]; e != null; e = e.next) {
                e.value = null;

                /** OpenSymphony BEGIN */
                itemRemoved(e.key);

                /** OpenSymphony END */
            }

            tab[i] = null;
        }

        // Clean out the entire disk cache
        persistClear();

        count = 0;
        recordModification(tab);
    }

    /**
     * Returns a shallow copy of this.
     * <tt>AbstractConcurrentReadCache</tt> instance: the keys and
     * values themselves are not cloned.
     *
     * @return a shallow copy of this map.
     */
    public synchronized Object clone() {
        try {
            AbstractConcurrentReadCache t = (AbstractConcurrentReadCache) super.clone();
            t.keySet = null;
            t.entrySet = null;
            t.values = null;

            Entry[] tab = table;
            t.table = new Entry[tab.length];

            Entry[] ttab = t.table;

            for (int i = 0; i < tab.length; ++i) {
                Entry first = tab[i];

                if (first != null) {
                    ttab[i] = (Entry) (first.clone());
                }
            }

            return t;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError();
        }
    }

    /**
     * Tests if some key maps into the specified value in this table.
     * This operation is more expensive than the <code>containsKey</code>
     * method.<p>
     *
     * Note that this method is identical in functionality to containsValue,
     * (which is part of the Map interface in the collections framework).
     *
     * @param      value   a value to search for.
     * @return     <code>true</code> if and only if some key maps to the
     *             <code>value</code> argument in this table as
     *             determined by the <tt>equals</tt> method;
     *             <code>false</code> otherwise.
     * @exception  NullPointerException  if the value is <code>null</code>.
     * @see        #containsKey(Object)
     * @see        #containsValue(Object)
     * @see           Map
     */
    public boolean contains(Object value) {
        return containsValue(value);
    }

    /**
     * Tests if the specified object is a key in this table.
     *
     * @param   key   possible key.
     * @return  <code>true</code> if and only if the specified object
     *          is a key in this table, as determined by the
     *          <tt>equals</tt> method; <code>false</code> otherwise.
     * @exception  NullPointerException  if the key is
     *               <code>null</code>.
     * @see     #contains(Object)
     */
    public boolean containsKey(Object key) {
        return get(key) != null;

        /** OpenSymphony BEGIN */

        // TODO: Also check the persistence?

        /** OpenSymphony END */
    }

    /**
     * Returns <tt>true</tt> if this map maps one or more keys to the
     * specified value. Note: This method requires a full internal
     * traversal of the hash table, and so is much slower than
     * method <tt>containsKey</tt>.
     *
     * @param value value whose presence in this map is to be tested.
     * @return <tt>true</tt> if this map maps one or more keys to the
     * specified value.
     * @exception  NullPointerException  if the value is <code>null</code>.
     */
    public boolean containsValue(Object value) {
        if (value == null) {
            throw new NullPointerException();
        }

        Entry[] tab = getTableForReading();

        for (int i = 0; i < tab.length; ++i) {
            for (Entry e = tab[i]; e != null; e = e.next) {
                Object v = e.value;

                if ((v != null) && value.equals(v)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Returns an enumeration of the values in this table.
     * Use the Enumeration methods on the returned object to fetch the elements
     * sequentially.
     *
     * @return  an enumeration of the values in this table.
     * @see     java.util.Enumeration
     * @see     #keys()
     * @see        #values()
     * @see        Map
     */
    public Enumeration elements() {
        return new ValueIterator();
    }

    /**
     * Returns a collection view of the mappings contained in this map.
     * Each element in the returned collection is a <tt>Map.Entry</tt>.  The
     * collection is backed by the map, so changes to the map are reflected in
     * the collection, and vice-versa.  The collection supports element
     * removal, which removes the corresponding mapping from the map, via the
     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> operations.
     * It does not support the <tt>add</tt> or <tt>addAll</tt> operations.
     *
     * @return a collection view of the mappings contained in this map.
     */
    public Set entrySet() {
        Set es = entrySet;

        if (es != null) {
            return es;
        } else {
            return entrySet = new AbstractSet() {
                        public Iterator iterator() {
                            return new HashIterator();
                        }

                        public boolean contains(Object o) {
                            if (!(o instanceof Map.Entry)) {
                                return false;
                            }

                            Map.Entry entry = (Map.Entry) o;
                            Object key = entry.getKey();
                            Object v = AbstractConcurrentReadCache.this.get(key);

                            return (v != null) && v.equals(entry.getValue());
                        }

                        public boolean remove(Object o) {
                            if (!(o instanceof Map.Entry)) {
                                return false;
                            }

                            return AbstractConcurrentReadCache.this.findAndRemoveEntry((Map.Entry) o);
                        }

                        public int size() {
                            return AbstractConcurrentReadCache.this.size();
                        }

                        public void clear() {
                            AbstractConcurrentReadCache.this.clear();
                        }
                    };
        }
    }

    /**
     * Returns the value to which the specified key is mapped in this table.
     *
     * @param   key   a key in the table.
     * @return  the value to which the key is mapped in this table;
     *          <code>null</code> if the key is not mapped to any value in
     *          this table.
     * @exception  NullPointerException  if the key is
     *               <code>null</code>.
     * @see     #put(Object, Object)
     */
    public Object get(Object key) {
        if (log.isDebugEnabled()) {
            log.debug("get called (key=" + key + ")");
        }

        // throw null pointer exception if key null
        int hash = hash(key);

        /*
           Start off at the apparently correct bin.  If entry is found, we
           need to check after a barrier anyway.  If not found, we need a
           barrier to check if we are actually in right bin. So either
           way, we encounter only one barrier unless we need to retry.
           And we only need to fully synchronize if there have been
           concurrent modifications.
        */
        Entry[] tab = table;
        int index = hash & (tab.length - 1);
        Entry first = tab[index];
        Entry e = first;

        for (;;) {
            if (e == null) {
                // If key apparently not there, check to
                // make sure this was a valid read
                tab = getTableForReading();

                if (first == tab[index]) {
                    /** OpenSymphony BEGIN */

                    /* Previous code
                    return null;*/

                    // Not in the table, try persistence
                    Object value = persistRetrieve(key);

                    if (value != null) {
                        // Update the map, but don't persist the data
                        put(key, value, false);
                    }

                    return value;

                    /** OpenSymphony END */
                } else {
                    // Wrong list -- must restart traversal at new first
                    e = first = tab[index = hash & (tab.length - 1)];
                }
            }
            // checking for pointer equality first wins in most applications
            else if ((key == e.key) || ((e.hash == hash) && key.equals(e.key))) {
                Object value = e.value;

⌨️ 快捷键说明

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