This is an automated email from the ASF dual-hosted git repository.

wanghailin pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 9fdedc487e [Improve][Connector][Hive] skip temporary hidden 
directories (#8402)
9fdedc487e is described below

commit 9fdedc487edc395c910b559426c81661d6a5dc14
Author: sohurdc <[email protected]>
AuthorDate: Wed Jan 1 20:16:10 2025 +0800

    [Improve][Connector][Hive] skip temporary hidden directories (#8402)
---
 .../file/source/reader/AbstractReadStrategy.java   |   5 +-
 .../source/reader/AbstractReadStrategyTest.java    | 134 +++++++++++++++++++++
 2 files changed, 138 insertions(+), 1 deletion(-)

diff --git 
a/seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategy.java
 
b/seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategy.java
index c3fe01bf3e..c2ecc654fe 100644
--- 
a/seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategy.java
+++ 
b/seatunnel-connectors-v2/connector-file/connector-file-base/src/main/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategy.java
@@ -110,7 +110,10 @@ public abstract class AbstractReadStrategy implements 
ReadStrategy {
         FileStatus[] stats = hadoopFileSystemProxy.listStatus(path);
         for (FileStatus fileStatus : stats) {
             if (fileStatus.isDirectory()) {
-                
fileNames.addAll(getFileNamesByPath(fileStatus.getPath().toString()));
+                // skip hidden tmp directory, such as .hive-staging_hive
+                if (!fileStatus.getPath().getName().startsWith(".")) {
+                    
fileNames.addAll(getFileNamesByPath(fileStatus.getPath().toString()));
+                }
                 continue;
             }
             if (fileStatus.isFile() && filterFileByPattern(fileStatus) && 
fileStatus.getLen() > 0) {
diff --git 
a/seatunnel-connectors-v2/connector-file/connector-file-base/src/test/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategyTest.java
 
b/seatunnel-connectors-v2/connector-file/connector-file-base/src/test/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategyTest.java
new file mode 100644
index 0000000000..5575e4dcc9
--- /dev/null
+++ 
b/seatunnel-connectors-v2/connector-file/connector-file-base/src/test/java/org/apache/seatunnel/connectors/seatunnel/file/source/reader/AbstractReadStrategyTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.connectors.seatunnel.file.source.reader;
+
+import 
org.apache.seatunnel.connectors.seatunnel.file.writer.ParquetReadStrategyTest;
+
+import org.apache.avro.Schema;
+import org.apache.avro.generic.GenericArray;
+import org.apache.avro.generic.GenericData;
+import org.apache.avro.generic.GenericRecord;
+import org.apache.avro.util.Utf8;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.parquet.avro.AvroParquetWriter;
+import org.apache.parquet.hadoop.ParquetWriter;
+import org.apache.parquet.hadoop.metadata.CompressionCodecName;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import static 
org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_DEFAULT;
+
+public class AbstractReadStrategyTest {
+
+    @DisabledOnOs(OS.WINDOWS)
+    @Test
+    public void testReadDirectorySkipHiddenDirectories() throws Exception {
+        AutoGenerateParquetData.generateTestData();
+        try (ParquetReadStrategy parquetReadStrategy = new 
ParquetReadStrategy(); ) {
+            ParquetReadStrategyTest.LocalConf localConf =
+                    new 
ParquetReadStrategyTest.LocalConf(FS_DEFAULT_NAME_DEFAULT);
+            parquetReadStrategy.init(localConf);
+            List<String> list =
+                    
parquetReadStrategy.getFileNamesByPath(AutoGenerateParquetData.DATA_FILE_PATH);
+            Assertions.assertEquals(1, list.size());
+            Assertions.assertTrue(
+                    
list.get(0).endsWith(AutoGenerateParquetData.DATA_FILE_PATH_KEEP));
+        } finally {
+            
AutoGenerateParquetData.deleteFile(AutoGenerateParquetData.DATA_FILE_PATH);
+        }
+    }
+
+    public static class AutoGenerateParquetData {
+
+        public static final String DATA_FILE_PATH = "/tmp/tmp_1";
+        public static final String DATA_FILE_PATH_KEEP = 
"/tmp/tmp_1/dt=20241230/00000";
+        public static final String DATA_FILE_PATH_IGNORE = 
"/tmp/tmp_1/.hive-stage/00000";
+
+        public static void generateTestData() throws IOException {
+            deleteFile(DATA_FILE_PATH);
+            createFile(DATA_FILE_PATH_KEEP);
+            createFile(DATA_FILE_PATH_IGNORE);
+        }
+
+        public static void write(String filePath) throws IOException {
+            String schemaString =
+                    
"{\"type\":\"record\",\"name\":\"User\",\"fields\":[{\"name\":\"id\",\"type\":{\"type\":
 \"array\", \"items\": {\"type\": \"array\", \"items\": 
\"bytes\"}}},{\"name\":\"id2\",\"type\":{\"type\": \"array\", \"items\": 
{\"type\": \"array\", \"items\": 
\"bytes\"}}},{\"name\":\"long\",\"type\":\"long\"}]}";
+            Schema schema = new Schema.Parser().parse(schemaString);
+
+            Configuration conf = new Configuration();
+
+            Path file = new Path(filePath);
+
+            ParquetWriter<GenericRecord> writer =
+                    AvroParquetWriter.<GenericRecord>builder(file)
+                            .withSchema(schema)
+                            .withConf(conf)
+                            .withCompressionCodec(CompressionCodecName.SNAPPY)
+                            .build();
+
+            GenericRecord record1 = new GenericData.Record(schema);
+            GenericArray<GenericData.Array<Utf8>> id =
+                    new GenericData.Array<>(2, schema.getField("id").schema());
+            id.add(new GenericData.Array<>(2, 
schema.getField("id").schema().getElementType()));
+            id.add(new GenericData.Array<>(2, 
schema.getField("id").schema().getElementType()));
+            record1.put("id", id);
+            record1.put("id2", id);
+            record1.put("long", Long.MAX_VALUE);
+            writer.write(record1);
+            writer.close();
+        }
+
+        public static void createFile(String dir) throws IOException {
+            File f2 = new File(dir);
+            if (!f2.exists()) {
+                if (!f2.getParentFile().exists()) {
+                    boolean b = f2.getParentFile().mkdirs();
+                    Assertions.assertTrue(b);
+                }
+                write(f2.getPath());
+            }
+        }
+
+        public static void deleteFile(String file) {
+            File parquetFile = new File(file);
+            if (parquetFile.exists()) {
+                if (parquetFile.isDirectory()) {
+                    File[] l = parquetFile.listFiles();
+                    if (l != null) {
+                        for (File s : l) {
+                            deleteFile(s.getPath());
+                        }
+                    }
+                    boolean b = parquetFile.delete();
+                    Assertions.assertTrue(b);
+                } else {
+                    boolean b = parquetFile.delete();
+                    Assertions.assertTrue(b);
+                }
+            }
+        }
+    }
+}

Reply via email to