2222import org .apache .iotdb .common .rpc .thrift .TSStatus ;
2323import org .apache .iotdb .commons .conf .IoTDBConstant ;
2424import org .apache .iotdb .commons .exception .IllegalPathException ;
25+ import org .apache .iotdb .commons .exception .IoTDBException ;
26+ import org .apache .iotdb .commons .exception .IoTDBRuntimeException ;
2527import org .apache .iotdb .commons .exception .pipe .PipeRuntimeOutOfMemoryCriticalException ;
2628import org .apache .iotdb .commons .path .PartialPath ;
2729import org .apache .iotdb .commons .pipe .config .PipeConfig ;
7476import org .apache .iotdb .db .queryengine .plan .Coordinator ;
7577import org .apache .iotdb .db .queryengine .plan .analyze .ClusterPartitionFetcher ;
7678import org .apache .iotdb .db .queryengine .plan .analyze .schema .ClusterSchemaFetcher ;
79+ import org .apache .iotdb .db .queryengine .plan .execution .config .ConfigTaskResult ;
7780import org .apache .iotdb .db .queryengine .plan .execution .config .executor .ClusterConfigTaskExecutor ;
81+ import org .apache .iotdb .db .queryengine .plan .execution .config .metadata .DatabaseSchemaTask ;
7882import org .apache .iotdb .db .queryengine .plan .planner .plan .node .metedata .write .view .AlterLogicalViewNode ;
7983import org .apache .iotdb .db .queryengine .plan .statement .Statement ;
8084import org .apache .iotdb .db .queryengine .plan .statement .StatementType ;
97101import org .apache .iotdb .service .rpc .thrift .TPipeTransferReq ;
98102import org .apache .iotdb .service .rpc .thrift .TPipeTransferResp ;
99103
104+ import com .google .common .util .concurrent .ListenableFuture ;
100105import org .apache .tsfile .utils .Pair ;
101106import org .slf4j .Logger ;
102107import org .slf4j .LoggerFactory ;
113118import java .util .Objects ;
114119import java .util .Optional ;
115120import java .util .Set ;
121+ import java .util .concurrent .ConcurrentHashMap ;
122+ import java .util .concurrent .ExecutionException ;
116123import java .util .concurrent .atomic .AtomicLong ;
117124import java .util .concurrent .atomic .AtomicReference ;
118125import java .util .stream .Collectors ;
119126import java .util .stream .Stream ;
120127
128+ import static org .apache .iotdb .commons .utils .ErrorHandlingCommonUtils .getRootCause ;
129+
121130public class IoTDBDataNodeReceiver extends IoTDBFileReceiver {
122131
123132 private static final Logger LOGGER = LoggerFactory .getLogger (IoTDBDataNodeReceiver .class );
@@ -152,6 +161,14 @@ public class IoTDBDataNodeReceiver extends IoTDBFileReceiver {
152161 private static final SessionManager SESSION_MANAGER = SessionManager .getInstance ();
153162
154163 private PipeMemoryBlock allocatedMemoryBlock ;
164+ private final Set <String > autoCreatedTreeDatabases = ConcurrentHashMap .newKeySet ();
165+ private final Set <String > conflictedTreeDatabases = ConcurrentHashMap .newKeySet ();
166+
167+ private enum TreeDatabaseCreationResult {
168+ SKIPPED ,
169+ CREATED_OR_EXISTED ,
170+ CONFLICTED
171+ }
155172
156173 static {
157174 try {
@@ -876,6 +893,11 @@ private TSStatus executeStatement(final Statement statement) {
876893 return RpcUtils .getStatus (status .getCode (), status .getMessage ());
877894 }
878895
896+ if (autoCreateTreeDatabaseIfNecessary (getTreeDatabaseName (statement ))
897+ == TreeDatabaseCreationResult .CONFLICTED ) {
898+ clearTreeDatabaseName (statement );
899+ }
900+
879901 return Coordinator .getInstance ()
880902 .executeForTreeModel (
881903 shouldMarkAsPipeRequest .get () ? new PipeEnrichedStatement (statement ) : statement ,
@@ -889,6 +911,91 @@ private TSStatus executeStatement(final Statement statement) {
889911 .status ;
890912 }
891913
914+ private TreeDatabaseCreationResult autoCreateTreeDatabaseIfNecessary (final String database ) {
915+ if (database == null
916+ || LoadTsFileStatement .getDatabaseLevelByTreeDatabase (database ) == null
917+ || !IoTDBDescriptor .getInstance ().getConfig ().isAutoCreateSchemaEnabled ()) {
918+ return TreeDatabaseCreationResult .SKIPPED ;
919+ }
920+ if (autoCreatedTreeDatabases .contains (database )) {
921+ return TreeDatabaseCreationResult .CREATED_OR_EXISTED ;
922+ }
923+ if (conflictedTreeDatabases .contains (database )) {
924+ return TreeDatabaseCreationResult .CONFLICTED ;
925+ }
926+
927+ try {
928+ final DatabaseSchemaStatement statement =
929+ new DatabaseSchemaStatement (DatabaseSchemaStatement .DatabaseSchemaStatementType .CREATE );
930+ statement .setDatabasePath (new PartialPath (database ));
931+ statement .setEnablePrintExceptionLog (false );
932+
933+ final TSStatus permissionStatus = statement .checkPermissionBeforeProcess (username );
934+ if (permissionStatus .getCode () != TSStatusCode .SUCCESS_STATUS .getStatusCode ()) {
935+ throw new PipeException (permissionStatus .getMessage ());
936+ }
937+
938+ final DatabaseSchemaTask task = new DatabaseSchemaTask (statement );
939+ final ListenableFuture <ConfigTaskResult > future =
940+ task .execute (ClusterConfigTaskExecutor .getInstance ());
941+ final ConfigTaskResult result = future .get ();
942+ final int statusCode = result .getStatusCode ().getStatusCode ();
943+ if (statusCode == TSStatusCode .SUCCESS_STATUS .getStatusCode ()
944+ || statusCode == TSStatusCode .DATABASE_ALREADY_EXISTS .getStatusCode ()) {
945+ autoCreatedTreeDatabases .add (database );
946+ return TreeDatabaseCreationResult .CREATED_OR_EXISTED ;
947+ }
948+ if (statusCode == TSStatusCode .DATABASE_CONFLICT .getStatusCode ()) {
949+ conflictedTreeDatabases .add (database );
950+ return TreeDatabaseCreationResult .CONFLICTED ;
951+ }
952+ throw new PipeException (
953+ String .format (
954+ "Auto create tree database failed: %s, status: %s" ,
955+ database , result .getStatus () == null ? result .getStatusCode () : result .getStatus ()));
956+ } catch (final IllegalPathException e ) {
957+ throw new PipeException (String .format ("Illegal tree database %s." , database ), e );
958+ } catch (final ExecutionException | InterruptedException e ) {
959+ if (e instanceof InterruptedException ) {
960+ Thread .currentThread ().interrupt ();
961+ }
962+ final Throwable rootCause = getRootCause (e );
963+ final int errorCode ;
964+ if (rootCause instanceof IoTDBException ) {
965+ errorCode = ((IoTDBException ) rootCause ).getErrorCode ();
966+ } else if (rootCause instanceof IoTDBRuntimeException ) {
967+ errorCode = ((IoTDBRuntimeException ) rootCause ).getErrorCode ();
968+ } else {
969+ errorCode = TSStatusCode .INTERNAL_SERVER_ERROR .getStatusCode ();
970+ }
971+ if (errorCode == TSStatusCode .DATABASE_ALREADY_EXISTS .getStatusCode ()) {
972+ autoCreatedTreeDatabases .add (database );
973+ return TreeDatabaseCreationResult .CREATED_OR_EXISTED ;
974+ }
975+ if (errorCode == TSStatusCode .DATABASE_CONFLICT .getStatusCode ()) {
976+ conflictedTreeDatabases .add (database );
977+ return TreeDatabaseCreationResult .CONFLICTED ;
978+ }
979+ throw new PipeException ("Auto create tree database failed because " + e .getMessage (), e );
980+ }
981+ }
982+
983+ private String getTreeDatabaseName (final Statement statement ) {
984+ if (statement instanceof LoadTsFileStatement ) {
985+ return ((LoadTsFileStatement ) statement ).getDatabase ();
986+ }
987+ return null ;
988+ }
989+
990+ static void clearTreeDatabaseName (final Statement statement ) {
991+ if (statement instanceof LoadTsFileStatement ) {
992+ final LoadTsFileStatement loadTsFileStatement = (LoadTsFileStatement ) statement ;
993+ loadTsFileStatement .setDatabase (null );
994+ loadTsFileStatement .setDatabaseLevel (
995+ IoTDBDescriptor .getInstance ().getConfig ().getDefaultDatabaseLevel ());
996+ }
997+ }
998+
892999 @ Override
8931000 protected TSStatus login () {
8941001 final IClientSession session = SESSION_MANAGER .getCurrSession ();
0 commit comments