Compacts logs up to the given index.

@param compactIndex the index to which to compact logs
772242
private void compactLogs(long compactIndex) {
    raft.getThreadContext().execute(() -> {
      logger.debug("Compacting logs up to index {}", compactIndex);
      try {
        raft.getLog().compact(compactIndex);
      } catch (Exception e) {
        logger.error("An exception occurred during log compaction: {}", e);
      } finally {
        this.compactFuture.complete(null);
        this.compactFuture = null;
        // Immediately attempt to take new snapshots since compaction is already run after a time interval.
        takeSnapshots(false, false);
      }
    });
  }
1104743
private void compactByAge() {
    if (maxLogAge != null) {
      long currentTime = System.currentTimeMillis();
      JournalSegment<LogEntry> compactSegment = null;
      Long compactIndex = null;
      for (JournalSegment<LogEntry> segment : journal.segments()) {
        if (currentTime - segment.descriptor().updated() > maxLogAge.toMillis()) {
          log.debug("Found expired journal segment {}", segment.file().file());
          compactSegment = segment;
        } else if (compactSegment != null) {
          compactIndex = segment.index();
          break;
        }
      }

      if (compactIndex != null) {
        log.info("Compacting journal by age up to {}", compactIndex);
        journal.compact(compactIndex);
      }
    }
  }
932419
private List<Segment> getCompactableSegments(SegmentManager manager) {
    List<Segment> segments = new ArrayList<>(manager.segments().size());
    Iterator<Segment> iterator = manager.segments().iterator();
    Segment segment = iterator.next();
    while (iterator.hasNext()) {
      Segment nextSegment = iterator.next();

      // Segments that have already been compacted are eligible for compaction. For uncompacted segments, the segment must be full, consist
      // of entries less than the minorIndex, and a later segment with at least one committed entry must exist in the log. This ensures that
      // a non-empty entry always remains at the end of the log.
      if (segment.isCompacted() || (segment.isFull() && segment.lastIndex() < compactor.minorIndex() && nextSegment.firstIndex() <= manager.commitIndex() && !nextSegment.isEmpty())) {
        segments.add(segment);
      } else {
        break;
      }

      segment = nextSegment;
    }
    return segments;
  }
170714
public Future<?> submitIndexBuild(final SecondaryIndexBuilder builder)
    {
        Runnable runnable = new Runnable()
        {
            public void run()
            {
                metrics.beginCompaction(builder);
                try
                {
                    builder.build();
                }
                finally
                {
                    metrics.finishCompaction(builder);
                }
            }
        };
        if (executor.isShutdown())
        {
            logger.info("Compaction executor has shut down, not submitting index build");
            return null;
        }

        return executor.submit(runnable);
    }
131562
public Log release(long index) {
    assertIsOpen();
    assertValidIndex(index);

    Segment segment = segments.segment(index);
    Assert.index(segment != null, "invalid index: " + index);
    segment.release(index);
    return this;
  }
667081
boolean isCompactionRequired(SegmentProperties info) {
        long startOffset = getCompactionStartOffset(info);
        long lastIndexOffset = this.indexReader.getLastIndexedOffset(info);
        if (startOffset + this.connector.getMaxCompactionSize() >= lastIndexOffset) {
            // Either:
            // 1. Nothing was indexed
            // 2. Compaction has already reached the indexed limit.
            // 3. Not enough "uncompacted" data - at least this.maxCompactLength must be accumulated to trigger a compaction.
            return false;
        }

        long totalEntryCount = this.indexReader.getTotalEntryCount(info);
        long entryCount = this.indexReader.getEntryCount(info);
        long utilization = totalEntryCount == 0 ? 100 : MathHelpers.minMax(Math.round(100.0 * entryCount / totalEntryCount), 0, 100);
        long utilizationThreshold = (int) MathHelpers.minMax(this.indexReader.getCompactionUtilizationThreshold(info), 0, 100);
        return utilization < utilizationThreshold;
    }
316657
public void compactRange() throws RocksDbException {
        try {
            rocksDb.compactRange();
        } catch (Exception e) {
            throw e instanceof RocksDbException ? (RocksDbException) e : new RocksDbException(e);
        }
    }
1343061
private void checkEntry(long index, Segment segment, Segment compactSegment) {
    try (Entry entry = segment.get(index)) {
      // If an entry was found, only remove the entry from the segment if it's not a tombstone that has been released.
      if (entry != null) {
        checkEntry(index, entry, segment, compactSegment);
      } else {
        compactSegment.skip(1);
      }
    }
  }
394937
private void ensureCapacity(int segmentIndex) {
        while(segmentIndex >= segments.length) {
            segments = Arrays.copyOf(segments, segments.length * 3 / 2);
        }

        long numSegmentsPopulated = length >> log2OfSegmentSize;

        for(long i=numSegmentsPopulated; i <= segmentIndex; i++) {
            segments[(int)i] = memoryPool.getSegment();
            length += 1 << log2OfSegmentSize;
        }
    }
946752
private void consumeCompaction(CompactionUpdateBatch updateBatch) throws Exception {
        int ignoreCount = 0;
        int updateCount = updateBatch.size();
        int totalIgnoreBytes = 0;
        int totalUpdateBytes = updateBatch.getDataSizeTotal();
        
        /* Using lwMark is to guarantee that redo logs from compaction will not increase
         * the hwMark of the underlying array file. If hwMark is being used, the current
         * redo entry is discarded upon crash. Upon restart, the hwMark from the underlying
         * array file may prevent updates in the lost redo entry from being resent.   
         */
        long updateScn = _addressArray.getLWMark();
        Segment segTarget = updateBatch.getTargetSegment();
        
        for(int i = 0; i < updateCount; i++) {
            int index = updateBatch.getUpdateIndex(i);
            long origAddr = updateBatch.getOriginDataAddr(i);
            long currAddr = getAddress(index);
            
            if(currAddr == 0 ||      /* data at the given index is deleted by writer */ 
               currAddr != origAddr  /* data at the given index is updated by writer */) {
                /*
                 * The address generated by the compactor is obsolete.
                 */
                int updateBytes = updateBatch.getUpdateDataSize(i);
                totalIgnoreBytes += updateBytes;
                ignoreCount++;
            } else {
                /*
                 * The address generated by the compactor has not been touched by the writer.
                 * Update the address array directly.
                 */ 
                setCompactionAddress(index, updateBatch.getUpdateDataAddr(i), updateScn);
            }
        }
        
        int consumeCount = updateCount - ignoreCount;
        int totalConsumeBytes = totalUpdateBytes - totalIgnoreBytes;
        
        if(_log.isTraceEnabled()) {
            _log.trace("consumed compaction batch " +
                       updateBatch.getDescriptiveId() +
                       " updates " + consumeCount + "/" + updateCount +
                       " bytes " + totalConsumeBytes + "/" + totalUpdateBytes);
        }
        
        // Update segment load size
        segTarget.decrLoadSize(totalIgnoreBytes);
    }
1206597
static Slice compactSlice(Slice slice, int index, int length)
    {
        if (slice.isCompact() && index == 0 && length == slice.length()) {
            return slice;
        }
        return Slices.copyOf(slice, index, length);
    }
1144856
private void compactEntries(Segment segment, Segment compactSegment) {
    for (long i = segment.firstIndex(); i <= segment.lastIndex(); i++) {
      checkEntry(i, segment, compactSegment);
    }
  }
275810
public void compact() {
    if (keys.length > size) {
      Class<?>[] newKeys = new Class<?>[size];
      Object[] newVals = new Object[size];
      System.arraycopy(keys, 0, newKeys, 0, size);
      System.arraycopy(values, 0, newVals, 0, size);
      keys = newKeys;
      values = newVals;
    }
  }
692445
@GuardedBy("lock")
    protected void compact() {
        if(read_pos == 0)
            return;
        if(size() == 0) {
            read_pos=write_pos=0;
            return;
        }
        int length=write_pos - read_pos;
        System.arraycopy(buf, read_pos, buf, 0, length);
        write_pos-=read_pos;
        read_pos=0;
        not_full.signalAll();
    }
527694
private void ensureIndex(final int index) {
        if (index < 0) throw new IndexOutOfBoundsException("Index (" + index + ") is negative");
        if (index > size())
            throw new IndexOutOfBoundsException("Index (" + index + ") is greater than list size (" + (size()) + ")");
    }
1167497
public Log commit(long index) {
    assertIsOpen();
    if (index > 0) {
      assertValidIndex(index);
      segments.commitIndex(index);
      if (storage.flushOnCommit()) {
        segments.currentSegment().flush();
      }
    }
    return this;
  }
750853
private synchronized CompletableFuture<Void> compact(Compaction compaction, CompletableFuture<Void> future, ThreadContext context) {
    CompactionManager manager = compaction.manager(this);
    AtomicInteger counter = new AtomicInteger();

    Collection<CompactionTask> tasks = manager.buildTasks(storage, segments);
    if (!tasks.isEmpty()) {
      LOGGER.info("Compacting log with compaction: {}", compaction);
      LOGGER.debug("Executing {} compaction task(s)", tasks.size());
      for (CompactionTask task : tasks) {
        LOGGER.debug("Executing {}", task);
        ThreadContext taskThread = new ThreadPoolContext(executor, segments.serializer());
        taskThread.execute(task).whenComplete((result, error) -> {
          LOGGER.debug("{} complete", task);
          if (counter.incrementAndGet() == tasks.size()) {
            if (context != null) {
              context.executor().execute(() -> future.complete(null));
            } else {
              future.complete(null);
            }
          }
        });
      }
    } else {
      future.complete(null);
    }
    return future;
  }