19
19
package org .apache .flink .runtime .io .network .partition ;
20
20
21
21
import org .apache .flink .annotation .VisibleForTesting ;
22
- import org .apache .flink .api .java .tuple .Tuple2 ;
23
22
import org .apache .flink .core .memory .MemorySegment ;
24
23
import org .apache .flink .runtime .io .network .buffer .Buffer ;
25
24
import org .apache .flink .runtime .io .network .buffer .BufferHeader ;
32
31
import java .nio .channels .FileChannel ;
33
32
import java .util .ArrayDeque ;
34
33
import java .util .Queue ;
34
+ import java .util .function .BiConsumer ;
35
35
import java .util .function .Consumer ;
36
36
37
37
import static org .apache .flink .runtime .io .network .partition .BufferReaderWriterUtil .HEADER_LENGTH ;
@@ -74,8 +74,10 @@ class PartitionedFileReader {
74
74
/** Number of remaining bytes in the current data region read. */
75
75
private long currentRegionRemainingBytes ;
76
76
77
- /** A queue storing pairs of file offsets and sizes to be read. */
78
- private final Queue <Tuple2 <Long , Long >> offsetAndSizesToRead = new ArrayDeque <>();
77
+ /** A queue storing {@link BufferPositionDescriptor} to be read. */
78
+ private final Queue <BufferPositionDescriptor > readBufferPositions = new ArrayDeque <>();
79
+
80
+ private BufferPositionDescriptor currentBufferPositionDescriptor ;
79
81
80
82
PartitionedFileReader (
81
83
PartitionedFile partitionedFile ,
@@ -100,23 +102,23 @@ class PartitionedFileReader {
100
102
101
103
private void moveToNextReadablePosition (ByteBuffer indexEntryBuf ) throws IOException {
102
104
while (currentRegionRemainingBytes <= 0 && hasNextPositionToRead ()) {
103
- if (!offsetAndSizesToRead .isEmpty ()) {
104
- Tuple2 <Long , Long > offsetAndSize = offsetAndSizesToRead .poll ();
105
- nextOffsetToRead = offsetAndSize .f0 ;
106
- currentRegionRemainingBytes = offsetAndSize .f1 ;
105
+ if (!readBufferPositions .isEmpty ()) {
106
+ BufferPositionDescriptor descriptor = readBufferPositions .poll ();
107
+ nextOffsetToRead = descriptor .offset ;
108
+ currentRegionRemainingBytes = descriptor .size ;
109
+ currentBufferPositionDescriptor = descriptor ;
107
110
} else {
108
111
// move to next region which has buffers
109
112
if (nextRegionToRead < partitionedFile .getNumRegions ()) {
110
- updateReadableOffsetAndSize (indexEntryBuf , offsetAndSizesToRead );
113
+ updateReadableOffsetAndSize (indexEntryBuf , readBufferPositions );
111
114
++nextRegionToRead ;
112
115
}
113
116
}
114
117
}
115
118
}
116
119
117
120
private boolean hasNextPositionToRead () {
118
- return !offsetAndSizesToRead .isEmpty ()
119
- || nextRegionToRead < partitionedFile .getNumRegions ();
121
+ return !readBufferPositions .isEmpty () || nextRegionToRead < partitionedFile .getNumRegions ();
120
122
}
121
123
122
124
/**
@@ -144,31 +146,31 @@ private boolean hasNextPositionToRead() {
144
146
*
145
147
* @param indexEntryBuf A ByteBuffer containing index entries which provide offset and size
146
148
* information.
147
- * @param offsetAndSizesToRead A queue to store the updated offsets and sizes .
149
+ * @param readBufferPositions A queue to store the buffer position descriptors .
148
150
* @throws IOException If an I/O error occurs when accessing the index file channel.
149
151
*/
150
152
@ VisibleForTesting
151
153
void updateReadableOffsetAndSize (
152
- ByteBuffer indexEntryBuf , Queue <Tuple2 < Long , Long >> offsetAndSizesToRead )
154
+ ByteBuffer indexEntryBuf , Queue <BufferPositionDescriptor > readBufferPositions )
153
155
throws IOException {
154
156
int startSubpartition = subpartitionIndexSet .getStartIndex ();
155
157
int endSubpartition = subpartitionIndexSet .getEndIndex ();
156
158
157
159
if (startSubpartition >= subpartitionOrderRotationIndex
158
160
|| endSubpartition < subpartitionOrderRotationIndex ) {
159
161
updateReadableOffsetAndSize (
160
- startSubpartition , endSubpartition , indexEntryBuf , offsetAndSizesToRead );
162
+ startSubpartition , endSubpartition , indexEntryBuf , readBufferPositions );
161
163
} else {
162
164
updateReadableOffsetAndSize (
163
165
subpartitionOrderRotationIndex ,
164
166
endSubpartition ,
165
167
indexEntryBuf ,
166
- offsetAndSizesToRead );
168
+ readBufferPositions );
167
169
updateReadableOffsetAndSize (
168
170
startSubpartition ,
169
171
subpartitionOrderRotationIndex - 1 ,
170
172
indexEntryBuf ,
171
- offsetAndSizesToRead );
173
+ readBufferPositions );
172
174
}
173
175
}
174
176
@@ -181,15 +183,15 @@ void updateReadableOffsetAndSize(
181
183
* @param startSubpartition The starting index of the subpartition range to be processed.
182
184
* @param endSubpartition The ending index of the subpartition range to be processed.
183
185
* @param indexEntryBuf A ByteBuffer containing the index entries to read offsets and sizes.
184
- * @param offsetAndSizesToRead A queue to store the updated offsets and sizes .
186
+ * @param readBufferPositions A queue to store the buffer position descriptors .
185
187
* @throws IOException If an I/O error occurs during reading of index entries.
186
188
* @throws IllegalStateException If offsets are not contiguous and not from a single buffer.
187
189
*/
188
190
private void updateReadableOffsetAndSize (
189
191
int startSubpartition ,
190
192
int endSubpartition ,
191
193
ByteBuffer indexEntryBuf ,
192
- Queue <Tuple2 < Long , Long >> offsetAndSizesToRead )
194
+ Queue <BufferPositionDescriptor > readBufferPositions )
193
195
throws IOException {
194
196
partitionedFile .getIndexEntry (
195
197
indexFileChannel , indexEntryBuf , nextRegionToRead , startSubpartition );
@@ -202,18 +204,28 @@ private void updateReadableOffsetAndSize(
202
204
long endPartitionSize = indexEntryBuf .getLong ();
203
205
204
206
if (startPartitionOffset != endPartitionOffset || startPartitionSize != endPartitionSize ) {
205
- offsetAndSizesToRead .add (
206
- Tuple2 . of (
207
+ readBufferPositions .add (
208
+ new BufferPositionDescriptor (
207
209
startPartitionOffset ,
208
- endPartitionOffset + endPartitionSize - startPartitionOffset ));
210
+ endPartitionOffset + endPartitionSize - startPartitionOffset ,
211
+ 1 ));
209
212
} else if (startPartitionSize != 0 ) {
210
213
// this branch is for broadcast subpartitions
211
- for (int i = startSubpartition ; i <= endSubpartition ; i ++) {
212
- offsetAndSizesToRead .add (Tuple2 .of (startPartitionOffset , startPartitionSize ));
213
- }
214
+ readBufferPositions .add (
215
+ new BufferPositionDescriptor (
216
+ startPartitionOffset ,
217
+ startPartitionSize ,
218
+ endSubpartition - startSubpartition + 1 ));
214
219
}
215
220
}
216
221
222
+ @ VisibleForTesting
223
+ void readCurrentRegion (
224
+ Queue <MemorySegment > freeSegments , BufferRecycler recycler , Consumer <Buffer > consumer )
225
+ throws IOException {
226
+ readCurrentRegion (freeSegments , recycler , (buffer , repeatCount ) -> consumer .accept (buffer ));
227
+ }
228
+
217
229
/**
218
230
* Reads a buffer from the current region of the target {@link PartitionedFile} and moves the
219
231
* read position forward.
@@ -226,7 +238,9 @@ private void updateReadableOffsetAndSize(
226
238
* @return Whether the file reader has remaining data to read.
227
239
*/
228
240
boolean readCurrentRegion (
229
- Queue <MemorySegment > freeSegments , BufferRecycler recycler , Consumer <Buffer > consumer )
241
+ Queue <MemorySegment > freeSegments ,
242
+ BufferRecycler recycler ,
243
+ BiConsumer <Buffer , Integer > consumer )
230
244
throws IOException {
231
245
if (currentRegionRemainingBytes == 0 ) {
232
246
return false ;
@@ -300,7 +314,7 @@ private BufferAndHeader processBuffer(
300
314
ByteBuffer byteBuffer ,
301
315
Buffer buffer ,
302
316
BufferAndHeader partialBuffer ,
303
- Consumer <Buffer > consumer ) {
317
+ BiConsumer <Buffer , Integer > consumer ) {
304
318
BufferHeader header = partialBuffer .header ;
305
319
CompositeBuffer targetBuffer = partialBuffer .buffer ;
306
320
while (byteBuffer .hasRemaining ()) {
@@ -331,7 +345,7 @@ private BufferAndHeader processBuffer(
331
345
}
332
346
333
347
header = null ;
334
- consumer .accept (targetBuffer );
348
+ consumer .accept (targetBuffer , currentBufferPositionDescriptor . repeatCount );
335
349
targetBuffer = null ;
336
350
}
337
351
return new BufferAndHeader (targetBuffer , header );
@@ -366,4 +380,44 @@ private static class BufferAndHeader {
366
380
this .header = header ;
367
381
}
368
382
}
383
+
384
+ /**
385
+ * Represents the position and size of a buffer along with the repeat count. For a regular
386
+ * buffer, the repeat count is typically one. For a broadcast buffer, the repeat count
387
+ * corresponds to the number of subpartitions.
388
+ */
389
+ @ VisibleForTesting
390
+ static class BufferPositionDescriptor {
391
+ private final long offset ;
392
+ private final long size ;
393
+ private final int repeatCount ;
394
+
395
+ /**
396
+ * Constructs a BufferPositionDescriptor with specified offset, size, and repeat count.
397
+ *
398
+ * @param offset the offset of the buffer
399
+ * @param size the size of the buffer
400
+ * @param repeatCount the repeat count for the buffer
401
+ */
402
+ BufferPositionDescriptor (long offset , long size , int repeatCount ) {
403
+ this .offset = offset ;
404
+ this .size = size ;
405
+ this .repeatCount = repeatCount ;
406
+ }
407
+
408
+ @ VisibleForTesting
409
+ long getOffset () {
410
+ return offset ;
411
+ }
412
+
413
+ @ VisibleForTesting
414
+ long getSize () {
415
+ return size ;
416
+ }
417
+
418
+ @ VisibleForTesting
419
+ int getRepeatCount () {
420
+ return repeatCount ;
421
+ }
422
+ }
369
423
}
0 commit comments