3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.util
;
21 import java
.io
.FileNotFoundException
;
22 import java
.io
.IOException
;
23 import java
.lang
.reflect
.InvocationTargetException
;
24 import java
.lang
.reflect
.Method
;
26 import java
.net
.URISyntaxException
;
27 import java
.util
.List
;
28 import java
.util
.Locale
;
30 import java
.util
.concurrent
.ConcurrentHashMap
;
31 import org
.apache
.hadoop
.conf
.Configuration
;
32 import org
.apache
.hadoop
.fs
.FSDataOutputStream
;
33 import org
.apache
.hadoop
.fs
.FSDataOutputStreamBuilder
;
34 import org
.apache
.hadoop
.fs
.FileStatus
;
35 import org
.apache
.hadoop
.fs
.FileSystem
;
36 import org
.apache
.hadoop
.fs
.LocalFileSystem
;
37 import org
.apache
.hadoop
.fs
.LocatedFileStatus
;
38 import org
.apache
.hadoop
.fs
.Path
;
39 import org
.apache
.hadoop
.fs
.PathFilter
;
40 import org
.apache
.hadoop
.fs
.RemoteIterator
;
41 import org
.apache
.hadoop
.fs
.permission
.FsPermission
;
42 import org
.apache
.hadoop
.hbase
.HConstants
;
43 import org
.apache
.hadoop
.hbase
.TableName
;
44 import org
.apache
.yetus
.audience
.InterfaceAudience
;
45 import org
.slf4j
.Logger
;
46 import org
.slf4j
.LoggerFactory
;
47 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.annotations
.VisibleForTesting
;
48 import org
.apache
.hbase
.thirdparty
.com
.google
.common
.collect
.Lists
;
51 * Utility methods for interacting with the underlying file system.
53 * Note that {@link #setStoragePolicy(FileSystem, Path, String)} is tested in TestFSUtils and
54 * pre-commit will run the hbase-server tests if there's code change in this class. See
55 * <a href="https://issues.apache.org/jira/browse/HBASE-20838">HBASE-20838</a> for more details.
57 @InterfaceAudience.Private
58 public abstract class CommonFSUtils
{
59 private static final Logger LOG
= LoggerFactory
.getLogger(CommonFSUtils
.class);
61 /** Parameter name for HBase WAL directory */
62 public static final String HBASE_WAL_DIR
= "hbase.wal.dir";
64 /** Parameter to disable stream capability enforcement checks */
65 public static final String UNSAFE_STREAM_CAPABILITY_ENFORCE
=
66 "hbase.unsafe.stream.capability.enforce";
68 /** Full access permissions (starting point for a umask) */
69 public static final String FULL_RWX_PERMISSIONS
= "777";
71 protected CommonFSUtils() {
76 * Compare of path component. Does not consider schema; i.e. if schemas
77 * different but <code>path</code> starts with <code>rootPath</code>,
78 * then the function returns true
79 * @param rootPath value to check for
80 * @param path subject to check
81 * @return True if <code>path</code> starts with <code>rootPath</code>
83 public static boolean isStartingWithPath(final Path rootPath
, final String path
) {
84 String uriRootPath
= rootPath
.toUri().getPath();
85 String tailUriPath
= (new Path(path
)).toUri().getPath();
86 return tailUriPath
.startsWith(uriRootPath
);
90 * Compare path component of the Path URI; e.g. if hdfs://a/b/c and /a/b/c, it will compare the
91 * '/a/b/c' part. Does not consider schema; i.e. if schemas different but path or subpath matches,
92 * the two will equate.
93 * @param pathToSearch Path we will be trying to match against.
94 * @param pathTail what to match
95 * @return True if <code>pathTail</code> is tail on the path of <code>pathToSearch</code>
97 public static boolean isMatchingTail(final Path pathToSearch
, String pathTail
) {
98 return isMatchingTail(pathToSearch
, new Path(pathTail
));
102 * Compare path component of the Path URI; e.g. if hdfs://a/b/c and /a/b/c, it will compare the
103 * '/a/b/c' part. If you passed in 'hdfs://a/b/c and b/c, it would return true. Does not consider
104 * schema; i.e. if schemas different but path or subpath matches, the two will equate.
105 * @param pathToSearch Path we will be trying to match agains against
106 * @param pathTail what to match
107 * @return True if <code>pathTail</code> is tail on the path of <code>pathToSearch</code>
109 public static boolean isMatchingTail(final Path pathToSearch
, final Path pathTail
) {
110 if (pathToSearch
.depth() != pathTail
.depth()) {
113 Path tailPath
= pathTail
;
115 Path toSearch
= pathToSearch
;
117 boolean result
= false;
119 tailName
= tailPath
.getName();
120 if (tailName
== null || tailName
.length() <= 0) {
124 toSearchName
= toSearch
.getName();
125 if (toSearchName
== null || toSearchName
.length() <= 0) {
128 // Move up a parent on each path for next go around. Path doesn't let us go off the end.
129 tailPath
= tailPath
.getParent();
130 toSearch
= toSearch
.getParent();
131 } while(tailName
.equals(toSearchName
));
137 * @param fs filesystem object
138 * @param dir directory to delete
139 * @return True if deleted <code>dir</code>
140 * @throws IOException e
142 public static boolean deleteDirectory(final FileSystem fs
, final Path dir
) throws IOException
{
143 return fs
.exists(dir
) && fs
.delete(dir
, true);
147 * Return the number of bytes that large input files should be optimally
148 * be split into to minimize i/o time.
150 * @param fs filesystem object
151 * @return the default block size for the path's filesystem
153 public static long getDefaultBlockSize(final FileSystem fs
, final Path path
) {
154 return fs
.getDefaultBlockSize(path
);
158 * Get the default replication.
160 * @param fs filesystem object
161 * @param f path of file
162 * @return default replication for the path's filesystem
164 public static short getDefaultReplication(final FileSystem fs
, final Path path
) {
165 return fs
.getDefaultReplication(path
);
169 * Returns the default buffer size to use during writes.
171 * The size of the buffer should probably be a multiple of hardware
172 * page size (4096 on Intel x86), and it determines how much data is
173 * buffered during read and write operations.
175 * @param fs filesystem object
176 * @return default buffer size to use during writes
178 public static int getDefaultBufferSize(final FileSystem fs
) {
179 return fs
.getConf().getInt("io.file.buffer.size", 4096);
183 * Create the specified file on the filesystem. By default, this will:
185 * <li>apply the umask in the configuration (if it is enabled)</li>
186 * <li>use the fs configured buffer size (or 4096 if not set)</li>
187 * <li>use the default replication</li>
188 * <li>use the default block size</li>
189 * <li>not track progress</li>
192 * @param fs {@link FileSystem} on which to write the file
193 * @param path {@link Path} to the file to write
194 * @param perm intial permissions
195 * @param overwrite Whether or not the created file should be overwritten.
196 * @return output stream to the created file
197 * @throws IOException if the file cannot be created
199 public static FSDataOutputStream
create(FileSystem fs
, Path path
,
200 FsPermission perm
, boolean overwrite
) throws IOException
{
201 if (LOG
.isTraceEnabled()) {
202 LOG
.trace("Creating file={} with permission={}, overwrite={}", path
, perm
, overwrite
);
204 return fs
.create(path
, perm
, overwrite
, getDefaultBufferSize(fs
),
205 getDefaultReplication(fs
, path
), getDefaultBlockSize(fs
, path
), null);
209 * Get the file permissions specified in the configuration, if they are
212 * @param fs filesystem that the file will be created on.
213 * @param conf configuration to read for determining if permissions are
214 * enabled and which to use
215 * @param permssionConfKey property key in the configuration to use when
216 * finding the permission
217 * @return the permission to use when creating a new file on the fs. If
218 * special permissions are not specified in the configuration, then
219 * the default permissions on the the fs will be returned.
221 public static FsPermission
getFilePermissions(final FileSystem fs
,
222 final Configuration conf
, final String permssionConfKey
) {
223 boolean enablePermissions
= conf
.getBoolean(
224 HConstants
.ENABLE_DATA_FILE_UMASK
, false);
226 if (enablePermissions
) {
228 FsPermission perm
= new FsPermission(FULL_RWX_PERMISSIONS
);
229 // make sure that we have a mask, if not, go default.
230 String mask
= conf
.get(permssionConfKey
);
232 return FsPermission
.getFileDefault();
235 FsPermission umask
= new FsPermission(mask
);
236 return perm
.applyUMask(umask
);
237 } catch (IllegalArgumentException e
) {
239 "Incorrect umask attempted to be created: "
240 + conf
.get(permssionConfKey
)
241 + ", using default file permissions.", e
);
242 return FsPermission
.getFileDefault();
245 return FsPermission
.getFileDefault();
249 * Verifies root directory path is a valid URI with a scheme
251 * @param root root directory path
252 * @return Passed <code>root</code> argument.
253 * @throws IOException if not a valid URI with a scheme
255 public static Path
validateRootPath(Path root
) throws IOException
{
257 URI rootURI
= new URI(root
.toString());
258 String scheme
= rootURI
.getScheme();
259 if (scheme
== null) {
260 throw new IOException("Root directory does not have a scheme");
263 } catch (URISyntaxException e
) {
264 throw new IOException("Root directory path is not a valid " +
265 "URI -- check your " + HConstants
.HBASE_DIR
+ " configuration", e
);
270 * Checks for the presence of the WAL log root path (using the provided conf object) in the given
271 * path. If it exists, this method removes it and returns the String representation of remaining
273 * @param path must not be null
274 * @param conf must not be null
275 * @return String representation of the remaining relative path
276 * @throws IOException from underlying filesystem
278 public static String
removeWALRootPath(Path path
, final Configuration conf
) throws IOException
{
279 Path root
= getWALRootDir(conf
);
280 String pathStr
= path
.toString();
281 // check that the path is absolute... it has the root path in it.
282 if (!pathStr
.startsWith(root
.toString())) {
285 // if not, return as it is.
286 return pathStr
.substring(root
.toString().length() + 1);// remove the "/" too.
290 * Return the 'path' component of a Path. In Hadoop, Path is a URI. This
291 * method returns the 'path' component of a Path's URI: e.g. If a Path is
292 * <code>hdfs://example.org:9000/hbase_trunk/TestTable/compaction.dir</code>,
293 * this method returns <code>/hbase_trunk/TestTable/compaction.dir</code>.
294 * This method is useful if you want to print out a Path without qualifying
295 * Filesystem instance.
296 * @param p Filesystem Path whose 'path' component we are to return.
297 * @return Path portion of the Filesystem
299 public static String
getPath(Path p
) {
300 return p
.toUri().getPath();
304 * @param c configuration
305 * @return {@link Path} to hbase root directory from
306 * configuration as a qualified Path.
307 * @throws IOException e
309 public static Path
getRootDir(final Configuration c
) throws IOException
{
310 Path p
= new Path(c
.get(HConstants
.HBASE_DIR
));
311 FileSystem fs
= p
.getFileSystem(c
);
312 return p
.makeQualified(fs
.getUri(), fs
.getWorkingDirectory());
315 public static void setRootDir(final Configuration c
, final Path root
) {
316 c
.set(HConstants
.HBASE_DIR
, root
.toString());
319 public static void setFsDefault(final Configuration c
, final Path root
) {
320 c
.set("fs.defaultFS", root
.toString()); // for hadoop 0.21+
323 public static FileSystem
getRootDirFileSystem(final Configuration c
) throws IOException
{
324 Path p
= getRootDir(c
);
325 return p
.getFileSystem(c
);
329 * @param c configuration
330 * @return {@link Path} to hbase log root directory: e.g. {@value HBASE_WAL_DIR} from
331 * configuration as a qualified Path. Defaults to HBase root dir.
332 * @throws IOException e
334 public static Path
getWALRootDir(final Configuration c
) throws IOException
{
335 Path p
= new Path(c
.get(HBASE_WAL_DIR
, c
.get(HConstants
.HBASE_DIR
)));
336 if (!isValidWALRootDir(p
, c
)) {
337 return getRootDir(c
);
339 FileSystem fs
= p
.getFileSystem(c
);
340 return p
.makeQualified(fs
.getUri(), fs
.getWorkingDirectory());
344 public static void setWALRootDir(final Configuration c
, final Path root
) {
345 c
.set(HBASE_WAL_DIR
, root
.toString());
348 public static FileSystem
getWALFileSystem(final Configuration c
) throws IOException
{
349 Path p
= getWALRootDir(c
);
350 FileSystem fs
= p
.getFileSystem(c
);
351 // hadoop-core does fs caching, so need to propagate this if set
352 String enforceStreamCapability
= c
.get(UNSAFE_STREAM_CAPABILITY_ENFORCE
);
353 if (enforceStreamCapability
!= null) {
354 fs
.getConf().set(UNSAFE_STREAM_CAPABILITY_ENFORCE
, enforceStreamCapability
);
356 if (fs
instanceof LocalFileSystem
) {
357 // running on LocalFileSystem, which does not support the required capabilities `HSYNC`
358 // and `HFLUSH`. disable enforcement.
359 final boolean value
= false;
360 LOG
.warn("Cannot enforce durability guarantees while running on {}. Setting {}={} for"
361 + " this FileSystem.", fs
.getUri(), UNSAFE_STREAM_CAPABILITY_ENFORCE
, value
);
362 fs
.getConf().setBoolean(UNSAFE_STREAM_CAPABILITY_ENFORCE
, value
);
367 private static boolean isValidWALRootDir(Path walDir
, final Configuration c
) throws IOException
{
368 Path rootDir
= getRootDir(c
);
369 FileSystem fs
= walDir
.getFileSystem(c
);
370 Path qualifiedWalDir
= walDir
.makeQualified(fs
.getUri(), fs
.getWorkingDirectory());
371 if (!qualifiedWalDir
.equals(rootDir
)) {
372 if (qualifiedWalDir
.toString().startsWith(rootDir
.toString() + "/")) {
373 throw new IllegalStateException("Illegal WAL directory specified. " +
374 "WAL directories are not permitted to be under the root directory if set.");
381 * Returns the WAL region directory based on the given table name and region name
382 * @param conf configuration to determine WALRootDir
383 * @param tableName Table that the region is under
384 * @param encodedRegionName Region name used for creating the final region directory
385 * @return the region directory used to store WALs under the WALRootDir
386 * @throws IOException if there is an exception determining the WALRootDir
388 public static Path
getWALRegionDir(final Configuration conf
, final TableName tableName
,
389 final String encodedRegionName
) throws IOException
{
390 return new Path(getWALTableDir(conf
, tableName
), encodedRegionName
);
394 * Returns the Table directory under the WALRootDir for the specified table name
395 * @param conf configuration used to get the WALRootDir
396 * @param tableName Table to get the directory for
397 * @return a path to the WAL table directory for the specified table
398 * @throws IOException if there is an exception determining the WALRootDir
400 public static Path
getWALTableDir(final Configuration conf
, final TableName tableName
)
402 Path baseDir
= new Path(getWALRootDir(conf
), HConstants
.BASE_NAMESPACE_DIR
);
403 return new Path(new Path(baseDir
, tableName
.getNamespaceAsString()),
404 tableName
.getQualifierAsString());
408 * For backward compatibility with HBASE-20734, where we store recovered edits in a wrong
409 * directory without BASE_NAMESPACE_DIR. See HBASE-22617 for more details.
410 * @deprecated For compatibility, will be removed in 4.0.0.
413 public static Path
getWrongWALRegionDir(final Configuration conf
, final TableName tableName
,
414 final String encodedRegionName
) throws IOException
{
415 Path wrongTableDir
= new Path(new Path(getWALRootDir(conf
), tableName
.getNamespaceAsString()),
416 tableName
.getQualifierAsString());
417 return new Path(wrongTableDir
, encodedRegionName
);
421 * Returns the {@link org.apache.hadoop.fs.Path} object representing the table directory under
424 * @param rootdir qualified path of HBase root directory
425 * @param tableName name of table
426 * @return {@link org.apache.hadoop.fs.Path} for table
428 public static Path
getTableDir(Path rootdir
, final TableName tableName
) {
429 return new Path(getNamespaceDir(rootdir
, tableName
.getNamespaceAsString()),
430 tableName
.getQualifierAsString());
434 * Returns the {@link org.apache.hadoop.hbase.TableName} object representing
435 * the table directory under
438 * @param tablePath path of table
439 * @return {@link org.apache.hadoop.fs.Path} for table
441 public static TableName
getTableName(Path tablePath
) {
442 return TableName
.valueOf(tablePath
.getParent().getName(), tablePath
.getName());
446 * Returns the {@link org.apache.hadoop.fs.Path} object representing
447 * the namespace directory under path rootdir
449 * @param rootdir qualified path of HBase root directory
450 * @param namespace namespace name
451 * @return {@link org.apache.hadoop.fs.Path} for table
453 public static Path
getNamespaceDir(Path rootdir
, final String namespace
) {
454 return new Path(rootdir
, new Path(HConstants
.BASE_NAMESPACE_DIR
,
455 new Path(namespace
)));
458 // this mapping means that under a federated FileSystem implementation, we'll
459 // only log the first failure from any of the underlying FileSystems at WARN and all others
461 private static final Map
<FileSystem
, Boolean
> warningMap
= new ConcurrentHashMap
<>();
464 * Sets storage policy for given path.
465 * If the passed path is a directory, we'll set the storage policy for all files
466 * created in the future in said directory. Note that this change in storage
467 * policy takes place at the FileSystem level; it will persist beyond this RS's lifecycle.
468 * If we're running on a version of FileSystem that doesn't support the given storage policy
469 * (or storage policies at all), then we'll issue a log message and continue.
471 * See http://hadoop.apache.org/docs/r2.6.0/hadoop-project-dist/hadoop-hdfs/ArchivalStorage.html
473 * @param fs We only do anything it implements a setStoragePolicy method
474 * @param path the Path whose storage policy is to be set
475 * @param storagePolicy Policy to set on <code>path</code>; see hadoop 2.6+
476 * org.apache.hadoop.hdfs.protocol.HdfsConstants for possible list e.g
477 * 'COLD', 'WARM', 'HOT', 'ONE_SSD', 'ALL_SSD', 'LAZY_PERSIST'.
479 public static void setStoragePolicy(final FileSystem fs
, final Path path
,
480 final String storagePolicy
) {
482 setStoragePolicy(fs
, path
, storagePolicy
, false);
483 } catch (IOException e
) {
484 // should never arrive here
485 LOG
.warn("We have chosen not to throw exception but some unexpectedly thrown out", e
);
489 static void setStoragePolicy(final FileSystem fs
, final Path path
, final String storagePolicy
,
490 boolean throwException
) throws IOException
{
491 if (storagePolicy
== null) {
492 if (LOG
.isTraceEnabled()) {
493 LOG
.trace("We were passed a null storagePolicy, exiting early.");
497 String trimmedStoragePolicy
= storagePolicy
.trim();
498 if (trimmedStoragePolicy
.isEmpty()) {
499 LOG
.trace("We were passed an empty storagePolicy, exiting early.");
502 trimmedStoragePolicy
= trimmedStoragePolicy
.toUpperCase(Locale
.ROOT
);
504 if (trimmedStoragePolicy
.equals(HConstants
.DEFER_TO_HDFS_STORAGE_POLICY
)) {
505 LOG
.trace("We were passed the defer-to-hdfs policy {}, exiting early.", trimmedStoragePolicy
);
509 invokeSetStoragePolicy(fs
, path
, trimmedStoragePolicy
);
510 } catch (IOException e
) {
511 LOG
.trace("Failed to invoke set storage policy API on FS", e
);
512 if (throwException
) {
519 * All args have been checked and are good. Run the setStoragePolicy invocation.
521 private static void invokeSetStoragePolicy(final FileSystem fs
, final Path path
,
522 final String storagePolicy
) throws IOException
{
523 Exception toThrow
= null;
526 fs
.setStoragePolicy(path
, storagePolicy
);
527 LOG
.debug("Set storagePolicy={} for path={}", storagePolicy
, path
);
528 } catch (Exception e
) {
530 // This swallows FNFE, should we be throwing it? seems more likely to indicate dev
531 // misuse than a runtime problem with HDFS.
532 if (!warningMap
.containsKey(fs
)) {
533 warningMap
.put(fs
, true);
534 LOG
.warn("Unable to set storagePolicy=" + storagePolicy
+ " for path=" + path
+ ". " +
535 "DEBUG log level might have more details.", e
);
536 } else if (LOG
.isDebugEnabled()) {
537 LOG
.debug("Unable to set storagePolicy=" + storagePolicy
+ " for path=" + path
, e
);
540 // Hadoop 2.8+, 3.0-a1+ added FileSystem.setStoragePolicy with a default implementation
541 // that throws UnsupportedOperationException
542 if (e
instanceof UnsupportedOperationException
) {
543 if (LOG
.isDebugEnabled()) {
544 LOG
.debug("The underlying FileSystem implementation doesn't support " +
545 "setStoragePolicy. This is probably intentional on their part, since HDFS-9345 " +
546 "appears to be present in your version of Hadoop. For more information check " +
547 "the Hadoop documentation on 'ArchivalStorage', the Hadoop FileSystem " +
548 "specification docs from HADOOP-11981, and/or related documentation from the " +
549 "provider of the underlying FileSystem (its name should appear in the " +
550 "stacktrace that accompanies this message). Note in particular that Hadoop's " +
551 "local filesystem implementation doesn't support storage policies.", e
);
556 if (toThrow
!= null) {
557 throw new IOException(toThrow
);
562 * @param conf must not be null
563 * @return True if this filesystem whose scheme is 'hdfs'.
564 * @throws IOException from underlying FileSystem
566 public static boolean isHDFS(final Configuration conf
) throws IOException
{
567 FileSystem fs
= FileSystem
.get(conf
);
568 String scheme
= fs
.getUri().getScheme();
569 return scheme
.equalsIgnoreCase("hdfs");
573 * Checks if the given path is the one with 'recovered.edits' dir.
574 * @param path must not be null
575 * @return True if we recovered edits
577 public static boolean isRecoveredEdits(Path path
) {
578 return path
.toString().contains(HConstants
.RECOVERED_EDITS_DIR
);
582 * @param conf must not be null
583 * @return Returns the filesystem of the hbase rootdir.
584 * @throws IOException from underlying FileSystem
586 public static FileSystem
getCurrentFileSystem(Configuration conf
) throws IOException
{
587 return getRootDir(conf
).getFileSystem(conf
);
591 * Calls fs.listStatus() and treats FileNotFoundException as non-fatal
592 * This accommodates differences between hadoop versions, where hadoop 1
593 * does not throw a FileNotFoundException, and return an empty FileStatus[]
594 * while Hadoop 2 will throw FileNotFoundException.
596 * Where possible, prefer FSUtils#listStatusWithStatusFilter(FileSystem,
597 * Path, FileStatusFilter) instead.
599 * @param fs file system
600 * @param dir directory
601 * @param filter path filter
602 * @return null if dir is empty or doesn't exist, otherwise FileStatus array
604 public static FileStatus
[] listStatus(final FileSystem fs
,
605 final Path dir
, final PathFilter filter
) throws IOException
{
606 FileStatus
[] status
= null;
608 status
= filter
== null ? fs
.listStatus(dir
) : fs
.listStatus(dir
, filter
);
609 } catch (FileNotFoundException fnfe
) {
610 // if directory doesn't exist, return null
611 if (LOG
.isTraceEnabled()) {
612 LOG
.trace("{} doesn't exist", dir
);
615 if (status
== null || status
.length
< 1) {
622 * Calls fs.listStatus() and treats FileNotFoundException as non-fatal
623 * This would accommodates differences between hadoop versions
625 * @param fs file system
626 * @param dir directory
627 * @return null if dir is empty or doesn't exist, otherwise FileStatus array
629 public static FileStatus
[] listStatus(final FileSystem fs
, final Path dir
) throws IOException
{
630 return listStatus(fs
, dir
, null);
634 * Calls fs.listFiles() to get FileStatus and BlockLocations together for reducing rpc call
636 * @param fs file system
637 * @param dir directory
638 * @return LocatedFileStatus list
640 public static List
<LocatedFileStatus
> listLocatedStatus(final FileSystem fs
,
641 final Path dir
) throws IOException
{
642 List
<LocatedFileStatus
> status
= null;
644 RemoteIterator
<LocatedFileStatus
> locatedFileStatusRemoteIterator
= fs
645 .listFiles(dir
, false);
646 while (locatedFileStatusRemoteIterator
.hasNext()) {
647 if (status
== null) {
648 status
= Lists
.newArrayList();
650 status
.add(locatedFileStatusRemoteIterator
.next());
652 } catch (FileNotFoundException fnfe
) {
653 // if directory doesn't exist, return null
654 if (LOG
.isTraceEnabled()) {
655 LOG
.trace("{} doesn't exist", dir
);
662 * Calls fs.delete() and returns the value returned by the fs.delete()
664 * @param fs must not be null
665 * @param path must not be null
666 * @param recursive delete tree rooted at path
667 * @return the value returned by the fs.delete()
668 * @throws IOException from underlying FileSystem
670 public static boolean delete(final FileSystem fs
, final Path path
, final boolean recursive
)
672 return fs
.delete(path
, recursive
);
676 * Calls fs.exists(). Checks if the specified path exists
678 * @param fs must not be null
679 * @param path must not be null
680 * @return the value returned by fs.exists()
681 * @throws IOException from underlying FileSystem
683 public static boolean isExists(final FileSystem fs
, final Path path
) throws IOException
{
684 return fs
.exists(path
);
688 * Log the current state of the filesystem from a certain root directory
689 * @param fs filesystem to investigate
690 * @param root root file/directory to start logging from
691 * @param log log to output information
692 * @throws IOException if an unexpected exception occurs
694 public static void logFileSystemState(final FileSystem fs
, final Path root
, Logger log
)
696 log
.debug("File system contents for path {}", root
);
697 logFSTree(log
, fs
, root
, "|-");
701 * Recursive helper to log the state of the FS
703 * @see #logFileSystemState(FileSystem, Path, Logger)
705 private static void logFSTree(Logger log
, final FileSystem fs
, final Path root
, String prefix
)
707 FileStatus
[] files
= listStatus(fs
, root
, null);
712 for (FileStatus file
: files
) {
713 if (file
.isDirectory()) {
714 log
.debug(prefix
+ file
.getPath().getName() + "/");
715 logFSTree(log
, fs
, file
.getPath(), prefix
+ "---");
717 log
.debug(prefix
+ file
.getPath().getName());
722 public static boolean renameAndSetModifyTime(final FileSystem fs
, final Path src
, final Path dest
)
724 // set the modify time for TimeToLive Cleaner
725 fs
.setTimes(src
, EnvironmentEdgeManager
.currentTime(), -1);
726 return fs
.rename(src
, dest
);
730 * Check if short circuit read buffer size is set and if not, set it to hbase value.
731 * @param conf must not be null
733 public static void checkShortCircuitReadBufferSize(final Configuration conf
) {
734 final int defaultSize
= HConstants
.DEFAULT_BLOCKSIZE
* 2;
735 final int notSet
= -1;
736 // DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_BUFFER_SIZE_KEY is only defined in h2
737 final String dfsKey
= "dfs.client.read.shortcircuit.buffer.size";
738 int size
= conf
.getInt(dfsKey
, notSet
);
739 // If a size is set, return -- we will use it.
740 if (size
!= notSet
) {
743 // But short circuit buffer size is normally not set. Put in place the hbase wanted size.
744 int hbaseSize
= conf
.getInt("hbase." + dfsKey
, defaultSize
);
745 conf
.setIfUnset(dfsKey
, Integer
.toString(hbaseSize
));
748 private static final class DfsBuilderUtility
{
749 private static final Class
<?
> BUILDER
;
750 private static final Method REPLICATE
;
753 String builderName
= "org.apache.hadoop.hdfs.DistributedFileSystem$HdfsDataOutputStreamBuilder";
754 Class
<?
> builderClass
= null;
756 builderClass
= Class
.forName(builderName
);
757 } catch (ClassNotFoundException e
) {
758 LOG
.debug("{} not available, will not set replicate when creating output stream", builderName
);
760 Method replicateMethod
= null;
761 if (builderClass
!= null) {
763 replicateMethod
= builderClass
.getMethod("replicate");
764 LOG
.debug("Using builder API via reflection for DFS file creation.");
765 } catch (NoSuchMethodException e
) {
766 LOG
.debug("Could not find replicate method on builder; will not set replicate when" +
767 " creating output stream", e
);
770 BUILDER
= builderClass
;
771 REPLICATE
= replicateMethod
;
775 * Attempt to use builder API via reflection to call the replicate method on the given builder.
777 static void replicate(FSDataOutputStreamBuilder
<?
, ?
> builder
) {
778 if (BUILDER
!= null && REPLICATE
!= null && BUILDER
.isAssignableFrom(builder
.getClass())) {
780 REPLICATE
.invoke(builder
);
781 } catch (IllegalAccessException
| InvocationTargetException e
) {
782 // Should have caught this failure during initialization, so log full trace here
783 LOG
.warn("Couldn't use reflection with builder API", e
);
790 * Attempt to use builder API via reflection to create a file with the given parameters and
791 * replication enabled.
793 * Will not attempt to enable replication when passed an HFileSystem.
795 public static FSDataOutputStream
createForWal(FileSystem fs
, Path path
, boolean overwrite
)
797 FSDataOutputStreamBuilder
<?
, ?
> builder
= fs
.createFile(path
).overwrite(overwrite
);
798 DfsBuilderUtility
.replicate(builder
);
799 return builder
.build();
803 * Attempt to use builder API via reflection to create a file with the given parameters and
804 * replication enabled.
806 * Will not attempt to enable replication when passed an HFileSystem.
808 public static FSDataOutputStream
createForWal(FileSystem fs
, Path path
, boolean overwrite
,
809 int bufferSize
, short replication
, long blockSize
, boolean isRecursive
) throws IOException
{
810 FSDataOutputStreamBuilder
<?
, ?
> builder
= fs
.createFile(path
).overwrite(overwrite
)
811 .bufferSize(bufferSize
).replication(replication
).blockSize(blockSize
);
815 DfsBuilderUtility
.replicate(builder
);
816 return builder
.build();
820 * Helper exception for those cases where the place where we need to check a stream capability
821 * is not where we have the needed context to explain the impact and mitigation for a lack.
823 public static class StreamLacksCapabilityException
extends Exception
{
824 public StreamLacksCapabilityException(String message
, Throwable cause
) {
825 super(message
, cause
);
827 public StreamLacksCapabilityException(String message
) {