protected final AsyncWriter createAsyncWriter(FileSystem fs, Path path) throws IOException {
    return AsyncFSWALProvider.createAsyncWriter(conf, fs, path, false, this.blocksize,
      eventLoopGroup, channelClass, streamSlowMonitor);
  }
An asynchronous implementation of FSWAL.
<p>
Here 'waitingConsumePayloads' acts as the RingBuffer in FSHLog.
<p>
For append, we process it as follow:
<ol>
<li>In the caller thread(typically, in the rpc handler thread):
<ol>
<li>Insert the entry into 'waitingConsumePayloads'. Use ringbuffer sequence as txid.</li>
<li>Schedule the consumer task if needed. See {@link #shouldScheduleConsumer()} for more details.
</li>
</ol>
</li>
<li>In the consumer task(executed in a single threaded thread pool)
<ol>
<li>Poll the entry from {@link #waitingConsumePayloads} and insert it into
{@link #toWriteAppends}</li>
<li>Poll the entry from {@link #toWriteAppends}, append it to the AsyncWriter, and insert it into
{@link #unackedAppends}</li>
<li>If the buffered size reaches {@link #batchSize}, or there is a sync request, then we call
sync on the AsyncWriter.</li>
<li>In the callback methods:
<ul>
<li>If succeeded, poll the entry from {@link #unackedAppends} and drop it.</li>
<li>If failed, add all the entries in {@link #unackedAppends} back to {@link #toWriteAppends} and
wait for writing them again.</li>
</ul>
</li>
</ol>
</li>
</ol>
For sync, the processing stages are almost same. And different from FSHLog, we will open a new
writer and rewrite unacked entries to the new writer and sync again if we hit a sync error.
<p>
Here we only describe the logic of doReplaceWriter. The main logic of rollWriter is same with
FSHLog.<br>
For a normal roll request(for example, we have reached the log roll size):
<ol>
<li>In the log roller thread, we will set {@link #waitingRoll} to true and
{@link #readyForRolling} to false, and then wait on {@link #readyForRolling}(see
{@link #waitForSafePoint()}).</li>
<li>In the consumer thread, we will stop polling entries from {@link #waitingConsumePayloads} if
{@link #waitingRoll} is true, and also stop writing the entries in {@link #toWriteAppends} out.
</li>
<li>If there are unflush data in the writer, sync them.</li>
<li>When all out-going sync request is finished, i.e, the {@link #unackedAppends} is empty,
signal the {@link #readyForRollingCond}.</li>
<li>Back to the log roller thread, now we can confirm that there are no out-going entries, i.e.,
we reach a safe point. So it is safe to replace old writer with new writer now.</li>
<li>Set {@link #writerBroken} and {@link #waitingRoll} to false.</li>
<li>Schedule the consumer task.</li>
<li>Schedule a background task to close the old writer.</li>
</ol>
For a broken writer roll request, the only difference is that we can bypass the wait for safe
point stage.
hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AsyncFSWAL.java