Conversation
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
13b8616 to
c457bf3
Compare
c457bf3 to
acffc41
Compare
441d711 to
bfcc182
Compare
|
run buildall |
FE UT Coverage ReportIncrement line coverage |
FE Regression Coverage ReportIncrement line coverage |
|
run p0 |
|
run check_coverage_fe |
|
run p0 |
FE Regression Coverage ReportIncrement line coverage |
…n SQL and catalog DDL guard (#67630) ## What problem does this PR solve? Issue: #66497 (design v5.1, slice 3). Target: `branch-4.1`. This is PR3C, building on #67201 (PR3A, DDL surface) and #67235 (PR3B, durable jobs), both already merged into branch-4.1. It adds the FE admission path for top-level Lance CREATE, CREATE OR REPLACE, and DROP INDEX, returns durable job IDs, and exposes job inspection SQL. **`enable_lance_index_mutation` remains false by default.** This slice does not execute index mutations: admitted jobs remain PENDING until dispatch/worker support and FORCE_RELEASE arrive in later slices. Enabling it now leaves unresolved jobs that prevent target-changing ALTER CATALOG and DROP CATALOG. ## Behavior - Admission reads dataset version, schema fields, logical indexes, and physical index families from one opened latest Dataset. It does not call `countRows()` or `getIndexStatistics()`. Schema contract v1 preserves Arrow field identity, nullability, vector dimensions/element types, and relevant type parameters for later worker revalidation. For fixed-size lists the pinned SDK reconstructs no child field — the element type lives only in the manifest logical type and element nullability is synthesized as nullable (a manifest-format fact that also binds existing datasets) — so the contract sources element facts from the reconstructed Arrow view and is pinned by a real on-disk dataset fixture. - Reserved names and ambiguous case-only collisions are rejected (reserved names fail before any metadata read). REPLACE and DROP persist the stored display name of a unique case-insensitive match. Column identities that are ambiguous under the table's case-insensitive lookup relation are rejected before anything is journaled. CREATE IF NOT EXISTS is a no-op only when algorithm, physical family, column (compared in the same path-segment representation on both sides), and exposed whitelist properties match — an omitted `num_bits` compares as the persisted 8; DROP IF EXISTS is a no-op when the authoritative name is absent. - Metric comparison ignores case. Numeric properties use strict parsed-long equality for numeric primitives or integer strings; fractions, exponent notation, overflow, and malformed values fail closed. Unexposed properties are skipped, and `num_partitions` is not compared. - An admitted statement returns one `JobId` row after the job and fence are durable; an IF no-op returns the same column with zero rows. The response works for direct and forwarded connections. - `SHOW LANCE INDEX JOBS [FROM [catalog.]db] [WHERE TableName = "t" [AND State = "PENDING"]]` and `SHOW LANCE INDEX JOB <id>` authorize each persisted target. Orphans — including targets whose provider lookup fails (credential expiry, outage) and targets whose currently resolved dataset locator no longer matches the job's persisted locator after a legal identity change — require global ADMIN; unauthorized rows are omitted, and unauthorized/missing job IDs share error 5103, so provider failures never leak through the authorization boundary. Locators, credentials, properties JSON, and schema-contract contents are not exposed. WHERE values accept what the parser actually produces for string literals, including `VarcharLiteral`; the `FROM` database name is canonicalized through the selected catalog's resolution semantics. ## Concurrency and configuration Catalog identity is captured under the CatalogMgr lock before the remote snapshot read. After the read, admission rechecks catalog existence, identity properties, and a local identity-change generation under the same lock used by catalog DDL, then allocates the ID and creates the job. This closes both the guard-check/create race and A → B → A identity changes. IF no-ops also revalidate the target. Identity changes invalidate in-flight reads even when a tentative ALTER is rolled back; same-value rewrites with unchanged key spelling and credential-only changes remain allowed. Metadata I/O runs outside the DDL lock. Final admission uses the lock order CatalogMgr → job manager → journal. DROP and changes to target-identity properties — `lance.catalog.type`, `warehouse`, namespace parent/delimiter/root_database, and the storage-routing endpoint/region keys the Lance property chain actually consumes — reject unresolved jobs; access keys and tokens stay rotatable. Renames and replay are not blocked by the unresolved-job guard. The gate and unresolved-job quotas (table/catalog/global defaults 8/64/256) are mutable and masterOnly. ADMIN SET changes runtime values on the master; it does not persist them to the custom configuration file or automatically synchronize other FEs. Restart loads configured file values/defaults, while promotion uses the promoted FE's own configuration. The two static bounds (`num_partitions` 4096, `num_sub_vectors` 256) are masterOnly — validation runs on the master — so a single-FE ADMIN SET takes effect only there; use ADMIN SET ALL FRONTENDS CONFIG to update the cluster. ADMIN SET callbacks validate positive quotas/bounds. File-loaded quotas are checked again before ID allocation; the job manager independently rejects non-positive limits. Gate-off admission uses error 5102. Job SHOW commands use FORWARD_NO_SYNC: follower requests execute on the master, without waiting for follower journal replay. This does not make SHOW a follower-local stale read. ## Validation - FE reactor compilation passed (JDK 17, Maven 3.9.9). - 262 tests passed across 16 focused FE test classes, with zero failures/errors/skips: configuration, catalog guard, admission, snapshots, index families, static validation, schema contracts, job queries, loader defenses, parser, command responses, and job authorization. Beyond the admission/concurrency cases (concurrent DROP and identity ALTER versus admission, A → B → A, failed ALTER rollback, replay with null old properties, target changes during IF no-ops, strict numeric parsing, real command-to-CatalogMgr integration), coverage includes WHERE predicate shapes through the real parser (LIKE, reversed literals, `VarcharLiteral` values, which the parser produces for regular string literals), reserved-name rejection without a snapshot read, half-orphan row hiding for non-ADMIN, gate-off persistence assertions, the exactly-one-operation precondition, multi-column stored indexes in the IF preflight, unparsable snapshot properties, the loader's physical-entry defenses (bounds, duplicate UUIDs recorded before the system-entry filter, system-entry filtering, ordering), malformed provider schema facts (negative field ids, non-positive dimensions), the catalog's identity epoch, failure sanitization and REST early rejection, storage-routing key guarding, SHOW locator revalidation and provider-failure non-disclosure, and a real on-disk Lance dataset fixture pinning the fixed-size-list contract semantics. - JaCoCo new-code line coverage: 93% on the new classes (each ≥ 86%), 81% on the new lines of modified files, 90% overall. The remainder is the JNI dataset-open path exercised by the external regression suite. - The full FE test suite (fe-common + fe-core + reactor dependencies, ~9.6k tests) ran to completion on both the pre-review and the review-fix heads: the only failures are this machine's documented timezone-, network- and native-library-related environmental tests — 38 failing methods across 15 classes, verified identical (same classes, same counts) by running the same classes on the merge base. - Maven validate/Checkstyle passed with zero violations; `git diff --check` passed. - Groovy compilation and a harness exercising the actual regression suite's original-value restoration and cleanup-failure propagation passed. - The external MinIO/REST regression was not run locally; the corresponding Docker environment is not running. BE compilation was not run. The external regression suite runs as `nonConcurrent`, captures the original master gate/quota values, and restores them even on failure. Cleanup failures are reported. Admitted PENDING jobs/catalogs remain durable in this slice; per-run names avoid same-name collisions, but repeated runs still consume the global unresolved-job quota. ## Deferred Dispatch, BE selection, worker execution, possible-live slot configuration, and the local/file operator assertion belong to subsequent dispatch/worker slices. FORCE_RELEASE/RESOLVE and retention GC belong to PR3E (#67754). The gate default remains unchanged. REST catalog mutations, ALTER TABLE ADD/DROP INDEX, and BUILD INDEX remain unsupported. ## Release note Experimental, default-disabled FE admission and job inspection for Lance index mutations; actual index execution remains deferred. --------- Co-authored-by: u70b3 <u70b3@users.noreply.github.com>
bfcc182 to
3f94597
Compare
|
run buildall |
|
run p0 |
…n SQL and catalog DDL guard (#67630) ## What problem does this PR solve? Issue: #66497 (design v5.1, slice 3). Target: `branch-4.1`. This is PR3C, building on #67201 (PR3A, DDL surface) and #67235 (PR3B, durable jobs), both already merged into branch-4.1. It adds the FE admission path for top-level Lance CREATE, CREATE OR REPLACE, and DROP INDEX, returns durable job IDs, and exposes job inspection SQL. **`enable_lance_index_mutation` remains false by default.** This slice does not execute index mutations: admitted jobs remain PENDING until dispatch/worker support and FORCE_RELEASE arrive in later slices. Enabling it now leaves unresolved jobs that prevent target-changing ALTER CATALOG and DROP CATALOG. ## Behavior - Admission reads dataset version, schema fields, logical indexes, and physical index families from one opened latest Dataset. It does not call `countRows()` or `getIndexStatistics()`. Schema contract v1 preserves Arrow field identity, nullability, vector dimensions/element types, and relevant type parameters for later worker revalidation. For fixed-size lists the pinned SDK reconstructs no child field — the element type lives only in the manifest logical type and element nullability is synthesized as nullable (a manifest-format fact that also binds existing datasets) — so the contract sources element facts from the reconstructed Arrow view and is pinned by a real on-disk dataset fixture. - Reserved names and ambiguous case-only collisions are rejected (reserved names fail before any metadata read). REPLACE and DROP persist the stored display name of a unique case-insensitive match. Column identities that are ambiguous under the table's case-insensitive lookup relation are rejected before anything is journaled. CREATE IF NOT EXISTS is a no-op only when algorithm, physical family, column (compared in the same path-segment representation on both sides), and exposed whitelist properties match — an omitted `num_bits` compares as the persisted 8; DROP IF EXISTS is a no-op when the authoritative name is absent. - Metric comparison ignores case. Numeric properties use strict parsed-long equality for numeric primitives or integer strings; fractions, exponent notation, overflow, and malformed values fail closed. Unexposed properties are skipped, and `num_partitions` is not compared. - An admitted statement returns one `JobId` row after the job and fence are durable; an IF no-op returns the same column with zero rows. The response works for direct and forwarded connections. - `SHOW LANCE INDEX JOBS [FROM [catalog.]db] [WHERE TableName = "t" [AND State = "PENDING"]]` and `SHOW LANCE INDEX JOB <id>` authorize each persisted target. Orphans — including targets whose provider lookup fails (credential expiry, outage) and targets whose currently resolved dataset locator no longer matches the job's persisted locator after a legal identity change — require global ADMIN; unauthorized rows are omitted, and unauthorized/missing job IDs share error 5103, so provider failures never leak through the authorization boundary. Locators, credentials, properties JSON, and schema-contract contents are not exposed. WHERE values accept what the parser actually produces for string literals, including `VarcharLiteral`; the `FROM` database name is canonicalized through the selected catalog's resolution semantics. ## Concurrency and configuration Catalog identity is captured under the CatalogMgr lock before the remote snapshot read. After the read, admission rechecks catalog existence, identity properties, and a local identity-change generation under the same lock used by catalog DDL, then allocates the ID and creates the job. This closes both the guard-check/create race and A → B → A identity changes. IF no-ops also revalidate the target. Identity changes invalidate in-flight reads even when a tentative ALTER is rolled back; same-value rewrites with unchanged key spelling and credential-only changes remain allowed. Metadata I/O runs outside the DDL lock. Final admission uses the lock order CatalogMgr → job manager → journal. DROP and changes to target-identity properties — `lance.catalog.type`, `warehouse`, namespace parent/delimiter/root_database, and the storage-routing endpoint/region keys the Lance property chain actually consumes — reject unresolved jobs; access keys and tokens stay rotatable. Renames and replay are not blocked by the unresolved-job guard. The gate and unresolved-job quotas (table/catalog/global defaults 8/64/256) are mutable and masterOnly. ADMIN SET changes runtime values on the master; it does not persist them to the custom configuration file or automatically synchronize other FEs. Restart loads configured file values/defaults, while promotion uses the promoted FE's own configuration. The two static bounds (`num_partitions` 4096, `num_sub_vectors` 256) are masterOnly — validation runs on the master — so a single-FE ADMIN SET takes effect only there; use ADMIN SET ALL FRONTENDS CONFIG to update the cluster. ADMIN SET callbacks validate positive quotas/bounds. File-loaded quotas are checked again before ID allocation; the job manager independently rejects non-positive limits. Gate-off admission uses error 5102. Job SHOW commands use FORWARD_NO_SYNC: follower requests execute on the master, without waiting for follower journal replay. This does not make SHOW a follower-local stale read. ## Validation - FE reactor compilation passed (JDK 17, Maven 3.9.9). - 262 tests passed across 16 focused FE test classes, with zero failures/errors/skips: configuration, catalog guard, admission, snapshots, index families, static validation, schema contracts, job queries, loader defenses, parser, command responses, and job authorization. Beyond the admission/concurrency cases (concurrent DROP and identity ALTER versus admission, A → B → A, failed ALTER rollback, replay with null old properties, target changes during IF no-ops, strict numeric parsing, real command-to-CatalogMgr integration), coverage includes WHERE predicate shapes through the real parser (LIKE, reversed literals, `VarcharLiteral` values, which the parser produces for regular string literals), reserved-name rejection without a snapshot read, half-orphan row hiding for non-ADMIN, gate-off persistence assertions, the exactly-one-operation precondition, multi-column stored indexes in the IF preflight, unparsable snapshot properties, the loader's physical-entry defenses (bounds, duplicate UUIDs recorded before the system-entry filter, system-entry filtering, ordering), malformed provider schema facts (negative field ids, non-positive dimensions), the catalog's identity epoch, failure sanitization and REST early rejection, storage-routing key guarding, SHOW locator revalidation and provider-failure non-disclosure, and a real on-disk Lance dataset fixture pinning the fixed-size-list contract semantics. - JaCoCo new-code line coverage: 93% on the new classes (each ≥ 86%), 81% on the new lines of modified files, 90% overall. The remainder is the JNI dataset-open path exercised by the external regression suite. - The full FE test suite (fe-common + fe-core + reactor dependencies, ~9.6k tests) ran to completion on both the pre-review and the review-fix heads: the only failures are this machine's documented timezone-, network- and native-library-related environmental tests — 38 failing methods across 15 classes, verified identical (same classes, same counts) by running the same classes on the merge base. - Maven validate/Checkstyle passed with zero violations; `git diff --check` passed. - Groovy compilation and a harness exercising the actual regression suite's original-value restoration and cleanup-failure propagation passed. - The external MinIO/REST regression was not run locally; the corresponding Docker environment is not running. BE compilation was not run. The external regression suite runs as `nonConcurrent`, captures the original master gate/quota values, and restores them even on failure. Cleanup failures are reported. Admitted PENDING jobs/catalogs remain durable in this slice; per-run names avoid same-name collisions, but repeated runs still consume the global unresolved-job quota. ## Deferred Dispatch, BE selection, worker execution, possible-live slot configuration, and the local/file operator assertion belong to subsequent dispatch/worker slices. FORCE_RELEASE/RESOLVE and retention GC belong to PR3E (#67754). The gate default remains unchanged. REST catalog mutations, ALTER TABLE ADD/DROP INDEX, and BUILD INDEX remain unsupported. ## Release note Experimental, default-disabled FE admission and job inspection for Lance index mutations; actual index execution remains deferred. --------- Co-authored-by: u70b3 <u70b3@users.noreply.github.com>
|
run p0 |
|
/review |
|
run p0 |
3 similar comments
|
run p0 |
|
run p0 |
|
run p0 |
|
@Gabriel39 @zhangstar333 @yiguolei This is ready for review when you have time. The only red gate is check_coverage_fe — a CI download flake before compilation (details: #67754 (comment)), a rerun is in flight; everything else is green. |
3f94597 to
bff53fa
Compare
|
run buildall |
… its locator RESOLVE authorized through SHOW's targetResolves, which slice 3C's review round made exception-safe for listing: there a provider outage folds into the orphan verdict. That is safe for a display, not for a durable release: the half-orphan branch would skip the authoritative read and release the fence while "table gone" cannot be told apart from "network down" — and nothing in the suite could catch it, because the existing blip test only fails the second resolution (inside the read). Resolve the target three ways up front instead: - RESOLVED — names resolve and the catalog's current durable locator still matches the job's: table-level ALTER authorization and the full protocol (capture, authoritative read, refresh, admission transfer). The locator leg mirrors SHOW LANCE INDEX JOBS, so a repointed dataset reusing the same names never upgrades a stale name into table-level authorization. - MISSING — catalog, database or table verifiably absent, or the locator positively points elsewhere: the orphan family under global ADMIN; a positive repoint takes the half-orphan path (no read, best-effort refresh, release). - FAILED — a resolution that errors out, or a locator that cannot be resolved right now (resolveCurrentIndexJobLocator folds provider outages into null): never an orphan verdict. After ADMIN authorization the statement fails with the typed 5105 so the fence is kept and the operator fixes the cause and retries; SHOW fails the same uncertainty closed by hiding the row, RESOLVE fails it closed by not releasing. Like the 5104 state rejection, the 5105 is only visible to an already authorized caller. Tests: a db or table resolution failure at authorization time keeps the job (5105 for ADMIN, fixed 5103 otherwise, zero manager calls); an unresolvable locator fails closed the same way; a positively repointed locator takes the half-orphan branch (ADMIN-only, no authoritative read, best-effort refresh, one release); the resolved-target fixtures stub the matching locator.
…gate, and log its cause Two review findings on the typed 5105 (ERR_LANCE_INDEX_JOB_RESOLUTION_INCOMPLETE): 1. It was thrown right after authorization, ahead of the idempotent short-circuit and the UNKNOWN state gate, so it could misstate durable facts: a retry of a successful FORCE during a provider outage got a "was not released ... remains UNKNOWN" error instead of the idempotent OK, and a terminal job with an unresolvable target got the same misstatement instead of the accurate 5104. Both checks run after authorization, so moving the rejection behind them changes no disclosure surface; an UNKNOWN job with a failed resolution still gets the 5105. 2. The message told the operator to "see fe.log for the cause", but resolution failures were swallowed without a log line anywhere (the target resolution caught silently, and the locator helper folds provider outages into a null). The command now logs the cause server-side at each failure point; client-facing text still passes only through the sanitized root-cause chain. Also in this round: - Guard the external-relation casts in the authoritative read with instanceof (no raw ClassCastException at a command boundary), and catch Exception during target resolution, mirroring SHOW's targetResolves. - The manager's idempotent short-circuit now honors only a released record in a null/UNKNOWN state: a force-released flag on a non-UNKNOWN state can only come from a corrupt journal or image, so it falls through to the revision CAS and the state gate (fail-closed). Tests: a released job survives a resolution failure with the idempotent OK; a PENDING job with a failed resolution gets 5104, not 5105; the corrupt force-released/PENDING record does not short-circuit; half-orphan authorization gains the same privilege-verification assertions as the full-orphan case; opcode 501 gets the unique-assignment wiring pin; the retention cleaner gets its first unit tests (seconds-to-millis config conversion, per-round cap, a failed round swallowed); the regression suite drops an unused REST port variable.
bff53fa to
c1e63ff
Compare
What lands
RESOLVE SQL (design 2.3/7.1): grammar (
RESOLVEandFORCE_RELEASEare new non-reserved keywords, COMMENT is mandatory),ForwardWithSyncto master. The release flow:captureLanceIndexTarget→ read/refresh →withLanceIndexAdmissionrecheck), serialized against DROP CATALOG / identity ALTER exactly like admission.The durable release is one ordinary job upsert with the five FORCE audit fields set; the fence, the unresolved quota charge and the possible-live slot flip off through the existing field semantics in
applyToMemory— no new teardown code.Failure semantics (7.1 step 4): any target-resolution, read or refresh failure is the typed 5105 (
ERR_LANCE_INDEX_JOB_RESOLUTION_INCOMPLETE); nothing is journaled, the job stays UNKNOWN holding fence/quota/slot, and the operator fixes the cause (including the 4.3 credential rotation case) and retries the same statement. The cause is logged server-side (fe.log) at the point of failure; failure details returned to the client pass through the catalog's sanitized root-cause chain only — no locator, credential or dataset URI is echoed. Like the 5104 state rejection, the 5105 is only visible to an already authorized caller.Retention GC: resolved records (force-released UNKNOWN and terminal COMMITTED/NOT_COMMITTED alike) are audit-only; a master-only
LanceIndexJobCleanerdaemon (intervallance_index_job_clean_interval_second, default 1h) removes records resolved longer thanlance_index_job_keep_max_second(default 7d, aligned withhistory_job_keep_max_second) through one batch edit-log record (OP_LANCE_INDEX_JOB_REMOVE = 501) per round, so every FE serves the same SHOW LANCE INDEX JOBS view. Unresolved records are never removed regardless of age (fail-closed, including corrupt identity-less records); the retention clock is the durable update time, which the force release bumps onto the force time.Config: the two retention items are mutable, masterOnly, positive-validated (same handler as the existing quotas).
Two design readings that need reviewer confirmation
enable_lance_index_mutation. The gate controls mutation admission; FORCE is the escape hatch and must stay usable exactly when the gate is off — otherwise PENDING/UNKNOWN jobs could never be released once the gate is closed, and the catalog DDL guard would freeze that catalog forever. Nothing in 2.3 or 9.7 scopes the mutation gate to RESOLVE.ignoreIfNotExists=trueas best-effort invalidation. A non-null exception during target resolution is never treated as an orphan verdict — it fails with 5105 so the fence is kept when "table gone" cannot be told apart from "network down". An unresolvable locator is treated the same way: absence of evidence is not an orphan verdict. SHOW fails that uncertainty closed by hiding the row behind the ADMIN rule; RESOLVE fails it closed by not releasing. (Slice 3C's guard makes orphans unreachable on the normal path; they can only come from pre-guard journals/images.)Operational notes
possibleLiveOwned/terminationProof; the derived slot is released byforceReleased=trueand the raw values stay for audit.forceWarning: the old worker may still overwrite, remove, or reintroduce the index name; the mutation outcome remains UNKNOWN. (SHOW WARNINGS is a stub in the new planner; the OK packet is the only working warning channel.)startMasterOnlyDaemonThreads(MasterDaemon itself does no master check); both retention configs are re-read every round, so ADMIN SET takes effect without restart.Tests
resolve/force_releasestay usable as identifiers/aliases, rejection family); RESOLVE command (5103 byte-identical for missing vs unauthorized, ALTER vs ADMIN authorization, proxy identity, note validation, 5104 gate, idempotent replay — including under a provider outage after a successful release, a terminal job sees 5104 rather than a state-misstating 5105, full/half-orphan paths, resolution failures and an unresolvable locator at authorization time keep everything with zero manager calls, a positively repointed locator takes the ADMIN half-orphan branch, read/refresh failures keep everything with zero manager calls, non-external relation guard, REST defensive 5101, FORWARD_WITH_SYNC). Full FE suite (mvn clean test -pl fe-common,fe-core -am, checkstyle bound into the build): fe-common all green and fe-core 9602 tests with 19F+2E in 14 classes (date/timezone literals, huggingface network unreachable, native-lib link, disk-rebalance scheduling) that reproduce on the pre-change base — environmental, unrelated to this PR (DiskReblanceWhenSchedulerIdlere-verified directly on the base commit; two module-aborting environmental classes, the timezone-boundPropertySchemaTestand the oidc-dependentAuthenticationPluginManagerTest, are excluded from the run and fail identically on the base tree). The 598 tests across the 43 Lance-matching classes (fe-common + fe-core, this slice's nine among them) are all green; the RESOLVE command class alone runs 26.external_table_p0/lance/test_lance_index_resolve.groovy, nonConcurrent, per-run suffix, master-config capture/restore): syntax rejection family, missing job 5103, unauthorized 5103 under a second identity, PENDING job rejected with 5104, retention config SHOW/SET smoke (defaults, zero/negative rejected), GC never touches an unresolved job. Needs the external MinIO/REST docker env — runs in pipeline, not locally.Deliberately not done
markRefresh*): UNKNOWN owes no refresh (6.3), and the refresh of the release protocol is the command's own synchronous action. The only adjacent change is thatgetJobsNeedingRefreshnow excludes force-released records — they owe no refresh, and picking them up would only add audit noise to the next slice's driver.Release note
Add the
RESOLVE LANCE INDEX JOB <id> AS FORCE_RELEASE COMMENT '<note>'statement that lets an operator durably release a Lance index job whose mutation outcome is UNKNOWN, plus a master-only retention cleaner that garbage-collects resolved Lance index job records afterlance_index_job_keep_max_second(default 7 days).