You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by xi...@apache.org on 2023/01/31 01:47:45 UTC
[iotdb] branch rel/1.0 updated: [To rel/1.0][IOTDB-4684]Devices with the same name but different alignment properties are compacted into the wrong alignment property (#8838)
This is an automated email from the ASF dual-hosted git repository.
xingtanzjr pushed a commit to branch rel/1.0
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rel/1.0 by this push:
new ad1d905219 [To rel/1.0][IOTDB-4684]Devices with the same name but different alignment properties are compacted into the wrong alignment property (#8838)
ad1d905219 is described below
commit ad1d9052195a85ba671c82b96c16f50552beb414
Author: 周沛辰 <45...@users.noreply.github.com>
AuthorDate: Tue Jan 31 09:47:40 2023 +0800
[To rel/1.0][IOTDB-4684]Devices with the same name but different alignment properties are compacted into the wrong alignment property (#8838)
---
.../execute/utils/MultiTsFileDeviceIterator.java | 60 +++++++-----
.../utils/MultiTsFileDeviceIteratorTest.java | 105 +++++++++++++++++++++
.../iotdb/tsfile/read/TsFileDeviceIterator.java | 2 +-
3 files changed, 144 insertions(+), 23 deletions(-)
diff --git a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/utils/MultiTsFileDeviceIterator.java b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/utils/MultiTsFileDeviceIterator.java
index 54467257ce..88acd5b8d6 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/utils/MultiTsFileDeviceIterator.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/compaction/execute/utils/MultiTsFileDeviceIterator.java
@@ -47,7 +47,12 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
public class MultiTsFileDeviceIterator implements AutoCloseable {
- private final List<TsFileResource> tsFileResources;
+
+ // sort from the newest to the oldest by version (Used by FastPerformer and ReadPointPerformer)
+ private final List<TsFileResource> tsFileResourcesSortedByDesc;
+
+ // sort from the oldest to the newest by version (Used by ReadChunkPerformer)
+ private List<TsFileResource> tsFileResourcesSortedByAsc;
private Map<TsFileResource, TsFileSequenceReader> readerMap = new HashMap<>();
private final Map<TsFileResource, TsFileDeviceIterator> deviceIteratorMap = new HashMap<>();
private final Map<TsFileResource, List<Modification>> modificationCache = new HashMap<>();
@@ -55,11 +60,14 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
/** Used for inner space compaction. */
public MultiTsFileDeviceIterator(List<TsFileResource> tsFileResources) throws IOException {
- this.tsFileResources = new ArrayList<>(tsFileResources);
+ this.tsFileResourcesSortedByDesc = new ArrayList<>(tsFileResources);
+ this.tsFileResourcesSortedByAsc = new ArrayList<>(tsFileResources);
// sort the files from the oldest to the newest
- Collections.sort(this.tsFileResources, TsFileResource::compareFileName);
+ Collections.sort(this.tsFileResourcesSortedByAsc, TsFileResource::compareFileName);
+ // sort the files from the newest to the oldest
+ Collections.sort(this.tsFileResourcesSortedByDesc, TsFileResource::compareFileNameByDesc);
try {
- for (TsFileResource tsFileResource : this.tsFileResources) {
+ for (TsFileResource tsFileResource : this.tsFileResourcesSortedByDesc) {
TsFileSequenceReader reader = new TsFileSequenceReader(tsFileResource.getTsFilePath());
readerMap.put(tsFileResource, reader);
deviceIteratorMap.put(tsFileResource, reader.getAllDevicesIteratorWithIsAligned());
@@ -77,11 +85,11 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
/** Used for cross space compaction with read point performer. */
public MultiTsFileDeviceIterator(
List<TsFileResource> seqResources, List<TsFileResource> unseqResources) throws IOException {
- this.tsFileResources = new ArrayList<>(seqResources);
- tsFileResources.addAll(unseqResources);
+ this.tsFileResourcesSortedByDesc = new ArrayList<>(seqResources);
+ tsFileResourcesSortedByDesc.addAll(unseqResources);
// sort the files from the newest to the oldest
- Collections.sort(this.tsFileResources, TsFileResource::compareFileNameByDesc);
- for (TsFileResource tsFileResource : tsFileResources) {
+ Collections.sort(this.tsFileResourcesSortedByDesc, TsFileResource::compareFileNameByDesc);
+ for (TsFileResource tsFileResource : tsFileResourcesSortedByDesc) {
TsFileSequenceReader reader =
FileReaderManager.getInstance().get(tsFileResource.getTsFilePath(), true);
readerMap.put(tsFileResource, reader);
@@ -95,12 +103,12 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
List<TsFileResource> unseqResources,
Map<TsFileResource, TsFileSequenceReader> readerMap)
throws IOException {
- this.tsFileResources = new ArrayList<>(seqResources);
- tsFileResources.addAll(unseqResources);
+ this.tsFileResourcesSortedByDesc = new ArrayList<>(seqResources);
+ tsFileResourcesSortedByDesc.addAll(unseqResources);
// sort tsfiles from the newest to the oldest
- Collections.sort(this.tsFileResources, TsFileResource::compareFileNameByDesc);
+ Collections.sort(this.tsFileResourcesSortedByDesc, TsFileResource::compareFileNameByDesc);
this.readerMap = readerMap;
- for (TsFileResource tsFileResource : tsFileResources) {
+ for (TsFileResource tsFileResource : tsFileResourcesSortedByDesc) {
TsFileSequenceReader reader = new TsFileSequenceReader(tsFileResource.getTsFilePath());
readerMap.put(tsFileResource, reader);
deviceIteratorMap.put(tsFileResource, reader.getAllDevicesIteratorWithIsAligned());
@@ -113,7 +121,8 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
hasNext =
hasNext
|| iterator.hasNext()
- || (iterator.current() != null && !iterator.current().equals(currentDevice));
+ || (iterator.current() != null
+ && !iterator.current().left.equals(currentDevice.left));
}
return hasNext;
}
@@ -126,9 +135,15 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
public Pair<String, Boolean> nextDevice() {
List<TsFileResource> toBeRemovedResources = new LinkedList<>();
Pair<String, Boolean> minDevice = null;
- for (TsFileResource resource : deviceIteratorMap.keySet()) {
+ // get the device from source files sorted from the newest to the oldest by version
+ for (TsFileResource resource : tsFileResourcesSortedByDesc) {
+ if (!deviceIteratorMap.containsKey(resource)) {
+ continue;
+ }
TsFileDeviceIterator deviceIterator = deviceIteratorMap.get(resource);
- if (deviceIterator.current() == null || deviceIterator.current().equals(currentDevice)) {
+ if (deviceIterator.current() == null
+ || deviceIterator.current().left.equals(currentDevice.left)) {
+ // if current file has same device with current device, then get its next device
if (deviceIterator.hasNext()) {
deviceIterator.next();
} else {
@@ -139,6 +154,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
}
}
if (minDevice == null || minDevice.left.compareTo(deviceIterator.current().left) > 0) {
+ // get the device that is minimal in lexicographical order according to the all files
minDevice = deviceIterator.current();
}
}
@@ -158,7 +174,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
public Map<String, MeasurementSchema> getAllSchemasOfCurrentDevice() throws IOException {
Map<String, MeasurementSchema> schemaMap = new ConcurrentHashMap<>();
// get schemas from the newest file to the oldest file
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByDesc) {
if (!deviceIteratorMap.containsKey(resource)
|| !deviceIteratorMap.get(resource).current().equals(currentDevice)) {
// if this tsfile has no more device or next device is not equals to the current device,
@@ -195,7 +211,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
getTimeseriesMetadataOffsetOfCurrentDevice() throws IOException {
Map<String, Map<TsFileResource, Pair<Long, Long>>> timeseriesMetadataOffsetMap =
new HashMap<>();
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByDesc) {
if (!deviceIteratorMap.containsKey(resource)
|| !deviceIteratorMap.get(resource).current().equals(currentDevice)) {
// if this tsfile has no more device or next device is not equals to the current device,
@@ -232,7 +248,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
getTimeseriesSchemaAndMetadataOffsetOfCurrentDevice() throws IOException {
Map<String, Pair<MeasurementSchema, Map<TsFileResource, Pair<Long, Long>>>>
timeseriesMetadataOffsetMap = new HashMap<>();
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByDesc) {
if (!deviceIteratorMap.containsKey(resource)
|| !deviceIteratorMap.get(resource).current().equals(currentDevice)) {
// if this tsfile has no more device or next device is not equals to the current device,
@@ -294,7 +310,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
LinkedList<Pair<TsFileSequenceReader, List<AlignedChunkMetadata>>> readerAndChunkMetadataList =
new LinkedList<>();
- for (TsFileResource tsFileResource : tsFileResources) {
+ for (TsFileResource tsFileResource : tsFileResourcesSortedByAsc) {
if (!deviceIteratorMap.containsKey(tsFileResource)) {
continue;
}
@@ -382,7 +398,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
this.device = device;
if (needDeserializeTimeseries) {
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByAsc) {
TsFileSequenceReader reader = readerMap.get(resource);
chunkMetadataIteratorMap.put(
resource, reader.getMeasurementChunkMetadataListMapIterator(device));
@@ -406,7 +422,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
private boolean collectSeries() {
String lastSeries = null;
List<String> tempCollectedSeries = new ArrayList<>();
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByAsc) {
TsFileSequenceReader reader = readerMap.get(resource);
Map<String, List<ChunkMetadata>> chunkMetadataListMap = chunkMetadataCacheMap.get(reader);
if (chunkMetadataListMap.size() == 0) {
@@ -489,7 +505,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable {
readerAndChunkMetadataForThisSeries = new LinkedList<>();
PartialPath path = new PartialPath(device, currentCompactingSeries);
- for (TsFileResource resource : tsFileResources) {
+ for (TsFileResource resource : tsFileResourcesSortedByAsc) {
TsFileSequenceReader reader = readerMap.get(resource);
Map<String, List<ChunkMetadata>> chunkMetadataListMap = chunkMetadataCacheMap.get(reader);
diff --git a/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/MultiTsFileDeviceIteratorTest.java b/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/MultiTsFileDeviceIteratorTest.java
index b8dc2a574c..9ab358f6e4 100644
--- a/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/MultiTsFileDeviceIteratorTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/engine/compaction/utils/MultiTsFileDeviceIteratorTest.java
@@ -39,6 +39,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_SEPARATOR;
+
public class MultiTsFileDeviceIteratorTest extends AbstractCompactionTest {
@Before
@@ -192,4 +194,107 @@ public class MultiTsFileDeviceIteratorTest extends AbstractCompactionTest {
}
Assert.assertEquals(30, deviceNum);
}
+
+ /**
+ * Create device with nonAligned property. Deleted it and create new device with same deviceID but
+ * aligned property. Check whether the deviceID and its property can be obtained correctly.
+ */
+ @Test
+ public void getDeletedDevicesWithSameNameFromDifferentFilesWithFourLayersInNodeTreeTest()
+ throws MetadataException, IOException, WriteProcessException {
+ TSFileDescriptor.getInstance().getConfig().setMaxDegreeOfIndexNode(3);
+ int oldAlignedDeviceOffset = TsFileGeneratorUtils.alignDeviceOffset;
+ TsFileGeneratorUtils.alignDeviceOffset = 0;
+ // create nonAligned device
+ registerTimeseriesInMManger(30, 5, false);
+ createFiles(3, 10, 5, 100, 0, 0, 50, 50, false, true);
+ createFiles(4, 5, 5, 100, 1000, 0, 50, 50, false, true);
+
+ // generate mods file, delete devices
+ List<String> seriesPaths = new ArrayList<>();
+ for (int i = 0; i < 15; i++) {
+ for (int j = 0; j < 5; j++) {
+ seriesPaths.add(COMPACTION_TEST_SG + PATH_SEPARATOR + "d" + i + PATH_SEPARATOR + "s" + j);
+ }
+ }
+ generateModsFile(seriesPaths, seqResources, Long.MIN_VALUE, Long.MAX_VALUE);
+ generateModsFile(seriesPaths, unseqResources, Long.MIN_VALUE, Long.MAX_VALUE);
+ deleteTimeseriesInMManager(seriesPaths);
+
+ // create aligned device with the same deviceID
+ createFiles(2, 7, 5, 100, 1600, 1600, 50, 50, true, true);
+ createFiles(3, 30, 3, 100, 1000, 0, 50, 50, true, false);
+
+ // sort the deviceId in lexicographical order from small to large
+ List<String> deviceIds = new ArrayList<>();
+ for (int i = 0; i < 30; i++) {
+ deviceIds.add("root.testsg.d" + (i + TsFileGeneratorUtils.getAlignDeviceOffset()));
+ }
+ deviceIds.sort(String::compareTo);
+
+ int deviceNum = 0;
+ try (MultiTsFileDeviceIterator multiTsFileDeviceIterator =
+ new MultiTsFileDeviceIterator(seqResources, unseqResources)) {
+ while (multiTsFileDeviceIterator.hasNextDevice()) {
+ Pair<String, Boolean> deviceInfo = multiTsFileDeviceIterator.nextDevice();
+ Assert.assertEquals(deviceIds.get(deviceNum), deviceInfo.left);
+ Assert.assertTrue(deviceInfo.right);
+ deviceNum++;
+ }
+ }
+ Assert.assertEquals(30, deviceNum);
+ TsFileGeneratorUtils.alignDeviceOffset = oldAlignedDeviceOffset;
+ }
+
+ /**
+ * Create device with nonAligned property. Deleted it and create new device with same deviceID but
+ * aligned property. Check whether the deviceID and its property can be obtained correctly.
+ */
+ @Test
+ public void getDeletedDevicesWithSameNameFromSeqFilesWithFourLayersInNodeTreeTest()
+ throws MetadataException, IOException, WriteProcessException {
+ TSFileDescriptor.getInstance().getConfig().setMaxDegreeOfIndexNode(3);
+ int oldAlignedDeviceOffset = TsFileGeneratorUtils.alignDeviceOffset;
+ TsFileGeneratorUtils.alignDeviceOffset = 0;
+ registerTimeseriesInMManger(30, 5, false);
+ createFiles(3, 10, 5, 100, 0, 0, 50, 50, false, true);
+ createFiles(4, 30, 5, 100, 1000, 0, 50, 50, false, true);
+
+ // generate mods file, delete d0 ~ d14
+ List<String> seriesPaths = new ArrayList<>();
+ for (int i = 0; i < 15; i++) {
+ for (int j = 0; j < 5; j++) {
+ seriesPaths.add(COMPACTION_TEST_SG + PATH_SEPARATOR + "d" + i + PATH_SEPARATOR + "s" + j);
+ }
+ }
+ generateModsFile(seriesPaths, seqResources, Long.MIN_VALUE, Long.MAX_VALUE);
+ generateModsFile(seriesPaths, unseqResources, Long.MIN_VALUE, Long.MAX_VALUE);
+ deleteTimeseriesInMManager(seriesPaths);
+
+ createFiles(2, 10, 5, 100, 2000, 2000, 50, 50, true, true);
+
+ // sort the deviceId in lexicographical order from small to large
+ List<String> deviceIds = new ArrayList<>();
+ for (int i = 0; i < 30; i++) {
+ deviceIds.add("root.testsg.d" + (i + TsFileGeneratorUtils.getAlignDeviceOffset()));
+ }
+ deviceIds.sort(String::compareTo);
+
+ int deviceNum = 0;
+ try (MultiTsFileDeviceIterator multiTsFileDeviceIterator =
+ new MultiTsFileDeviceIterator(seqResources)) {
+ while (multiTsFileDeviceIterator.hasNextDevice()) {
+ Pair<String, Boolean> deviceInfo = multiTsFileDeviceIterator.nextDevice();
+ Assert.assertEquals(deviceIds.get(deviceNum), deviceInfo.left);
+ if (Integer.parseInt(deviceInfo.left.substring(13)) < 10) {
+ Assert.assertTrue(deviceInfo.right);
+ } else {
+ Assert.assertFalse(deviceInfo.right);
+ }
+ deviceNum++;
+ }
+ }
+ Assert.assertEquals(30, deviceNum);
+ TsFileGeneratorUtils.alignDeviceOffset = oldAlignedDeviceOffset;
+ }
}
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileDeviceIterator.java b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileDeviceIterator.java
index a487d55b2a..76609747c3 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileDeviceIterator.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/read/TsFileDeviceIterator.java
@@ -80,7 +80,7 @@ public class TsFileDeviceIterator implements Iterator<Pair<String, Boolean>> {
}
Pair<String, long[]> startEndPair = queue.remove();
try {
- // get the first measurment node of this device, to know if the device is alignd
+ // get the first measurement node of this device, to know if the device is aligned
this.measurementNode =
MetadataIndexNode.deserializeFrom(
reader.readData(startEndPair.right[0], startEndPair.right[1]));