Package proj.zoie.hourglass.impl

Source Code of proj.zoie.hourglass.impl.HourglassReaderManager

package proj.zoie.hourglass.impl;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.SimpleFSDirectory;

import proj.zoie.api.DirectoryManager;
import proj.zoie.api.ZoieException;
import proj.zoie.api.ZoieHealth;
import proj.zoie.api.ZoieIndexReader;
import proj.zoie.api.ZoieMultiReader;
import proj.zoie.api.ZoieVersion;
import proj.zoie.api.impl.util.FileUtil;
import proj.zoie.api.indexing.IndexReaderDecorator;
import proj.zoie.impl.indexing.ZoieSystem;
import proj.zoie.impl.indexing.internal.IndexSignature;
import proj.zoie.impl.indexing.internal.ZoieIndexDeletionPolicy;

public class HourglassReaderManager<R extends IndexReader, D, V extends ZoieVersion>
{
  public static final Logger log = Logger.getLogger(HourglassReaderManager.class.getName());
  private final HourglassDirectoryManagerFactory _dirMgrFactory;
  private final Hourglass<R, D, V> hg;
  private final IndexReaderDecorator<R> _decorator;
  private volatile Box<R, D, V> box;
  private volatile boolean isShutdown = false;
  private ExecutorService threadPool = Executors.newCachedThreadPool();
  public HourglassReaderManager(final Hourglass<R, D, V> hourglass, HourglassDirectoryManagerFactory dirMgrFactory,
      IndexReaderDecorator<R> decorator,
      List<ZoieIndexReader<R>> initArchives)
  {
    hg = hourglass;
    _dirMgrFactory = dirMgrFactory;
    _decorator = decorator;
    box = new Box<R, D, V>(initArchives, Collections.EMPTY_LIST, Collections.EMPTY_LIST, _decorator);
    threadPool.execute(new Runnable(){
      final int trimThreshold = hourglass._scheduler.getTrimThreshold();

      @Override
      public void run()
      {
        while(true)
        {
          try
          {
            Thread.sleep(60000);
          } catch (InterruptedException e)
          {
            log.warn(e);
          }
          List<ZoieIndexReader<R>> archives = new LinkedList<ZoieIndexReader<R>>(box._archives);
          List<ZoieIndexReader<R>> add = new LinkedList<ZoieIndexReader<R>>();
          try
          {
            hourglass._shutdownLock.readLock().lock();
            if (isShutdown)
            {
              log.info("Already shut down. Quiting maintenance thread.");
              break;
            }
            if (archives.size() > trimThreshold)
            {
              log.info("to maintain");
            } else continue;
//            consolidate(archives, add);
            trim(archives);
            // swap the archive with consolidated one
            swapArchives(archives, add);
          } finally
          {
            hourglass._shutdownLock.readLock().unlock();
          }
        }
      }});
  }
  /**
   * consolidate the archived Index to one big optimized index and put in add
   * @param toRemove
   * @param add
   */
  private void trim(List<ZoieIndexReader<R>> toRemove)
  {
    long timenow = System.currentTimeMillis();
    List<ZoieIndexReader<R>> toKeep = new LinkedList<ZoieIndexReader<R>>();
    Calendar now = Calendar.getInstance();
    now.setTimeInMillis(timenow);
    Calendar threshold = hg._scheduler.getTrimTime(now);
    for(int i=0; i<toRemove.size(); i++)
    {
      SimpleFSDirectory dir = (SimpleFSDirectory) toRemove.get(i).directory();
      String path = dir.getFile().getName();
      Calendar archivetime = null;
      try
      {
        archivetime = HourglassDirectoryManagerFactory.getCalendarTime(path);
      } catch (ParseException e)
      {
        log.error("index directory name bad. potential corruption. Move on without trimming.", e);
        toKeep.add(toRemove.get(i));
        continue;
      }
      if (archivetime.before(threshold))
      {
        log.info("trimming: remove " + path);
        log.info(dir.getFile() + " -before--" + (dir.getFile().exists()?" not deleted ":" deleted"));
        FileUtil.rmDir(dir.getFile());
        log.info(dir.getFile() + " -after--" + (dir.getFile().exists()?" not deleted ":" deleted"));
      } else
      {
        toKeep.add(toRemove.get(i));
      }
    }
    toRemove.removeAll(toKeep);
  }
  /**
   * consolidate the archived Index to one big optimized index and put in add
   * @param archived
   * @param add
   */
  private void consolidate(List<ZoieIndexReader<R>> archived, List<ZoieIndexReader<R>> add)
  {
    log.info("begin consolidate ... ");
    long b4 = System.currentTimeMillis();
    SimpleFSDirectory target = (SimpleFSDirectory) archived.get(0).directory();
    log.info("into: "+target.getFile().getAbsolutePath());
    SimpleFSDirectory sources[] = new SimpleFSDirectory[archived.size()-1];
    @SuppressWarnings("unchecked")
    IndexSignature<V> sigs[] = (IndexSignature<V>[])new IndexSignature[archived.size()];
    sigs[0] = _dirMgrFactory.getIndexSignature(target.getFile()); // the target index signature
    log.info("target version: " + sigs[0].getVersion());
    for(int i=1; i<archived.size(); i++)
    {
      sources[i-1] = (SimpleFSDirectory) archived.get(i).directory();
      sigs[i] = _dirMgrFactory.getIndexSignature(sources[i-1].getFile())// get other index signatures
      log.info("from: " + sources[i-1].getFile().getAbsolutePath());
    }
    IndexWriter idxWriter = null;
    try
    {
      idxWriter = new IndexWriter(target, null, false, new ZoieIndexDeletionPolicy(), MaxFieldLength.UNLIMITED);
      idxWriter.addIndexesNoOptimize(sources);
      idxWriter.optimize(1);
    } catch (CorruptIndexException e)
    {
      ZoieHealth.setFatal();
      log.error("index currupted during consolidation", e);
    } catch (LockObtainFailedException e)
    {
      ZoieHealth.setFatal();
      log.error("LockObtainFailedException during consolidation", e);
    } catch (IOException e)
    {
      ZoieHealth.setFatal();
      log.error("IOException during consolidation", e);
    } finally
    {
      if (idxWriter != null)
      {
        try
        {
          idxWriter.close();
          // remove the originals from disk
          for(SimpleFSDirectory dir : sources)
          {
            IndexSignature<V> sig = _dirMgrFactory.getIndexSignature(dir.getFile());
            log.info(dir.getFile() + "---" + (dir.getFile().exists()?" not deleted ":" deleted") + " version: " + sig.getVersion());
            FileUtil.rmDir(dir.getFile());
            log.info(dir.getFile() + "---" + (dir.getFile().exists()?" not deleted ":" deleted"));
          }
          V tgtversion = null;
          for(int i = sigs.length - 1; i >= 0; i--)
          { // get the largest version so far
            if (tgtversion ==null || sigs[i].getVersion().compareTo(tgtversion)>0) tgtversion = sigs[i].getVersion();
          }
          // save the version to target
          IndexSignature<V> tgtsig = _dirMgrFactory.getIndexSignature(target.getFile());
          tgtsig.updateVersion(tgtversion);
          _dirMgrFactory.saveIndexSignature(target.getFile(), tgtsig);
          log.info("saveIndexSignature to " + target.getFile().getAbsolutePath() + " at version: " + tgtsig.getVersion());
          // open index reader for the consolidated index
          IndexReader reader = IndexReader.open(target, true);
          // decorate the index
          ZoieMultiReader<R> zoiereader = new ZoieMultiReader<R>(reader, _decorator);
          add.add(zoiereader);
          long b5 = System.currentTimeMillis();
          log.info("done consolidate in " + (System.currentTimeMillis() - b4)+"ms  blocked for " + (System.currentTimeMillis()-b5));
        } catch (CorruptIndexException e)
        {
          ZoieHealth.setFatal();
          log.error("index currupted during consolidation", e);
        } catch (IOException e)
        {
          ZoieHealth.setFatal();
          log.error("IOException during consolidation", e);
        }
      }
    }
  }
  /**
   * The readers removed will also be decRef(). But the readers to be added will NOT get incRef(),
   * which means we assume the newly added ones have already been incRef().
   * remove and add should be <b>disjoint</b>
   * @param remove the readers to be remove. This has to be disjoint from add.
   * @param add
   */
  public synchronized void swapArchives(List<ZoieIndexReader<R>> remove, List<ZoieIndexReader<R>> add)
  {
    List<ZoieIndexReader<R>> archives = new LinkedList<ZoieIndexReader<R>>(add);
    if (!box._archives.containsAll(remove))
    {
      log.error("swapArchives: potential sync issue. ");
    }
    archives.addAll(box._archives);
    archives.removeAll(remove);
    for(ZoieIndexReader<R> r : remove)
    {
      r.decZoieRef();
      if (log.isDebugEnabled())
      {
        log.debug("remove time " + r.directory() + " refCount: " + r.getRefCount());
      }
    }
    Box<R, D, V> newbox = new Box<R, D, V>(archives, box._retiree, box._actives, _decorator);
    box = newbox;
  }
  public synchronized ZoieSystem<R, D, V> retireAndNew(final ZoieSystem<R, D, V> old)
  {
    DirectoryManager _dirMgr = _dirMgrFactory.getDirectoryManager();
    _dirMgrFactory.clearRecentlyChanged();
    ZoieSystem<R, D, V> newzoie = hg.createZoie(_dirMgr);
    List<ZoieSystem<R, D, V>> actives = new LinkedList<ZoieSystem<R, D, V>>(box._actives);
    List<ZoieSystem<R, D, V>> retiring = new LinkedList<ZoieSystem<R, D, V>>(box._retiree);
    if (old!=null)
    {
      actives.remove(old);
      retiring.add(old);
      threadPool.execute(new Runnable()
      {
        @Override
        public void run()
        {
          retire(old);
        }});
    }
    actives.add(newzoie);
    Box<R, D, V> newbox = new Box<R, D, V>(box._archives, retiring, actives, _decorator);
    box = newbox;
    return newzoie;
  }
  /**
   * @param zoie
   * @param reader the IndexReader opened on the index the give zoie had written to.
   */
  public synchronized void archive(ZoieSystem<R, D, V> zoie, ZoieMultiReader<R> reader)
  {
    List<ZoieIndexReader<R>> _archives = new LinkedList<ZoieIndexReader<R>>(box._archives);
    List<ZoieSystem<R, D, V>> actives = new LinkedList<ZoieSystem<R, D, V>>(box._actives);
    List<ZoieSystem<R, D, V>> retiring = new LinkedList<ZoieSystem<R, D, V>>(box._retiree);
    retiring.remove(zoie);
    if (reader != null)
    {
      _archives.add(reader);
    }
    Box<R, D, V> newbox = new Box<R, D, V>(_archives, retiring, actives, _decorator);
    box = newbox;
  }
  private synchronized void preshutdown()
  {
    log.info("shutting down thread pool.");
    threadPool.shutdown();
    isShutdown = true;
  }
  public void shutdown()
  {
    preshutdown();
    while(true)
    {
      TimeUnit unit=TimeUnit.SECONDS;
      long t=10L;
      try
      {
        if (threadPool.awaitTermination(t, unit)) break;
      } catch (InterruptedException e)
      {
        log.warn("Exception when trying to shutdown. Will retry.", e);
      }
    }
    log.info("shutting down thread pool complete.");
    log.info("shutting down indices.");
    box.shutdown();
    log.info("shutting down indices complete.");
  }
  public synchronized List<ZoieIndexReader<R>> getIndexReaders() throws IOException
  {
    List<ZoieIndexReader<R>> list = new ArrayList<ZoieIndexReader<R>>();
    // add the archived index readers
    for(ZoieIndexReader<R> r : box._archives)
    {
      r.incZoieRef();
      list.add(r);
    }
    // add the retiring index readers
    for(ZoieSystem<R, D, V> zoie : box._retiree)
    {
      list.addAll(zoie.getIndexReaders());
    }
    // add the active index readers
    for(ZoieSystem<R, D, V> zoie : box._actives)
    {
      list.addAll(zoie.getIndexReaders());
    }
    return list;
 
  protected void retire(ZoieSystem<R, D, V> zoie)
  {
    long t0 = System.currentTimeMillis();
    log.info("retiring " + zoie.getAdminMBean().getIndexDir());
    while(true)
    {
      long flushwait = 200000L;
      try
      {
        zoie.flushEvents(flushwait);
        zoie.getAdminMBean().setUseCompoundFile(true);
        zoie.getAdminMBean().optimize(1);
        break;
      } catch (IOException e)
      {
        log.error("retiring " + zoie.getAdminMBean().getIndexDir() + " Should investigate. But move on now.", e);
        break;
      } catch (ZoieException e)
      {
        if (e.getMessage().indexOf("timed out")<0)
        {
          break;
        } else
        {
          log.info("retiring " + zoie.getAdminMBean().getIndexDir() + " flushing processing " + flushwait +"ms elapsed");
        }
      }
    }
    IndexReader reader = null;
    try
    {
      reader = getArchive(zoie);
    } catch (CorruptIndexException e)
    {
      log.error("retiring " + zoie.getAdminMBean().getIndexDir() + " Should investigate. But move on now.", e);
    } catch (IOException e)
    {
      log.error("retiring " + zoie.getAdminMBean().getIndexDir() + " Should investigate. But move on now.", e);
    }
    ZoieMultiReader<R> zoiereader = null;
    try
    {
      zoiereader = new ZoieMultiReader<R>(reader, _decorator);
    } catch (IOException e)
    {
      log.error(e);
    }
    archive(zoie, zoiereader);
    log.info("retired " + zoie.getAdminMBean().getIndexDir() + " in " + (System.currentTimeMillis()-t0)+"ms");
    log.info("Disk Index Size Total Now: " + (hg.getSizeBytes()/1024L) + "KB");
    zoie.shutdown();
  }
  private IndexReader getArchive(ZoieSystem<R, D, V> zoie) throws CorruptIndexException, IOException
  {
    String dirName = zoie.getAdminMBean().getIndexDir();
    Directory dir = new SimpleFSDirectory(new File(dirName));
    IndexReader reader = null;
    if (IndexReader.indexExists(dir))
    {
      reader  = IndexReader.open(dir, true);
    }
    else
    {
      log.info("empty index " + dirName);
      reader = null;
    }
    return reader;
  }
}
TOP

Related Classes of proj.zoie.hourglass.impl.HourglassReaderManager

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.