kagrawal-tibco opened a new issue, #13676:
URL: https://github.com/apache/ignite/issues/13676

   h3. Problem
   If a page-memory partition (aimem or aipersist) contains a committed 
tombstone that GC has not yet removed, a full-state transfer (Raft 
InstallSnapshot) of that partition never completes. The receiving replica stays 
in snapshot install indefinitely. Its safe time never advances, so read-only 
transactions mapped to it (implicit RO SQL prefers the local replica) fail with 
IGN-REP-3 "replication timeout", even though the group has a healthy primary 
and majority.
   
   h3. Root cause
   # {{ScanVersionsCursor.rowVersionToReadResult}} 
(modules/storage-page-memory, 3.1.0 line 108-109) returns 
{{ReadResult.empty(rowId)}} for a committed tombstone. {{ReadResult.empty}} has 
a null {{commitTimestamp}}.
   #* {{RocksDbMvPartitionStorage}} returns the same version as 
{{ReadResult.createFromCommitted(rowId, null, rowCommitTimestamp)}}, so the two 
engines disagree on the {{scanVersions}} contract for tombstones.
   # {{PartitionMvStorageAccessImpl.getAllRowVersions}} passes every 
{{scanVersions}} result through unchanged.
   # {{OutgoingSnapshot.rowEntry}} (3.1.0 line 456; main line ~479) treats 
every non-write-intent version as committed and runs {{commitTimestamps[j++] = 
version.commitTimestamp().longValue();}}, which throws a NullPointerException 
for the tombstone. That covers a tombstone at the head of the chain (a deleted 
row) and one in the middle (deleted, then re-inserted).
   # {{OutgoingSnapshotsManager.respond}} (line 207-214) passes the throwable 
to {{failureProcessor.process(new FailureContext(throwable, "Something went 
wrong while handling a request"))}} and returns *without sending any response*.
   # {{IncomingSnapshotCopier}} sends its requests with {{NETWORK_TIMEOUT = 
Long.MAX_VALUE}} (line 93), so the copier waits forever.
   #* IGNITE-27497 (shorter copier timeout) would limit the wait, but every 
retry would hit the same NPE as long as the tombstone exists on the sender.
   
   h3. When it happens
   All of these must be true:
   * A replica needs a full-state transfer: it restarted, or fell behind, after 
the leader's Raft log had been truncated by a snapshot. With hourly snapshots, 
that is roughly 1-2 h of uptime.
   * The partition uses a page-memory storage engine (aimem or aipersist).
   * The partition holds rows deleted by a committed transaction whose 
tombstones are still above the low watermark. A longer 
{{gc-data-availability-time}} keeps them longer.
   
   h3. Observed
   Ignite 3.1.0, embedded in TIBCO BusinessEvents, 5-node cluster. The receiver 
is node cache4, the sender is node cache1, and the zone uses the aimem profile. 
Receiver log, 2026-10-08:
   {noformat}
   16:36:33Z ZonePartitionKey [zoneId=21, partitionId=0]  "Copier has loaded 
the snapshot meta" ... (cfgIndex=26341)
             no "finished loading multi-versioned data" afterwards; the install 
never completes
   17:26:39Z same partition, new sender incarnation         "Copier has loaded 
the snapshot meta" ... (cfgIndex=29373)
             again no completion
   {noformat}
   A later install of the same partition from another node (2026-10-09, about 
17 h later) completed normally.
   The sender's log for that window had already been rotated, so the NPE itself 
was not captured. The diagnosis comes from the code above and the bytecode of 
the 3.1.0 jars ({{ReadResult.empty}} passes null for both timestamps).
   
   h3. Suggested fix
   # Storage: make page memory return a committed tombstone the way RocksDB 
does, i.e. {{ReadResult.createFromCommitted(rowId, null, 
rowVersion.timestamp())}} in {{ScanVersionsCursor}} (and anywhere else 
{{scanVersions}} maps tombstones to {{ReadResult.empty}}).
   # Also harden {{OutgoingSnapshotsManager.respond}}: on an unexpected 
exception, send an error response (or close the snapshot) so the receiver fails 
the install and retries, instead of waiting forever.
   # Test: an {{AbstractMvPartitionStorageTest}} case that commits a tombstone 
and checks that {{scanVersions}} returns it with a non-null 
{{commitTimestamp}}. We expect it to fail on page memory and pass on RocksDB; 
it has not been run yet.
   
   h3. Workaround
   Unverified. Once the deletes are older than {{gc-data-availability-time}} 
and GC has removed the tombstones, restarting the stuck node should let a new 
install complete.
   


-- 
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