Siyao Meng created HDDS-16921:
---------------------------------

             Summary: SCM checkpoint install rollback restores the old DB 
without closing the open checkpoint DB, so it reloads the rejected checkpoint
                 Key: HDDS-16921
                 URL: https://issues.apache.org/jira/browse/HDDS-16921
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: MC-6-close-scm-db-before-rollback-restore.patch, 
TestBugMC6RollbackKeepsCheckpointStore.java

h3. Mechanism
{{SCMHAManagerImpl.installCheckpoint}} closes the metadata store, swaps the 
checkpoint into {{scm.db}} and calls {{reloadSCMState}}. If that fails, the 
rollback calls {{HAUtils.replaceDBWithCheckpoint}} with the backup of the old 
DB and then {{reloadSCMState}} again, before {{exitSystem}}. When the first 
reload failed after {{SCMMetadataStoreImpl.start}} had opened the checkpoint (a 
later service rejected it), that store is still open during the rollback:
* the directory of the open RocksDB is renamed to a second {{scm.db.backup.*}} 
and the old DB is copied back to {{scm.db}};
* {{SCMMetadataStoreImpl.start}} does nothing while its store is set, so the 
rollback's {{reloadSCMState}} rebinds every service to the rejected checkpoint 
again instead of the restored old DB. With a deterministic failure it fails 
again with the same error.

h3. Trigger
# A follower SCM installs a checkpoint that RocksDB opens but a service rejects 
in {{startServices}}. Examples: a damaged data block in a table that a service 
reads by key, a failed precondition in a service's {{reinitialize}}, or (as in 
the reproduction) an apparent layout version this software does not know.
# The rollback runs.

h3. Impact
* In production {{exitSystem(1)}} in the {{finally}} block terminates the 
process right after the rollback, so nothing serves the wrong state, and on 
restart {{scm.db}} holds the old DB. What remains is that the rollback reload, 
which is meant to check the old DB before terminating, checks the wrong DB, and 
that the open DB's directory is renamed under it: new RocksDB files of the open 
store would be created in the restored {{scm.db}} before the exit (argued, not 
observed).
* Only with a test exit manager, which returns instead of terminating, does the 
SCM go on serving the rejected checkpoint, whose directory has been renamed, 
while {{scm.db}} on disk holds the old DB.

h3. Reproduction
PASS on the unmodified source. [^TestBugMC6RollbackKeepsCheckpointStore.java] 
({{hadoop-ozone/integration-test}}) runs a one SCM mini cluster, takes a 
checkpoint of its DB, sets the checkpoint's apparent layout version one above 
the software version and its transaction info above the applied index, 
allocates a container and writes a marker key that only the current DB has, and 
installs the checkpoint through {{SCMStateMachine.pause}}, 
{{setInstallingSnapshotData}} and {{reinitialize}}, with a counting exit 
manager. Output: {{exitSystem(1, Failed to reload SCM state and instantiate 
services.)}}; after the rollback {{the live store reads apparent version 101 
(checkpoint value 101), marker null, ContainerManager has #1: false}}, while 
{{restored DB on disk at scm.db has marker old and #1: true}}. A passing test 
means the defect is present.

h3. Patch
[^MC-6-close-scm-db-before-rollback-restore.patch], against 
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at 
52812559dad.

The patch calls {{stopServices()}} (close the metadata store) in the rollback 
before the old DB is restored, so the rollback's reload opens the restored old 
DB. It is a no op when the failed reload never opened the store. The process 
still exits as before. With the patch the reproduction fails because after the 
rollback the live store and ContainerManager read the restored old DB (marker 
present, container #1 present).

Covered by {{testRollbackAfterReloadFailureRestoresOldDB}} in the existing 
{{TestSCMInstallSnapshotWithHA}}. Without the change the rollback's own 
{{reloadSCMState}} throws "Initialization failed. Disk contains unknown 
apparent version 101 for software version ZDU (100)", because it reloaded the 
rejected checkpoint. With it {{TestSCMInstallSnapshotWithHA}} and 
{{TestSCMInstallSnapshot}} (6 tests), {{TestSCMHAManagerImpl}} and 
{{TestSCMStateMachine}} (18 tests) pass and checkstyle is clean.

Found by TLA+ model checking and code review of the SCM Ratis snapshot and 
checkpoint install paths under HDDS-15926, on commit 
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. 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