2121
2222import org .apache .iotdb .common .rpc .thrift .TSStatus ;
2323import org .apache .iotdb .commons .pipe .datastructure .pattern .IoTDBPipePattern ;
24+ import org .apache .iotdb .db .conf .IoTDBDescriptor ;
2425import org .apache .iotdb .db .pipe .connector .payload .evolvable .request .PipeTransferTabletRawReq ;
2526import org .apache .iotdb .db .pipe .event .common .tsfile .container .scan .TsFileInsertionScanDataContainer ;
2627import org .apache .iotdb .db .queryengine .plan .statement .Statement ;
2728import org .apache .iotdb .db .queryengine .plan .statement .StatementNode ;
2829import org .apache .iotdb .db .queryengine .plan .statement .StatementVisitor ;
30+ import org .apache .iotdb .db .queryengine .plan .statement .crud .InsertMultiTabletsStatement ;
2931import org .apache .iotdb .db .queryengine .plan .statement .crud .LoadTsFileStatement ;
3032import org .apache .iotdb .db .storageengine .dataregion .modification .ModificationFile ;
3133import org .apache .iotdb .db .storageengine .dataregion .tsfile .TsFileResource ;
34+ import org .apache .iotdb .db .storageengine .load .memory .LoadTsFileMemoryBlock ;
35+ import org .apache .iotdb .db .storageengine .load .memory .LoadTsFileMemoryManager ;
3236import org .apache .iotdb .rpc .TSStatusCode ;
3337
3438import org .apache .commons .io .FileUtils ;
3842import org .slf4j .LoggerFactory ;
3943
4044import java .io .File ;
45+ import java .util .ArrayList ;
46+ import java .util .List ;
4147import java .util .Optional ;
48+ import java .util .stream .Collectors ;
49+
50+ import static org .apache .iotdb .db .pipe .resource .memory .PipeMemoryWeightUtil .calculateTabletSizeInBytes ;
4251
4352public class LoadTreeStatementDataTypeConvertExecutionVisitor
4453 extends StatementVisitor <Optional <TSStatus >, Void > {
45-
46- private final StatementExecutor statementExecutor ;
47-
4854 private static final Logger LOGGER =
4955 LoggerFactory .getLogger (LoadTreeStatementDataTypeConvertExecutionVisitor .class );
5056
57+ private static final long TABLET_BATCH_MEMORY_SIZE_IN_BYTES =
58+ IoTDBDescriptor .getInstance ()
59+ .getConfig ()
60+ .getLoadTsFileTabletConversionBatchMemorySizeInBytes ();
61+
62+ private final StatementExecutor statementExecutor ;
63+
5164 @ FunctionalInterface
5265 public interface StatementExecutor {
5366 TSStatus execute (final Statement statement );
@@ -69,60 +82,83 @@ public Optional<TSStatus> visitLoadFile(
6982
7083 LOGGER .info ("Start data type conversion for LoadTsFileStatement: {}" , loadTsFileStatement );
7184
72- for (final File file : loadTsFileStatement .getTsFiles ()) {
73- try (final TsFileInsertionScanDataContainer container =
74- new TsFileInsertionScanDataContainer (
75- file , new IoTDBPipePattern (null ), Long .MIN_VALUE , Long .MAX_VALUE , null , null )) {
76- for (final Pair <Tablet , Boolean > tabletWithIsAligned : container .toTabletWithIsAligneds ()) {
77- final LoadConvertedInsertTabletStatement statement =
78- new LoadConvertedInsertTabletStatement (
79- PipeTransferTabletRawReq .toTPipeTransferRawReq (
80- tabletWithIsAligned .getLeft (), tabletWithIsAligned .getRight ())
81- .constructStatement (),
82- loadTsFileStatement .isConvertOnTypeMismatch ());
83-
84- TSStatus result ;
85- try {
86- result =
87- statement .accept (
88- LoadTsFileDataTypeConverter .STATEMENT_STATUS_VISITOR ,
89- statementExecutor .execute (statement ));
90-
91- // Retry max 5 times if the write process is rejected
92- for (int i = 0 ;
93- i < 5
94- && result .getCode ()
95- == TSStatusCode .LOAD_TEMPORARY_UNAVAILABLE_EXCEPTION .getStatusCode ();
96- i ++) {
97- Thread .sleep (100L * (i + 1 ));
98- result =
99- statement .accept (
100- LoadTsFileDataTypeConverter .STATEMENT_STATUS_VISITOR ,
101- statementExecutor .execute (statement ));
85+ final LoadTsFileMemoryBlock block =
86+ LoadTsFileMemoryManager .getInstance ()
87+ .allocateMemoryBlock (TABLET_BATCH_MEMORY_SIZE_IN_BYTES );
88+ final List <PipeTransferTabletRawReq > tabletRawReqs = new ArrayList <>();
89+ final List <Long > tabletRawReqSizes = new ArrayList <>();
90+
91+ try {
92+ for (final File file : loadTsFileStatement .getTsFiles ()) {
93+ try (final TsFileInsertionScanDataContainer container =
94+ new TsFileInsertionScanDataContainer (
95+ file , new IoTDBPipePattern (null ), Long .MIN_VALUE , Long .MAX_VALUE , null , null )) {
96+ for (final Pair <Tablet , Boolean > tabletWithIsAligned :
97+ container .toTabletWithIsAligneds ()) {
98+ final PipeTransferTabletRawReq tabletRawReq =
99+ PipeTransferTabletRawReq .toTPipeTransferRawReq (
100+ tabletWithIsAligned .getLeft (), tabletWithIsAligned .getRight ());
101+ final long curMemory = calculateTabletSizeInBytes (tabletWithIsAligned .getLeft ()) + 1 ;
102+ if (block .hasEnoughMemory (curMemory )) {
103+ tabletRawReqs .add (tabletRawReq );
104+ tabletRawReqSizes .add (curMemory );
105+ block .addMemoryUsage (curMemory );
106+ continue ;
102107 }
103- } catch (final Exception e ) {
104- if (e instanceof InterruptedException ) {
105- Thread .currentThread ().interrupt ();
108+
109+ final TSStatus result =
110+ executeInsertMultiTabletsWithRetry (
111+ tabletRawReqs , loadTsFileStatement .isConvertOnTypeMismatch ());
112+
113+ for (final long memoryCost : tabletRawReqSizes ) {
114+ block .reduceMemoryUsage (memoryCost );
115+ }
116+ tabletRawReqs .clear ();
117+ tabletRawReqSizes .clear ();
118+
119+ if (!handleTSStatus (result , loadTsFileStatement )) {
120+ return Optional .empty ();
106121 }
107- result = statement .accept (LoadTsFileDataTypeConverter .STATEMENT_EXCEPTION_VISITOR , e );
122+
123+ tabletRawReqs .add (tabletRawReq );
124+ tabletRawReqSizes .add (curMemory );
125+ block .addMemoryUsage (curMemory );
126+ }
127+ } catch (final Exception e ) {
128+ LOGGER .warn (
129+ "Failed to convert data type for LoadTsFileStatement: {}." , loadTsFileStatement , e );
130+ return Optional .empty ();
131+ }
132+ }
133+
134+ if (!tabletRawReqs .isEmpty ()) {
135+ try {
136+ final TSStatus result =
137+ executeInsertMultiTabletsWithRetry (
138+ tabletRawReqs , loadTsFileStatement .isConvertOnTypeMismatch ());
139+
140+ for (final long memoryCost : tabletRawReqSizes ) {
141+ block .reduceMemoryUsage (memoryCost );
108142 }
143+ tabletRawReqs .clear ();
144+ tabletRawReqSizes .clear ();
109145
110- if (!(result .getCode () == TSStatusCode .SUCCESS_STATUS .getStatusCode ()
111- || result .getCode () == TSStatusCode .REDIRECTION_RECOMMEND .getStatusCode ()
112- || result .getCode ()
113- == TSStatusCode .LOAD_IDEMPOTENT_CONFLICT_EXCEPTION .getStatusCode ())) {
114- LOGGER .warn (
115- "Failed to convert data type for LoadTsFileStatement: {}, status code is {}." ,
116- loadTsFileStatement ,
117- result .getCode ());
146+ if (!handleTSStatus (result , loadTsFileStatement )) {
118147 return Optional .empty ();
119148 }
149+ } catch (final Exception e ) {
150+ LOGGER .warn (
151+ "Failed to convert data type for LoadTsFileStatement: {}." , loadTsFileStatement , e );
152+ return Optional .empty ();
120153 }
121- } catch (final Exception e ) {
122- LOGGER .warn (
123- "Failed to convert data type for LoadTsFileStatement: {}." , loadTsFileStatement , e );
124- return Optional .empty ();
125154 }
155+ } finally {
156+ for (final long memoryCost : tabletRawReqSizes ) {
157+ block .reduceMemoryUsage (memoryCost );
158+ }
159+ tabletRawReqs .clear ();
160+ tabletRawReqSizes .clear ();
161+ block .close ();
126162 }
127163
128164 if (loadTsFileStatement .isDeleteAfterLoad ()) {
@@ -142,4 +178,57 @@ file, new IoTDBPipePattern(null), Long.MIN_VALUE, Long.MAX_VALUE, null, null)) {
142178
143179 return Optional .of (new TSStatus (TSStatusCode .SUCCESS_STATUS .getStatusCode ()));
144180 }
181+
182+ private TSStatus executeInsertMultiTabletsWithRetry (
183+ final List <PipeTransferTabletRawReq > tabletRawReqs , boolean isConvertOnTypeMismatch ) {
184+ final InsertMultiTabletsStatement batchStatement = new InsertMultiTabletsStatement ();
185+ batchStatement .setInsertTabletStatementList (
186+ tabletRawReqs .stream ()
187+ .map (
188+ req ->
189+ new LoadConvertedInsertTabletStatement (
190+ req .constructStatement (), isConvertOnTypeMismatch ))
191+ .collect (Collectors .toList ()));
192+
193+ TSStatus result ;
194+ try {
195+ result =
196+ batchStatement .accept (
197+ LoadTsFileDataTypeConverter .STATEMENT_STATUS_VISITOR ,
198+ statementExecutor .execute (batchStatement ));
199+
200+ // Retry max 5 times if the write process is rejected
201+ for (int i = 0 ;
202+ i < 5
203+ && result .getCode ()
204+ == TSStatusCode .LOAD_TEMPORARY_UNAVAILABLE_EXCEPTION .getStatusCode ();
205+ i ++) {
206+ Thread .sleep (100L * (i + 1 ));
207+ result =
208+ batchStatement .accept (
209+ LoadTsFileDataTypeConverter .STATEMENT_STATUS_VISITOR ,
210+ statementExecutor .execute (batchStatement ));
211+ }
212+ } catch (final Exception e ) {
213+ if (e instanceof InterruptedException ) {
214+ Thread .currentThread ().interrupt ();
215+ }
216+ result = batchStatement .accept (LoadTsFileDataTypeConverter .STATEMENT_EXCEPTION_VISITOR , e );
217+ }
218+ return result ;
219+ }
220+
221+ private static boolean handleTSStatus (
222+ final TSStatus result , final LoadTsFileStatement loadTsFileStatement ) {
223+ if (!(result .getCode () == TSStatusCode .SUCCESS_STATUS .getStatusCode ()
224+ || result .getCode () == TSStatusCode .REDIRECTION_RECOMMEND .getStatusCode ()
225+ || result .getCode () == TSStatusCode .LOAD_IDEMPOTENT_CONFLICT_EXCEPTION .getStatusCode ())) {
226+ LOGGER .warn (
227+ "Failed to convert data type for LoadTsFileStatement: {}, status code is {}." ,
228+ loadTsFileStatement ,
229+ result .getCode ());
230+ return false ;
231+ }
232+ return true ;
233+ }
145234}
0 commit comments