private boolean isLastRangeAndOpening(ReplicationBarrierResult barrierResult, int index) {
    return index == barrierResult.getBarriers().length
      && barrierResult.getState() == RegionState.State.OPENING;
  }
<p>
Helper class to determine whether we can push a given WAL entry without breaking the replication
order. The class is designed to per {@link ReplicationSourceWALReader}, so not thread safe.
</p>
<p>
We record all the open sequence number for a region in a special family in meta, which is called
'rep_barrier', so there will be a sequence of open sequence number (b1, b2, b3, ...). We call
[bn, bn+1) a range, and it is obvious that a region will always be on the same RS within a range.
<p>
When split and merge, we will also record the parent for the generated region(s) in the special
family in meta. And also, we will write an extra 'open sequence number' for the parent region(s),
which is the max sequence id of the region plus one.
</p>
</p>
<p>
For each peer, we record the last pushed sequence id for each region. It is managed by the
replication storage.
</p>
<p>
The algorithm works like this:
<ol>
<li>Locate the sequence id we want to push in the barriers</li>
<li>If it is before the first barrier, we are safe to push. This usually because we enable serial
replication for this table after we create the table and write data into the table.</li>
<li>In general, if the previous range is finished, then we are safe to push. The way to determine
whether a range is finish is straight-forward: check whether the last pushed sequence id is equal
to the end barrier of the range minus 1. There are several exceptions:
<ul>
<li>If it is in the first range, we need to check whether there are parent regions. If so, we
need to make sure that the data for parent regions have all been pushed.</li>
<li>If it is in the last range, we need to check the region state. If state is OPENING, then we
are not safe to push. This is because that, before we call reportRIT to master which update the
open sequence number into meta table, we will write a open region event marker to WAL first, and
its sequence id is greater than the newest open sequence number(which has not been updated to
meta table yet so we do not know). For this scenario, the WAL entry for this open region event
marker actually belongs to the range after the 'last' range, so we are not safe to push it.
Otherwise the last pushed sequence id will be updated to this value and then we think the
previous range has already been finished, but this is not true.</li>
<li>Notice that the above two exceptions are not conflicts, since the first range can also be the
last range if we only have one range.</li>
</ul>
</li>
</ol>
</p>
<p>
And for performance reason, we do not want to check meta for every WAL entry, so we introduce two
in memory maps. The idea is simple:
<ul>
<li>If a range can be pushed, then put its end barrier into the {@code canPushUnder} map.</li>
<li>Before accessing meta, first check the sequence id stored in the {@code canPushUnder} map. If
the sequence id of WAL entry is less the one stored in {@code canPushUnder} map, then we are safe
to push.</li>
</ul>
And for the last range, we do not have an end barrier, so we use the continuity of sequence id to
determine whether we can push. The rule is:
<ul>
<li>When an entry is able to push, then put its sequence id into the {@code pushed} map.</li>
<li>Check if the sequence id of WAL entry equals to the one stored in the {@code pushed} map plus
one. If so, we are safe to push, and also update the {@code pushed} map with the sequence id of
the WAL entry.</li>
</ul>
</p>
hbase-server/src/main/java/org/apache/hadoop/hbase/replication/regionserver/SerialReplicationChecker.java