Siyao Meng created HDDS-16920:
---------------------------------
Summary: SCM creates the DB inconsistent marker only after moving
scm.db away, so a stop in between restarts on an empty DB
Key: HDDS-16920
URL: https://issues.apache.org/jira/browse/HDDS-16920
Project: Apache Ozone
Issue Type: Bug
Reporter: Siyao Meng
Attachments: MC-2-create-db-marker-before-moving-scm-db.patch,
TestBugMC2CrashAfterDBMoveOpensEmptyDB.java
h3. Mechanism
{{HAUtils.replaceDBWithCheckpoint}} renames {{scm.db}} to
{{scm.db.backup.<index>_<time>}} and only then creates
{{dbInconsistentMarker}}. The marker is meant to stop SCM from starting on a
half installed DB ("this marker file will fail it from starting up"). If the
process stops between the rename and the marker, the directory has neither
{{scm.db}} nor the marker. On the next start {{SCMMetadataStoreImpl.start}}
checks only the marker, and {{DBStoreBuilder.createDBStore}} creates a new
empty DB because {{createIfMissing}} is true. The old DB stays in the backup
directory and nothing restores or deletes it.
h3. Trigger
# A follower SCM installs a checkpoint from the leader
({{SCMHAManagerImpl.installCheckpoint}}).
# The SCM process stops (kill, OOM) right after {{Files.move}} of {{scm.db}}
and before {{Files.createFile}} of the marker. The window is two consecutive
file system calls; in the reproduction the stop is injected.
h3. Impact
* The SCM starts on an empty {{scm.db}} without any error, against the marker
contract. Its old DB is left orphaned in {{scm.db.backup.*}}.
* Committed state is not lost cluster wide (the other SCMs have it). The window
is entered only after Ratis acknowledged the install, so with the current code
the follower cannot catch up afterwards anyway, whether it restarts on the
empty DB or on the old one. As long as it stays a follower it does not start
its datanode server, so no datanode report is processed against the empty DB
(argued, not run).
h3. Reproduction
PASS on the unmodified source. [^TestBugMC2CrashAfterDBMoveOpensEmptyDB.java]
({{hadoop-hdds/server-scm}}) writes a real SCM DB with a container and a
transaction info, runs {{HAUtils.replaceDBWithCheckpoint}} with a static
{{Files.move}} spy that does the real move and then throws an {{Error}} (the
stop), and opens a new {{SCMMetadataStoreImpl}} on the same directory. Output:
{{after the crash: scm.db exists=false, marker exists=false, backups=1}}, then
{{restart accepted, scm.db exists=true, transactionInfo=null, container
#1=null}}. A passing test means the defect is present.
h3. Patch
[^MC-2-create-db-marker-before-moving-scm-db.patch], against
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at
52812559dad.
The patch creates the marker before the move and deletes it again if the move
fails, so a failed backup leaves the directory unchanged. The rest of the
method is unchanged. A stop anywhere between the move and the end of the copy
now leaves the marker, and the existing check refuses to start ("Cannot load
SCM DB as it is in an inconsistent state"). With the patch the reproduction
fails because the marker exists after the stop.
Covered by {{testReplaceDBWithCheckpointCreatesMarkerBeforeMovingDB}} and
{{testReplaceDBWithCheckpointRemovesMarkerIfMoveFails}} in a new
{{TestHAUtils}} (there is no existing unit test class for {{HAUtils}}). Without
the change the first fails with "Expecting AtomicBoolean(false) to have value:
true". With it {{TestHAUtils}}, {{TestRDBSnapshotProvider}} and
{{TestSCMHAUtils}} (5 tests) and the mini cluster suites
{{TestSCMInstallSnapshotWithHA}} and {{TestSCMInstallSnapshot}} (5 tests) pass,
and checkstyle is clean. The patch does not add an fsync of the marker or the
directory, so it covers a process stop; after a power loss the file system may
still persist the rename without the marker.
{{OzoneManager.replaceOMDBWithCheckpoint}} still moves the {{om.db}} items to
the backup before {{moveCheckpointFiles}} creates the marker (by code reading);
HDDS-16026 changed its failure handling, not this order, and the OM side is a
separate follow up that this patch does not change.
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]