nirdosh0110 commented on code in PR #8584:
URL: https://github.com/apache/hbase/pull/8584#discussion_r3934210025


##########
hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java:
##########
@@ -1092,6 +1092,24 @@ public void removeRegion(final RegionInfo regionInfo) {
     flushedSequenceIdByRegion.remove(encodedName);
   }
 
+  /**
+   * Called on region OPEN to seed {@link #flushedSequenceIdByRegion} with the 
region's
+   * {@code openSeqNum}. Without this, the entry stays absent until the 
hosting server's next
+   * heartbeat, so {@link #getLastFlushedSequenceId} returns {@link 
HConstants#NO_SEQNUM} and
+   * WALSplitter conservatively treats already-durable edits as unflushed - 
producing orphaned
+   * recovered.edits when the source server crashes soon after a drain-move. 
Uses {@code merge} with
+   * {@link Math#max} so a heartbeat-supplied value (which may reflect flushes 
after open) is never
+   * regressed - and, unlike {@code putIfAbsent}, a stale-low prior value is 
lifted to
+   * {@code openSeqNum}. Safe because at OPEN a region cannot have flushed 
past its own
+   * {@code openSeqNum}. See HBASE-30335.
+   */
+  public void reportRegionOpen(final RegionInfo regionInfo, final long 
openSeqNum) {
+    if (openSeqNum < 0) { // NO_SEQNUM == -1
+      return;
+    }
+    flushedSequenceIdByRegion.merge(regionInfo.getEncodedNameAsBytes(), 
openSeqNum, Math::max);

Review Comment:
   Good catch — the race is real. `updateLastFlushedSequenceIds` reads 
`flushedSequenceIdByRegion` at line 292 and does a conditional `put` at line 
300 without holding any lock, so the following interleaving is possible:
   
   1. Stale heartbeat thread reads `existingValue = null`.
   2. `reportRegionOpen(regionInfo, openSeqNum=10)` executes its atomic 
`merge(Math::max)` → map now has `10`.
   3. Stale heartbeat thread resumes and writes `completedSeqId = 3` → map 
regresses to `3`.
   
   The read-then-put pattern predates this PR, but HBASE-30335 sharpens the 
exposure. Before this change every writer to the map was the same heartbeat 
path carrying monotonically-nondecreasing values from a single RS — a lost 
update was self-healing on the next heartbeat. With the new OPEN-time seed, the 
writer values are heterogeneous (a fresh `openSeqNum` after reopen can be 
strictly greater than any stale RS's `completedSequenceId` observed during 
graceful drain / failover), and a regression on this path is not self-healing 
because the OPEN seed happens once per region open, not periodically.
   
   Filing this as a follow-up JIRA to keep this PR's diff focused on the seed 
installation and to make bisection precise if either change regresses. The 
follow-up will convert both the region-level and per-store read-then-put pairs 
to atomic `compute(...)` and add a concurrency test that races 
`reportRegionOpen(high)` against a heartbeat-shaped `regionServerReport(low)` 
and asserts the final map holds `high`. Will link the follow-up PR here once 
it's up.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to