Package org.apache.jackrabbit.core.query.lucene

Source Code of org.apache.jackrabbit.core.query.lucene.DocNumberCache

/*
* Copyright 2004-2005 The Apache Software Foundation or its licensors,
*                     as applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.core.query.lucene;

import org.apache.commons.collections.map.LRUMap;
import org.apache.log4j.Logger;

/**
* Implements a Document number cache with a fixed size and a LRU strategy.
*/
final class DocNumberCache {

    /**
     * Logger instance for this class.
     */
    private static final Logger log = Logger.getLogger(DocNumberCache.class);

    /**
     * Log cache statistics at most every 10 seconds.
     */
    private static final long LOG_INTERVAL = 1000 * 10;

    /**
     * The number of cache segments.
     */
    private static final int CACHE_SEGMENTS = 0x10;

    /**
     * Mask to calculate segment number.
     */
    private static final int CACHE_SEGMENTS_MASK = CACHE_SEGMENTS - 1;

    /**
     * LRU Maps where key=uuid value=reader;docNumber
     */
    private final LRUMap[] docNumbers = new LRUMap[CACHE_SEGMENTS];

    /**
     * Timestamp of the last cache statistics log.
     */
    private long lastLog;

    /**
     * Cache misses.
     */
    private long misses;

    /**
     * Cache accesses;
     */
    private long accesses;

    /**
     * Creates a new <code>DocNumberCache</code> with a limiting
     * <code>size</code>.
     *
     * @param size the cache limit.
     */
    DocNumberCache(int size) {
        size = size % CACHE_SEGMENTS;
        if (size < 0x40) {
            // minimum size is 0x40 * 0x10 = 1024
            size = 0x40;
        }
        for (int i = 0; i < docNumbers.length; i++) {
            docNumbers[i] = new LRUMap(size);
        }
    }

    /**
     * Puts a document number into the cache using a uuid as key. An entry is
     * only overwritten if the according reader is younger than the reader
     * associated with the existing entry.
     *
     * @param uuid the key.
     * @param reader the index reader from where the document number was read.
     * @param n the document number.
     */
    void put(String uuid, CachingIndexReader reader, int n) {
        LRUMap cacheSegment = docNumbers[getSegmentIndex(uuid.charAt(0))];
        synchronized (cacheSegment) {
            Entry e = (Entry) cacheSegment.get(uuid);
            if (e != null) {
                // existing entry
                // ignore if reader is older than the one in entry
                if (reader.getCreationTick() <= e.reader.getCreationTick()) {
                    if (log.isDebugEnabled()) {
                        log.debug("Ignoring put(). New entry is not from a newer reader. " +
                                "existing: " + e.reader.getCreationTick() +
                                ", new: " + reader.getCreationTick());
                    }
                    e = null;
                }
            } else {
                // entry did not exist
                e = new Entry(reader, n);
            }

            if (e != null) {
                cacheSegment.put(uuid, e);
            }
        }
    }

    /**
     * Returns the cache entry for <code>uuid</code>, or <code>null</code> if
     * no entry exists for <code>uuid</code>.
     *
     * @param uuid the key.
     * @return cache entry or <code>null</code>.
     */
    Entry get(String uuid) {
        LRUMap cacheSegment = docNumbers[getSegmentIndex(uuid.charAt(0))];
        Entry entry;
        synchronized (cacheSegment) {
            entry = (Entry) cacheSegment.get(uuid);
        }
        if (log.isInfoEnabled()) {
            accesses++;
            if (entry == null) {
                misses++;
            }
            // log at most after 1000 accesses and every 10 seconds
            if (accesses > 1000 && System.currentTimeMillis() - lastLog > LOG_INTERVAL) {
                long ratio = 100;
                if (misses != 0) {
                    ratio -= misses * 100L / accesses;
                }
                StringBuffer statistics = new StringBuffer();
                int inUse = 0;
                for (int i = 0; i < docNumbers.length; i++) {
                    inUse += docNumbers[i].size();
                }
                statistics.append("size=").append(inUse);
                statistics.append("/").append(docNumbers[0].maxSize() * CACHE_SEGMENTS);
                statistics.append(", #accesses=").append(accesses);
                statistics.append(", #hits=").append((accesses - misses));
                statistics.append(", #misses=").append(misses);
                statistics.append(", cacheRatio=").append(ratio).append("%");
                log.info(statistics);
                accesses = 0;
                misses = 0;
                lastLog = System.currentTimeMillis();
            }
        }
        return entry;
    }

    /**
     * Returns the segment index for character c.
     */
    private static final int getSegmentIndex(char c) {
        if (c > '9') {
            c += 9;
        }
        return c & CACHE_SEGMENTS_MASK;
    }

    public static final class Entry {

        /**
         * The IndexReader.
         */
        final CachingIndexReader reader;

        /**
         * The document number.
         */
        final int doc;

        Entry(CachingIndexReader reader, int doc) {
            this.reader = reader;
            this.doc = doc;
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.core.query.lucene.DocNumberCache

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.