All Downloads are FREE. Search and download functionalities are using the official Maven repository.

proj.zoie.impl.indexing.internal.SearchIndexManager Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
package proj.zoie.impl.indexing.internal;
/**
 * 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.
 */

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.index.IndexReader;

import proj.zoie.api.DirectoryManager;
import proj.zoie.api.DocIDMapperFactory;
import proj.zoie.api.IndexReaderFactory;
import proj.zoie.api.ZoieHealth;
import proj.zoie.api.ZoieIndexReader;
import proj.zoie.api.indexing.IndexReaderDecorator;

public class SearchIndexManager implements IndexReaderFactory>
{
    private static final Logger log = Logger.getLogger(SearchIndexManager.class);
    
    public static enum Status
    {
      Sleep, Working
    }

	  private DirectoryManager _dirMgr;
	  private final	IndexReaderDecorator	_indexReaderDecorator;

	  final DocIDMapperFactory _docIDMapperFactory;
	  private final DiskSearchIndex _diskIndex;
	  
	  private volatile Status _diskIndexerStatus;
	  private volatile Mem _mem;
	  /**
	   * the access lock for _mem for the purpose of proper reference counting
	   * for disk IndexReader
	   */
	  private final Object _memLock = new Object();
	  private final RAMIndexFactory _ramIndexFactory;
	  
	  private volatile String _memAVersion = null;
	  private volatile String _memBVersion = null;
	  private volatile String _diskVersion = null;
	  
	  private final Comparator _versionComparator;
	  
	  /**
	   * @param location 
	   * @param indexReaderDecorator
	   */
	  public SearchIndexManager(DirectoryManager dirMgr,Comparator versionComparator,IndexReaderDecorator indexReaderDecorator,DocIDMapperFactory docIDMapperFactory, RAMIndexFactory ramIndexFactory)
	  {
	    _dirMgr = dirMgr;
	    _versionComparator = versionComparator;
	    _docIDMapperFactory = docIDMapperFactory;
	    _ramIndexFactory = ramIndexFactory;
	    if (indexReaderDecorator!=null)
	    {
	      _indexReaderDecorator=indexReaderDecorator;
	    }
	    else
	    {
	      throw new IllegalArgumentException("indexReaderDecorator cannot be null");
	    }
        _diskIndexerStatus = Status.Sleep;
        _diskIndex = new DiskSearchIndex(_dirMgr, _indexReaderDecorator,this); 
        ZoieIndexReader diskIndexReader = null;
        
        try
        {
          diskIndexReader = _diskIndex.getNewReader();
        }
        catch (IOException e)
        {
          log.error(e.getMessage(),e);
          return;
        }
        String version = _diskIndex.getVersion();
        RAMSearchIndex memIndexA = _ramIndexFactory.newInstance(version, _indexReaderDecorator,this);
        Mem mem = new Mem(memIndexA, null, memIndexA, null, diskIndexReader);
        if (diskIndexReader != null)
        {
          diskIndexReader.incZoieRef();
        }
        _mem = mem;
	  }
	  
	  public DocIDMapperFactory getDocIDMapperFactory(){
		  return _docIDMapperFactory;
	  }
	  
    public int getDiskSegmentCount() throws IOException
    {
      return _diskIndex.getSegmentCount();
    }
    public String getDiskSegmentInfo()
    {
      return _diskIndex.getSegmentInfo();
    }

	  public int getRAMASegmentCount()
	  {
	    Mem mem = _mem;
	    if (mem.get_memIndexA()==null) return -1;
	    int ret;
      try
      {
        ret = mem.get_memIndexA().getSegmentCount();
      } catch (IOException e)
      {
        ret = -1;
      }
      return ret;
	  }

	  public int getRAMBSegmentCount()
	  {
      Mem mem = _mem;
      if (mem.get_memIndexB()==null) return -1;
      int ret;
      try
      {
        ret = mem.get_memIndexB().getSegmentCount();
      } catch (IOException e)
      {
        ret = -1;
      }
      return ret;
	  }

	  public void setNumLargeSegments(int numLargeSegments)
	  {
	    _diskIndex._mergePolicyParams.setNumLargeSegments(numLargeSegments);
	  }

	  public int getNumLargeSegments()
	  {
	    return _diskIndex._mergePolicyParams.getNumLargeSegments();
	  }

	  public void setMaxSmallSegments(int maxSmallSegments)
	  {
	    _diskIndex._mergePolicyParams.setMaxSmallSegments(maxSmallSegments);
	  }

	  public int getMaxSmallSegments()
	  {
	    return _diskIndex._mergePolicyParams.getMaxSmallSegments();
	  }

	  public void setPartialExpunge(boolean doPartialExpunge)
	  {
	    _diskIndex._mergePolicyParams.setPartialExpunge(doPartialExpunge);
	  }

	  public boolean getPartialExpunge()
	  {
	    return _diskIndex._mergePolicyParams.getPartialExpunge();
	  }

	  public void setMergeFactor(int mergeFactor)
	  {
		  _diskIndex._mergePolicyParams.setMergeFactor(mergeFactor);
	  }
	  
	  public int getMergeFactor()
	  {
		return _diskIndex._mergePolicyParams.getMergeFactor();
	  }
		
	  public void setMaxMergeDocs(int maxMergeDocs)
	  {
		  _diskIndex._mergePolicyParams.setMaxMergeDocs(maxMergeDocs);
	  }
		
	  public int getMaxMergeDocs()
	  {
		return _diskIndex._mergePolicyParams.getMaxMergeDocs();
	  }
	  
	  public void setUseCompoundFile(boolean useCompoundFile)
	  {
		  _diskIndex._mergePolicyParams.setUseCompoundFile(useCompoundFile);
	  }
	  
	  public boolean isUseCompoundFile()
	  {
	    return _diskIndex._mergePolicyParams.isUseCompoundFile();
	  }
	  
	  /**
	   * Gets the current disk indexer status
	   * @return
	   */
	  public Status getDiskIndexerStatus()
	  {
	    return _diskIndexerStatus;
	  }
	  
	  public List> getIndexReaders()
	  throws IOException
	  {
	    ArrayList> readers = new ArrayList>();
	    ZoieIndexReader reader = null;

	    synchronized(this)
      {
	      synchronized(_memLock)
	      {
	        Mem mem = _mem;
	        RAMSearchIndex memIndexB = mem.get_memIndexB();
	        RAMSearchIndex memIndexA = mem.get_memIndexA();

	        // the following order, e.g. B,A,Disk matters, see ZoieIndexReader.getSubZoieReaderAccessor:
	        // when doing UID->docid mapping, the freshest index needs to be first

	        String currentVersion = null;
	        if (memIndexB != null)                           // load memory index B
	        {
            synchronized(memIndexB)
            {
              reader = memIndexB.openIndexReader();
              if (reader != null)
              {
                reader = reader.copy();
                reader.setDelDocIds();
                readers.add(reader);
              }
            }
            _memBVersion = memIndexB.getVersion();
	        }

	        if (memIndexA != null)                           // load memory index A
	        {
            synchronized(memIndexA)
            {
              reader = memIndexA.openIndexReader();
              if (reader != null)
              {
                reader = reader.copy();
                reader.setDelDocIds();
                readers.add(reader);
              }
            }
	          _memAVersion = memIndexA.getVersion();
	        }

	        // load disk index
	        {
	          reader = mem.get_diskIndexReader();
	          if (reader != null)
	          {
              reader = reader.copy();
	            reader.setDelDocIds();
	            readers.add(reader);
	          }
	          
	          _diskVersion = getCurrentDiskVersion();
	        }
	      }
	    }
	    return readers;
	  }
	  
	  

	@Override
	public String getCurrentReaderVersion() {
	  String version = _memAVersion;
	  if (_versionComparator.compare(version, _memBVersion)<0){
		  version = _memBVersion;
	  }
	  if (_versionComparator.compare(version, _diskVersion) < 0){
		  version = _diskVersion;
	  }
	  return version;
	  
	}
	
	public Comparator getVersionComparator(){
	  return _versionComparator;
	}

	public void returnIndexReaders(List> readers)
	  {
	    for(ZoieIndexReader r : readers)
	    {
//	      try
//	      {
	        r.decZoieRef();//.decRef();
//	      } catch (IOException e)
//	      {
//	        log.error("error when decRef on reader ", e);
//	      }
	    }
	  }
	  
	  public synchronized void setDiskIndexerStatus(Status status)
	  {	    
	    // going from sleep to wake, disk index starts to index
	    // which according to the spec, index B is created and it starts to collect data
	    // IMPORTANT: do nothing if the status is not being changed.
	    if (_diskIndexerStatus != status)
	    {

	      log.info("updating batch indexer status from "+_diskIndexerStatus+" to "+status);
	      
	      if (status == Status.Working)
	      { // sleeping to working
	        String version = _diskIndex.getVersion();
	        Mem oldMem = _mem;

	        RAMSearchIndex memIndexA = oldMem.get_memIndexA();
	        if(memIndexA != null) memIndexA.closeIndexWriter();

	        RAMSearchIndex memIndexB = _ramIndexFactory.newInstance(version, _indexReaderDecorator,this);
	        Mem mem = new Mem(memIndexA, memIndexB, memIndexB, memIndexA, oldMem.get_diskIndexReader());
	        _mem = mem;
	        log.info("Current writable index is B, new B created");
	      }
	      else
	      {
	        // from working to sleep
	        ZoieIndexReader diskIndexReader = null;
	        try
	        {
            synchronized(_diskIndex)
            {
              // a new reader is already loaded in loadFromIndex
              diskIndexReader = _diskIndex.openIndexReader();
              if (diskIndexReader != null)
                diskIndexReader.incZoieRef();
            }

            Mem oldMem = _mem;
            Mem mem = new Mem(oldMem.get_memIndexB(), null, oldMem.get_memIndexB(), null, diskIndexReader);
            if (oldMem.get_memIndexA()!=null){oldMem.get_memIndexA().close();}
            lockAndSwapMem(diskIndexReader, oldMem.get_diskIndexReader(), mem);
            log.info("Current writable index is A, B is flushed");
	        }
	        catch (IOException e)
	        {
	          log.error(e.getMessage(),e);
	          return;
	        }
          finally
          {
            if (diskIndexReader != null)
              diskIndexReader.decZoieRef();
          }
	      }
	      _diskIndexerStatus = status;
	    }
	  }

	  public DiskSearchIndex getDiskIndex()
	  {
	    return _diskIndex;
	  }

	  public RAMSearchIndex getCurrentWritableMemoryIndex()
	  {
	    return _mem.get_currentWritable();
	  }
	  
	  public RAMSearchIndex getCurrentReadOnlyMemoryIndex()
	  {
	    return _mem.get_currentReadOnly();
	  }
	  
	  /**
	   * Clean up
	   */
	  public void close(){
	    Mem mem = _mem;
	    if (mem.get_memIndexA()!=null)
	    {
	      mem.get_memIndexA().close();
	    }
	    if (mem.get_memIndexB()!=null)
	    {
	      mem.get_memIndexB().close();
	    }
	    if (mem.get_diskIndexReader()!=null)
	    {
//	      try
//	      {
	        mem.get_diskIndexReader().decZoieRef();//.decRef();
            _diskIndex.close();
//          }
//	      catch (IOException e)
//          {
//	        log.error("error closing remaining diskReader pooled in mem: " + e);
//          }
	    }
	  }

	  
	  public String getCurrentDiskVersion() throws IOException
	  {
	    return _diskIndex.getVersion();
	  }

	  public int getDiskIndexSize()
	  {
	    return _diskIndex.getNumdocs();
	  }
	  
	  public int getRamAIndexSize()
	  {
        RAMSearchIndex memIndexA = _mem.get_memIndexA();
	    return (memIndexA==null) ? 0 : memIndexA.getNumdocs();
	  }
	  
	  public String getRamAVersion()
	  {
        RAMSearchIndex memIndexA = _mem.get_memIndexA();
	    return (memIndexA==null) ? null : memIndexA.getVersion();
	  }
	  
	  public int getRamBIndexSize()
	  {
        RAMSearchIndex memIndexB = _mem.get_memIndexB();
	    return (memIndexB==null) ? 0 : memIndexB.getNumdocs();
	  }
	  
	  public String getRamBVersion()
	  {
	    RAMSearchIndex memIndexB = _mem.get_memIndexB();
	    return (memIndexB==null) ? null : memIndexB.getVersion();
	  }
	  
	  /**
	   * utility method to delete a directory
	   * @param dir
	   * @throws IOException
	   */
	  private static void deleteDir(File dir) throws IOException
	  {
	    if (dir == null) return;
	    
	    if (dir.isDirectory())
	    {
	      File[] files=dir.listFiles();
	      for (File file : files)
	      {
	        deleteDir(file);
	      }
	      if (!dir.delete())
	      {
	        throw new IOException("cannot remove directory: "+dir.getAbsolutePath());
	      }
	    }
	    else
	    {
	      if (!dir.delete())
	      {
	        throw new IOException("cannot delete file: "+dir.getAbsolutePath());
	      }
	    }
	  }

  /**
   * Purges an index
   */
  public void purgeIndex()
  {
    log.info("purging index ...");
    _diskIndex.clearDeletes();
    _diskIndex.refresh();
    _diskIndex.closeIndexWriter();
    _dirMgr.purge();
    _diskIndex.refresh();
    if (_mem.get_memIndexA()!=null){_mem.get_memIndexA().close();}
    if (_mem.get_memIndexB()!=null){_mem.get_memIndexB().close();}
    RAMSearchIndex memIndexA = _ramIndexFactory.newInstance(_diskIndex.getVersion(), _indexReaderDecorator, this);
    Mem mem = new Mem(memIndexA, null, memIndexA, null, null);
    _mem = mem;

    log.info("index purged");
  }
	  
	  public void refreshDiskReader() throws IOException
	  {
		  log.info("refreshing disk reader ...");
		  ZoieIndexReader diskIndexReader = null;
		  try
		  {
		    // load a new reader, not in the lock because this should be done in the background
		    // and should not contend with the readers
		    diskIndexReader = _diskIndex.getNewReader();
		  }
		  catch(IOException e)
		  {
	      ZoieHealth.setFatal();
		    log.error(e.getMessage(),e);
		    throw e;
		  }
		  Mem oldMem = _mem;
		  Mem mem = new Mem(oldMem.get_memIndexA(),
		      oldMem.get_memIndexB(),
		      oldMem.get_currentWritable(),
		      oldMem.get_currentReadOnly(),
		      diskIndexReader);
		  lockAndSwapMem(diskIndexReader, oldMem.get_diskIndexReader(), mem);
		  log.info("disk reader refreshed");
	  }

  /**
   * swap the disk IndexReader cached in mem. In order to count the reference properly,
   * we need to lock the access to _mem so that it is safe to compare whether the old
   * and new disk IndexReader are different. decRef the old IndexReader only when they
   * differ.
   * @param diskIndexReader the new disk IndexReader
   * @param oldDiskReader the old disk IndexReader from old mem
   * @param mem the new mem
   */
  private void lockAndSwapMem(ZoieIndexReader diskIndexReader, ZoieIndexReader  oldDiskReader, Mem mem)
  {
    synchronized(_memLock)
    {
      if (oldDiskReader!=diskIndexReader)
      {
        if (oldDiskReader != null)
        {
//          try
//          {
            oldDiskReader.decZoieRef();
//          } catch (IOException e)
//          {
//            log.error("swaping old and new disk reader failure: " + e);
//          }
        }
        diskIndexReader.incZoieRef();
        _mem = mem;
      }
    }
  }

  private final static class Mem
  {
    private final RAMSearchIndex _memIndexA;
    private final RAMSearchIndex _memIndexB;
    private final RAMSearchIndex _currentWritable;
    private final RAMSearchIndex _currentReadOnly;
    private final ZoieIndexReader _diskIndexReader;
    Mem(RAMSearchIndex a, RAMSearchIndex b, RAMSearchIndex w, 
    	RAMSearchIndex r, ZoieIndexReader d)
    {
      _memIndexA = a;
      _memIndexB = b;
      _currentWritable = w;
      _currentReadOnly = r;
      _diskIndexReader = d;
    }
    
    protected RAMSearchIndex get_memIndexA()
    {
      return _memIndexA;
    }

    protected RAMSearchIndex get_memIndexB()
    {
      return _memIndexB;
    }

    protected RAMSearchIndex get_currentWritable()
    {
      return _currentWritable;
    }

    protected RAMSearchIndex get_currentReadOnly()
    {
      return _currentReadOnly;
    }

    protected ZoieIndexReader get_diskIndexReader()
    {
      return _diskIndexReader;
    }
  }

  @Override
  public Analyzer getAnalyzer()
  {
    throw new UnsupportedOperationException();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy