Skip to content

Commit cf6b063

Browse files
committed
Spark: Copy back 4.2 as 4.1
1 parent 711cffe commit cf6b063

580 files changed

Lines changed: 141660 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

spark/v4.1/build.gradle

Lines changed: 361 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.iceberg;
20+
21+
import com.google.errorprone.annotations.FormatMethod;
22+
import com.google.errorprone.annotations.FormatString;
23+
import java.io.IOException;
24+
import java.io.UncheckedIOException;
25+
import java.util.List;
26+
import java.util.UUID;
27+
import java.util.concurrent.TimeUnit;
28+
import org.apache.hadoop.conf.Configuration;
29+
import org.apache.iceberg.io.CloseableIterable;
30+
import org.apache.iceberg.relocated.com.google.common.collect.ImmutableList;
31+
import org.apache.iceberg.relocated.com.google.common.collect.Lists;
32+
import org.apache.iceberg.spark.Spark3Util;
33+
import org.apache.iceberg.spark.SparkSessionCatalog;
34+
import org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions;
35+
import org.apache.iceberg.util.ThreadPools;
36+
import org.apache.spark.sql.SparkSession;
37+
import org.apache.spark.sql.catalyst.analysis.NoSuchTableException;
38+
import org.apache.spark.sql.catalyst.parser.ParseException;
39+
import org.openjdk.jmh.annotations.Benchmark;
40+
import org.openjdk.jmh.annotations.BenchmarkMode;
41+
import org.openjdk.jmh.annotations.Fork;
42+
import org.openjdk.jmh.annotations.Measurement;
43+
import org.openjdk.jmh.annotations.Mode;
44+
import org.openjdk.jmh.annotations.Param;
45+
import org.openjdk.jmh.annotations.Scope;
46+
import org.openjdk.jmh.annotations.Setup;
47+
import org.openjdk.jmh.annotations.State;
48+
import org.openjdk.jmh.annotations.TearDown;
49+
import org.openjdk.jmh.annotations.Threads;
50+
import org.openjdk.jmh.annotations.Timeout;
51+
import org.openjdk.jmh.annotations.Warmup;
52+
import org.openjdk.jmh.infra.Blackhole;
53+
54+
/**
55+
* A benchmark that evaluates the delete file index build and lookup performance.
56+
*
57+
* <p>To run this benchmark for spark-4.1: <code>
58+
* ./gradlew -DsparkVersions=4.1 :iceberg-spark:iceberg-spark-extensions-4.1_2.13:jmh
59+
* -PjmhIncludeRegex=DeleteFileIndexBenchmark
60+
* -PjmhOutputPath=benchmark/iceberg-delete-file-index-benchmark.txt
61+
* </code>
62+
*/
63+
@Fork(1)
64+
@State(Scope.Benchmark)
65+
@Warmup(iterations = 3)
66+
@Measurement(iterations = 10)
67+
@Timeout(time = 20, timeUnit = TimeUnit.MINUTES)
68+
@BenchmarkMode(Mode.SingleShotTime)
69+
public class DeleteFileIndexBenchmark {
70+
71+
private static final String TABLE_NAME = "test_table";
72+
private static final String PARTITION_COLUMN = "ss_ticket_number";
73+
74+
private static final int NUM_PARTITIONS = 50;
75+
private static final int NUM_DATA_FILES_PER_PARTITION = 50_000;
76+
private static final int NUM_DELETE_FILES_PER_PARTITION = 100;
77+
78+
private final Configuration hadoopConf = new Configuration();
79+
private SparkSession spark;
80+
private Table table;
81+
82+
private List<DataFile> dataFiles;
83+
84+
@Param({"partition", "file", "dv"})
85+
private String type;
86+
87+
@Setup
88+
public void setupBenchmark() throws NoSuchTableException, ParseException {
89+
setupSpark();
90+
initTable();
91+
initDataAndDeletes();
92+
loadDataFiles();
93+
}
94+
95+
private void initDataAndDeletes() {
96+
if (type.equals("partition")) {
97+
initDataAndPartitionScopedDeletes();
98+
} else if (type.equals("file")) {
99+
initDataAndFileScopedDeletes();
100+
} else {
101+
initDataAndDVs();
102+
}
103+
}
104+
105+
@TearDown
106+
public void tearDownBenchmark() {
107+
dropTable();
108+
tearDownSpark();
109+
}
110+
111+
@Benchmark
112+
@Threads(1)
113+
public void buildIndexAndLookup(Blackhole blackhole) {
114+
DeleteFileIndex deletes = buildDeletes();
115+
for (DataFile dataFile : dataFiles) {
116+
DeleteFile[] deleteFiles = deletes.forDataFile(dataFile.dataSequenceNumber(), dataFile);
117+
blackhole.consume(deleteFiles);
118+
}
119+
}
120+
121+
private void loadDataFiles() {
122+
table.refresh();
123+
124+
Snapshot snapshot = table.currentSnapshot();
125+
126+
ManifestGroup manifestGroup =
127+
new ManifestGroup(table.io(), snapshot.dataManifests(table.io()), ImmutableList.of());
128+
129+
try (CloseableIterable<ManifestEntry<DataFile>> entries = manifestGroup.entries()) {
130+
List<DataFile> files = Lists.newArrayList();
131+
for (ManifestEntry<DataFile> entry : entries) {
132+
files.add(entry.file().copyWithoutStats());
133+
}
134+
this.dataFiles = files;
135+
} catch (IOException e) {
136+
throw new UncheckedIOException(e);
137+
}
138+
}
139+
140+
private DeleteFileIndex buildDeletes() {
141+
table.refresh();
142+
143+
List<ManifestFile> deleteManifests = table.currentSnapshot().deleteManifests(table.io());
144+
145+
return DeleteFileIndex.builderFor(table.io(), deleteManifests)
146+
.specsById(table.specs())
147+
.planWith(ThreadPools.getWorkerPool())
148+
.build();
149+
}
150+
151+
private void initDataAndPartitionScopedDeletes() {
152+
for (int partitionOrdinal = 0; partitionOrdinal < NUM_PARTITIONS; partitionOrdinal++) {
153+
StructLike partition = TestHelpers.Row.of(partitionOrdinal);
154+
155+
RowDelta rowDelta = table.newRowDelta();
156+
157+
for (int fileOrdinal = 0; fileOrdinal < NUM_DATA_FILES_PER_PARTITION; fileOrdinal++) {
158+
DataFile dataFile = FileGenerationUtil.generateDataFile(table, partition);
159+
rowDelta.addRows(dataFile);
160+
}
161+
162+
for (int fileOrdinal = 0; fileOrdinal < NUM_DELETE_FILES_PER_PARTITION; fileOrdinal++) {
163+
DeleteFile deleteFile = FileGenerationUtil.generatePositionDeleteFile(table, partition);
164+
rowDelta.addDeletes(deleteFile);
165+
}
166+
167+
rowDelta.commit();
168+
}
169+
}
170+
171+
private void initDataAndFileScopedDeletes() {
172+
for (int partitionOrdinal = 0; partitionOrdinal < NUM_PARTITIONS; partitionOrdinal++) {
173+
StructLike partition = TestHelpers.Row.of(partitionOrdinal);
174+
175+
RowDelta rowDelta = table.newRowDelta();
176+
177+
for (int fileOrdinal = 0; fileOrdinal < NUM_DATA_FILES_PER_PARTITION; fileOrdinal++) {
178+
DataFile dataFile = FileGenerationUtil.generateDataFile(table, partition);
179+
DeleteFile deleteFile = FileGenerationUtil.generatePositionDeleteFile(table, dataFile);
180+
rowDelta.addRows(dataFile);
181+
rowDelta.addDeletes(deleteFile);
182+
}
183+
184+
rowDelta.commit();
185+
}
186+
}
187+
188+
private void initDataAndDVs() {
189+
for (int partitionOrdinal = 0; partitionOrdinal < NUM_PARTITIONS; partitionOrdinal++) {
190+
StructLike partition = TestHelpers.Row.of(partitionOrdinal);
191+
192+
RowDelta rowDelta = table.newRowDelta();
193+
194+
for (int fileOrdinal = 0; fileOrdinal < NUM_DATA_FILES_PER_PARTITION; fileOrdinal++) {
195+
DataFile dataFile = FileGenerationUtil.generateDataFile(table, partition);
196+
DeleteFile dv = FileGenerationUtil.generateDV(table, dataFile);
197+
rowDelta.addRows(dataFile);
198+
rowDelta.addDeletes(dv);
199+
}
200+
201+
rowDelta.commit();
202+
}
203+
}
204+
205+
private void setupSpark() {
206+
this.spark =
207+
SparkSession.builder()
208+
.config("spark.ui.enabled", false)
209+
.config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
210+
.config("spark.sql.extensions", IcebergSparkSessionExtensions.class.getName())
211+
.config("spark.sql.catalog.spark_catalog", SparkSessionCatalog.class.getName())
212+
.config("spark.sql.catalog.spark_catalog.type", "hadoop")
213+
.config("spark.sql.catalog.spark_catalog.warehouse", newWarehouseDir())
214+
.master("local[*]")
215+
.getOrCreate();
216+
}
217+
218+
private void tearDownSpark() {
219+
spark.stop();
220+
}
221+
222+
private void initTable() throws NoSuchTableException, ParseException {
223+
sql(
224+
"CREATE TABLE %s ( "
225+
+ " `ss_sold_date_sk` INT, "
226+
+ " `ss_sold_time_sk` INT, "
227+
+ " `ss_item_sk` INT, "
228+
+ " `ss_customer_sk` STRING, "
229+
+ " `ss_cdemo_sk` STRING, "
230+
+ " `ss_hdemo_sk` STRING, "
231+
+ " `ss_addr_sk` STRING, "
232+
+ " `ss_store_sk` STRING, "
233+
+ " `ss_promo_sk` STRING, "
234+
+ " `ss_ticket_number` INT, "
235+
+ " `ss_quantity` STRING, "
236+
+ " `ss_wholesale_cost` STRING, "
237+
+ " `ss_list_price` STRING, "
238+
+ " `ss_sales_price` STRING, "
239+
+ " `ss_ext_discount_amt` STRING, "
240+
+ " `ss_ext_sales_price` STRING, "
241+
+ " `ss_ext_wholesale_cost` STRING, "
242+
+ " `ss_ext_list_price` STRING, "
243+
+ " `ss_ext_tax` STRING, "
244+
+ " `ss_coupon_amt` STRING, "
245+
+ " `ss_net_paid` STRING, "
246+
+ " `ss_net_paid_inc_tax` STRING, "
247+
+ " `ss_net_profit` STRING "
248+
+ ")"
249+
+ "USING iceberg "
250+
+ "PARTITIONED BY (%s) "
251+
+ "TBLPROPERTIES ("
252+
+ " '%s' '%b',"
253+
+ " '%s' '%s',"
254+
+ " '%s' '%d')",
255+
TABLE_NAME,
256+
PARTITION_COLUMN,
257+
TableProperties.MANIFEST_MERGE_ENABLED,
258+
false,
259+
TableProperties.DELETE_MODE,
260+
RowLevelOperationMode.MERGE_ON_READ.modeName(),
261+
TableProperties.FORMAT_VERSION,
262+
type.equals("dv") ? 3 : 2);
263+
264+
this.table = Spark3Util.loadIcebergTable(spark, TABLE_NAME);
265+
}
266+
267+
private void dropTable() {
268+
sql("DROP TABLE IF EXISTS %s PURGE", TABLE_NAME);
269+
}
270+
271+
private String newWarehouseDir() {
272+
return hadoopConf.get("hadoop.tmp.dir") + UUID.randomUUID();
273+
}
274+
275+
@FormatMethod
276+
private void sql(@FormatString String query, Object... args) {
277+
spark.sql(String.format(query, args));
278+
}
279+
}

0 commit comments

Comments
 (0)