Skip to content

Commit 454e246

Browse files
authored
Core: Refactor metadata tables and scans (#4566)
1 parent b70056c commit 454e246

19 files changed

Lines changed: 237 additions & 319 deletions

core/src/main/java/org/apache/iceberg/AllDataFilesTable.java

Lines changed: 7 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@
1919

2020
package org.apache.iceberg;
2121

22-
import java.io.IOException;
23-
import org.apache.iceberg.exceptions.RuntimeIOException;
2422
import org.apache.iceberg.io.CloseableIterable;
25-
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
26-
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
27-
import org.apache.iceberg.util.ParallelIterable;
2823

2924
/**
3025
* A {@link Table} implementation that exposes a table's valid data files as rows.
@@ -53,47 +48,25 @@ MetadataTableType metadataTableType() {
5348
return MetadataTableType.ALL_DATA_FILES;
5449
}
5550

56-
public static class AllDataFilesTableScan extends BaseFilesTableScan {
51+
public static class AllDataFilesTableScan extends BaseAllFilesTableScan {
5752

58-
AllDataFilesTableScan(TableOperations ops, Table table, Schema fileSchema) {
59-
super(ops, table, fileSchema, MetadataTableType.ALL_DATA_FILES);
53+
AllDataFilesTableScan(TableOperations ops, Table table, Schema schema) {
54+
super(ops, table, schema, MetadataTableType.ALL_DATA_FILES);
6055
}
6156

62-
private AllDataFilesTableScan(TableOperations ops, Table table, Schema schema, Schema fileSchema,
57+
private AllDataFilesTableScan(TableOperations ops, Table table, Schema schema,
6358
TableScanContext context) {
64-
super(ops, table, schema, fileSchema, context, MetadataTableType.ALL_DATA_FILES);
59+
super(ops, table, schema, MetadataTableType.ALL_DATA_FILES, context);
6560
}
6661

6762
@Override
6863
protected TableScan newRefinedScan(TableOperations ops, Table table, Schema schema, TableScanContext context) {
69-
return new AllDataFilesTableScan(ops, table, schema, fileSchema(), context);
70-
}
71-
72-
@Override
73-
public TableScan useSnapshot(long scanSnapshotId) {
74-
throw new UnsupportedOperationException("Cannot select snapshot: all_data_files is for all snapshots");
75-
}
76-
77-
@Override
78-
public TableScan asOfTime(long timestampMillis) {
79-
throw new UnsupportedOperationException("Cannot select snapshot: all_data_files is for all snapshots");
80-
}
81-
82-
@Override
83-
public CloseableIterable<FileScanTask> planFiles() {
84-
return super.planFilesAllSnapshots();
64+
return new AllDataFilesTableScan(ops, table, schema, context);
8565
}
8666

8767
@Override
8868
protected CloseableIterable<ManifestFile> manifests() {
89-
try (CloseableIterable<ManifestFile> iterable = new ParallelIterable<>(
90-
Iterables.transform(table().snapshots(),
91-
snapshot -> (Iterable<ManifestFile>) () -> snapshot.dataManifests().iterator()),
92-
context().planExecutor())) {
93-
return CloseableIterable.withNoopClose(Sets.newHashSet(iterable));
94-
} catch (IOException e) {
95-
throw new RuntimeIOException(e, "Failed to close parallel iterable");
96-
}
69+
return reachableManifests(Snapshot::dataManifests);
9770
}
9871
}
9972
}

core/src/main/java/org/apache/iceberg/AllEntriesTable.java

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,14 @@
1919

2020
package org.apache.iceberg;
2121

22-
import java.io.IOException;
23-
import java.util.List;
24-
import java.util.concurrent.ExecutorService;
25-
import org.apache.iceberg.exceptions.RuntimeIOException;
22+
import org.apache.iceberg.ManifestEntriesTable.ManifestReadTask;
2623
import org.apache.iceberg.expressions.Expression;
2724
import org.apache.iceberg.expressions.Expressions;
2825
import org.apache.iceberg.expressions.ResidualEvaluator;
2926
import org.apache.iceberg.io.CloseableIterable;
30-
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
3127
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
3228
import org.apache.iceberg.types.TypeUtil;
3329
import org.apache.iceberg.types.Types.StructType;
34-
import org.apache.iceberg.util.ParallelIterable;
3530

3631
/**
3732
* A {@link Table} implementation that exposes a table's manifest entries as rows, for both delete and data files.
@@ -74,11 +69,11 @@ MetadataTableType metadataTableType() {
7469
private static class Scan extends BaseAllMetadataTableScan {
7570

7671
Scan(TableOperations ops, Table table, Schema schema) {
77-
super(ops, table, schema);
72+
super(ops, table, schema, MetadataTableType.ALL_ENTRIES);
7873
}
7974

8075
private Scan(TableOperations ops, Table table, Schema schema, TableScanContext context) {
81-
super(ops, table, schema, context);
76+
super(ops, table, schema, MetadataTableType.ALL_ENTRIES, context);
8277
}
8378

8479
@Override
@@ -88,34 +83,16 @@ protected TableScan newRefinedScan(TableOperations ops, Table table, Schema sche
8883
}
8984

9085
@Override
91-
protected String tableType() {
92-
return MetadataTableType.ALL_ENTRIES.name();
93-
}
86+
protected CloseableIterable<FileScanTask> doPlanFiles() {
87+
CloseableIterable<ManifestFile> manifests = reachableManifests(Snapshot::allManifests);
9488

95-
@Override
96-
protected CloseableIterable<FileScanTask> planFiles(
97-
TableOperations ops, Snapshot snapshot, Expression rowFilter,
98-
boolean ignoreResiduals, boolean caseSensitive, boolean colStats) {
99-
CloseableIterable<ManifestFile> manifests = allManifestFiles(
100-
ops.current().snapshots(), context().planExecutor());
10189
String schemaString = SchemaParser.toJson(schema());
10290
String specString = PartitionSpecParser.toJson(PartitionSpec.unpartitioned());
103-
Expression filter = ignoreResiduals ? Expressions.alwaysTrue() : rowFilter;
91+
Expression filter = shouldIgnoreResiduals() ? Expressions.alwaysTrue() : filter();
10492
ResidualEvaluator residuals = ResidualEvaluator.unpartitioned(filter);
10593

106-
return CloseableIterable.transform(manifests, manifest -> new ManifestEntriesTable.ManifestReadTask(
107-
ops.io(), manifest, schema(), schemaString, specString, residuals, ops.current().specsById()));
108-
}
109-
}
110-
111-
private static CloseableIterable<ManifestFile> allManifestFiles(
112-
List<Snapshot> snapshots, ExecutorService workerPool) {
113-
try (CloseableIterable<ManifestFile> iterable = new ParallelIterable<>(
114-
Iterables.transform(snapshots, snapshot -> (Iterable<ManifestFile>) () -> snapshot.allManifests().iterator()),
115-
workerPool)) {
116-
return CloseableIterable.withNoopClose(Sets.newHashSet(iterable));
117-
} catch (IOException e) {
118-
throw new RuntimeIOException(e, "Failed to close parallel iterable");
94+
return CloseableIterable.transform(manifests, manifest ->
95+
new ManifestReadTask(table(), manifest, schema(), schemaString, specString, residuals));
11996
}
12097
}
12198
}

core/src/main/java/org/apache/iceberg/AllManifestsTable.java

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ MetadataTableType metadataTableType() {
8585
public static class AllManifestsTableScan extends BaseAllMetadataTableScan {
8686

8787
AllManifestsTableScan(TableOperations ops, Table table, Schema fileSchema) {
88-
super(ops, table, fileSchema);
88+
super(ops, table, fileSchema, MetadataTableType.ALL_MANIFESTS);
8989
}
9090

9191
private AllManifestsTableScan(TableOperations ops, Table table, Schema schema,
9292
TableScanContext context) {
93-
super(ops, table, schema, context);
93+
super(ops, table, schema, MetadataTableType.ALL_MANIFESTS, context);
9494
}
9595

9696
@Override
@@ -100,43 +100,27 @@ protected TableScan newRefinedScan(TableOperations ops, Table table, Schema sche
100100
}
101101

102102
@Override
103-
public TableScan useSnapshot(long scanSnapshotId) {
104-
throw new UnsupportedOperationException("Cannot select snapshot: all_manifests is for all snapshots");
105-
}
106-
107-
@Override
108-
public TableScan asOfTime(long timestampMillis) {
109-
throw new UnsupportedOperationException("Cannot select snapshot: all_manifests is for all snapshots");
110-
}
111-
112-
@Override
113-
protected String tableType() {
114-
return MetadataTableType.ALL_MANIFESTS.name();
115-
}
116-
117-
@Override
118-
protected CloseableIterable<FileScanTask> planFiles(
119-
TableOperations ops, Snapshot snapshot, Expression rowFilter,
120-
boolean ignoreResiduals, boolean caseSensitive, boolean colStats) {
103+
protected CloseableIterable<FileScanTask> doPlanFiles() {
104+
FileIO io = table().io();
121105
String schemaString = SchemaParser.toJson(schema());
122106
String specString = PartitionSpecParser.toJson(PartitionSpec.unpartitioned());
123107
Map<Integer, PartitionSpec> specs = Maps.newHashMap(table().specs());
108+
Expression filter = shouldIgnoreResiduals() ? Expressions.alwaysTrue() : filter();
109+
ResidualEvaluator residuals = ResidualEvaluator.unpartitioned(filter);
124110

125-
return CloseableIterable.withNoopClose(Iterables.transform(ops.current().snapshots(), snap -> {
111+
return CloseableIterable.withNoopClose(Iterables.transform(table().snapshots(), snap -> {
126112
if (snap.manifestListLocation() != null) {
127-
Expression filter = ignoreResiduals ? Expressions.alwaysTrue() : rowFilter;
128-
ResidualEvaluator residuals = ResidualEvaluator.unpartitioned(filter);
129113
DataFile manifestListAsDataFile = DataFiles.builder(PartitionSpec.unpartitioned())
130-
.withInputFile(ops.io().newInputFile(snap.manifestListLocation()))
114+
.withInputFile(io.newInputFile(snap.manifestListLocation()))
131115
.withRecordCount(1)
132116
.withFormat(FileFormat.AVRO)
133117
.build();
134-
return new ManifestListReadTask(ops.io(), schema(), specs, new BaseFileScanTask(
118+
return new ManifestListReadTask(io, schema(), specs, new BaseFileScanTask(
135119
manifestListAsDataFile, null,
136120
schemaString, specString, residuals));
137121
} else {
138122
return StaticDataTask.of(
139-
ops.io().newInputFile(ops.current().metadataFileLocation()),
123+
io.newInputFile(tableOps().current().metadataFileLocation()),
140124
MANIFEST_FILE_SCHEMA, schema(), snap.allManifests(),
141125
manifest -> ManifestsTable.manifestFileToRow(specs.get(manifest.partitionSpecId()), manifest)
142126
);

core/src/main/java/org/apache/iceberg/BaseAllMetadataTableScan.java

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,40 +19,56 @@
1919

2020
package org.apache.iceberg;
2121

22+
import java.io.IOException;
23+
import java.io.UncheckedIOException;
24+
import org.apache.iceberg.events.Listeners;
25+
import org.apache.iceberg.events.ScanEvent;
2226
import org.apache.iceberg.io.CloseableIterable;
27+
import org.apache.iceberg.relocated.com.google.common.base.Function;
28+
import org.apache.iceberg.relocated.com.google.common.collect.Iterables;
29+
import org.apache.iceberg.relocated.com.google.common.collect.Sets;
30+
import org.apache.iceberg.util.ParallelIterable;
31+
import org.slf4j.Logger;
32+
import org.slf4j.LoggerFactory;
2333

2434
abstract class BaseAllMetadataTableScan extends BaseMetadataTableScan {
35+
private static final Logger LOG = LoggerFactory.getLogger(BaseAllMetadataTableScan.class);
2536

26-
BaseAllMetadataTableScan(TableOperations ops, Table table, Schema fileSchema) {
27-
super(ops, table, fileSchema);
37+
BaseAllMetadataTableScan(TableOperations ops, Table table, Schema schema, MetadataTableType tableType) {
38+
super(ops, table, schema, tableType);
2839
}
2940

30-
BaseAllMetadataTableScan(TableOperations ops, Table table, Schema schema, TableScanContext context) {
31-
super(ops, table, schema, context);
41+
BaseAllMetadataTableScan(TableOperations ops, Table table, Schema schema, MetadataTableType tableType,
42+
TableScanContext context) {
43+
super(ops, table, schema, tableType, context);
3244
}
3345

34-
/**
35-
* Type of scan being performed, such as {@link MetadataTableType#ALL_DATA_FILES} when scanning
36-
* a table's {@link org.apache.iceberg.AllDataFilesTable}.
37-
* <p>
38-
* Used for logging and error messages.
39-
*/
40-
protected abstract String tableType();
41-
4246
@Override
43-
public TableScan appendsBetween(long fromSnapshotId, long toSnapshotId) {
44-
throw new UnsupportedOperationException(
45-
String.format("Cannot incrementally scan table of type %s", tableType()));
47+
public TableScan useSnapshot(long scanSnapshotId) {
48+
throw new UnsupportedOperationException("Cannot select snapshot in table: " + tableType());
4649
}
4750

4851
@Override
49-
public TableScan appendsAfter(long fromSnapshotId) {
50-
throw new UnsupportedOperationException(
51-
String.format("Cannot incrementally scan table of type %s", tableType()));
52+
public TableScan asOfTime(long timestampMillis) {
53+
throw new UnsupportedOperationException("Cannot select snapshot in table: " + tableType());
5254
}
5355

5456
@Override
5557
public CloseableIterable<FileScanTask> planFiles() {
56-
return super.planFilesAllSnapshots();
58+
LOG.info("Scanning metadata table {} with filter {}.", table(), filter());
59+
Listeners.notifyAll(new ScanEvent(table().name(), 0L, filter(), schema()));
60+
61+
return doPlanFiles();
62+
}
63+
64+
protected CloseableIterable<ManifestFile> reachableManifests(Function<Snapshot, Iterable<ManifestFile>> toManifests) {
65+
Iterable<Snapshot> snapshots = table().snapshots();
66+
Iterable<Iterable<ManifestFile>> manifestIterables = Iterables.transform(snapshots, toManifests);
67+
68+
try (CloseableIterable<ManifestFile> iterable = new ParallelIterable<>(manifestIterables, planExecutor())) {
69+
return CloseableIterable.withNoopClose(Sets.newHashSet(iterable));
70+
} catch (IOException e) {
71+
throw new UncheckedIOException("Failed to close parallel iterable", e);
72+
}
5773
}
5874
}

0 commit comments

Comments
 (0)