Siyao Meng created HDDS-16804:
---------------------------------

             Summary: ReplicationSupervisor loses a command of the new SCM 
leader when an equal task of the previous leader is still queued
                 Key: HDDS-16804
                 URL: https://issues.apache.org/jira/browse/HDDS-16804
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: 
MC-5-run-new-scm-leader-command-when-queued-duplicate-is-dropped.patch, 
TestBugMC5NewLeaderCommandLost.java

h3. Mechanism
{{ReplicationSupervisor.addToQueue}} drops a task when an equal one is already 
in {{inFlight}}. Task equality does not include the SCM term: 
{{ReconcileContainerTask}} compares the container ID (HDDS-13086), 
{{ECReconstructionCoordinatorTask}} the container ID, {{ReplicationTask}} the 
container ID and the target. When a queued task gets a thread, 
{{TaskRunner.run}} drops it if its term is older than the datanode's current 
SCM term ("Ignoring ... since SCM leader has new term", HDDS-7620). The two 
rules do not compose: a command of the new leader that arrives while the equal 
task of the old leader is still queued is dropped as a duplicate, and the 
queued task is then dropped for its term. Neither runs. The datanode term is 
already advanced in {{StateContext.addCommand}} when the new command reaches 
the supervisor.

h3. Trigger
# All threads of the supervisor are busy 
({{hdds.datanode.replication.streams.limit}}, 10 by default, shared by the 
three task types unless per volume pools are enabled) and a task sent by the 
SCM leader of term N waits in its queue.
# SCM leadership changes.
# The new leader sends an equal command (same container for reconcile and EC 
reconstruction, same container and target for replication) before the queued 
task gets a thread.
# The queued task gets a thread and is dropped for its term.

For reconcile, step 3 means the request is issued again through the new leader 
({{ozone admin container reconcile}}), because SCM sends reconcile commands 
only on request. For replication and EC reconstruction, step 3 means the old 
task is still queued when the new leader's ReplicationManager starts 
({{hdds.scm.wait.time.after.safemode.exit}}, default 5m, after it becomes ready 
as leader) and the new leader chooses this datanode again with the same source 
and target or as coordinator of the same container (read from the code, not 
run).

h3. Impact
* Reconcile: the container is not reconciled on that datanode although both 
requests were accepted. SCM does not send the command again, so it stays that 
way until somebody repeats the request. The only trace is the INFO line on the 
datanode.
* Replication and EC reconstruction: the new leader's command is lost on the 
datanode in the same way (run). The new leader's pending operation expires 
after {{hdds.scm.replication.event.timeout}} (default 12m) and 
ReplicationManager sends the command again on a later pass 
({{hdds.scm.replication.thread.interval}}, default 300s), so the effect is a 
delayed repair (read from the code, not run).
* No data is affected. A task that is already running when the new command 
arrives is not affected.

h3. Reproduction
PASS, deterministic, unmodified source. [^TestBugMC5NewLeaderCommandLost.java] 
({{hadoop-hdds/container-service}}) sends 11 commands of term 1 and then 11 
commands of term 2 for the same containers through {{StateContext.addCommand}}, 
{{StateContext.getNextCommand}} and the real command handler into a 
{{ReplicationSupervisor}} with default settings. Only the component that does 
the work (container controller, push replicator, EC reconstruction coordinator) 
is a stand in that counts its calls and keeps running tasks open until 
released. For each of the three command types the 11th container is processed 0 
times after two commands, and the supervisor logs "Ignoring QUEUED ... since 
SCM leader has new term (1 < 2)". A control with duplicates in the same term 
processes every container once. A passing test means the defect is present. Not 
run on a cluster with a real SCM failover.

h3. Patch
[^MC-5-run-new-scm-leader-command-when-queued-duplicate-is-dropped.patch], 
against 1e528b97aed3eef1be6846f1f0767c1ef98a883a. It also applies to master at 
8ca44914771.

{{ReplicationSupervisor}} keeps, for each task in flight, the equal command it 
received last. When a task is dropped without running and a command of a newer 
term was received for it meanwhile, that command is queued. Tasks of an 
obsolete term are still dropped and a duplicate of a running task is still 
dropped, so there is at most one of any set of equal tasks, as before. Not 
changed by this patch: a later command of the same term that is deduplicated 
against a queued task which then passes its deadline is still dropped 
(replication and EC reconstruction only, reconcile commands carry no deadline). 
Adding the term to the task equality is not an alternative: with the term in 
{{ReconcileContainerCommand.equals}} the supervisor accepts the new leader's 
command next to a reconciliation of the same container that is still running 
(run), which is what HDDS-13086 removed.

Covered by two tests in the existing {{TestReplicationSupervisor}}. 
{{commandOfNewLeaderRunsWhenQueuedTaskOfOldLeaderIsDropped}} fails without the 
change because the new leader's command never runs. 
{{commandOfNewLeaderIsDeduplicatedAgainstRunningTask}} passes with and without 
it and pins that a running task gets no second run. With the patch 
{{TestReplicationSupervisor}} (56 tests) and the command handler, 
{{StateContext}}, {{DatanodeStateMachine}} and replication unit suites (130 
tests in total) pass, checkstyle is clean. With the patch the reproduction 
fails for all three command types because every container is processed. 
{{TestContainerReplication}} (16 tests on a mini cluster) passes with the patch.

Found by TLA+ model checking and code review of the container reconciliation 
paths in the datanode and SCM under HDDS-15926, on commit 
1e528b97aed3eef1be6846f1f0767c1ef98a883a. Checked against HDDS issues and 
apache/ozone pull requests for duplicates before filing. The attached patch is 
a proposal for review. Generated with Specula (Claude Opus 5.5).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to