private synchronized void cleanOldLogs() {
    List<Pair<Path, Long>> logsToArchive = null;
    long now = System.nanoTime();
    boolean mayLogTooOld = nextLogTooOldNs <= now;
    ArrayList<byte[]> regionsBlockingWal = null;
    // For each log file, look at its Map of regions to the highest sequence id; if all sequence ids
    // are older than what is currently in memory, the WAL can be GC'd.
    for (Map.Entry<Path, WALProps> e : this.walFile2Props.entrySet()) {
      if (!e.getValue().closed) {
        LOG.debug("{} is not closed yet, will try archiving it next time", e.getKey());
        continue;
      }
      Path log = e.getKey();
      ArrayList<byte[]> regionsBlockingThisWal = null;
      long ageNs = now - e.getValue().rollTimeNs;
      if (ageNs > walTooOldNs) {
        if (mayLogTooOld && regionsBlockingWal == null) {
          regionsBlockingWal = new ArrayList<>();
        }
        regionsBlockingThisWal = regionsBlockingWal;
      }
      Map<byte[], Long> sequenceNums = e.getValue().encodedName2HighestSequenceId;
      if (this.sequenceIdAccounting.areAllLower(sequenceNums, regionsBlockingThisWal)) {
        if (logsToArchive == null) {
          logsToArchive = new ArrayList<>();
        }
        logsToArchive.add(Pair.newPair(log, e.getValue().logSize));
        if (LOG.isTraceEnabled()) {
          LOG.trace("WAL file ready for archiving " + log);
        }
      } else if (regionsBlockingThisWal != null) {
        StringBuilder sb = new StringBuilder(log.toString()).append(" has not been archived for ")
          .append(TimeUnit.NANOSECONDS.toSeconds(ageNs)).append(" seconds; blocked by: ");
        boolean isFirst = true;
        for (byte[] region : regionsBlockingThisWal) {
          if (!isFirst) {
            sb.append("; ");
          }
          isFirst = false;
          sb.append(Bytes.toString(region));
        }
        LOG.warn(sb.toString());
        nextLogTooOldNs = now + SURVIVED_TOO_LONG_LOG_INTERVAL_NS;
        regionsBlockingThisWal.clear();
      }
    }

    if (logsToArchive != null) {
      final List<Pair<Path, Long>> localLogsToArchive = logsToArchive;
      // make it async
      for (Pair<Path, Long> log : localLogsToArchive) {
        logArchiveExecutor.execute(() -> {
          archive(log);
        });
        this.walFile2Props.remove(log.getFirst());
      }
    }
  }
Archive old logs. A WAL is eligible for archiving if all its WALEdits have been flushed.
<p/>
Use synchronized because we may call this method in different threads, normally when replacing
writer, and since now close writer may be asynchronous, we will also call this method in the
closeExecutor, right after we actually close a WAL writer.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java