Skip to content

Commit 323b5dd

Browse files
committed
update
1 parent 97321b8 commit 323b5dd

7 files changed

Lines changed: 397 additions & 0 deletions

File tree

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.parquet.storage;
21+
22+
import java.net.URI;
23+
24+
/**
25+
* Simple helper to select a {@link StorageProvider} implementation based on a
26+
* Hadoop/NIO constructs. This keeps provider discovery logic outside of call-sites.
27+
*/
28+
public final class Storage {
29+
private Storage() {}
30+
31+
/**
32+
* Return the appropriate provider for the given URI scheme.
33+
* - file:// or no scheme → NIO provider
34+
* - hdfs:// → Hadoop provider (if available)
35+
*/
36+
public static StorageProvider select(URI uri) {
37+
final String scheme = uri == null ? null : uri.getScheme();
38+
39+
if (scheme == null || "file".equals(scheme)) {
40+
return new org.apache.parquet.storage.impl.NioStorageProvider();
41+
}
42+
43+
try {
44+
Class<?> confClass = Class.forName("org.apache.hadoop.conf.Configuration");
45+
Object conf = confClass.getDeclaredConstructor().newInstance();
46+
Class<?> providerClass = Class.forName("org.apache.parquet.storage.impl.hadoop.HadoopStorageProvider");
47+
return (StorageProvider) providerClass.getConstructor(confClass).newInstance(conf);
48+
} catch (ClassNotFoundException e) {
49+
throw new IllegalStateException(
50+
"Hadoop not on classpath for URI scheme hdfs, please ensure hadoop dependencies are available in classpath",
51+
e);
52+
} catch (ReflectiveOperationException e) {
53+
throw new IllegalStateException("Failed to initialize HadoopStorageProvider", e);
54+
}
55+
}
56+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.parquet.storage;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.OutputStream;
25+
26+
/**
27+
* Simple abstraction for file IO that allows Parquet components to work with
28+
* different storage back-ends (NIO, Hadoop, cloud SDKs, etc.) without taking
29+
* an explicit dependency on the back-end libraries.
30+
*
31+
* <p>The interface purposefully exposes a very small surface – just the
32+
* operations currently needed by the Parquet code we intend to decouple from
33+
* Hadoop. Additional methods can be added incrementally as other areas are
34+
* ported.</p>
35+
*
36+
* <p>This interface lives in the <code>parquet-common</code> module so that it
37+
* can be referenced by any other module without creating additional coupling
38+
* between them.</p>
39+
*/
40+
public interface StorageProvider {
41+
42+
/**
43+
* Opens the given path for reading.
44+
*
45+
* @param path fully-qualified file path (implementation specific semantics)
46+
* @return an InputStream that must be closed by the caller
47+
*/
48+
InputStream openForRead(String path) throws IOException;
49+
50+
/**
51+
* Opens the given path for writing. If the file already exists the behaviour
52+
* depends on the overwrite flag.
53+
*
54+
* @param path fully-qualified file path
55+
* @param overwrite whether an existing file should be replaced
56+
* @return an OutputStream that must be closed by the caller
57+
*/
58+
OutputStream openForWrite(String path, boolean overwrite) throws IOException;
59+
60+
/**
61+
* Deletes the file at path if it exists.
62+
*/
63+
boolean delete(String path) throws IOException;
64+
65+
/**
66+
* Renames the file located at source to target.
67+
*/
68+
boolean rename(String source, String target) throws IOException;
69+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.parquet.storage.impl;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.OutputStream;
25+
import java.nio.file.Files;
26+
import java.nio.file.Path;
27+
import java.nio.file.Paths;
28+
import java.nio.file.StandardCopyOption;
29+
import java.nio.file.StandardOpenOption;
30+
import org.apache.parquet.storage.StorageProvider;
31+
32+
/**
33+
* A StorageProvider that relies solely on the Java NIO standard library. It
34+
* can work with any FileSystem implementation available
35+
* on the class-path.
36+
*/
37+
public class NioStorageProvider implements StorageProvider {
38+
39+
public NioStorageProvider() {}
40+
41+
private static Path toPath(String s) {
42+
try {
43+
java.net.URI uri = java.net.URI.create(s);
44+
if (uri.getScheme() != null) {
45+
return Paths.get(uri);
46+
}
47+
} catch (IllegalArgumentException ignore) {
48+
}
49+
return Paths.get(s);
50+
}
51+
52+
@Override
53+
public InputStream openForRead(String path) throws IOException {
54+
return Files.newInputStream(toPath(path));
55+
}
56+
57+
@Override
58+
public OutputStream openForWrite(String path, boolean overwrite) throws IOException {
59+
Path p = toPath(path);
60+
if (overwrite) {
61+
return Files.newOutputStream(
62+
p, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
63+
} else {
64+
return Files.newOutputStream(p, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
65+
}
66+
}
67+
68+
@Override
69+
public boolean delete(String path) throws IOException {
70+
return Files.deleteIfExists(toPath(path));
71+
}
72+
73+
@Override
74+
public boolean rename(String source, String target) throws IOException {
75+
Path src = toPath(source);
76+
Path tgt = toPath(target);
77+
if (Files.exists(tgt)) return false;
78+
try {
79+
Files.move(src, tgt, StandardCopyOption.ATOMIC_MOVE);
80+
} catch (AtomicMoveNotSupportedException e) {
81+
Files.move(src, tgt);
82+
}
83+
return true;
84+
}
85+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
org.apache.parquet.storage.impl.NioStorageProvider
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.parquet.storage;
21+
22+
import static org.junit.Assert.*;
23+
24+
import java.io.IOException;
25+
import java.net.URI;
26+
import org.junit.Test;
27+
28+
public class TestStorage {
29+
30+
@Test
31+
public void testFileSchemeReturnsNioProvider() {
32+
StorageProvider provider = Storage.select(URI.create("file:///tmp/test.parquet"));
33+
assertTrue(
34+
"file:// should return NioStorageProvider",
35+
provider instanceof org.apache.parquet.storage.impl.NioStorageProvider);
36+
}
37+
38+
@Test
39+
public void testNullUriReturnsNioProvider() {
40+
StorageProvider provider = Storage.select(null);
41+
assertTrue(
42+
"null URI should return NioStorageProvider",
43+
provider instanceof org.apache.parquet.storage.impl.NioStorageProvider);
44+
}
45+
46+
@Test
47+
public void testRelativePathReturnsNioProvider() {
48+
StorageProvider provider = Storage.select(URI.create("relative/path"));
49+
assertTrue(
50+
"relative path should return NioStorageProvider",
51+
provider instanceof org.apache.parquet.storage.impl.NioStorageProvider);
52+
}
53+
54+
@Test
55+
public void testHdfsSchemeReturnsHadoopProvider() {
56+
StorageProvider provider = Storage.select(URI.create("hdfs://namenode:8020/test.parquet"));
57+
assertNotNull("Should return a provider", provider);
58+
}
59+
60+
@Test
61+
public void testUnknownSchemeReturnsNioProvider() {
62+
StorageProvider provider = Storage.select(URI.create("s3://bucket/test.parquet"));
63+
assertTrue(
64+
"unknown scheme should return NioStorageProvider",
65+
provider instanceof org.apache.parquet.storage.impl.NioStorageProvider);
66+
}
67+
68+
@Test
69+
public void testNioProviderBasicOperations() throws IOException {
70+
StorageProvider provider = Storage.select(URI.create("file:///tmp/test.parquet"));
71+
72+
assertTrue(provider instanceof org.apache.parquet.storage.impl.NioStorageProvider);
73+
}
74+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.parquet.storage.impl.hadoop;
21+
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import java.io.OutputStream;
25+
import org.apache.hadoop.conf.Configuration;
26+
import org.apache.hadoop.fs.FSDataInputStream;
27+
import org.apache.hadoop.fs.FSDataOutputStream;
28+
import org.apache.hadoop.fs.FileSystem;
29+
import org.apache.hadoop.fs.Path;
30+
import org.apache.parquet.storage.StorageProvider;
31+
32+
/**
33+
* Hadoop-backed implementation of {@link StorageProvider}. Lives in the
34+
* parquet-hadoop module, under the same {@code org.apache.parquet.storage.impl}
35+
* hierarchy as other providers.
36+
*/
37+
public class HadoopStorageProvider implements StorageProvider {
38+
39+
private final FileSystem fs;
40+
41+
/**
42+
* Uses default Hadoop Configuration.
43+
*/
44+
public HadoopStorageProvider() throws IOException {
45+
this(new Configuration());
46+
}
47+
48+
public HadoopStorageProvider(Configuration conf) throws IOException {
49+
this.fs = FileSystem.get(conf);
50+
}
51+
52+
@Override
53+
public InputStream openForRead(String path) throws IOException {
54+
Path p = new Path(path);
55+
FSDataInputStream in = fs.open(p);
56+
// Deliberately return the Hadoop stream as InputStream; callers should
57+
// not rely on Hadoop-specific methods.
58+
return in;
59+
}
60+
61+
@Override
62+
public OutputStream openForWrite(String path, boolean overwrite) throws IOException {
63+
Path p = new Path(path);
64+
FSDataOutputStream out = fs.create(p, overwrite);
65+
return out;
66+
}
67+
68+
@Override
69+
public boolean delete(String path) throws IOException {
70+
return fs.delete(new Path(path), false);
71+
}
72+
73+
@Override
74+
public boolean rename(String source, String target) throws IOException {
75+
return fs.rename(new Path(source), new Path(target));
76+
}
77+
}

0 commit comments

Comments
 (0)