Skip to content

Commit 13faa15

Browse files
authored
Added flags to mark whether a device has device descendants to optimize query like select xx from xxx.** (#17672) (#17802)
* flag- * Fix * Address device descendant flag review comments (cherry picked from commit a565a06)
1 parent 3c959c3 commit 13faa15

14 files changed

Lines changed: 908 additions & 37 deletions

File tree

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java

Lines changed: 110 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,59 @@ public synchronized boolean createSnapshot(File snapshotDir) {
174174
return store.createSnapshot(snapshotDir);
175175
}
176176

177+
private void applySubtreeMeasurementDelta(IMemMNode startNode, final long delta) {
178+
if (delta == 0 || startNode == null) {
179+
return;
180+
}
181+
IMemMNode current = startNode;
182+
while (current != null) {
183+
current.setSubtreeMeasurementCount(current.getSubtreeMeasurementCount() + delta);
184+
current = current.getParent();
185+
}
186+
}
187+
188+
private IDeviceMNode<IMemMNode> setToEntityAndUpdateFlags(final IMemMNode node) {
189+
final boolean wasDevice = node.isDevice();
190+
final IDeviceMNode<IMemMNode> deviceMNode = store.setToEntity(node);
191+
if (!wasDevice) {
192+
markAncestorsHavingDeviceDescendant(node);
193+
}
194+
return deviceMNode;
195+
}
196+
197+
private void markAncestorsHavingDeviceDescendant(final IMemMNode deviceNode) {
198+
IMemMNode current = deviceNode.getParent();
199+
while (current != null && !current.hasDeviceDescendant()) {
200+
current.setHasDeviceDescendant(true);
201+
current = current.getParent();
202+
}
203+
}
204+
205+
private boolean hasDeviceDescendantInChildren(final IMemMNode node) {
206+
try (final IMNodeIterator<IMemMNode> iterator = store.getChildrenIterator(node)) {
207+
while (iterator.hasNext()) {
208+
final IMemMNode child = iterator.next();
209+
if (child.isDevice() || child.hasDeviceDescendant()) {
210+
return true;
211+
}
212+
}
213+
return false;
214+
}
215+
}
216+
217+
private void refreshAncestorsHavingDeviceDescendant(IMemMNode startNode) {
218+
IMemMNode current = startNode;
219+
while (current != null) {
220+
current.setHasDeviceDescendant(hasDeviceDescendantInChildren(current));
221+
current = current.getParent();
222+
}
223+
}
224+
225+
private long getTemplateMeasurementCount(final int templateId) {
226+
final Template template = ClusterTemplateManager.getInstance().getTemplate(templateId);
227+
return template == null ? 0L : template.getMeasurementNumber();
228+
}
229+
177230
public static MTreeBelowSGMemoryImpl loadFromSnapshot(
178231
File snapshotDir,
179232
String storageGroupFullPath,
@@ -184,13 +237,16 @@ public static MTreeBelowSGMemoryImpl loadFromSnapshot(
184237
Function<IMeasurementMNode<IMemMNode>, Map<String, String>> tagGetter,
185238
Function<IMeasurementMNode<IMemMNode>, Map<String, String>> attributeGetter)
186239
throws IOException, IllegalPathException {
187-
return new MTreeBelowSGMemoryImpl(
188-
new PartialPath(storageGroupFullPath),
189-
MemMTreeStore.loadFromSnapshot(
190-
snapshotDir, measurementProcess, deviceProcess, regionStatistics, metric),
191-
tagGetter,
192-
attributeGetter,
193-
regionStatistics);
240+
final MTreeBelowSGMemoryImpl mtree =
241+
new MTreeBelowSGMemoryImpl(
242+
new PartialPath(storageGroupFullPath),
243+
MemMTreeStore.loadFromSnapshot(
244+
snapshotDir, measurementProcess, deviceProcess, regionStatistics, metric),
245+
tagGetter,
246+
attributeGetter,
247+
regionStatistics);
248+
mtree.rebuildSubtreeMeasurementCount();
249+
return mtree;
194250
}
195251

196252
// endregion
@@ -268,7 +324,7 @@ public IMeasurementMNode<IMemMNode> createTimeSeries(
268324
if (device.isDevice()) {
269325
entityMNode = device.getAsDeviceMNode();
270326
} else {
271-
entityMNode = store.setToEntity(device);
327+
entityMNode = setToEntityAndUpdateFlags(device);
272328
}
273329

274330
// create a non-aligned time series
@@ -290,6 +346,7 @@ public IMeasurementMNode<IMemMNode> createTimeSeries(
290346
entityMNode.addAlias(alias, measurementMNode);
291347
}
292348

349+
applySubtreeMeasurementDelta(measurementMNode.getAsMNode(), 1L);
293350
return measurementMNode;
294351
}
295352
}
@@ -360,7 +417,7 @@ public List<IMeasurementMNode<IMemMNode>> createAlignedTimeSeries(
360417
if (device.isDevice()) {
361418
entityMNode = device.getAsDeviceMNode();
362419
} else {
363-
entityMNode = store.setToEntity(device);
420+
entityMNode = setToEntityAndUpdateFlags(device);
364421
entityMNode.setAligned(true);
365422
}
366423

@@ -386,6 +443,7 @@ public List<IMeasurementMNode<IMemMNode>> createAlignedTimeSeries(
386443
if (aliasList != null && aliasList.get(i) != null) {
387444
entityMNode.addAlias(aliasList.get(i), measurementMNode);
388445
}
446+
applySubtreeMeasurementDelta(measurementMNode.getAsMNode(), 1L);
389447
measurementMNodeList.add(measurementMNode);
390448
}
391449
return measurementMNodeList;
@@ -539,6 +597,7 @@ public IMeasurementMNode<IMemMNode> deleteTimeseries(PartialPath path) throws Me
539597
if (deletedNode.getAlias() != null) {
540598
parent.getAsDeviceMNode().deleteAliasChild(deletedNode.getAlias());
541599
}
600+
applySubtreeMeasurementDelta(parent, -1L);
542601
}
543602
deleteEmptyInternalMNode(parent.getAsDeviceMNode());
544603
return deletedNode;
@@ -551,14 +610,15 @@ public void deleteEmptyInternalMNode(IDeviceMNode<IMemMNode> entityMNode) {
551610
boolean hasMeasurement = false;
552611
boolean hasNonViewMeasurement = false;
553612
IMemMNode child;
554-
IMNodeIterator<IMemMNode> iterator = store.getChildrenIterator(curNode);
555-
while (iterator.hasNext()) {
556-
child = iterator.next();
557-
if (child.isMeasurement()) {
558-
hasMeasurement = true;
559-
if (!child.getAsMeasurementMNode().isLogicalView()) {
560-
hasNonViewMeasurement = true;
561-
break;
613+
try (final IMNodeIterator<IMemMNode> iterator = store.getChildrenIterator(curNode)) {
614+
while (iterator.hasNext()) {
615+
child = iterator.next();
616+
if (child.isMeasurement()) {
617+
hasMeasurement = true;
618+
if (!child.getAsMeasurementMNode().isLogicalView()) {
619+
hasNonViewMeasurement = true;
620+
break;
621+
}
562622
}
563623
}
564624
}
@@ -567,6 +627,7 @@ public void deleteEmptyInternalMNode(IDeviceMNode<IMemMNode> entityMNode) {
567627
synchronized (this) {
568628
curNode = store.setToInternal(entityMNode);
569629
}
630+
refreshAncestorsHavingDeviceDescendant(curNode.getParent());
570631
} else if (!hasNonViewMeasurement) {
571632
// has some measurement but they are all logical view
572633
entityMNode.setAligned(null);
@@ -889,7 +950,7 @@ public void activateTemplate(PartialPath activatePath, Template template)
889950
if (cur.isDevice()) {
890951
entityMNode = cur.getAsDeviceMNode();
891952
} else {
892-
entityMNode = store.setToEntity(cur);
953+
entityMNode = setToEntityAndUpdateFlags(cur);
893954
}
894955
}
895956

@@ -907,6 +968,7 @@ public void activateTemplate(PartialPath activatePath, Template template)
907968
entityMNode.setUseTemplate(true);
908969
entityMNode.setSchemaTemplateId(template.getId());
909970
regionStatistics.activateTemplate(template.getId());
971+
applySubtreeMeasurementDelta(entityMNode.getAsMNode(), (long) template.getMeasurementNumber());
910972
}
911973

912974
public Map<PartialPath, List<Integer>> constructSchemaBlackListWithTemplate(
@@ -968,6 +1030,8 @@ protected void updateEntity(IDeviceMNode<IMemMNode> node) {
9681030
resultTemplateSetInfo.put(
9691031
node.getPartialPath(), Collections.singletonList(node.getSchemaTemplateId()));
9701032
regionStatistics.deactivateTemplate(node.getSchemaTemplateId());
1033+
applySubtreeMeasurementDelta(
1034+
node.getAsMNode(), -getTemplateMeasurementCount(node.getSchemaTemplateId()));
9711035
node.deactivateTemplate();
9721036
deleteEmptyInternalMNode(node);
9731037
}
@@ -991,7 +1055,7 @@ public void activateTemplateWithoutCheck(
9911055
if (cur.isDevice()) {
9921056
entityMNode = cur.getAsDeviceMNode();
9931057
} else {
994-
entityMNode = store.setToEntity(cur);
1058+
entityMNode = setToEntityAndUpdateFlags(cur);
9951059
}
9961060

9971061
if (!entityMNode.isAligned()) {
@@ -1000,6 +1064,7 @@ public void activateTemplateWithoutCheck(
10001064
entityMNode.setUseTemplate(true);
10011065
entityMNode.setSchemaTemplateId(templateId);
10021066
regionStatistics.activateTemplate(templateId);
1067+
applySubtreeMeasurementDelta(entityMNode.getAsMNode(), getTemplateMeasurementCount(templateId));
10031068
}
10041069

10051070
public long countPathsUsingTemplate(PartialPath pathPattern, int templateId)
@@ -1011,6 +1076,30 @@ public long countPathsUsingTemplate(PartialPath pathPattern, int templateId)
10111076
}
10121077
}
10131078

1079+
public void rebuildSubtreeMeasurementCount() {
1080+
rebuildSubtreeMeasurementCountFromNode(rootNode);
1081+
}
1082+
1083+
private long rebuildSubtreeMeasurementCountFromNode(final IMemMNode node) {
1084+
long count = node.isMeasurement() ? 1L : 0L;
1085+
boolean hasDeviceDescendant = false;
1086+
try (final IMNodeIterator<IMemMNode> iterator = store.getChildrenIterator(node)) {
1087+
while (iterator.hasNext()) {
1088+
final IMemMNode child = iterator.next();
1089+
count += rebuildSubtreeMeasurementCountFromNode(child);
1090+
if (child.isDevice() || child.hasDeviceDescendant()) {
1091+
hasDeviceDescendant = true;
1092+
}
1093+
}
1094+
}
1095+
if (node.isDevice() && node.getAsDeviceMNode().isUseTemplate()) {
1096+
count += getTemplateMeasurementCount(node.getAsDeviceMNode().getSchemaTemplateId());
1097+
}
1098+
node.setSubtreeMeasurementCount(count);
1099+
node.setHasDeviceDescendant(hasDeviceDescendant);
1100+
return count;
1101+
}
1102+
10141103
// endregion
10151104

10161105
// region Interfaces for schema reader
@@ -1278,7 +1367,7 @@ public IMeasurementMNode<IMemMNode> createLogicalView(
12781367
if (device.isDevice()) {
12791368
entityMNode = device.getAsDeviceMNode();
12801369
} else {
1281-
entityMNode = store.setToEntity(device);
1370+
entityMNode = setToEntityAndUpdateFlags(device);
12821371
// this parent has no measurement before. The leafName is his first child who is a logical
12831372
// view.
12841373
entityMNode.setAligned(null);
@@ -1287,6 +1376,7 @@ public IMeasurementMNode<IMemMNode> createLogicalView(
12871376
measurementMNode.setParent(entityMNode.getAsMNode());
12881377
store.addChild(entityMNode.getAsMNode(), leafName, measurementMNode.getAsMNode());
12891378

1379+
applySubtreeMeasurementDelta(measurementMNode.getAsMNode(), 1L);
12901380
return measurementMNode;
12911381
}
12921382
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/IMemMNode.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,33 @@
1919
package org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode;
2020

2121
import org.apache.iotdb.commons.schema.node.IMNode;
22+
import org.apache.iotdb.db.schemaengine.schemaregion.mtree.impl.mem.mnode.basic.BasicMNode;
2223

23-
public interface IMemMNode extends IMNode<IMemMNode> {}
24+
public interface IMemMNode extends IMNode<IMemMNode> {
25+
26+
BasicMNode getBasicMNode();
27+
28+
/**
29+
* The count of measurement nodes contained in the subtree rooted at this node. The counter is
30+
* maintained in memory only.
31+
*/
32+
default long getSubtreeMeasurementCount() {
33+
return getBasicMNode().getSubtreeMeasurementCount();
34+
}
35+
36+
default void setSubtreeMeasurementCount(final long subtreeMeasurementCount) {
37+
getBasicMNode().setSubtreeMeasurementCount(subtreeMeasurementCount);
38+
}
39+
40+
/**
41+
* Whether there is any device node in the subtree rooted at this node, excluding the node itself.
42+
* This flag is maintained in memory only.
43+
*/
44+
default boolean hasDeviceDescendant() {
45+
return getBasicMNode().hasDeviceDescendant();
46+
}
47+
48+
default void setHasDeviceDescendant(final boolean hasDeviceDescendant) {
49+
getBasicMNode().setHasDeviceDescendant(hasDeviceDescendant);
50+
}
51+
}

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/mnode/basic/BasicMNode.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ public class BasicMNode implements IMemMNode {
4646
private IMemMNode parent;
4747
private final BasicMNodeInfo basicMNodeInfo;
4848

49+
/** Cached count of measurements in this node's subtree, rebuilt on restart. */
50+
private long subtreeMeasurementCount = 0L;
51+
52+
/** Cached flag showing whether there is any device in the subtree below this node. */
53+
private boolean hasDeviceDescendant = false;
54+
4955
/** from root to this node, only be set when used once for InternalMNode */
5056
private String fullPath;
5157

@@ -55,6 +61,11 @@ public BasicMNode(IMemMNode parent, String name) {
5561
this.basicMNodeInfo = new BasicMNodeInfo(name);
5662
}
5763

64+
@Override
65+
public BasicMNode getBasicMNode() {
66+
return this;
67+
}
68+
5869
@Override
5970
public String getName() {
6071
return basicMNodeInfo.getName();
@@ -98,6 +109,25 @@ public void setFullPath(String fullPath) {
98109
this.fullPath = fullPath;
99110
}
100111

112+
public long getSubtreeMeasurementCount() {
113+
return subtreeMeasurementCount;
114+
}
115+
116+
@Override
117+
public void setSubtreeMeasurementCount(final long subtreeMeasurementCount) {
118+
this.subtreeMeasurementCount = subtreeMeasurementCount;
119+
}
120+
121+
@Override
122+
public boolean hasDeviceDescendant() {
123+
return hasDeviceDescendant;
124+
}
125+
126+
@Override
127+
public void setHasDeviceDescendant(final boolean hasDeviceDescendant) {
128+
this.hasDeviceDescendant = hasDeviceDescendant;
129+
}
130+
101131
@Override
102132
public PartialPath getPartialPath() {
103133
List<String> detachedPath = new ArrayList<>();
@@ -224,6 +254,8 @@ public <R, C> R accept(MNodeVisitor<R, C> visitor, C context) {
224254
* <li>basicMNodeInfo reference, 8B
225255
* <li>parent reference, 8B
226256
* <li>fullPath reference, 8B
257+
* <li>subtreeMeasurementCount, 8B
258+
* <li>hasDeviceDescendant, 1B
227259
* </ol>
228260
* <li>MapEntry in parent
229261
* <ol>
@@ -235,7 +267,7 @@ public <R, C> R accept(MNodeVisitor<R, C> visitor, C context) {
235267
*/
236268
@Override
237269
public int estimateSize() {
238-
return 8 + 8 + 8 + 8 + 8 + 8 + 28 + basicMNodeInfo.estimateSize();
270+
return 8 + 8 + 8 + 8 + 8 + 1 + 8 + 8 + 28 + basicMNodeInfo.estimateSize();
239271
}
240272

241273
@Override

0 commit comments

Comments
 (0)