Skip to content

Commit 0a699b3

Browse files
authored
[lake/paimon] TieringSourceReader adjust to scan arrow record batch and write arrow record batch to lake (#3430)
1 parent 0afc21a commit 0a699b3

16 files changed

Lines changed: 1273 additions & 51 deletions

File tree

fluss-client/src/main/java/org/apache/fluss/client/table/scanner/log/ArrowLogFetchCollector.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ protected int recordCount(List<ArrowBatchData> fetchedRecords) {
6565
protected ArrowScanRecords toResult(
6666
Map<TableBucket, List<ArrowBatchData>> fetchedRecords,
6767
Map<TableBucket, Long> consumedUpToOffsets) {
68-
// Arrow scan paths don't need consumedUpToOffsets (issue #2371 is specific to
69-
// row-based tiering), so it's discarded here rather than carried in ArrowScanRecords.
70-
return new ArrowScanRecords(fetchedRecords);
68+
return new ArrowScanRecords(fetchedRecords, consumedUpToOffsets);
7169
}
7270

7371
@Override

fluss-client/src/main/java/org/apache/fluss/client/table/scanner/log/ArrowScanRecords.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.apache.fluss.utils.IOUtils;
2525

2626
import javax.annotation.Nonnull;
27+
import javax.annotation.Nullable;
2728

2829
import java.util.Collections;
2930
import java.util.Iterator;
@@ -43,8 +44,18 @@ public class ArrowScanRecords implements Iterable<ArrowBatchData>, AutoCloseable
4344

4445
private final Map<TableBucket, List<ArrowBatchData>> records;
4546

47+
/** The exclusive upper bound of consumed offsets per polled bucket in this round. */
48+
private final Map<TableBucket, Long> consumedUpToOffsets;
49+
4650
public ArrowScanRecords(Map<TableBucket, List<ArrowBatchData>> records) {
51+
this(records, Collections.emptyMap());
52+
}
53+
54+
public ArrowScanRecords(
55+
Map<TableBucket, List<ArrowBatchData>> records,
56+
Map<TableBucket, Long> consumedUpToOffsets) {
4757
this.records = records;
58+
this.consumedUpToOffsets = consumedUpToOffsets;
4859
}
4960

5061
/** Get just the Arrow batches for the given bucket. */
@@ -56,11 +67,23 @@ public List<ArrowBatchData> records(TableBucket scanBucket) {
5667
return Collections.unmodifiableList(recs);
5768
}
5869

59-
/** Returns the buckets that contain Arrow batches. */
70+
/** Returns the buckets that were polled in this round. */
6071
public Set<TableBucket> buckets() {
6172
return Collections.unmodifiableSet(records.keySet());
6273
}
6374

75+
/**
76+
* Get the exclusive upper bound of offsets consumed for the given bucket in this poll round.
77+
*
78+
* @param bucket the bucket to query
79+
* @return the exclusive upper bound offset, or {@code null} if the bucket was not polled in
80+
* this round
81+
*/
82+
@Nullable
83+
public Long consumedUpToOffset(TableBucket bucket) {
84+
return consumedUpToOffsets.get(bucket);
85+
}
86+
6487
/** Returns the total number of rows in all batches. */
6588
public int count() {
6689
int count = 0;

fluss-common/src/main/java/org/apache/fluss/lake/batch/ArrowRecordBatch.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,32 @@
1818
package org.apache.fluss.lake.batch;
1919

2020
import org.apache.fluss.annotation.PublicEvolving;
21+
import org.apache.fluss.record.ArrowBatchData;
2122

2223
/**
23-
* The Arrow implementation of the RecordBatch interface.
24+
* The Arrow implementation of the {@link RecordBatch} interface.
25+
*
26+
* <p>Wraps an {@link ArrowBatchData} for use by lake writers that support batch writing via {@link
27+
* org.apache.fluss.lake.writer.SupportsRecordBatchWrite}.
2428
*
2529
* @since 0.7
2630
*/
2731
@PublicEvolving
28-
public class ArrowRecordBatch implements RecordBatch {}
32+
public class ArrowRecordBatch implements RecordBatch, AutoCloseable {
33+
34+
private final ArrowBatchData arrowBatchData;
35+
36+
public ArrowRecordBatch(ArrowBatchData arrowBatchData) {
37+
this.arrowBatchData = arrowBatchData;
38+
}
39+
40+
/** Returns the underlying {@link ArrowBatchData}. */
41+
public ArrowBatchData getArrowBatchData() {
42+
return arrowBatchData;
43+
}
44+
45+
@Override
46+
public void close() {
47+
arrowBatchData.close();
48+
}
49+
}

fluss-common/src/main/java/org/apache/fluss/record/ArrowBatchData.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import org.apache.fluss.annotation.Internal;
2121

22+
import org.apache.arrow.memory.ArrowBuf;
23+
import org.apache.arrow.vector.FieldVector;
2224
import org.apache.arrow.vector.VectorSchemaRoot;
2325

2426
import static org.apache.fluss.utils.Preconditions.checkArgument;
@@ -38,6 +40,7 @@ public class ArrowBatchData implements AutoCloseable {
3840
private final long baseLogOffset;
3941
private final long timestamp;
4042
private final int schemaId;
43+
private boolean closed;
4144

4245
public ArrowBatchData(
4346
VectorSchemaRoot vectorSchemaRoot, long baseLogOffset, long timestamp, int schemaId) {
@@ -72,6 +75,17 @@ public int getRecordCount() {
7275
return vectorSchemaRoot.getRowCount();
7376
}
7477

78+
/** Returns the total size in bytes of the underlying Arrow buffers. */
79+
public long getSizeInBytes() {
80+
long size = 0;
81+
for (FieldVector vector : vectorSchemaRoot.getFieldVectors()) {
82+
for (ArrowBuf buf : vector.getBuffers(false)) {
83+
size += buf.readableBytes();
84+
}
85+
}
86+
return size;
87+
}
88+
7589
/**
7690
* Creates a new {@link ArrowBatchData} containing a contiguous slice of this batch's rows and
7791
* releases the original vector data.
@@ -92,12 +106,37 @@ skipRows < getRecordCount(),
92106
int remainingRows = getRecordCount() - skipRows;
93107
VectorSchemaRoot slicedRoot = vectorSchemaRoot.slice(skipRows, remainingRows);
94108
// release original vector buffers; sliced vectors hold independent copies
95-
vectorSchemaRoot.close();
109+
close();
96110
return new ArrowBatchData(slicedRoot, baseLogOffset + skipRows, timestamp, schemaId);
97111
}
98112

113+
/**
114+
* Creates a new {@link ArrowBatchData} containing only the first {@code rowCount} rows and
115+
* releases the original vector data.
116+
*
117+
* <p>After this method returns, the original {@link ArrowBatchData} instance MUST NOT be used
118+
* or closed. The caller is responsible for closing the returned instance.
119+
*
120+
* @param rowCount the number of leading rows to keep
121+
* @return a new {@link ArrowBatchData} containing the first {@code rowCount} rows
122+
*/
123+
public ArrowBatchData truncateAndTransferOwnership(int rowCount) {
124+
checkArgument(rowCount > 0, "rowCount must be > 0, but is %s", rowCount);
125+
checkArgument(
126+
rowCount <= getRecordCount(),
127+
"rowCount(%s) must be <= recordCount(%s)",
128+
rowCount,
129+
getRecordCount());
130+
VectorSchemaRoot slicedRoot = vectorSchemaRoot.slice(0, rowCount);
131+
close();
132+
return new ArrowBatchData(slicedRoot, baseLogOffset, timestamp, schemaId);
133+
}
134+
99135
@Override
100136
public void close() {
101-
vectorSchemaRoot.close();
137+
if (!closed) {
138+
closed = true;
139+
vectorSchemaRoot.close();
140+
}
102141
}
103142
}

fluss-common/src/main/java/org/apache/fluss/utils/UnshadedArrowReadUtils.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ private UnshadedArrowReadUtils() {}
5454
public static Schema toArrowSchema(RowType rowType) {
5555
org.apache.fluss.shaded.arrow.org.apache.arrow.vector.types.pojo.Schema shadedSchema =
5656
ArrowUtils.toArrowSchema(rowType);
57-
return Schema.deserializeMessage(ByteBuffer.wrap(shadedSchema.serializeAsMessage()));
57+
// Use toByteArray()/deserialize() instead of serializeAsMessage()/deserializeMessage()
58+
// for compatibility with Arrow 12.x (used by Spark 3.4/3.5)
59+
return Schema.deserialize(ByteBuffer.wrap(shadedSchema.toByteArray()));
5860
}
5961

6062
public static void loadArrowBatch(

fluss-flink/fluss-flink-common/src/main/java/org/apache/fluss/flink/tiering/source/TieringSourceReader.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,16 @@ private static <WriteResult> TieringSourceFetcherManager<WriteResult> createFetc
9090
LakeTieringFactory<WriteResult, ?> lakeTieringFactory,
9191
Duration pollTimeout) {
9292
TieringMetrics tieringMetrics = new TieringMetrics(context.metricGroup());
93+
ClassLoader userClassLoader = context.getUserCodeClassLoader().asClassLoader();
9394
return new TieringSourceFetcherManager<>(
9495
elementsQueue,
9596
() ->
9697
new TieringSplitReader<>(
97-
connection, lakeTieringFactory, pollTimeout, tieringMetrics),
98+
connection,
99+
lakeTieringFactory,
100+
userClassLoader,
101+
pollTimeout,
102+
tieringMetrics),
98103
context.getConfiguration(),
99104
(ignore) -> {});
100105
}

0 commit comments

Comments
 (0)