![JAR search and dependency download from the Maven repository](/logo.png)
org.dinky.shaded.paimon.utils.ParallelExecution Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dinky.shaded.paimon.utils;
import org.dinky.shaded.paimon.data.RandomAccessInputView;
import org.dinky.shaded.paimon.data.SimpleCollectingOutputView;
import org.dinky.shaded.paimon.data.serializer.Serializer;
import org.dinky.shaded.paimon.memory.ArraySegmentPool;
import org.dinky.shaded.paimon.memory.MemorySegment;
import org.dinky.shaded.paimon.reader.RecordReader;
import javax.annotation.Nullable;
import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Supplier;
/**
* A class to help parallel execution.
*
* @param Record Type.
* @param Extra message of one {@link RecordReader}.
*/
public class ParallelExecution implements Closeable {
private final Serializer serializer;
private final BlockingQueue idlePages;
private final BlockingQueue> results;
private final ExecutorService executorService;
private final AtomicReference exception;
private final CountDownLatch latch;
public ParallelExecution(
Serializer serializer,
int pageSize,
int parallelism,
List, E>>> readers) {
this.serializer = serializer;
int totalPages = parallelism * 2;
this.idlePages = new ArrayBlockingQueue<>(totalPages);
for (int i = 0; i < totalPages; i++) {
idlePages.add(MemorySegment.allocateHeapMemory(pageSize));
}
this.executorService =
new ThreadPoolExecutor(
parallelism,
parallelism,
1,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new ExecutorThreadFactory(Thread.currentThread().getName() + "-parallel"));
this.results = new LinkedBlockingQueue<>();
this.exception = new AtomicReference<>();
this.latch = new CountDownLatch(readers.size());
for (Supplier, E>> readerSupplier : readers) {
Serializer duplicate = this.serializer.duplicate();
executorService.submit(() -> asyncRead(readerSupplier, duplicate));
}
}
@Nullable
public ParallelBatch take() throws InterruptedException, IOException {
ParallelBatch element;
do {
if (latch.getCount() == 0 && results.isEmpty()) {
return null;
}
element = results.poll(2, TimeUnit.SECONDS);
if (exception.get() != null) {
throw new IOException(exception.get());
}
} while (element == null);
return element;
}
private void asyncRead(
Supplier, E>> readerSupplier, Serializer serializer) {
Pair, E> pair = readerSupplier.get();
try (CloseableIterator iterator = pair.getLeft().toCloseableIterator()) {
int count = 0;
SimpleCollectingOutputView outputView = null;
while (iterator.hasNext()) {
T next = iterator.next();
while (true) {
if (outputView == null) {
outputView = newOutputView();
count = 0;
}
try {
serializer.serialize(next, outputView);
count++;
break;
} catch (EOFException e) {
sendToResults(outputView, count, pair.getRight());
outputView = null;
}
}
}
if (outputView != null) {
sendToResults(outputView, count, pair.getRight());
}
latch.countDown();
} catch (Throwable e) {
this.exception.set(e);
}
}
private SimpleCollectingOutputView newOutputView() throws InterruptedException {
MemorySegment page = idlePages.take();
return new SimpleCollectingOutputView(
new ArraySegmentPool(Collections.singletonList(page)), page.size());
}
private void sendToResults(SimpleCollectingOutputView outputView, int count, E extraMessage) {
results.add(iterator(outputView.getCurrentSegment(), count, extraMessage));
}
@Override
public void close() throws IOException {
this.executorService.shutdownNow();
}
private ParallelBatch iterator(MemorySegment page, int numRecords, E extraMessage) {
RandomAccessInputView inputView =
new RandomAccessInputView(
new ArrayList<>(Collections.singletonList(page)), page.size());
return new ParallelBatch() {
int numReturn = 0;
@Nullable
@Override
public T next() throws IOException {
if (numReturn >= numRecords) {
return null;
}
numReturn++;
return serializer.deserialize(inputView);
}
@Override
public void releaseBatch() {
idlePages.add(page);
}
@Override
public E extraMesage() {
return extraMessage;
}
};
}
/** A batch provides next and extra message. */
public interface ParallelBatch {
@Nullable
T next() throws IOException;
void releaseBatch();
E extraMesage();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy