Skip to content

Commit c38bd9e

Browse files
committed
[FLINK-39765][cdc-pipeline/mysql] Implement lineage (FLIP-314) support for mysql source connectors
1 parent 4b62e3d commit c38bd9e

9 files changed

Lines changed: 673 additions & 4 deletions

File tree

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.flink.cdc.common.lineage;
19+
20+
import org.apache.flink.streaming.api.lineage.DatasetConfigFacet;
21+
import org.apache.flink.streaming.api.lineage.DatasetSchemaFacet;
22+
import org.apache.flink.streaming.api.lineage.DatasetSchemaField;
23+
import org.apache.flink.streaming.api.lineage.LineageDataset;
24+
import org.apache.flink.streaming.api.lineage.LineageDatasetFacet;
25+
26+
import javax.annotation.Nullable;
27+
28+
import java.util.HashMap;
29+
import java.util.LinkedHashMap;
30+
import java.util.Map;
31+
32+
/** A {@link LineageDataset} implementation for CDC source tables. */
33+
public class CDCLineageDataset implements LineageDataset {
34+
35+
private final String name;
36+
private final String namespace;
37+
private final Map<String, String> config;
38+
@Nullable private final LinkedHashMap<String, String> schema;
39+
40+
/**
41+
* Creates a CDC lineage dataset without a schema facet.
42+
*
43+
* @param name dataset name, usually a concrete table name
44+
* @param namespace dataset namespace identifying the source system
45+
* @param config config facet values for the dataset
46+
*/
47+
public CDCLineageDataset(String name, String namespace, Map<String, String> config) {
48+
this(name, namespace, config, null);
49+
}
50+
51+
/**
52+
* Creates a CDC lineage dataset with optional schema metadata.
53+
*
54+
* @param name dataset name, usually a concrete table name
55+
* @param namespace dataset namespace identifying the source system
56+
* @param config config facet values for the dataset
57+
* @param schema optional ordered map from field name to field type
58+
*/
59+
public CDCLineageDataset(
60+
String name,
61+
String namespace,
62+
Map<String, String> config,
63+
@Nullable LinkedHashMap<String, String> schema) {
64+
this.name = name;
65+
this.namespace = namespace;
66+
this.config = config;
67+
this.schema = schema;
68+
}
69+
70+
/**
71+
* Returns the dataset name.
72+
*
73+
* @return dataset name, usually a concrete table name
74+
*/
75+
@Override
76+
public String name() {
77+
return name;
78+
}
79+
80+
/**
81+
* Returns the namespace identifying the source system.
82+
*
83+
* @return dataset namespace
84+
*/
85+
@Override
86+
public String namespace() {
87+
return namespace;
88+
}
89+
90+
/**
91+
* Returns the dataset facets.
92+
*
93+
* <p>Every dataset contains a {@code config} facet. Datasets with non-empty schema metadata
94+
* also contain a {@code schema} facet.
95+
*
96+
* @return map of facet name to lineage dataset facet
97+
*/
98+
@Override
99+
public Map<String, LineageDatasetFacet> facets() {
100+
Map<String, LineageDatasetFacet> facets = new HashMap<>();
101+
facets.put(
102+
"config",
103+
new DatasetConfigFacet() {
104+
@Override
105+
public String name() {
106+
return "config";
107+
}
108+
109+
@Override
110+
public Map<String, String> config() {
111+
return config;
112+
}
113+
});
114+
if (schema != null && !schema.isEmpty()) {
115+
facets.put(
116+
"schema",
117+
new DatasetSchemaFacet() {
118+
@Override
119+
public String name() {
120+
return "schema";
121+
}
122+
123+
@Override
124+
public Map<String, DatasetSchemaField<String>> fields() {
125+
Map<String, DatasetSchemaField<String>> result = new LinkedHashMap<>();
126+
for (Map.Entry<String, String> entry : schema.entrySet()) {
127+
String fieldName = entry.getKey();
128+
String fieldType = entry.getValue();
129+
result.put(
130+
fieldName,
131+
new DatasetSchemaField<String>() {
132+
@Override
133+
public String name() {
134+
return fieldName;
135+
}
136+
137+
@Override
138+
public String type() {
139+
return fieldType;
140+
}
141+
});
142+
}
143+
return result;
144+
}
145+
});
146+
}
147+
return facets;
148+
}
149+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.flink.cdc.common.lineage;
19+
20+
import org.apache.flink.api.connector.source.Boundedness;
21+
import org.apache.flink.streaming.api.lineage.LineageDataset;
22+
import org.apache.flink.streaming.api.lineage.SourceLineageVertex;
23+
24+
import java.util.List;
25+
26+
/** A {@link SourceLineageVertex} implementation for CDC sources. */
27+
public class CDCSourceLineageVertex implements SourceLineageVertex {
28+
29+
private final Boundedness boundedness;
30+
private final List<LineageDataset> datasets;
31+
32+
/**
33+
* Creates a CDC source lineage vertex.
34+
*
35+
* @param boundedness source boundedness
36+
* @param datasets datasets produced by the source
37+
*/
38+
public CDCSourceLineageVertex(Boundedness boundedness, List<LineageDataset> datasets) {
39+
this.boundedness = boundedness;
40+
this.datasets = datasets;
41+
}
42+
43+
/**
44+
* Returns whether the source is bounded or continuously unbounded.
45+
*
46+
* @return source boundedness
47+
*/
48+
@Override
49+
public Boundedness boundedness() {
50+
return boundedness;
51+
}
52+
53+
/**
54+
* Returns the datasets produced by the source.
55+
*
56+
* @return source lineage datasets
57+
*/
58+
@Override
59+
public List<LineageDataset> datasets() {
60+
return datasets;
61+
}
62+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.flink.cdc.common.lineage;
19+
20+
import org.apache.flink.api.connector.source.Boundedness;
21+
import org.apache.flink.streaming.api.lineage.LineageDataset;
22+
import org.apache.flink.streaming.api.lineage.SourceLineageVertex;
23+
24+
import java.util.Collections;
25+
import java.util.HashMap;
26+
import java.util.LinkedHashMap;
27+
import java.util.List;
28+
import java.util.Map;
29+
import java.util.stream.Collectors;
30+
31+
/** Utilities for building lineage vertices from CDC source metadata. */
32+
public class LineageUtils {
33+
34+
/**
35+
* Builds the dataset namespace for a CDC source.
36+
*
37+
* <p>The namespace identifies the source system instance, for example {@code
38+
* mysql://localhost:3306}.
39+
*
40+
* @param type CDC source type, such as {@code mysql}
41+
* @param hostname source host name
42+
* @param port source port
43+
* @return namespace used by lineage datasets
44+
*/
45+
public static String getNamespace(String type, String hostname, int port) {
46+
return type + "://" + hostname + ":" + port;
47+
}
48+
49+
/**
50+
* Builds the config facet values shared by all datasets for a CDC source.
51+
*
52+
* @param type CDC source type, such as {@code mysql}
53+
* @return config facet map for lineage datasets
54+
*/
55+
private static Map<String, String> buildConfigMap(String type) {
56+
Map<String, String> config = new HashMap<>();
57+
config.put("type", type + "-cdc");
58+
return config;
59+
}
60+
61+
/**
62+
* Builds a source lineage vertex without schema facets.
63+
*
64+
* @param type CDC source type, such as {@code mysql}
65+
* @param hostname source host name
66+
* @param port source port
67+
* @param isBounded whether the source is bounded
68+
* @param tableList concrete source table names; if empty, a connector-level dataset is used
69+
* @return source lineage vertex for the CDC source
70+
*/
71+
public static SourceLineageVertex sourceLineageVertex(
72+
String type, String hostname, int port, boolean isBounded, List<String> tableList) {
73+
return sourceLineageVertex(type, hostname, port, isBounded, tableList, null);
74+
}
75+
76+
/**
77+
* Builds a source lineage vertex for a CDC source.
78+
*
79+
* <p>When {@code tableList} is not empty, each table becomes one lineage dataset. When it is
80+
* empty, a single connector-level dataset is returned. If schemas are provided for a table,
81+
* they are attached as schema facets on that table dataset.
82+
*
83+
* @param type CDC source type, such as {@code mysql}
84+
* @param hostname source host name
85+
* @param port source port
86+
* @param isBounded whether the source is bounded
87+
* @param tableList concrete source table names
88+
* @param tableSchemas optional map from table name to ordered field name/type pairs
89+
* @return source lineage vertex for the CDC source
90+
*/
91+
public static SourceLineageVertex sourceLineageVertex(
92+
String type,
93+
String hostname,
94+
int port,
95+
boolean isBounded,
96+
List<String> tableList,
97+
Map<String, LinkedHashMap<String, String>> tableSchemas) {
98+
String namespace = getNamespace(type, hostname, port);
99+
Boundedness boundedness =
100+
isBounded ? Boundedness.BOUNDED : Boundedness.CONTINUOUS_UNBOUNDED;
101+
102+
Map<String, String> config = buildConfigMap(type);
103+
104+
List<LineageDataset> datasets;
105+
if (tableList != null && !tableList.isEmpty()) {
106+
datasets =
107+
tableList.stream()
108+
.map(
109+
table -> {
110+
LinkedHashMap<String, String> schema =
111+
tableSchemas != null
112+
? tableSchemas.get(table)
113+
: null;
114+
return (LineageDataset)
115+
new CDCLineageDataset(
116+
table, namespace, config, schema);
117+
})
118+
.collect(Collectors.toList());
119+
} else {
120+
datasets = Collections.singletonList(new CDCLineageDataset(type, namespace, config));
121+
}
122+
123+
return new CDCSourceLineageVertex(boundedness, datasets);
124+
}
125+
}

0 commit comments

Comments
 (0)