pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / facet / src / java / org / apache / lucene / facet / search / TotalFacetCountsCache.java
diff --git a/lucene-java-3.4.0/lucene/contrib/facet/src/java/org/apache/lucene/facet/search/TotalFacetCountsCache.java b/lucene-java-3.4.0/lucene/contrib/facet/src/java/org/apache/lucene/facet/search/TotalFacetCountsCache.java
deleted file mode 100644 (file)
index 23b9562..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-package org.apache.lucene.facet.search;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.apache.lucene.index.IndexReader;
-
-import org.apache.lucene.facet.index.params.CategoryListParams;
-import org.apache.lucene.facet.index.params.FacetIndexingParams;
-import org.apache.lucene.facet.search.cache.CategoryListCache;
-import org.apache.lucene.facet.taxonomy.TaxonomyReader;
-
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-/**
- * Manage an LRU cache for {@link TotalFacetCounts} per index, taxonomy, and
- * facet indexing params.
- * 
- * @lucene.experimental
- */
-public final class TotalFacetCountsCache {
-  
-  /**
-   * Default size of in memory cache for computed total facet counts.
-   * Set to 2 for the case when an application reopened a reader and 
-   * the original one is still in use (Otherwise there will be 
-   * switching again and again between the two.) 
-   */
-  public static final int DEFAULT_CACHE_SIZE = 2; 
-
-  private static final TotalFacetCountsCache singleton = new TotalFacetCountsCache();
-  
-  /**
-   * Get the single instance of this cache
-   */
-  public static TotalFacetCountsCache getSingleton() {
-    return singleton;
-  }
-  
-  /**
-   * In-memory cache of TFCs.
-   * <ul>  
-   * <li>It's size is kept within limits through {@link #trimCache()}.
-   * <li>An LRU eviction policy is applied, by maintaining active keys in {@link #lruKeys}. 
-   * <li>After each addition to the cache, trimCache is called, to remove entries least recently used.
-   * </ul>  
-   * @see #markRecentlyUsed(TFCKey)
-   */
-  private ConcurrentHashMap<TFCKey,TotalFacetCounts> cache = new ConcurrentHashMap<TFCKey,TotalFacetCounts>();
-  
-  /**
-   * A queue of active keys for applying LRU policy on eviction from the {@link #cache}.
-   * @see #markRecentlyUsed(TFCKey)
-   */
-  private ConcurrentLinkedQueue<TFCKey> lruKeys = new ConcurrentLinkedQueue<TFCKey>();
-  
-  private int maxCacheSize = DEFAULT_CACHE_SIZE; 
-  
-  /** private constructor for singleton pattern */ 
-  private TotalFacetCountsCache() {
-  }
-  
-  /**
-   * Get the total facet counts for a reader/taxonomy pair and facet indexing parameters.
-   * If not in cache, computed here and added to the cache for later use.
-   * @param indexReader the documents index
-   * @param taxonomy the taxonomy index
-   * @param facetIndexingParams facet indexing parameters
-   * @param clCache category list cache for faster computation, can be null 
-   * @return the total facet counts.
-   */
-  public TotalFacetCounts getTotalCounts(IndexReader indexReader, TaxonomyReader taxonomy,
-      FacetIndexingParams facetIndexingParams, CategoryListCache clCache) throws IOException {
-    // create the key
-    TFCKey key = new TFCKey(indexReader, taxonomy, facetIndexingParams);
-    // it is important that this call is not synchronized, so that available TFC 
-    // would not wait for one that needs to be computed.  
-    TotalFacetCounts tfc = cache.get(key);
-    if (tfc != null) {
-      markRecentlyUsed(key); 
-      return tfc;
-    }
-    return computeAndCache(key, clCache);
-  }
-
-  /**
-   * Mark key as it as recently used.
-   * <p>
-   * <b>Implementation notes: Synchronization considerations and the interaction between lruKeys and cache:</b>
-   * <ol>
-   *  <li>A concurrent {@link LinkedHashMap} would have made this class much simpler.
-   *      But unfortunately, Java does not provide one.
-   *      Instead, we combine two concurrent objects:
-   *  <ul>
-   *   <li>{@link ConcurrentHashMap} for the cached TFCs.
-   *   <li>{@link ConcurrentLinkedQueue} for active keys
-   *  </ul>
-   *  <li>Both {@link #lruKeys} and {@link #cache} are concurrently safe.
-   *  <li>Checks for a cached item through getTotalCounts() are not synchronized.
-   *      Therefore, the case that a needed TFC is in the cache is very fast:
-   *      it does not wait for the computation of other TFCs.
-   *  <li>computeAndCache() is synchronized, and, has a (double) check of the required
-   *       TFC, to avoid computing the same TFC twice. 
-   *  <li>A race condition in this method (markRecentlyUsed) might result in two copies 
-   *      of the same 'key' in lruKeys, but this is handled by the loop in trimCache(), 
-   *      where an attempt to remove the same key twice is a no-op.
-   * </ol>
-   */
-  private void markRecentlyUsed(TFCKey key) {
-    lruKeys.remove(key);  
-    lruKeys.add(key);
-  }
-
-  private synchronized void trimCache() {
-    // loop until cache is of desired  size.
-    while (cache.size()>maxCacheSize ) { 
-      TFCKey key = lruKeys.poll();
-      if (key==null) { //defensive
-        // it is defensive since lruKeys presumably covers the cache keys 
-        key = cache.keys().nextElement(); 
-      }
-      // remove this element. Note that an attempt to remove with the same key again is a no-op,
-      // which gracefully handles the possible race in markRecentlyUsed(). 
-      cache.remove(key);
-    }
-  }
-  
-  /**
-   * compute TFC and cache it, after verifying it was not just added - for this
-   * matter this method is synchronized, which is not too bad, because there is
-   * lots of work done in the computations.
-   */
-  private synchronized TotalFacetCounts computeAndCache(TFCKey key, CategoryListCache clCache) throws IOException {
-    TotalFacetCounts tfc = cache.get(key); 
-    if (tfc == null) {
-      tfc = TotalFacetCounts.compute(key.indexReader, key.taxonomy, key.facetIndexingParams, clCache);
-      lruKeys.add(key);
-      cache.put(key,tfc);
-      trimCache();
-    }
-    return tfc;
-  }
-
-  /**
-   * Load {@link TotalFacetCounts} matching input parameters from the provided outputFile 
-   * and add them into the cache for the provided indexReader, taxonomy, and facetIndexingParams.
-   * If a {@link TotalFacetCounts} for these parameters already exists in the cache, it will be
-   * replaced by the loaded one.
-   * @param inputFile file from which to read the data 
-   * @param indexReader the documents index
-   * @param taxonomy the taxonomy index
-   * @param facetIndexingParams the facet indexing parameters
-   * @throws IOException on error
-   * @see #store(File, IndexReader, TaxonomyReader, FacetIndexingParams, CategoryListCache)
-   */
-  public synchronized void load(File inputFile, IndexReader indexReader, TaxonomyReader taxonomy,
-      FacetIndexingParams facetIndexingParams) throws IOException {
-    if (!inputFile.isFile() || !inputFile.exists() || !inputFile.canRead()) {
-      throw new IllegalArgumentException("Exepecting an existing readable file: "+inputFile);
-    }
-    TFCKey key = new TFCKey(indexReader, taxonomy, facetIndexingParams);
-    TotalFacetCounts tfc = TotalFacetCounts.loadFromFile(inputFile, taxonomy, facetIndexingParams);
-    cache.put(key,tfc);
-    trimCache();
-    markRecentlyUsed(key);
-  }
-  
-  /**
-   * Store the {@link TotalFacetCounts} matching input parameters into the provided outputFile,
-   * making them available for a later call to {@link #load(File, IndexReader, TaxonomyReader, FacetIndexingParams)}.
-   * If these {@link TotalFacetCounts} are available in the cache, they are used. But if they are
-   * not in the cache, this call will first compute them (which will also add them to the cache). 
-   * @param outputFile file to store in.
-   * @param indexReader the documents index
-   * @param taxonomy the taxonomy index
-   * @param facetIndexingParams the facet indexing parameters
-   * @param clCache category list cache for faster computation, can be null
-   * @throws IOException on error
-   * @see #load(File, IndexReader, TaxonomyReader, FacetIndexingParams)
-   * @see #getTotalCounts(IndexReader, TaxonomyReader, FacetIndexingParams, CategoryListCache)
-   */
-  public void store(File outputFile, IndexReader indexReader, TaxonomyReader taxonomy,
-      FacetIndexingParams facetIndexingParams, CategoryListCache clCache) throws IOException {
-    File parentFile = outputFile.getParentFile();
-    if (
-        ( outputFile.exists() && (!outputFile.isFile()      || !outputFile.canWrite())) ||
-        (!outputFile.exists() && (!parentFile.isDirectory() || !parentFile.canWrite()))
-      ) {
-      throw new IllegalArgumentException("Exepecting a writable file: "+outputFile);
-    }
-    TotalFacetCounts tfc = getTotalCounts(indexReader, taxonomy, facetIndexingParams, clCache);
-    TotalFacetCounts.storeToFile(outputFile, tfc);  
-  }
-  
-  private static class TFCKey {
-    final IndexReader indexReader;
-    final TaxonomyReader taxonomy;
-    private final Iterable<CategoryListParams> clps;
-    private final int hashCode;
-    private final int nDels; // needed when a reader used for faceted search was just used for deletion. 
-    final FacetIndexingParams facetIndexingParams;
-    
-    public TFCKey(IndexReader indexReader, TaxonomyReader taxonomy,
-        FacetIndexingParams facetIndexingParams) {
-      this.indexReader = indexReader;
-      this.taxonomy = taxonomy;
-      this.facetIndexingParams = facetIndexingParams;
-      this.clps = facetIndexingParams.getAllCategoryListParams();
-      this.nDels = indexReader.numDeletedDocs();
-      hashCode = indexReader.hashCode() ^ taxonomy.hashCode();
-    }
-    
-    @Override
-    public int hashCode() {
-      return hashCode;
-    }
-    
-    @Override
-    public boolean equals(Object other) {
-      TFCKey o = (TFCKey) other; 
-      if (indexReader != o.indexReader || taxonomy != o.taxonomy || nDels != o.nDels) {
-        return false;
-      }
-      Iterator<CategoryListParams> it1 = clps.iterator();
-      Iterator<CategoryListParams> it2 = o.clps.iterator();
-      while (it1.hasNext() && it2.hasNext()) {
-        if (!it1.next().equals(it2.next())) {
-          return false;
-        }
-      }
-      return it1.hasNext() == it2.hasNext();
-    }
-  }
-
-  /**
-   * Clear the cache.
-   */
-  public synchronized void clear() {
-    cache.clear();
-    lruKeys.clear();
-  }
-  
-  /**
-   * @return the maximal cache size
-   */
-  public int getCacheSize() {
-    return maxCacheSize;
-  }
-
-  /**
-   * Set the number of TotalFacetCounts arrays that will remain in memory cache.
-   * <p>
-   * If new size is smaller than current size, the cache is appropriately trimmed.
-   * <p>
-   * Minimal size is 1, so passing zero or negative size would result in size of 1.
-   * @param size new size to set
-   */
-  public void setCacheSize(int size) {
-    if (size < 1) size = 1;
-    int origSize = maxCacheSize;
-    maxCacheSize = size;
-    if (maxCacheSize < origSize) { // need to trim only if the cache was reduced
-      trimCache();
-    }
-  }
-}