Skip to content

Commit abb4893

Browse files
authored
[HUDI-2875] Make HoodieParquetWriter Thread safe and memory executor exit gracefully (#4264)
1 parent d794f4f commit abb4893

17 files changed

Lines changed: 121 additions & 12 deletions

File tree

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieConcatHandle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import org.apache.log4j.LogManager;
3636
import org.apache.log4j.Logger;
3737

38+
import javax.annotation.concurrent.NotThreadSafe;
39+
3840
import java.io.IOException;
3941
import java.util.Collections;
4042
import java.util.Iterator;
@@ -66,6 +68,7 @@
6668
* Users should ensure there are no duplicates when "insert" operation is used and if the respective config is enabled. So, above scenario should not
6769
* happen and every batch should have new records to be inserted. Above example is for illustration purposes only.
6870
*/
71+
@NotThreadSafe
6972
public class HoodieConcatHandle<T extends HoodieRecordPayload, I, K, O> extends HoodieMergeHandle<T, I, K, O> {
7073

7174
private static final Logger LOG = LogManager.getLogger(HoodieConcatHandle.class);

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieCreateHandle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,15 @@
4242
import org.apache.log4j.LogManager;
4343
import org.apache.log4j.Logger;
4444

45+
import javax.annotation.concurrent.NotThreadSafe;
46+
4547
import java.io.IOException;
4648
import java.util.Collections;
4749
import java.util.Iterator;
4850
import java.util.List;
4951
import java.util.Map;
5052

53+
@NotThreadSafe
5154
public class HoodieCreateHandle<T extends HoodieRecordPayload, I, K, O> extends HoodieWriteHandle<T, I, K, O> {
5255

5356
private static final Logger LOG = LogManager.getLogger(HoodieCreateHandle.class);

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieMergeHandle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
import org.apache.log4j.LogManager;
5555
import org.apache.log4j.Logger;
5656

57+
import javax.annotation.concurrent.NotThreadSafe;
58+
5759
import java.io.IOException;
5860
import java.util.Collections;
5961
import java.util.HashSet;
@@ -91,6 +93,7 @@
9193
*
9294
* </p>
9395
*/
96+
@NotThreadSafe
9497
public class HoodieMergeHandle<T extends HoodieRecordPayload, I, K, O> extends HoodieWriteHandle<T, I, K, O> {
9598

9699
private static final Logger LOG = LogManager.getLogger(HoodieMergeHandle.class);

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieSortedMergeHandle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
import org.apache.avro.generic.GenericRecord;
3434

35+
import javax.annotation.concurrent.NotThreadSafe;
36+
3537
import java.io.IOException;
3638
import java.util.Iterator;
3739
import java.util.List;
@@ -45,6 +47,7 @@
4547
* The implementation performs a merge-sort by comparing the key of the record being written to the list of
4648
* keys in newRecordKeys (sorted in-memory).
4749
*/
50+
@NotThreadSafe
4851
public class HoodieSortedMergeHandle<T extends HoodieRecordPayload, I, K, O> extends HoodieMergeHandle<T, I, K, O> {
4952

5053
private final Queue<String> newRecordKeysSorted = new PriorityQueue<>();

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/HoodieUnboundedCreateHandle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828
import org.apache.log4j.LogManager;
2929
import org.apache.log4j.Logger;
3030

31+
import javax.annotation.concurrent.NotThreadSafe;
32+
3133
/**
3234
* A HoodieCreateHandle which writes all data into a single file.
3335
* <p>
3436
* Please use this with caution. This can end up creating very large files if not used correctly.
3537
*/
38+
@NotThreadSafe
3639
public class HoodieUnboundedCreateHandle<T extends HoodieRecordPayload, I, K, O> extends HoodieCreateHandle<T, I, K, O> {
3740

3841
private static final Logger LOG = LogManager.getLogger(HoodieUnboundedCreateHandle.class);

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/io/storage/HoodieParquetWriter.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,18 @@
3030
import org.apache.parquet.hadoop.ParquetFileWriter;
3131
import org.apache.parquet.hadoop.ParquetWriter;
3232

33+
import javax.annotation.concurrent.NotThreadSafe;
34+
3335
import java.io.IOException;
3436
import java.util.concurrent.atomic.AtomicLong;
3537

3638
/**
3739
* HoodieParquetWriter extends the ParquetWriter to help limit the size of underlying file. Provides a way to check if
3840
* the current file can take more records with the <code>canWrite()</code>
41+
*
42+
* ATTENTION: HoodieParquetWriter is not thread safe and developer should take care of the order of write and close
3943
*/
44+
@NotThreadSafe
4045
public class HoodieParquetWriter<T extends HoodieRecordPayload, R extends IndexedRecord>
4146
extends ParquetWriter<IndexedRecord> implements HoodieFileWriter<R> {
4247

@@ -106,4 +111,9 @@ public void writeAvro(String key, IndexedRecord object) throws IOException {
106111
writeSupport.add(key);
107112
}
108113
}
114+
115+
@Override
116+
public void close() throws IOException {
117+
super.close();
118+
}
109119
}

hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/action/commit/HoodieMergeHelper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,16 @@ public void runMerge(HoodieTable<T, HoodieData<HoodieRecord<T>>, HoodieData<Hood
148148
} catch (Exception e) {
149149
throw new HoodieException(e);
150150
} finally {
151+
// HUDI-2875: mergeHandle is not thread safe, we should totally terminate record inputting
152+
// and executor firstly and then close mergeHandle.
151153
if (reader != null) {
152154
reader.close();
153155
}
154-
mergeHandle.close();
155156
if (null != wrapper) {
156157
wrapper.shutdownNow();
158+
wrapper.awaitTermination();
157159
}
160+
mergeHandle.close();
158161
}
159162
}
160163
}

hudi-client/hudi-flink-client/src/main/java/org/apache/hudi/execution/FlinkLazyInsertIterable.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ protected List<WriteStatus> computeNext() {
6666
} finally {
6767
if (null != bufferedIteratorExecutor) {
6868
bufferedIteratorExecutor.shutdownNow();
69+
bufferedIteratorExecutor.awaitTermination();
6970
}
7071
}
7172
}

hudi-client/hudi-flink-client/src/main/java/org/apache/hudi/table/action/commit/FlinkMergeHelper.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,16 @@ public void runMerge(HoodieTable<T, List<HoodieRecord<T>>, List<HoodieKey>, List
102102
} catch (Exception e) {
103103
throw new HoodieException(e);
104104
} finally {
105+
// HUDI-2875: mergeHandle is not thread safe, we should totally terminate record inputting
106+
// and executor firstly and then close mergeHandle.
105107
if (reader != null) {
106108
reader.close();
107109
}
108-
mergeHandle.close();
109110
if (null != wrapper) {
110111
wrapper.shutdownNow();
112+
wrapper.awaitTermination();
111113
}
114+
mergeHandle.close();
112115
}
113116
}
114117
}

hudi-client/hudi-java-client/src/main/java/org/apache/hudi/execution/JavaLazyInsertIterable.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ protected List<WriteStatus> computeNext() {
7474
} finally {
7575
if (null != bufferedIteratorExecutor) {
7676
bufferedIteratorExecutor.shutdownNow();
77+
bufferedIteratorExecutor.awaitTermination();
7778
}
7879
}
7980
}

0 commit comments

Comments
 (0)