Using Object Pool Design Pattern to Reduce Garbage Collection in Solr


Object Pool is a common used design pattern in Android.  The most famous example is android.os.Message class.

The same pattern can be used in Solr. When Solr is running in machine with limited resource or running at client machine, and it's important to reduce resource usage as possible as we can.

In Solr application, we usually have to create thousands or millions of SolrQueryRequest, SolrQueryResponse, UpdateCommand.

As described at Solr: Export Large(Millions) Data to a CSV File, it may create a lot of SolrQueryRequest objects in short time, also as described at Solr RefCounted: Don't forget to close SolrQueryRequest or decref solrCore.getSearcherIt's important to close SolrQueryRequest otherwise it will cause resource(SolrIndexSearcher) leak.

So this is a good place to use the object pool pattern to reuse SolrQueryRequest and encapsulate its creation and close operations.

PooledLocalSolrQueryRequest
How to Use PooledLocalSolrQueryRequest
1. Call one of the obtain methods in PooledLocalSolrQueryRequest: obtain(solrCore), obtain(solrCore, solrParams), obtain(solrCore, solrParams, streams) to get a SolrQueryRequest object: it will reuse existing one if exists or create a new if no available free object.

2. Call pooledRequest.recycle() when no need to use the pooledRequest instance any more.

3. Call PooledLocalSolrQueryRequest.closeAll() to clean all cached free PooledLocalSolrQueryRequest instances.
The Code
package org.codeexample.lifelongprogrammer.solr.util;

public class PooledLocalSolrQueryRequest extends LocalSolrQueryRequest {
  protected static final Logger logger = LoggerFactory
      .getLogger(CVCSVExportToFileHandler.class);
  
  /**
   * Private constructor, only allow new objects from obtain()
   */
  private PooledLocalSolrQueryRequest(SolrCore core,
      ModifiableSolrParams modifiableSolrParams) {
    super(core, modifiableSolrParams);
  }
  
  // Reference to next object in the pool
  private PooledLocalSolrQueryRequest next;
  
  private static final Object sPoolSync = new Object();
  private static PooledLocalSolrQueryRequest firstInstance;
  
  // private static int sPoolSize = 0;
  // private static final int MAX_POOL_SIZE = 50;
  
  /**
   * Return a new LocalSolrQueryRequest, caller has to set SolrParmas, and
   * ContentStream if needed.
   */
  public static PooledLocalSolrQueryRequest obtain(SolrCore core) {
    synchronized (sPoolSync) {
      if (firstInstance != null) {
        PooledLocalSolrQueryRequest m = firstInstance;
        firstInstance = m.next;
        m.next = null;
        // sPoolSize--;
        return m;
      }
    }
    return new PooledLocalSolrQueryRequest(core, new ModifiableSolrParams());
  }
  
  public static PooledLocalSolrQueryRequest obtain(SolrCore core,
      ModifiableSolrParams newParams) {
    PooledLocalSolrQueryRequest request = obtain(core);
    request.setParams(newParams);
    return request;
  }
  
  public static PooledLocalSolrQueryRequest obtain(SolrCore core,
      ModifiableSolrParams newParams, Iterable<ContentStream> newStream) {
    PooledLocalSolrQueryRequest request = obtain(core);
    request.setParams(newParams);
    request.setContentStreams(newStream);
    return request;
  }
  
  /**
   * Recycle this object. You must release all references to this instance after
   * calling this method.
   */
  public void recycle() {
    
    this.close();
    synchronized (sPoolSync) {
      // if (sPoolSize < MAX_POOL_SIZE) {
      next = firstInstance;
      firstInstance = this;
      // sPoolSize++;
      // }
    }
  }
  
  /**
   * Close All SolrQueryRequest
   */
  public static void closeAll() {
    synchronized (sPoolSync) {
      
      while (firstInstance != null) {
        firstInstance.close();
        firstInstance= null;
        firstInstance = firstInstance.next;
      }
    }
  }
}
Resources
Recycling objects in Android with an Object Pool to avoid garbage collection.
Object Pool
android.os.Message class
Solr: Export Large(Millions) Data to a CSV File
Solr RefCounted: Don't forget to close SolrQueryRequest or decref solrCore.getSearcher

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)