Commit Graph

3 Commits

Author SHA1 Message Date
Trevor Clinkenbeard d326d257dd Convert generic actors to standard coroutines 2026-07-17 01:05:38 -07:00
Michael Stack c4c1be3f41
fdbcli audit_storage metadata_encoding: fix counting of format-neutral entries (#13670)
* fdbcli audit_storage metadata_encoding: fix counting of format-neutral entries

The audit tool's status line reported MIGRATION IN PROGRESS
indefinitely on any running cluster in the FORWARD direction — the
FORWARD COMPLETE terminal state was unreachable. Root cause: two
categories of format-neutral entries were being counted as old-format:

1. Empty-value keyServers entries. These are KRM boundary sentinels
   (see krmDecodeRanges in fdbclient/KeyRangeMap.cpp:70-84 for how
   they are emitted at range ends). They mark the edge between
   adjacent same-valued ranges and do not carry any keyServers
   assignment. Every cluster has some — they cannot be migrated away.

2. serverKeysFalse ("this server does not own this range"). Written
   by both finishMoveKeys (old format, MoveKeys.cpp:1787) AND
   finishMoveShards (new format, MoveKeys.cpp:2138) on the drop-side
   of any move. Also written as range boundary markers around every
   assigned range (see unassignServerKeys in MoveKeys.cpp:91,127).
   Every running cluster has many — they cannot be migrated away.

Under the old counting logic, keyServersOld and serverKeysOld were
therefore never zero, and the terminal-state condition
(keyServersOld == 0 && serverKeysOld == 0) that gates FORWARD COMPLETE
never triggered. ROLLBACK COMPLETE was unaffected because its
condition looks at *New* counts.

Fix: exclude format-neutral entries from the counts. keyServers skips
empty values. serverKeys uses two new small helpers added to
SystemData.h/cpp:

  isServerKeysUnassigned(value)      — true for empty + serverKeysFalse
  isServerKeysOldFormatAssigned(value) — true for serverKeysTrue +
                                         serverKeysTrueEmptyRange

Not caught earlier because the audit command has no automated
callers — it is a manual operator command, and manual users would
see MIGRATION IN PROGRESS and assume DD needed more time. The first
automated consumer that asserts the FORWARD terminal state is the
k8s test test_shardencode_rollover_load, which hangs indefinitely
without this fix.

* audit_storage metadata_encoding: workload counterpart + review fixes

Round out PR1 with the sim-workload half of the counting fix plus four
fixes surfaced by code review of the audit-tool changes:

1. Sim workload counting fix. fdbserver/workloads/CheckMetadataEncoding.cpp
   had the identical miscounting bug as the fdbcli command — counted KRM
   boundary sentinels as keyServersOld and serverKeysFalse as
   serverKeysOld. Now uses the same isServerKeysUnassigned /
   isServerKeysOldFormatAssigned classifiers introduced in this PR.

2. Wrap the fdbcli dataMoves scan in a retry loop. Previously a
   retryable getRange error would swallow via tr.onError() without
   re-reading, leaving dataMovesCount at 0 and causing a false
   "ROLLBACK COMPLETE — safe to downgrade binary" report while data
   moves were still in flight.

3. Move terminal-state assertions (requireForwardComplete /
   requireRollbackComplete) out of the shardEncodeExpected branches.
   Previously the assertions were nested inside the branch that matched
   the knob, so a TOML that requested the assertion while the knob
   override failed to take effect would silently skip the check. Now
   the assertions always run when requested, and mismatched
   knob/option combinations fail loudly with an explicit
   misconfiguration error.

4. Emit the DataMoves trace detail only when the dataMoves range was
   actually scanned. Previously the trace unconditionally logged
   DataMoves=0 even when no scan ran (requireRollbackComplete=false),
   poisoning downstream log parsers that assume 0 means "no data
   moves in flight" rather than "not measured".

Also adds tests/fast/CheckMetadataEncodingForward.toml requiring
requireForwardComplete=true — the direct regression test for the
counting fix (without the fix, KRM sentinels/serverKeysFalse are
miscounted as old-format and FORWARD COMPLETE is unreachable).
2026-07-10 11:02:14 -07:00
Michael Stack 8e1f44238e
Add metadata encoding (SHARD_ENCODE_LOCATION_METADATA) audit, rollback support, and tests (#13310)
* Add metadata encoding audit, rollback support, and tests

Adds tooling and code to support safe SHARD_ENCODE_LOCATION_METADATA
rollback and migration verification:

audit_storage metadata_encoding:
  New AuditType that scans keyServers and serverKeys to report encoding
  format counts (old tag-based vs new UID-based). Reports migration
  status: FORWARD COMPLETE / ROLLBACK IN PROGRESS / ROLLBACK COMPLETE.

DD startup rewrite (DDTxnProcessor.cpp):
  When SHARD_ENCODE=false, clears stale DataMoveMetaData and rewrites
  shard-encoded keyServers entries to old format. serverKeys entries are
  left in place (readable in both formats, drain naturally).

MoveKeys graceful bail (MoveKeys.cpp):
  Functions that require shard-encoding throw dd_config_changed instead
  of asserting when they detect the knob flipped or DataMoveMetaData is
  unexpectedly empty from a concurrent DD restart.

Error handling (DataDistribution.cpp, DDRelocationQueue.actor.cpp):
  dd_config_changed added to normalDDQueueErrors to prevent SevError
  logging for expected operational restarts.

Knob infrastructure (ServerKnobs.cpp):
  SHARD_ENCODE randomization respects explicitlySetKnobs so TOML
  overrides take effect in simulation tests.

Tests:
  - CheckMetadataEncodingForward.toml: verifies new-format entries
  - CheckMetadataEncodingOldPath.toml: verifies old-format entries
  - ShardEncodeRollback.toml: full rollback test with Attrition,
    Rollback (TLog recovery), data consistency check

Documentation:
  - design/shard-encode-location-metadata.md: full feature description

* Address review feedback: fix doc, remove stale test refs, add pagination comment

- Fix doc: use correct command name (metadata_encoding not validate_metadata_encoding),
  remove get_audit_status references (audit runs client-side, no persisted state)
- Remove stale ShardEncodeRollback-1/2.toml refs from CMakeLists (files don't exist)
- Remove metadata_encoding from GetAuditStatusCommand (not queryable after the fact)
- Add comment explaining pagination: rewrite loops via caller until all entries converted

* Add more on how metadata handling changes particular regards coalescing

* Formatting

* Address review feedback on shard-encode rollback

Bundled review fixes for the design doc and the DD rollback path:

- Drop the version field from the DataMoveMetaData ASCII diagram. The
  field is serialized for evolvability but has no readers (only
  invalidVersion is ever written; the metaData.version reads in the
  tree are on CheckpointMetaData, a different struct). Removing it
  from the diagram avoids implying semantics that arent there.
- Clarify the S3 path lifetime in the LOGICAL_BULKLOAD section: the
  path lives in BulkLoadTaskState at \xff/bulkLoadTask/<range> and is
  fixed for the lifetime of a given dataMoveId. Same dataMoveId on DD
  restart is a continuation; a different dataMoveId for the same
  range signals a new task and possibly a new path.
- Rename ROLLBACK IN PROGRESS to MIGRATION IN PROGRESS in
  CheckMetadataEncodingCommand and the design doc. A snapshot of the
  keyspace cannot distinguish forward-in-progress from rollback-in-
  progress (both look like mixed format), so the previous label was
  over-claiming a direction the audit cannot actually verify. The
  status line now reports new-format counts only, with no "remaining"
  framing.
- Define the four states reported by audit_storage metadata_encoding
  (FORWARD COMPLETE, MIGRATION IN PROGRESS, ROLLBACK COMPLETE, NOT
  STARTED) at the first mention, with the trigger condition for each.
  Also note that ROLLBACK COMPLETE is what a cluster that never
  enabled the knob will show, since the conditions dont distinguish
  those cases.
- Expand the rewriteShardEncodedMetadata comment to describe the
  bounded scope honestly: Phase 2 rewrites only the first 1000
  keyServers entries per call, and clusters with more than that
  remnant rely on shard movement / wiggle for the bulk rewrite (per
  the "Migration for downgrade" section of the design doc). The
  function is safe to call on every DD init when knob is false; the
  no-op path is write-cost-free, three reads.
- Replace four ASSERTs in cleanUpSingleShardDataMove and the
  raw{Start,CheckFetching,Finish}Movement dispatch helpers with
  if-throws. cleanUpSingleShardDataMove now throws operation_cancelled
  when krmGetRanges paginates (the data-move range was subdivided into
  more shards than fit in one page; the caller's view is stale). The
  three raw* helpers now throw dd_config_changed when the
  MoveKeysParams field expected by the current SHARD_ENCODE_LOCATION_
  METADATA branch is missing, matching the existing forward-direction
  guards. All four guarded conditions become invalid when the knob
  flips while a data-move's params are in flight: params built under
  the old knob value reach dispatch under the new one. The asymmetry
  was pre-existing but only surfaced now because ShardEncodeRollback
  flips the knob mid-test.
2026-06-12 12:59:35 -07:00