2121
2222import org .apache .iotdb .commons .schema .table .column .TsTableColumnCategory ;
2323import org .apache .iotdb .db .queryengine .execution .MemoryEstimationHelper ;
24+ import org .apache .iotdb .db .queryengine .execution .fragment .DataNodeQueryContext ;
2425import org .apache .iotdb .db .queryengine .execution .operator .process .last .LastQueryUtil ;
2526import org .apache .iotdb .db .queryengine .execution .operator .source .relational .aggregation .LastAccumulator ;
2627import org .apache .iotdb .db .queryengine .execution .operator .source .relational .aggregation .LastByDescAccumulator ;
4445
4546import java .util .ArrayList ;
4647import java .util .List ;
48+ import java .util .Map ;
4749import java .util .Optional ;
4850import java .util .OptionalLong ;
4951import java .util .concurrent .TimeUnit ;
@@ -65,6 +67,7 @@ public class LastQueryAggTableScanOperator extends AbstractAggTableScanOperator
6567 private static final TableDeviceSchemaCache TABLE_DEVICE_SCHEMA_CACHE =
6668 TableDeviceSchemaCache .getInstance ();
6769
70+ private final QualifiedObjectName tableCompleteName ;
6871 private final String dbName ;
6972 private int outputDeviceIndex ;
7073 private DeviceEntry currentDeviceEntry ;
@@ -81,13 +84,18 @@ public class LastQueryAggTableScanOperator extends AbstractAggTableScanOperator
8184 // indicates the index of last(time) aggregation
8285 private int lastTimeAggregationIdx = -1 ;
8386
87+ private final Map <DeviceEntry , Integer > deviceCountMap ;
88+ private final DataNodeQueryContext dataNodeQueryContext ;
89+
8490 public LastQueryAggTableScanOperator (
8591 AbstractAggTableScanOperatorParameter parameter ,
8692 List <DeviceEntry > cachedDeviceEntries ,
8793 QualifiedObjectName qualifiedObjectName ,
8894 List <Integer > hitCachesIndexes ,
8995 List <Pair <OptionalLong , TsPrimitiveType []>> lastRowCacheResults ,
90- List <TimeValuePair []> lastValuesCacheResults ) {
96+ List <TimeValuePair []> lastValuesCacheResults ,
97+ Map <DeviceEntry , Integer > deviceCountMap ,
98+ DataNodeQueryContext dataNodeQueryContext ) {
9199
92100 super (parameter );
93101
@@ -101,6 +109,7 @@ public LastQueryAggTableScanOperator(
101109 this .hitCachesIndexes = hitCachesIndexes ;
102110 this .lastRowCacheResults = lastRowCacheResults ;
103111 this .lastValuesCacheResults = lastValuesCacheResults ;
112+ this .tableCompleteName = qualifiedObjectName ;
104113 this .dbName = qualifiedObjectName .getDatabaseName ();
105114
106115 this .operatorContext .recordSpecifiedInfo (
@@ -110,6 +119,8 @@ public LastQueryAggTableScanOperator(
110119 lastTimeAggregationIdx = i ;
111120 }
112121 }
122+ this .deviceCountMap = deviceCountMap ;
123+ this .dataNodeQueryContext = dataNodeQueryContext ;
113124 }
114125
115126 @ Override
@@ -518,28 +529,23 @@ private void updateLastCacheUseLastRowIfPossible() {
518529 case TIME :
519530 if (!hasSetLastTime ) {
520531 hasSetLastTime = true ;
532+ updateMeasurementList .add ("" );
521533 if (i == lastTimeAggregationIdx ) {
522534 LastDescAccumulator lastAccumulator =
523535 (LastDescAccumulator ) tableAggregator .getAccumulator ();
524536 if (lastAccumulator .hasInitResult ()) {
525- updateMeasurementList .add ("" );
526537 updateTimeValuePairList .add (
527538 new TimeValuePair (
528539 lastAccumulator .getMaxTime (),
529540 new TsPrimitiveType .TsLong (lastAccumulator .getMaxTime ())));
530541 } else {
531542 currentDeviceEntry = deviceEntries .get (currentDeviceIndex );
532- TABLE_DEVICE_SCHEMA_CACHE .updateLastCacheIfExists (
533- dbName ,
534- currentDeviceEntry .getDeviceID (),
535- new String [] {"" },
536- new TimeValuePair [] {EMPTY_TIME_VALUE_PAIR });
543+ updateTimeValuePairList .add (EMPTY_TIME_VALUE_PAIR );
537544 }
538545 } else {
539546 LastByDescAccumulator lastByAccumulator =
540547 (LastByDescAccumulator ) tableAggregator .getAccumulator ();
541548 if (lastByAccumulator .hasInitResult () && !lastByAccumulator .isXNull ()) {
542- updateMeasurementList .add ("" );
543549 updateTimeValuePairList .add (
544550 new TimeValuePair (
545551 lastByAccumulator .getLastTimeOfY (),
@@ -551,7 +557,7 @@ private void updateLastCacheUseLastRowIfPossible() {
551557 case FIELD :
552558 LastByDescAccumulator lastByAccumulator =
553559 (LastByDescAccumulator ) tableAggregator .getAccumulator ();
554- // only can update LastCache when last_by return non-null value
560+ updateMeasurementList . add ( schema . getName ());
555561 if (lastByAccumulator .hasInitResult () && !lastByAccumulator .isXNull ()) {
556562 long lastByTime = lastByAccumulator .getLastTimeOfY ();
557563
@@ -562,10 +568,11 @@ private void updateLastCacheUseLastRowIfPossible() {
562568 new TimeValuePair (lastByTime , new TsPrimitiveType .TsLong (lastByTime )));
563569 }
564570
565- updateMeasurementList .add (schema .getName ());
566571 updateTimeValuePairList .add (
567572 new TimeValuePair (
568573 lastByTime , cloneTsPrimitiveType (lastByAccumulator .getXResult ())));
574+ } else {
575+ updateTimeValuePairList .add (EMPTY_TIME_VALUE_PAIR );
569576 }
570577 break ;
571578 default :
@@ -575,17 +582,7 @@ private void updateLastCacheUseLastRowIfPossible() {
575582 channel += tableAggregator .getChannelCount ();
576583 }
577584
578- if (!updateMeasurementList .isEmpty ()) {
579- String [] updateMeasurementArray = updateMeasurementList .toArray (new String [0 ]);
580- TimeValuePair [] updateTimeValuePairArray =
581- updateTimeValuePairList .toArray (new TimeValuePair [0 ]);
582- currentDeviceEntry = deviceEntries .get (currentDeviceIndex );
583- TABLE_DEVICE_SCHEMA_CACHE .updateLastCacheIfExists (
584- dbName ,
585- currentDeviceEntry .getDeviceID (),
586- updateMeasurementArray ,
587- updateTimeValuePairArray );
588- }
585+ checkIfUpdated (updateMeasurementList , updateTimeValuePairList );
589586 }
590587
591588 private void updateLastCacheUseLastValuesIfPossible () {
@@ -604,19 +601,15 @@ private void updateLastCacheUseLastValuesIfPossible() {
604601 hasSetLastTime = true ;
605602 LastDescAccumulator lastAccumulator =
606603 (LastDescAccumulator ) tableAggregator .getAccumulator ();
604+ updateMeasurementList .add ("" );
607605 if (lastAccumulator .hasInitResult ()) {
608- updateMeasurementList .add ("" );
609606 updateTimeValuePairList .add (
610607 new TimeValuePair (
611608 lastAccumulator .getMaxTime (),
612609 new TsPrimitiveType .TsLong (lastAccumulator .getMaxTime ())));
613610 } else {
614611 currentDeviceEntry = deviceEntries .get (currentDeviceIndex );
615- TABLE_DEVICE_SCHEMA_CACHE .updateLastCacheIfExists (
616- dbName ,
617- currentDeviceEntry .getDeviceID (),
618- new String [] {"" },
619- new TimeValuePair [] {EMPTY_TIME_VALUE_PAIR });
612+ updateTimeValuePairList .add (EMPTY_TIME_VALUE_PAIR );
620613 }
621614 }
622615 break ;
@@ -643,16 +636,52 @@ private void updateLastCacheUseLastValuesIfPossible() {
643636 channel += tableAggregator .getChannelCount ();
644637 }
645638
639+ checkIfUpdated (updateMeasurementList , updateTimeValuePairList );
640+ }
641+
642+ private void checkIfUpdated (
643+ List <String > updateMeasurementList , List <TimeValuePair > updateTimeValuePairList ) {
646644 if (!updateMeasurementList .isEmpty ()) {
647- String [] updateMeasurementArray = updateMeasurementList .toArray (new String [0 ]);
648- TimeValuePair [] updateTimeValuePairArray =
649- updateTimeValuePairList .toArray (new TimeValuePair [0 ]);
650645 currentDeviceEntry = deviceEntries .get (currentDeviceIndex );
651- TABLE_DEVICE_SCHEMA_CACHE .updateLastCacheIfExists (
652- dbName ,
653- currentDeviceEntry .getDeviceID (),
654- updateMeasurementArray ,
655- updateTimeValuePairArray );
646+
647+ boolean deviceInMultiRegion =
648+ deviceCountMap != null && deviceCountMap .containsKey (currentDeviceEntry );
649+ if (!deviceInMultiRegion ) {
650+ TABLE_DEVICE_SCHEMA_CACHE .updateLastCacheIfExists (
651+ dbName ,
652+ currentDeviceEntry .getDeviceID (),
653+ updateMeasurementList .toArray (new String [0 ]),
654+ updateTimeValuePairList .toArray (new TimeValuePair [0 ]));
655+ return ;
656+ }
657+
658+ dataNodeQueryContext .lock (true );
659+ try {
660+ Pair <Integer , Map <String , TimeValuePair >> deviceInfo =
661+ dataNodeQueryContext .getDeviceInfo (tableCompleteName , currentDeviceEntry );
662+ Map <String , TimeValuePair > values = deviceInfo .getRight ();
663+
664+ int size = updateMeasurementList .size ();
665+ for (int i = 0 ; i < size ; i ++) {
666+ String measurementName = updateMeasurementList .get (i );
667+ TimeValuePair timeValuePair = updateTimeValuePairList .get (i );
668+ if (values .containsKey (measurementName )) {
669+ TimeValuePair oldValue = values .get (measurementName );
670+ if (timeValuePair .getTimestamp () > oldValue .getTimestamp ()) {
671+ values .put (measurementName , timeValuePair );
672+ }
673+ } else {
674+ values .put (measurementName , timeValuePair );
675+ }
676+ }
677+
678+ deviceInfo .left --;
679+ if (deviceInfo .left == 0 ) {
680+ dataNodeQueryContext .updateLastCache (tableCompleteName , currentDeviceEntry );
681+ }
682+ } finally {
683+ dataNodeQueryContext .unLock (true );
684+ }
656685 }
657686 }
658687
0 commit comments