yidawang-shopify opened a new pull request, #17668:
URL: https://github.com/apache/iceberg/pull/17668

   ## What
   
   Makes the Flink connector report **source → sink table lineage** through 
Flink's FLIP-314
   `JobStatusChangedListener`, so a listener can resolve which Iceberg tables a 
job reads and writes
   without anyone hand-declaring the edge.
   
   `IcebergSource` and `IcebergSink` implement `LineageVertexProvider`. A new 
`IcebergLineageUtil`
   builds the `LineageDataset` those vertices publish.
   
   ## Why the diff touches the table source and sink
   
   Flink only finds a lineage vertex if it can reach the `Source`/`Sink` 
**object**, and that depends
   on which `RuntimeProvider` the connector returns:
   
   | Provider | What the connector hands over | Planner can see the object? |
   |---|---|---|
   | `DataStreamScanProvider` / `DataStreamSinkProvider` | a callback that 
builds a topology | No — the object is a local inside the lambda |
   | `SourceProvider` / `SinkV2Provider` | the object itself | Yes |
   
   `LineageGraphUtils#processSource` reads the vertex off 
`SourceTransformation` and `processSink` off
   `SinkTransformation`, and those transformations only carry a vertex when the 
planner constructed
   them itself — i.e. from a declarative provider.
   
   So `IcebergTableSource` and `IcebergTableSink` now hand over 
`SourceProvider.of(source)` /
   `SinkV2Provider.of(sink)` instead of a callback. Everything else follows 
from that: the source
   infers its own parallelism now that it no longer goes through `buildStream`, 
and the sink gains a
   `build()` that does not attach a topology.
   
   ## What the dataset carries
   
   Iceberg's own vocabulary only — catalog, namespace, table, and the catalog's 
`uri`/`warehouse` —
   plus the `prefix` a REST catalog's server assigned to this client. Composing 
a vendor-specific
   fully-qualified name is left to the listener, which is the only party with 
the deployment context.
   Namespaces are reported verbatim for the same reason: Iceberg permits any 
depth, and flattening one
   to fit some vendor's scheme isn't the connector's decision.
   
   The prefix is read from the catalog rather than derived from `warehouse`, 
which is wrong for any
   catalog not backed by exactly one bucket. It is the handle used for every 
`/v1/<prefix>/...` call,
   arrives in `GET /v1/config`, and is merged into the catalog's properties at 
initialization.
   
   Coordinates live in a `DatasetConfigFacet` rather than in 
`LineageDataset#name()` because on the SQL
   path the planner wraps the dataset in `TableLineageDatasetImpl`, which 
overwrites `name()` with the
   Flink object identifier; `namespace()` and `facets()` survive.
   
   ## Cost on the submission path
   
   Because only a live catalog knows the prefix, resolving it inside 
`IcebergLineageUtil` would cost a
   catalog initialization per table at job submission — and more than once per 
table, since Flink asks
   a connector for its lineage vertex both when it extracts the dataset and 
when it constructs the
   transformation. So the source and sink builders read the prefix from the 
catalog they already opened
   to load the table and pass it in, and each vertex resolves its datasets 
once. An empty prefix records
   that a live catalog answered "none", which keeps that answer from being 
re-derived on every
   submission.
   
   Lineage is best-effort observability: every path yields no dataset rather 
than throwing, so a table
   whose coordinates can't be resolved never fails the job.
   
   ## Configuration
   
   | | Flag | Default | Lineage |
   |---|---|---|---|
   | Source | `table.exec.iceberg.use-flip27-source` | `true` | works as-is |
   | Sink | `table.exec.iceberg.use-v2-sink` | `false` | must opt in |
   | Sink | `table.exec.uid.generation` | `PLAN_ONLY` | must be `ALWAYS` |
   
   Source lineage needs no configuration change. Sink lineage needs both sink 
settings; with either
   missing the sink keeps the existing callback path and logs at INFO why. 
DataStream API users need no
   flags on either end, since they construct `IcebergSource`/`IcebergSink` 
directly.
   
   ## Scope
   
   `flink/v2.1` only, matching how recent Flink changes have landed. Happy to 
follow up with backports
   to `v2.0`/`v1.20` if reviewers would prefer them.
   
   ## Testing
   
   - `TestIcebergLineageUtil` — facet contents across REST/Hadoop/non-catalog 
loaders, and that a
     captured prefix is reported without opening a catalog.
   - `TestIcebergSqlLineage` — end-to-end `LineageGraph` on the SQL path via a 
registered
     `JobStatusChangedListener`.
   - `TestIcebergSourceInferParallelism` — the source's own parallelism 
inference.
   
   ## AI disclosure
   
   This change was developed with AI assistance (Claude), reflected in the 
commit's `Co-Authored-By`
   trailer. I've reviewed the implementation end-to-end and verified the REST 
`prefix` behaviour
   against a live REST catalog rather than only a fixture. Open question I'd 
value a reviewer's opinion
   on: whether `IcebergLineageUtil`'s prefix-capture entry points are the right 
public surface, or
   whether they should be package-private with the capture folded into the 
builders.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to