public void expungeDeletes() throws IOException {
   log.info("expunging deletes...");
   synchronized (_optimizeMonitor) {
     BaseSearchIndex<R, V> idx = getSearchIndex();
     IndexWriter writer = null;
     try {
       writer = idx.openIndexWriter(_analyzer, _similarity);
       writer.expungeDeletes(true);
     } finally {
       if (writer != null) {
         idx.closeIndexWriter();
       }
     }
     _idxMgr.refreshDiskReader();
   }
   log.info("deletes expunged");
 }
 @Override
 public void optimize(Optimize optimize) throws EngineException {
   if (optimizeMutex.compareAndSet(false, true)) {
     rwl.readLock().lock();
     try {
       if (indexWriter == null) {
         throw new EngineClosedException(shardId);
       }
       int maxNumberOfSegments = optimize.maxNumSegments();
       if (maxNumberOfSegments == -1) {
         // not set, optimize down to half the configured number of segments
         if (indexWriter.getMergePolicy() instanceof LogMergePolicy) {
           maxNumberOfSegments =
               ((LogMergePolicy) indexWriter.getMergePolicy()).getMergeFactor() / 2;
           if (maxNumberOfSegments < 0) {
             maxNumberOfSegments = 1;
           }
         }
       }
       if (optimize.onlyExpungeDeletes()) {
         indexWriter.expungeDeletes(optimize.waitForMerge());
       } else {
         indexWriter.optimize(maxNumberOfSegments, optimize.waitForMerge());
       }
       // once we did the optimization, we are "dirty" since we removed deletes potentially which
       // affects TermEnum
       dirty = true;
     } catch (Exception e) {
       throw new OptimizeFailedEngineException(shardId, e);
     } finally {
       rwl.readLock().unlock();
       optimizeMutex.set(false);
     }
   }
   if (optimize.flush()) {
     flush(new Flush());
   }
   if (optimize.refresh()) {
     refresh(new Refresh(false));
   }
 }