tkhurana opened a new pull request, #2603: URL: https://github.com/apache/phoenix/pull/2603
When >=2 co-active RegionServers drive the shared HA-status znode to the same target state, each does an optimistic CAS whose expected version comes from the watch-lagged local cache. The first writer wins; the others were aborting the RegionServer even though the shared status was already at the target. This hits the peer-degrade path (ACTIVE_IN_SYNC -> ACTIVE_NOT_IN_SYNC) and, more commonly, the forwarders racing ACTIVE_NOT_IN_SYNC -> ACTIVE_IN_SYNC. The two convergent losers differ by whether the winner's write reached the loser's cache before it fired, and each is reconciled from a source that is authoritative for its path -- never the watch-lagged cache used as a false-success signal: Cache-stale loser (client, HAGroupStoreClient.setHAGroupStatusIfNeeded): the CAS is attempted and loses stale; the loop re-reads fresh from ZK and retries, bounded by SET_HA_GROUP_STATUS_MAX_ATTEMPTS. Move the 'attempt > 1 && current == target' no-op ahead of validateTransitionAndGetWaitTime so a converged non-self-transitionable target (e.g. ACTIVE_IN_SYNC) returns a no-op success from the fresh re-read instead of throwing InvalidClusterRoleTransitionException on the X -> X self-transition. The first attempt never short-circuits, so the periodic STORE_AND_FORWARD heartbeat still writes its znode mtime bump that gates SYNC promotion. Watch-won loser (server, HAGroupStoreManager.setHAGroupStatusToSync): the winner's write already propagated to the cache, so validate rejects the ACTIVE_IN_SYNC -> ACTIVE_IN_SYNC self-transition before any CAS is attempted -- no stale-version exception is ever thrown, so the client cannot catch it. Swallow the InvalidClusterRoleTransitionException as a no-op success, guarded on isStateAlreadyUpdated(current == target) so a genuinely invalid transition still propagates. The ACTIVE_IN_SYNC local listener in ReplicationLogGroup already drives the loser to the correct end state (resume rotation, SYNC_AND_FORWARD -> SYNC), so the group-level goal is met and the loser need not retry its own write. Add HAGroupStoreManagerIT#testSetHAGroupStatusToSyncConvergentRaceIsNoOp covering the watch-won path: with the record already at ACTIVE_IN_SYNC, setHAGroupStatusToSync returns 0L with no ZK write instead of throwing. The existing HAGroupStoreClientIT convergent-race and heartbeat cases continue to cover the cache-stale path. -- 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]
