private void replayWALMetaEdit(Cell cell) throws IOException {
    startRegionOperation(Operation.REPLAY_EVENT);
    try {
      FlushDescriptor flushDesc = WALEdit.getFlushDescriptor(cell);
      if (flushDesc != null) {
        switch (flushDesc.getAction()) {
          case START_FLUSH:
            // for start flush, we need to take a snapshot of the current memstore
            synchronized (writestate) {
              if (!writestate.flushing) {
                this.writestate.flushing = true;
              } else {
                // usually this should not happen but let's make the code more robust, it is not a
                // big deal to just ignore it, the refreshStoreFiles call should have the ability to
                // clean up the inconsistent state.
                LOG.debug("NOT flushing {} as already flushing", getRegionInfo());
                break;
              }
            }
            MonitoredTask status =
              TaskMonitor.get().createStatus("Preparing flush " + getRegionInfo());
            Collection<HStore> storesToFlush = getStoresToFlush(flushDesc);
            try {
              PrepareFlushResult prepareResult =
                internalPrepareFlushCache(null, flushDesc.getFlushSequenceNumber(), storesToFlush,
                  status, false, FlushLifeCycleTracker.DUMMY);
              if (prepareResult.result == null) {
                // save the PrepareFlushResult so that we can use it later from commit flush
                this.prepareFlushResult = prepareResult;
                status.markComplete("Flush prepare successful");
                if (LOG.isDebugEnabled()) {
                  LOG.debug("{} prepared flush with seqId: {}", getRegionInfo(),
                    flushDesc.getFlushSequenceNumber());
                }
              } else {
                // special case empty memstore. We will still save the flush result in this case,
                // since our memstore is empty, but the primary is still flushing
                if (
                  prepareResult.getResult().getResult()
                      == FlushResult.Result.CANNOT_FLUSH_MEMSTORE_EMPTY
                ) {
                  this.prepareFlushResult = prepareResult;
                  if (LOG.isDebugEnabled()) {
                    LOG.debug("{} prepared empty flush with seqId: {}", getRegionInfo(),
                      flushDesc.getFlushSequenceNumber());
                  }
                }
                status.abort("Flush prepare failed with " + prepareResult.result);
                // nothing much to do. prepare flush failed because of some reason.
              }
            } finally {
              status.cleanup();
            }
            break;
          case ABORT_FLUSH:
            // do nothing, an abort flush means the source region server will crash itself, after
            // the primary region online, it will send us an open region marker, then we can clean
            // up the memstore.
            synchronized (writestate) {
              writestate.flushing = false;
            }
            break;
          case COMMIT_FLUSH:
          case CANNOT_FLUSH:
            // just call refreshStoreFiles
            refreshStoreFiles();
            logRegionFiles();
            synchronized (writestate) {
              writestate.flushing = false;
            }
            break;
          default:
            LOG.warn("{} received a flush event with unknown action: {}", getRegionInfo(),
              TextFormat.shortDebugString(flushDesc));
        }
      } else {
        // for all other region events, we will do a refreshStoreFiles
        refreshStoreFiles();
        logRegionFiles();
      }
    } finally {
      closeRegionOperation(Operation.REPLAY_EVENT);
    }
  }
Replay the meta edits, i.e, flush marker, compaction marker, bulk load marker, region event
marker, etc.
<p/>
For all events other than start flush, we will just call {@link #refreshStoreFiles()} as the
logic is straight-forward and robust. For start flush, we need to snapshot the memstore, so
later {@link #refreshStoreFiles()} call could drop the snapshot, otherwise we may run out of
memory.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java