Skip to content

Commit fcb2ab3

Browse files
authored
Pipe: switch to IdentityHashMap backed set to avoid infinite loop in table tsfile builder (apache#15371)
1 parent 3f96ada commit fcb2ab3

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/util/builder/PipeTableModeTsFileBuilder.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,12 @@
3636
import java.io.File;
3737
import java.io.IOException;
3838
import java.util.ArrayList;
39+
import java.util.Collections;
3940
import java.util.Comparator;
4041
import java.util.HashMap;
4142
import java.util.HashSet;
43+
import java.util.IdentityHashMap;
4244
import java.util.Iterator;
43-
import java.util.LinkedHashSet;
4445
import java.util.LinkedList;
4546
import java.util.List;
4647
import java.util.Map;
@@ -76,10 +77,7 @@ public List<Pair<String, File>> convertTabletToTsFileWithDBInfo() throws IOExcep
7677
}
7778
final List<Pair<String, File>> pairList = new ArrayList<>();
7879
for (Map.Entry<String, List<Tablet>> entry : dataBase2TabletList.entrySet()) {
79-
final LinkedHashSet<LinkedList<Pair<Tablet, List<Pair<IDeviceID, Integer>>>>> linkedHashSet =
80-
new LinkedHashSet<>();
81-
pairList.addAll(
82-
writeTableModelTabletsToTsFiles(entry.getValue(), entry.getKey(), linkedHashSet));
80+
pairList.addAll(writeTableModelTabletsToTsFiles(entry.getValue(), entry.getKey()));
8381
}
8482
return pairList;
8583
}
@@ -103,10 +101,7 @@ public synchronized void close() {
103101

104102
private <T extends Pair<Tablet, List<Pair<IDeviceID, Integer>>>>
105103
List<Pair<String, File>> writeTableModelTabletsToTsFiles(
106-
final List<Tablet> tabletList,
107-
final String dataBase,
108-
LinkedHashSet<LinkedList<T>> linkedHashSet)
109-
throws IOException {
104+
final List<Tablet> tabletList, final String dataBase) throws IOException {
110105

111106
final Map<String, List<T>> tableName2Tablets = new HashMap<>();
112107

@@ -130,24 +125,29 @@ List<Pair<String, File>> writeTableModelTabletsToTsFiles(
130125
});
131126
}
132127

128+
// Create a Set backed by an IdentityHashMap, so elements are compared by reference (==) rather
129+
// than equals()/hashCode()
130+
final Set<LinkedList<T>> device2TabletsLinkedList =
131+
Collections.newSetFromMap(new IdentityHashMap<>());
132+
133133
// Sort the tables by table name
134134
tableName2Tablets.entrySet().stream()
135135
.sorted(Map.Entry.comparingByKey(Comparator.naturalOrder()))
136-
.forEach(entry -> linkedHashSet.add(new LinkedList<>(entry.getValue())));
136+
.forEach(entry -> device2TabletsLinkedList.add(new LinkedList<>(entry.getValue())));
137137

138138
// Help GC
139139
tableName2Tablets.clear();
140140

141141
final List<Pair<String, File>> sealedFiles = new ArrayList<>();
142142

143143
// Try making the tsfile size as large as possible
144-
while (!linkedHashSet.isEmpty()) {
144+
while (!device2TabletsLinkedList.isEmpty()) {
145145
if (Objects.isNull(fileWriter)) {
146146
fileWriter = new TsFileWriter(createFile());
147147
}
148148

149149
try {
150-
tryBestToWriteTabletsIntoOneFile(linkedHashSet);
150+
tryBestToWriteTabletsIntoOneFile(device2TabletsLinkedList);
151151
} catch (final Exception e) {
152152
LOGGER.warn(
153153
"Batch id = {}: Failed to write tablets into tsfile, because {}",
@@ -202,8 +202,8 @@ List<Pair<String, File>> writeTableModelTabletsToTsFiles(
202202
}
203203

204204
private <T extends Pair<Tablet, List<Pair<IDeviceID, Integer>>>>
205-
void tryBestToWriteTabletsIntoOneFile(
206-
final LinkedHashSet<LinkedList<T>> device2TabletsLinkedList) throws IOException {
205+
void tryBestToWriteTabletsIntoOneFile(final Set<LinkedList<T>> device2TabletsLinkedList)
206+
throws IOException {
207207
final Iterator<LinkedList<T>> iterator = device2TabletsLinkedList.iterator();
208208

209209
while (iterator.hasNext()) {
@@ -237,6 +237,8 @@ void tryBestToWriteTabletsIntoOneFile(
237237
}
238238

239239
tabletsToWrite.add(pair);
240+
// NOTE: mutating a LinkedList that lives inside a Set violates the contract that the
241+
// element’s hashCode must remain stable while it’s in the set
240242
tablets.pollFirst();
241243
continue;
242244
}

0 commit comments

Comments
 (0)