Skip to content

fix(metadata): align MDT table services with the sub-directory bucketed layout - #19508

Draft
nsivabalan wants to merge 11 commits into
apache:masterfrom
nsivabalan:mdt_layout_spi_option_c
Draft

fix(metadata): align MDT table services with the sub-directory bucketed layout#19508
nsivabalan wants to merge 11 commits into
apache:masterfrom
nsivabalan:mdt_layout_spi_option_c

Conversation

@nsivabalan

Copy link
Copy Markdown
Contributor

Change Logs

Stacked on #19045. This branch is based on mdt_layout_spi, so the diff against master also
contains that PR's 8 commits (the HoodieMetadataTableLayout SPI, FlatMDTLayout /
SubDirBucketedMDTLayout, config plumbing and its tests). The commits belonging to this PR are
the last three:

  • cee7287 fix(metadata): align MDT table-service planners with the physical bucket layout
  • a60004a test(metadata): pin plan-level and key-space properties for bucketed MDT services
  • bb5bae0 fix(metadata): close the cleaner's file system view; tighten bucketing assertions

Review #19045 first; it should merge before this.

Follow-up to #19045, which introduced the HoodieMetadataTableLayout SPI and the opt-in SubDirBucketedMDTLayout. That PR left the MDT table services misaligned with the bucketed on-disk layout. This aligns them.

The problem. Under a non-flat layout the MDT write path is already keyed by physical partition paths: getPartitionFileSlices expands logical → physical before querying the file system view, and getRecordTagger realigns each record's partition path to its file slice's physical path. The table-service planners, however, enumerate partitions from marker discovery / getAllPartitionPaths, which return logical names — the single .hoodie_partition_metadata lives at the logical partition root by design.

That divergence is not only a compaction-execution failure. As soon as a compaction is requested, the FSV's pending-compaction map is keyed logically while every write-side lookup is keyed physically, so the join misses silently:

  • AbstractTableFileSystemView:250 — the phantom post-compaction file slice is not added, so MDT appends land in the slice being compacted and those log blocks end up in neither the compaction input nor the resulting slice → RLI entry loss.
  • AbstractTableFileSystemView:1606 (fetchMergedFileSlice) — merged reads during a pending compaction miss the map and drop pre-compaction log files → wrong index answers.

The fix — expand at the planner boundaries so the plan key space matches the already-physical write side:

Site Bug
HoodieTableMetadataUtil.expandToPhysicalPartitions shared helper; no-op for data tables and the flat default, idempotent for already-physical input
BaseTableServicePlanActionExecutor.getPartitions covers compaction and log compaction (shared chokepoint)
CleanPlanner.getPartitionPathsForFullCleaning cleaner deletes log files an in-flight compaction still needs → wedged MDT
CleanPlanner.hasPendingFiles listed the logical root directly, so it always reported "no pending files"; a partition with live pending files could be dropped wholesale
ListingBasedRollbackStrategy MDT is pinned to this strategy (DIRECT markers, rollback-using-markers disabled) and the listing is non-recursive, so rollback of a failed MDT compaction found nothing to delete and "succeeded" while the orphan base file survived

Idempotency is the property that keeps the incremental branch correct: a physical sub-path such as record_index/000003 has no entry in the persisted per-partition file-group counts, so the count resolves to 0 and the layout returns the input unchanged. Incremental table services source partitions from write stats, which are already physical.

Two supporting fixes the above make load-bearing:

  • FileGroupReaderBasedMergeHandle.init now mirrors HoodieAppendHandle's metafile-suppression guard. Compaction partitions are physical now, so without it compaction writes a .hoodie_partition_metadata inside a bucket directory — which makes partition discovery return bucket paths and breaks the cleaner and rollback globally. The marker and the write stat still derive from the same partition string, so reconcileAgainstMarkers cannot mistake the freshly written base file for an orphan.
  • HoodieBackedTableMetadataWriter.tagRecordsWithLocation built a HoodieFileGroupId from the logical partition where its streaming twin uses fileSlice.getFileGroupId(); it now uses the slice's own id.

Scope. No public contract, storage format, or config change. Every path is a no-op for data tables and for MDTs on the flat default layout, which is what every pre-existing table uses.

Tests

The bucketing tests on #19045 assert on side effects — bucket directories survive, HFiles appear after compaction. That is too weak for this bug class: when the key spaces diverge the corruption is silent and the on-disk layout still looks healthy. The tests here assert plan-level and key-space properties instead:

  • Compaction (testMDTCompactionPlansCarryPhysicalPartitions) — every operation in every persisted plan targets a bucket sub-path and never the logical partition root; compacted buckets are a subset of what the layout enumerates; compaction spans more than one bucket at bucketSize=2 (so the fan-out is genuinely exercised); the marker invariant still holds afterwards.
  • Cleaning (testMDTCleaningUnderBucketingWithFullCleaning) — runs with incremental cleaning disabled, forcing the full-listing path that enumerates logical names and joins them against a physically-keyed pending-compaction map. Asserts cleaning and compaction both fired (so they overlapped on the same buckets) and that no bucket was stripped of its data files.
  • Rollback (testRollbackEnumeratesPhysicalBucketPartitions) — a non-recursive listing of each enumerated partition must find data files, mirroring exactly what ListingBasedRollbackStrategy does. This is the silent no-op.
  • Unit (TestHoodieMetadataTableLayout) — fan-out, idempotency for already-physical input, de-duplication of mixed input, flat-layout and non-MDT passthrough, uncounted-partition fallback, and single-bucket partitions.

Two things the runs corrected in my own initial assumptions, both now encoded in tests: SubDirBucketedMDTLayout buckets every MDT partition rather than only the RLI (a single-file-group partition such as files lives at files/000000), which means the rollback listing gap applies beyond the RLI; and a completed MDT compaction appears on the timeline as a COMMIT_ACTION, with its plan still readable at the same instant time.

Local results: TestMDTLayoutBucketing 6/6, TestHoodieMetadataTableLayout 28/28, TestCleanPlanner + rollback suites 75/75, TestHoodieTableMetadataUtil + TestMetadataPartitionType 47/47.

Impact

Makes MDT compaction, log compaction, cleaning and rollback correct under SubDirBucketedMDTLayout. No behavior change for the flat default layout or for data tables.

Risk level: medium

Touches shared table-service planner code. The risk is contained by the layout gate — expandToPhysicalPartitions returns its input unchanged unless the table is an MDT on a non-flat layout — so data-table and flat-MDT paths are bit-identical. TestCleanPlanner and the rollback suites (75 tests) pass unchanged, which is the main regression signal for the shared code.

One residual worth stating plainly: expandToPhysicalPartitions is now load-bearing for the two FSV windows above. A future planner boundary that forgets the helper reintroduces a silent failure. The tests below pin the current boundaries, but the structural fix for that class of risk is the sibling-partition layout, which removes the logical/physical split on the service path rather than defending it. That is a larger redesign and belongs in its own RFC.

Documentation Update

None needed — no user-facing config or contract change.

Contributor's checklist

  • Read through contributor's guide
  • Change Logs and Impact were stated clearly
  • Adequate tests were added if applicable
  • CI passed (draft — awaiting CI)

nsivabalan and others added 11 commits June 29, 2026 20:04
…ctory bucketing for global RLI

Adds a pluggable layout SPI for the Hudi Metadata Table (MDT) so the on-disk
organization of file groups can be customized without forking the writer or
reader paths. Two implementations ship in OSS:

- FlatMDTLayout (default): existing behavior — every file group lives directly
  under its MDT partition directory, with a single .hoodie_partition_metadata
  at the partition root. Bit-for-bit identical to the prior layout for tables
  that do not opt in.
- SubDirBucketedMDTLayout (opt-in): file groups for non-partitioned MDT
  partitions (files, column_stats, bloom_filters, expression_index,
  secondary_index, and the global RLI) are grouped into bucket sub-directories
  (e.g. record_index/0000/, record_index/0001/) to lift the per-directory file
  count cap on HDFS-like filesystems. The single .hoodie_partition_metadata
  marker stays at the logical partition root so FSUtils.getAllPartitionPaths,
  direct Spark queries on the MDT, and hudi-cli all continue to see logical
  partition names rather than bucket sub-paths.

Scope:
- This patch supports the global RLI mode and all non-partitioned MDT
  partitions. Partitioned RLI is explicitly rejected at MDT initialization
  with a clear error message — the partitioned-RLI growth model needs a
  distinct bucketing strategy that lands in a separate follow-up patch / RFC.

SPI surface (hudi-common):
- HoodieMetadataTableLayout / LayoutContext / FileIdInfo
- FlatMDTLayout, SubDirBucketedMDTLayout
- HoodieMetadataTableLayouts factory (resolves via hoodie.metadata.layout.class
  on the MDT's own hoodie.properties)

Reader plug points:
- HoodieTableMetadataUtil.getPartitionFileSlices and
  getPartitionLatestFileSlicesIncludingInflight fan out across the layout's
  physical sub-paths. fileGroupCount is sourced from MDT-persisted properties
  (no FS listing on the read path).
- FileSystemBackedTableMetadata.getAllFilesInPartition[s] are layout-aware for
  MDT base paths.
- BaseHoodieTableFileIndex.filterFiles routes MDT partitions through the same
  util so direct Spark queries on the MDT path return correct results under
  bucketing.

Writer plug points:
- HoodieBackedTableMetadataWriter.initializeFileGroups consults the layout for
  fileId and relative path per file group; persists layout class + per-
  partition file-group counts on the MDT's hoodie.properties (only when a
  non-flat layout is in use, so default tables stay byte-identical).
- HoodieBackedTableMetadataWriter.resolveLayoutForMDTInit fails fast with
  HoodieMetadataException when the user requests a non-flat layout while RLI
  is configured in the partitioned mode.
- HoodieAppendHandle.doInit skips marker creation when writing to a layout
  sub-path on an MDT, so .hoodie_partition_metadata never appears inside a
  bucket directory.
- getRecordTagger realigns the record's partitionPath with the file slice's
  physical bucket path under non-flat layouts.

Tests:
- TestHoodieMetadataTableLayout: 16 unit tests covering both layouts, fileId
  round-trips, bucket arithmetic at boundary values, partitioned-RLI
  rejection, marker placement.
- TestMDTLayoutBucketing: parameterized end-to-end test running RLI workload
  under both layouts. Validates MDT-as-Hudi-table contract (logical partition
  names, no markers inside bucket dirs), correct RLI lookups, direct Spark
  scan returning rows. Both layouts pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rve flat-default time-travel

Two CI fixes for the HoodieMetadataTableLayout SPI:

1. Secondary/expression index bootstrap was failing because FlatMDTLayout
   (and SubDirBucketedMDTLayout) computed the file-group relative path and
   fileId from MetadataPartitionType.getPartitionPath(), which for SI/EI
   returns the static prefix ("secondary_index_", "expr_index_") rather
   than the real partition name ("secondary_index_idx0", "expr_index_idx_ts").
   Thread the real relativePartitionPath through LayoutContext and use it in
   both layouts; the writer's initializeFileGroups now passes it in.

2. BaseHoodieTableFileIndex.filterFiles previously short-circuited the
   time-travel branch for any MDT, which silently changed
   "MDT time-travel" semantics to "always latest" even for flat-default
   tables that never opted into the new layout. Narrow the special case to
   MDTs with a non-flat layout actually configured; flat-default keeps the
   bit-identical pre-PR call to getLatestMergedFileSlicesBeforeOrOn.

Test calls to new LayoutContext(...) updated for the new constructor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…n-flat layouts

For flat-default tables (which existed before the layout SPI), the file
slice's partition path always equals the record's MDT partition path, so the
partition-path realignment in HoodieBackedTableMetadataWriter.getRecordTagger
is semantically a no-op. Make that an explicit guard so flat-default tables
take a bit-identical code path through the record tagger, instead of relying
on an equality check inside the per-record lambda.

Similarly, HoodieAppendHandle.isMDTLayoutSubPath now returns false up front
when no non-flat MDT layout is configured on the table, so the 4-digit-suffix
heuristic only runs for tables that have actually opted into bucketing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ices loop

Trivial review-feedback pass:

- HoodieMetadataConfig / HoodieTableConfig: list the OOB layout-class values
  (FlatMDTLayout, SubDirBucketedMDTLayout) and cross-reference
  hoodie.metadata.layout.class from the bucket-size doc so users can find the
  related knob.
- FileIdInfo: add concrete fileId-to-FileIdInfo examples in the javadoc for
  the four shapes the SPI may parse (non-partitioned RLI, files, expression
  index, partitioned RLI).
- HoodieTableMetadataUtil.getPartitionFileSlices: hoist the timeline lookups
  out of the per-physical-partition loop (they depend only on metaClient and
  stay invariant across iterations); replace the post-loop "any" flag with an
  early-return guard on the resolved physical-partition list.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…init to ternary

Both constructors had a duplicated if/else block setting mdtLayout and
mdtLayoutPartitionFileGroupCounts based on whether the base path is an MDT.
Collapse each to a single boolean lookup + ternary, removing the else branch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…centralize bucket-sub-path heuristic

Addresses four review items:

- Move the bucket-sub-path heuristic out of HoodieAppendHandle into
  HoodieTableMetadataUtil.isMDTBucketSubPath so any caller that needs to ask
  "is this an MDT layout sub-path?" can share the same logic.
  HoodieAppendHandle.isMDTLayoutSubPath becomes a one-line delegate.

- HoodieTableConfig.addMetadataLayoutPartitionFileGroupCounts now rejects any
  attempt to overwrite an existing partition's count with a different value.
  Re-stamping the same count is still idempotent. The intent: the on-disk
  bucket layout for an existing MDT partition stays immutable so readers
  cannot find it relocated under their feet. New MDT partitions added later
  can still land freely.

- Rename the config key hoodie.metadata.layout.bucket.size to
  hoodie.metadata.layout.bucketed.file.group.per.bucket. The new name reads
  "how many file groups share one bucket" which matches the semantics. The
  Java accessor getMetadataLayoutBucketSize() is unchanged.

- New tests:
  * TestHoodieMetadataTableLayout adds 5 isMDTBucketSubPath cases
    (non-MDT, flat-default-MDT, bucketed-MDT root, bucketed-MDT 4-digit
    suffix, non-4-digit suffix).
  * TestHoodieTableConfig adds 3 tests for the partition-file-group-count
    map: initial round-trip + later partition append, idempotent re-stamp,
    and the conflict-rejection assertion.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… bucketing

Previous bucketing test ran only 3 commits, which is below the MDT
compaction trigger and below cleaner retention. cshuo and hudi-agent both
flagged that compaction (BaseHoodieCompactionPlanGenerator) and the
cleaner's full-listing path go through the FS view under the logical MDT
partition name, so under bucketing they could silently skip the bucketed
file groups entirely.

New test testMDTTableServicesWithBucketing runs 25 upsert commits with:

  - SubDirBucketedMDTLayout enabled with bucketSize=2 (multiple buckets)
  - hoodie.metadata.compact.max.delta.commits=5 so MDT compaction fires
    multiple times during the run
  - hoodie.clean.commits.retained=3 + auto-clean so the cleaner has work
    to do early

and then asserts:

  - At least one COMMIT_ACTION (compaction) instant lands on the MDT
    timeline
  - At least one cleaner instant lands on the data table timeline
  - Bucket sub-directories still exist after compaction + cleaning
  - Every bucket contains at least one HFile post-compaction (the
    regression cshuo flagged would leave a bucket with only log files)
  - The .hoodie_partition_metadata marker invariant still holds
    (marker at logical root, not inside any bucket dir)
  - Direct Spark scan on the MDT base path still returns rows

If the open compaction/cleaning fan-out concerns become real regressions,
this test will fire either zero-compaction-instants or HFile-absent on
the buckets that compaction skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… 6 digits

Two review-pass cleanups on the MDT layout SPI:

1. Rename SPI types with the Hoodie* prefix to match convention now (before the
   SPI escapes into user code):
     - LayoutContext -> HoodieMetadataLayoutContext
     - FileIdInfo    -> HoodieMetadataFileIdInfo
   Sibling types (HoodieMetadataTableLayout, HoodieMetadataTableLayouts) already
   carry the prefix. Cheap to rename now, painful once external implementors
   depend on the current names.

2. Widen the bucket-directory index from %04d to %06d in SubDirBucketedMDTLayout.
   The heuristic in HoodieTableMetadataUtil.isMDTBucketSubPath is bounded by the
   same width and now consumes SubDirBucketedMDTLayout.BUCKET_INDEX_WIDTH as
   the source of truth. With the old %04d ceiling, bucketIndex >= 10000 (10M
   file groups at bucketSize=1000, or 10K at bucketSize=1) would produce a
   5-digit suffix that the heuristic misreads as "not a bucket", causing a
   spurious .hoodie_partition_metadata marker inside the bucket dir and
   collapsing the "logical partition discovery" invariant. Widening to 6 digits
   raises the ceiling to 1M buckets and adds a MAX_BUCKETS ValidationUtils gate
   so overflow throws rather than silently misbehaves.

Tests updated to match: TestHoodieMetadataTableLayout (renamed
_trueForBucketedMDTWithFourDigitSuffix -> _trueForBucketedMDTWithSixDigitSuffix,
extended _falseForNonSixDigitSuffix to cover 7-digit) and
TestMDTLayoutBucketing (regex + %04d-formatted -> %06d-formatted).

Config documentation on HoodieMetadataConfig.METADATA_LAYOUT_CLASS and
HoodieTableConfig.METADATA_LAYOUT_CLASS updated from "4-digit bucket" to
"6-digit bucket" to stay consistent with the on-disk shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ket layout

The MDT write path is already keyed by physical partition paths under a
non-flat layout: getPartitionFileSlices expands logical -> physical before
querying the file system view, and getRecordTagger realigns each record's
partition path to its file slice's physical path. The table-service planners,
however, enumerate partitions from marker discovery / getAllPartitionPaths,
which return logical names because the single .hoodie_partition_metadata lives
at the logical partition root.

That divergence is not merely a compaction-execution failure. As soon as a
compaction is *requested*, the file system view's pending-compaction map is
keyed logically while every write-side lookup is keyed physically, so the join
misses silently:

  - AbstractTableFileSystemView:250   phantom post-compaction slice is not
    added, so MDT appends land in the slice being compacted and the appended
    log blocks end up in neither the compaction input nor the resulting slice
    (RLI entry loss).
  - AbstractTableFileSystemView:1606  merged reads during a pending compaction
    miss the map and drop pre-compaction log files (wrong index answers).

Expand at the planner boundaries so the plan key space matches the write side:

  - HoodieTableMetadataUtil.expandToPhysicalPartitions: shared helper. No-op
    for data tables and for the flat default layout, and idempotent for
    already-physical input (a bucket sub-path has no entry in the persisted
    file-group counts, so the layout returns it unchanged) -- which is what
    keeps the incremental branch, whose partitions come from write stats,
    correct.
  - BaseTableServicePlanActionExecutor.getPartitions: covers both compaction
    and log compaction, which share this chokepoint.
  - CleanPlanner.getPartitionPathsForFullCleaning: expanded after the user
    partition filters, so those keep matching logical names. Without this the
    cleaner deletes log files an in-flight compaction still needs, wedging the
    MDT.
  - CleanPlanner.hasPendingFiles: listed the logical root directly, so it
    always reported "no pending files" for a bucketed partition and a
    partition with live pending files could be dropped wholesale.
  - ListingBasedRollbackStrategy: the MDT is pinned to this strategy (DIRECT
    markers, rollback-using-markers disabled) and the listing is
    non-recursive, so rollback of a failed MDT compaction previously found
    nothing to delete and "succeeded" while the orphan base file survived.

Two supporting fixes that the above make load-bearing:

  - FileGroupReaderBasedMergeHandle.init now mirrors HoodieAppendHandle's
    metafile-suppression guard. Compaction partitions are physical now, so
    without it compaction writes a .hoodie_partition_metadata inside a bucket
    directory, which makes partition discovery return bucket paths and breaks
    the cleaner and rollback globally. The marker and the write stat continue
    to derive from the same partition string, so reconcileAgainstMarkers
    cannot mistake the freshly written base file for an orphan.
  - HoodieBackedTableMetadataWriter.tagRecordsWithLocation built a
    HoodieFileGroupId from the logical partition where its streaming twin uses
    fileSlice.getFileGroupId(); it now uses the slice's own id so the file
    group partition matches the physical partition its records carry.

Tests: unit coverage for the helper's fan-out, idempotency, de-duplication and
flat/non-MDT passthrough; functional coverage asserting on the persisted
compaction plan (every operation targets a bucket sub-path, never the logical
root, and the compacted buckets are a subset of what the layout enumerates),
on cleaning with incremental mode disabled so the logical full-listing path is
exercised, and on rollback partition enumeration via a non-recursive listing.
These assert plan-level and key-space properties rather than side effects,
since the failures this fixes leave the on-disk layout looking healthy.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…MDT services

The existing bucketing tests assert on side effects -- bucket directories
survive, HFiles appear after compaction. That is too weak for this bug class:
when the planner's logical partition keys diverge from the write side's
physical ones, the file system view's pending-compaction bookkeeping misses
silently and the on-disk layout still looks healthy afterwards.

These assert the properties that actually distinguish a correct run:

  - Compaction: every operation in every persisted plan targets a bucket
    sub-path and never the logical partition root, and the set of compacted
    buckets is a subset of what the layout enumerates. Reading each plan back
    is part of the assertion. Also re-checks the marker invariant after
    compaction, since a metafile written into a bucket directory would make
    partition discovery return bucket paths.
  - Cleaning: runs with incremental cleaning disabled so the cleaner takes the
    full-listing path -- the one that enumerates logical names and joins them
    against a physically-keyed pending-compaction map. Asserts cleaning and
    compaction both fired (so they overlapped on the same buckets) and that no
    bucket was stripped of its data files.
  - Rollback: a non-recursive listing of each enumerated partition must find
    data files, mirroring exactly what ListingBasedRollbackStrategy does. This
    is the silent no-op -- rollback of a failed MDT compaction previously
    "succeeded" while the orphan base file survived.

Unit coverage for expandToPhysicalPartitions: fan-out, idempotency for
already-physical input, de-duplication of mixed input, flat-layout and non-MDT
passthrough, and the uncounted-partition fallback.

Two assumptions corrected against observed behavior while writing these:
SubDirBucketedMDTLayout buckets every MDT partition rather than only the RLI,
so a single-file-group partition such as `files` lives at `files/000000` --
which means the rollback listing gap applies beyond the RLI. And a completed
MDT compaction appears on the timeline as a COMMIT_ACTION, with its plan still
readable at the same instant time.

Verified: TestMDTLayoutBucketing 6/6 via surefire; TestHoodieMetadataTableLayout
28/28; TestCleanPlanner and the rollback suites 75/75.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…g assertions

Self-review follow-ups on the two commits before this.

Production:
  - CleanPlanner.hasPendingFiles leaked its HoodieTableFileSystemView. That was
    pre-existing, but expanding to a per-bucket loop makes the view longer-lived,
    so switch to try-with-resources.
  - ListingBasedRollbackStrategy: use the local metaClient rather than calling
    table.getMetaClient() again for the same object.

Tests:
  - The "compaction spans more than one bucket" assertion was written as
    `size >= 1`, which the preceding recordIndexOpsSeen check already guarantees
    -- the comment claimed something stronger than the code checked, and it would
    have passed even with partially broken expansion. Tightened to `> 1`, which is
    what bucketSize=2 over this workload actually produces.
  - Corrected a comment claiming every compaction plan "must exist and parse"
    where the catch block in fact skips unreadable ones. The skip is needed (not
    every COMMIT_ACTION instant has a plan behind it), so the comment now says so.
  - Dropped the dataFilePath assertion: it pinned an Avro schema convention rather
    than anything this change affects.

Verified: TestMDTLayoutBucketing 6/6, TestCleanPlanner + rollback suites 75/75.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the size:XL PR with lines of changes > 1000 label Aug 4, 2026
@voonhous voonhous closed this Aug 4, 2026
@voonhous voonhous reopened this Aug 4, 2026
@hudi-bot

hudi-bot commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands @hudi-bot supports the following commands:
  • @hudi-bot run azure re-run the last Azure build

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL PR with lines of changes > 1000

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants