001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.fs; 019 020import java.io.Closeable; 021import java.io.FileNotFoundException; 022import java.io.IOException; 023import java.lang.ref.WeakReference; 024 025import java.net.InetSocketAddress; 026import java.net.URI; 027import java.net.URISyntaxException; 028import java.security.PrivilegedExceptionAction; 029import java.util.ArrayList; 030import java.util.EnumSet; 031import java.util.HashMap; 032import java.util.HashSet; 033import java.util.IdentityHashMap; 034import java.util.Iterator; 035import java.util.LinkedList; 036import java.util.List; 037import java.util.Map; 038import java.util.NoSuchElementException; 039import java.util.ServiceLoader; 040import java.util.Set; 041import java.util.Stack; 042import java.util.TreeSet; 043import java.util.concurrent.atomic.AtomicLong; 044 045import org.apache.commons.logging.Log; 046import org.apache.commons.logging.LogFactory; 047import org.apache.hadoop.classification.InterfaceAudience; 048import org.apache.hadoop.classification.InterfaceStability; 049import org.apache.hadoop.conf.Configuration; 050import org.apache.hadoop.conf.Configured; 051import org.apache.hadoop.fs.Options.ChecksumOpt; 052import org.apache.hadoop.fs.Options.Rename; 053import org.apache.hadoop.fs.permission.AclEntry; 054import org.apache.hadoop.fs.permission.AclStatus; 055import org.apache.hadoop.fs.permission.FsPermission; 056import org.apache.hadoop.io.MultipleIOException; 057import org.apache.hadoop.io.Text; 058import org.apache.hadoop.net.NetUtils; 059import org.apache.hadoop.security.AccessControlException; 060import org.apache.hadoop.security.Credentials; 061import org.apache.hadoop.security.SecurityUtil; 062import org.apache.hadoop.security.UserGroupInformation; 063import org.apache.hadoop.security.token.Token; 064import org.apache.hadoop.util.DataChecksum; 065import org.apache.hadoop.util.Progressable; 066import org.apache.hadoop.util.ReflectionUtils; 067import org.apache.hadoop.util.ShutdownHookManager; 068 069import com.google.common.annotations.VisibleForTesting; 070 071/**************************************************************** 072 * An abstract base class for a fairly generic filesystem. It 073 * may be implemented as a distributed filesystem, or as a "local" 074 * one that reflects the locally-connected disk. The local version 075 * exists for small Hadoop instances and for testing. 076 * 077 * <p> 078 * 079 * All user code that may potentially use the Hadoop Distributed 080 * File System should be written to use a FileSystem object. The 081 * Hadoop DFS is a multi-machine system that appears as a single 082 * disk. It's useful because of its fault tolerance and potentially 083 * very large capacity. 084 * 085 * <p> 086 * The local implementation is {@link LocalFileSystem} and distributed 087 * implementation is DistributedFileSystem. 088 *****************************************************************/ 089@InterfaceAudience.Public 090@InterfaceStability.Stable 091public abstract class FileSystem extends Configured implements Closeable { 092 public static final String FS_DEFAULT_NAME_KEY = 093 CommonConfigurationKeys.FS_DEFAULT_NAME_KEY; 094 public static final String DEFAULT_FS = 095 CommonConfigurationKeys.FS_DEFAULT_NAME_DEFAULT; 096 097 public static final Log LOG = LogFactory.getLog(FileSystem.class); 098 099 /** 100 * Priority of the FileSystem shutdown hook. 101 */ 102 public static final int SHUTDOWN_HOOK_PRIORITY = 10; 103 104 /** FileSystem cache */ 105 static final Cache CACHE = new Cache(); 106 107 /** The key this instance is stored under in the cache. */ 108 private Cache.Key key; 109 110 /** Recording statistics per a FileSystem class */ 111 private static final Map<Class<? extends FileSystem>, Statistics> 112 statisticsTable = 113 new IdentityHashMap<Class<? extends FileSystem>, Statistics>(); 114 115 /** 116 * The statistics for this file system. 117 */ 118 protected Statistics statistics; 119 120 /** 121 * A cache of files that should be deleted when filsystem is closed 122 * or the JVM is exited. 123 */ 124 private Set<Path> deleteOnExit = new TreeSet<Path>(); 125 126 boolean resolveSymlinks; 127 /** 128 * This method adds a file system for testing so that we can find it later. It 129 * is only for testing. 130 * @param uri the uri to store it under 131 * @param conf the configuration to store it under 132 * @param fs the file system to store 133 * @throws IOException 134 */ 135 static void addFileSystemForTesting(URI uri, Configuration conf, 136 FileSystem fs) throws IOException { 137 CACHE.map.put(new Cache.Key(uri, conf), fs); 138 } 139 140 /** 141 * Get a filesystem instance based on the uri, the passed 142 * configuration and the user 143 * @param uri of the filesystem 144 * @param conf the configuration to use 145 * @param user to perform the get as 146 * @return the filesystem instance 147 * @throws IOException 148 * @throws InterruptedException 149 */ 150 public static FileSystem get(final URI uri, final Configuration conf, 151 final String user) throws IOException, InterruptedException { 152 String ticketCachePath = 153 conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH); 154 UserGroupInformation ugi = 155 UserGroupInformation.getBestUGI(ticketCachePath, user); 156 return ugi.doAs(new PrivilegedExceptionAction<FileSystem>() { 157 @Override 158 public FileSystem run() throws IOException { 159 return get(uri, conf); 160 } 161 }); 162 } 163 164 /** 165 * Returns the configured filesystem implementation. 166 * @param conf the configuration to use 167 */ 168 public static FileSystem get(Configuration conf) throws IOException { 169 return get(getDefaultUri(conf), conf); 170 } 171 172 /** Get the default filesystem URI from a configuration. 173 * @param conf the configuration to use 174 * @return the uri of the default filesystem 175 */ 176 public static URI getDefaultUri(Configuration conf) { 177 return URI.create(fixName(conf.get(FS_DEFAULT_NAME_KEY, DEFAULT_FS))); 178 } 179 180 /** 181 * create PathId: A Factory method to create PathIds. PathIds are used 182 * by MapRFS in the direct shuffle to get access to the file paths. 183 */ 184 public PathId createPathId() { 185 //Base class throws Unsupported Exception 186 //TODO determine if this is the right approach 187 throw new UnsupportedOperationException(); 188 } 189 190 public FSDataInputStream openFid2(PathId pfid, String file, int readAheadBytesHint) 191 throws IOException { 192 throw new UnsupportedOperationException("See concrete FS for implementation"); 193 } 194 public FSDataOutputStream createFid(String pfid, String file) 195 throws IOException { 196 throw new UnsupportedOperationException("See concrete FS for implementation"); 197 } 198 public boolean deleteFid(String pfid, String dir) 199 throws IOException { 200 throw new UnsupportedOperationException("See concrete FS for implementation"); 201 } 202 public String mkdirsFid(Path p) throws IOException { 203 throw new UnsupportedOperationException("See concrete FS for implementation"); 204 } 205 public String mkdirsFid(String pfid, String dir) 206 throws IOException { 207 throw new UnsupportedOperationException("See concrete FS for implementation"); 208 } 209 public void setOwnerFid(String fid, String user, String group) throws IOException { 210 throw new UnsupportedOperationException("See concrete FS for implementation"); 211 } 212 213 214 /** Set the default filesystem URI in a configuration. 215 * @param conf the configuration to alter 216 * @param uri the new default filesystem uri 217 */ 218 public static void setDefaultUri(Configuration conf, URI uri) { 219 conf.set(FS_DEFAULT_NAME_KEY, uri.toString()); 220 } 221 222 /** Set the default filesystem URI in a configuration. 223 * @param conf the configuration to alter 224 * @param uri the new default filesystem uri 225 */ 226 public static void setDefaultUri(Configuration conf, String uri) { 227 setDefaultUri(conf, URI.create(fixName(uri))); 228 } 229 230 /** Called after a new FileSystem instance is constructed. 231 * @param name a uri whose authority section names the host, port, etc. 232 * for this FileSystem 233 * @param conf the configuration 234 */ 235 public void initialize(URI name, Configuration conf) throws IOException { 236 statistics = getStatistics(name.getScheme(), getClass()); 237 resolveSymlinks = conf.getBoolean( 238 CommonConfigurationKeys.FS_CLIENT_RESOLVE_REMOTE_SYMLINKS_KEY, 239 CommonConfigurationKeys.FS_CLIENT_RESOLVE_REMOTE_SYMLINKS_DEFAULT); 240 } 241 242 /** 243 * Return the protocol scheme for the FileSystem. 244 * <p/> 245 * This implementation throws an <code>UnsupportedOperationException</code>. 246 * 247 * @return the protocol scheme for the FileSystem. 248 */ 249 public String getScheme() { 250 throw new UnsupportedOperationException("Not implemented by the " + getClass().getSimpleName() + " FileSystem implementation"); 251 } 252 253 /** Returns a URI whose scheme and authority identify this FileSystem.*/ 254 public abstract URI getUri(); 255 256 /** 257 * Return a canonicalized form of this FileSystem's URI. 258 * 259 * The default implementation simply calls {@link #canonicalizeUri(URI)} 260 * on the filesystem's own URI, so subclasses typically only need to 261 * implement that method. 262 * 263 * @see #canonicalizeUri(URI) 264 */ 265 protected URI getCanonicalUri() { 266 return canonicalizeUri(getUri()); 267 } 268 269 /** 270 * Canonicalize the given URI. 271 * 272 * This is filesystem-dependent, but may for example consist of 273 * canonicalizing the hostname using DNS and adding the default 274 * port if not specified. 275 * 276 * The default implementation simply fills in the default port if 277 * not specified and if the filesystem has a default port. 278 * 279 * @return URI 280 * @see NetUtils#getCanonicalUri(URI, int) 281 */ 282 protected URI canonicalizeUri(URI uri) { 283 if (uri.getPort() == -1 && getDefaultPort() > 0) { 284 // reconstruct the uri with the default port set 285 try { 286 uri = new URI(uri.getScheme(), uri.getUserInfo(), 287 uri.getHost(), getDefaultPort(), 288 uri.getPath(), uri.getQuery(), uri.getFragment()); 289 } catch (URISyntaxException e) { 290 // Should never happen! 291 throw new AssertionError("Valid URI became unparseable: " + 292 uri); 293 } 294 } 295 296 return uri; 297 } 298 299 /** 300 * Get the default port for this file system. 301 * @return the default port or 0 if there isn't one 302 */ 303 protected int getDefaultPort() { 304 return 0; 305 } 306 307 protected static FileSystem getFSofPath(final Path absOrFqPath, 308 final Configuration conf) 309 throws UnsupportedFileSystemException, IOException { 310 absOrFqPath.checkNotSchemeWithRelative(); 311 absOrFqPath.checkNotRelative(); 312 313 // Uses the default file system if not fully qualified 314 return get(absOrFqPath.toUri(), conf); 315 } 316 317 /** 318 * Get a canonical service name for this file system. The token cache is 319 * the only user of the canonical service name, and uses it to lookup this 320 * filesystem's service tokens. 321 * If file system provides a token of its own then it must have a canonical 322 * name, otherwise canonical name can be null. 323 * 324 * Default Impl: If the file system has child file systems 325 * (such as an embedded file system) then it is assumed that the fs has no 326 * tokens of its own and hence returns a null name; otherwise a service 327 * name is built using Uri and port. 328 * 329 * @return a service string that uniquely identifies this file system, null 330 * if the filesystem does not implement tokens 331 * @see SecurityUtil#buildDTServiceName(URI, int) 332 */ 333 @InterfaceAudience.LimitedPrivate({ "HDFS", "MapReduce" }) 334 public String getCanonicalServiceName() { 335 return (getChildFileSystems() == null) 336 ? SecurityUtil.buildDTServiceName(getUri(), getDefaultPort()) 337 : null; 338 } 339 340 /** @deprecated call #getUri() instead.*/ 341 @Deprecated 342 public String getName() { return getUri().toString(); } 343 344 /** @deprecated call #get(URI,Configuration) instead. */ 345 @Deprecated 346 public static FileSystem getNamed(String name, Configuration conf) 347 throws IOException { 348 return get(URI.create(fixName(name)), conf); 349 } 350 351 /** Update old-format filesystem names, for back-compatibility. This should 352 * eventually be replaced with a checkName() method that throws an exception 353 * for old-format names. */ 354 private static String fixName(String name) { 355 // convert old-format name to new-format name 356 if (name.equals("local")) { // "local" is now "file:///". 357 LOG.warn("\"local\" is a deprecated filesystem name." 358 +" Use \"file:///\" instead."); 359 name = "file:///"; 360 } else if (name.indexOf('/')==-1) { // unqualified is "hdfs://" 361 LOG.warn("\""+name+"\" is a deprecated filesystem name." 362 +" Use \"hdfs://"+name+"/\" instead."); 363 name = "hdfs://"+name; 364 } 365 return name; 366 } 367 368 /** 369 * Get the local file system. 370 * @param conf the configuration to configure the file system with 371 * @return a LocalFileSystem 372 */ 373 public static LocalFileSystem getLocal(Configuration conf) 374 throws IOException { 375 return (LocalFileSystem)get(LocalFileSystem.NAME, conf); 376 } 377 378 /** Returns the FileSystem for this URI's scheme and authority. The scheme 379 * of the URI determines a configuration property name, 380 * <tt>fs.<i>scheme</i>.class</tt> whose value names the FileSystem class. 381 * The entire URI is passed to the FileSystem instance's initialize method. 382 */ 383 public static FileSystem get(URI uri, Configuration conf) throws IOException { 384 String scheme = uri.getScheme(); 385 String authority = uri.getAuthority(); 386 387 if (scheme == null && authority == null) { // use default FS 388 return get(conf); 389 } 390 391 if (scheme != null && authority == null) { // no authority 392 URI defaultUri = getDefaultUri(conf); 393 if (scheme.equals(defaultUri.getScheme()) // if scheme matches default 394 && defaultUri.getAuthority() != null) { // & default has authority 395 return get(defaultUri, conf); // return default 396 } 397 } 398 399 String disableCacheName = String.format("fs.%s.impl.disable.cache", scheme); 400 if (conf.getBoolean(disableCacheName, false)) { 401 return createFileSystem(uri, conf); 402 } 403 404 return CACHE.get(uri, conf); 405 } 406 407 /** 408 * Returns the FileSystem for this URI's scheme and authority and the 409 * passed user. Internally invokes {@link #newInstance(URI, Configuration)} 410 * @param uri of the filesystem 411 * @param conf the configuration to use 412 * @param user to perform the get as 413 * @return filesystem instance 414 * @throws IOException 415 * @throws InterruptedException 416 */ 417 public static FileSystem newInstance(final URI uri, final Configuration conf, 418 final String user) throws IOException, InterruptedException { 419 String ticketCachePath = 420 conf.get(CommonConfigurationKeys.KERBEROS_TICKET_CACHE_PATH); 421 UserGroupInformation ugi = 422 UserGroupInformation.getBestUGI(ticketCachePath, user); 423 return ugi.doAs(new PrivilegedExceptionAction<FileSystem>() { 424 @Override 425 public FileSystem run() throws IOException { 426 return newInstance(uri,conf); 427 } 428 }); 429 } 430 /** Returns the FileSystem for this URI's scheme and authority. The scheme 431 * of the URI determines a configuration property name, 432 * <tt>fs.<i>scheme</i>.class</tt> whose value names the FileSystem class. 433 * The entire URI is passed to the FileSystem instance's initialize method. 434 * This always returns a new FileSystem object. 435 */ 436 public static FileSystem newInstance(URI uri, Configuration conf) throws IOException { 437 String scheme = uri.getScheme(); 438 String authority = uri.getAuthority(); 439 440 if (scheme == null) { // no scheme: use default FS 441 return newInstance(conf); 442 } 443 444 if (authority == null) { // no authority 445 URI defaultUri = getDefaultUri(conf); 446 if (scheme.equals(defaultUri.getScheme()) // if scheme matches default 447 && defaultUri.getAuthority() != null) { // & default has authority 448 return newInstance(defaultUri, conf); // return default 449 } 450 } 451 return CACHE.getUnique(uri, conf); 452 } 453 454 /** Returns a unique configured filesystem implementation. 455 * This always returns a new FileSystem object. 456 * @param conf the configuration to use 457 */ 458 public static FileSystem newInstance(Configuration conf) throws IOException { 459 return newInstance(getDefaultUri(conf), conf); 460 } 461 462 /** 463 * Get a unique local file system object 464 * @param conf the configuration to configure the file system with 465 * @return a LocalFileSystem 466 * This always returns a new FileSystem object. 467 */ 468 public static LocalFileSystem newInstanceLocal(Configuration conf) 469 throws IOException { 470 return (LocalFileSystem)newInstance(LocalFileSystem.NAME, conf); 471 } 472 473 /** 474 * Close all cached filesystems. Be sure those filesystems are not 475 * used anymore. 476 * 477 * @throws IOException 478 */ 479 public static void closeAll() throws IOException { 480 CACHE.closeAll(); 481 } 482 483 /** 484 * Close all cached filesystems for a given UGI. Be sure those filesystems 485 * are not used anymore. 486 * @param ugi user group info to close 487 * @throws IOException 488 */ 489 public static void closeAllForUGI(UserGroupInformation ugi) 490 throws IOException { 491 CACHE.closeAll(ugi); 492 } 493 494 /** 495 * Make sure that a path specifies a FileSystem. 496 * @param path to use 497 */ 498 public Path makeQualified(Path path) { 499 checkPath(path); 500 return path.makeQualified(this.getUri(), this.getWorkingDirectory()); 501 } 502 503 /** 504 * Get a new delegation token for this file system. 505 * This is an internal method that should have been declared protected 506 * but wasn't historically. 507 * Callers should use {@link #addDelegationTokens(String, Credentials)} 508 * 509 * @param renewer the account name that is allowed to renew the token. 510 * @return a new delegation token 511 * @throws IOException 512 */ 513 @InterfaceAudience.Private() 514 public Token<?> getDelegationToken(String renewer) throws IOException { 515 return null; 516 } 517 518 /** 519 * Obtain all delegation tokens used by this FileSystem that are not 520 * already present in the given Credentials. Existing tokens will neither 521 * be verified as valid nor having the given renewer. Missing tokens will 522 * be acquired and added to the given Credentials. 523 * 524 * Default Impl: works for simple fs with its own token 525 * and also for an embedded fs whose tokens are those of its 526 * children file system (i.e. the embedded fs has not tokens of its 527 * own). 528 * 529 * @param renewer the user allowed to renew the delegation tokens 530 * @param credentials cache in which to add new delegation tokens 531 * @return list of new delegation tokens 532 * @throws IOException 533 */ 534 @InterfaceAudience.LimitedPrivate({ "HDFS", "MapReduce" }) 535 public Token<?>[] addDelegationTokens( 536 final String renewer, Credentials credentials) throws IOException { 537 if (credentials == null) { 538 credentials = new Credentials(); 539 } 540 final List<Token<?>> tokens = new ArrayList<Token<?>>(); 541 collectDelegationTokens(renewer, credentials, tokens); 542 return tokens.toArray(new Token<?>[tokens.size()]); 543 } 544 545 /** 546 * Recursively obtain the tokens for this FileSystem and all descended 547 * FileSystems as determined by getChildFileSystems(). 548 * @param renewer the user allowed to renew the delegation tokens 549 * @param credentials cache in which to add the new delegation tokens 550 * @param tokens list in which to add acquired tokens 551 * @throws IOException 552 */ 553 private void collectDelegationTokens(final String renewer, 554 final Credentials credentials, 555 final List<Token<?>> tokens) 556 throws IOException { 557 final String serviceName = getCanonicalServiceName(); 558 // Collect token of the this filesystem and then of its embedded children 559 if (serviceName != null) { // fs has token, grab it 560 final Text service = new Text(serviceName); 561 Token<?> token = credentials.getToken(service); 562 if (token == null) { 563 token = getDelegationToken(renewer); 564 if (token != null) { 565 tokens.add(token); 566 credentials.addToken(service, token); 567 } 568 } 569 } 570 // Now collect the tokens from the children 571 final FileSystem[] children = getChildFileSystems(); 572 if (children != null) { 573 for (final FileSystem fs : children) { 574 fs.collectDelegationTokens(renewer, credentials, tokens); 575 } 576 } 577 } 578 579 /** 580 * Get all the immediate child FileSystems embedded in this FileSystem. 581 * It does not recurse and get grand children. If a FileSystem 582 * has multiple child FileSystems, then it should return a unique list 583 * of those FileSystems. Default is to return null to signify no children. 584 * 585 * @return FileSystems used by this FileSystem 586 */ 587 @InterfaceAudience.LimitedPrivate({ "HDFS" }) 588 @VisibleForTesting 589 public FileSystem[] getChildFileSystems() { 590 return null; 591 } 592 593 /** create a file with the provided permission 594 * The permission of the file is set to be the provided permission as in 595 * setPermission, not permission&~umask 596 * 597 * It is implemented using two RPCs. It is understood that it is inefficient, 598 * but the implementation is thread-safe. The other option is to change the 599 * value of umask in configuration to be 0, but it is not thread-safe. 600 * 601 * @param fs file system handle 602 * @param file the name of the file to be created 603 * @param permission the permission of the file 604 * @return an output stream 605 * @throws IOException 606 */ 607 public static FSDataOutputStream create(FileSystem fs, 608 Path file, FsPermission permission) throws IOException { 609 // create the file with default permission 610 FSDataOutputStream out = fs.create(file); 611 // set its permission to the supplied one 612 fs.setPermission(file, permission); 613 return out; 614 } 615 616 /** create a directory with the provided permission 617 * The permission of the directory is set to be the provided permission as in 618 * setPermission, not permission&~umask 619 * 620 * @see #create(FileSystem, Path, FsPermission) 621 * 622 * @param fs file system handle 623 * @param dir the name of the directory to be created 624 * @param permission the permission of the directory 625 * @return true if the directory creation succeeds; false otherwise 626 * @throws IOException 627 */ 628 public static boolean mkdirs(FileSystem fs, Path dir, FsPermission permission) 629 throws IOException { 630 // create the directory using the default permission 631 boolean result = fs.mkdirs(dir); 632 // set its permission to be the supplied one 633 fs.setPermission(dir, permission); 634 return result; 635 } 636 637 /////////////////////////////////////////////////////////////// 638 // FileSystem 639 /////////////////////////////////////////////////////////////// 640 641 protected FileSystem() { 642 super(null); 643 } 644 645 /** 646 * Check that a Path belongs to this FileSystem. 647 * @param path to check 648 */ 649 protected void checkPath(Path path) { 650 URI uri = path.toUri(); 651 String thatScheme = uri.getScheme(); 652 if (thatScheme == null) // fs is relative 653 return; 654 URI thisUri = getCanonicalUri(); 655 String thisScheme = thisUri.getScheme(); 656 //authority and scheme are not case sensitive 657 if (thisScheme.equalsIgnoreCase(thatScheme)) {// schemes match 658 String thisAuthority = thisUri.getAuthority(); 659 String thatAuthority = uri.getAuthority(); 660 if (thatAuthority == null && // path's authority is null 661 thisAuthority != null) { // fs has an authority 662 URI defaultUri = getDefaultUri(getConf()); 663 if (thisScheme.equalsIgnoreCase(defaultUri.getScheme())) { 664 uri = defaultUri; // schemes match, so use this uri instead 665 } else { 666 uri = null; // can't determine auth of the path 667 } 668 } 669 if (uri != null) { 670 // canonicalize uri before comparing with this fs 671 uri = canonicalizeUri(uri); 672 thatAuthority = uri.getAuthority(); 673 if (thisAuthority == thatAuthority || // authorities match 674 (thisAuthority != null && 675 thisAuthority.equalsIgnoreCase(thatAuthority))) 676 return; 677 } 678 } 679 throw new IllegalArgumentException("Wrong FS: "+path+ 680 ", expected: "+this.getUri()); 681 } 682 683 /** 684 * Return an array containing hostnames, offset and size of 685 * portions of the given file. For a nonexistent 686 * file or regions, null will be returned. 687 * 688 * This call is most helpful with DFS, where it returns 689 * hostnames of machines that contain the given file. 690 * 691 * The FileSystem will simply return an elt containing 'localhost'. 692 * 693 * @param file FilesStatus to get data from 694 * @param start offset into the given file 695 * @param len length for which to get locations for 696 */ 697 public BlockLocation[] getFileBlockLocations(FileStatus file, 698 long start, long len) throws IOException { 699 if (file == null) { 700 return null; 701 } 702 703 if (start < 0 || len < 0) { 704 throw new IllegalArgumentException("Invalid start or len parameter"); 705 } 706 707 if (file.getLen() <= start) { 708 return new BlockLocation[0]; 709 710 } 711 String[] name = { "localhost:50010" }; 712 String[] host = { "localhost" }; 713 return new BlockLocation[] { 714 new BlockLocation(name, host, 0, file.getLen()) }; 715 } 716 717 718 /** 719 * Return an array containing hostnames, offset and size of 720 * portions of the given file. For a nonexistent 721 * file or regions, null will be returned. 722 * 723 * This call is most helpful with DFS, where it returns 724 * hostnames of machines that contain the given file. 725 * 726 * The FileSystem will simply return an elt containing 'localhost'. 727 * 728 * @param p path is used to identify an FS since an FS could have 729 * another FS that it could be delegating the call to 730 * @param start offset into the given file 731 * @param len length for which to get locations for 732 */ 733 public BlockLocation[] getFileBlockLocations(Path p, 734 long start, long len) throws IOException { 735 if (p == null) { 736 throw new NullPointerException(); 737 } 738 FileStatus file = getFileStatus(p); 739 return getFileBlockLocations(file, start, len); 740 } 741 742 /** 743 * Return a set of server default configuration values 744 * @return server default configuration values 745 * @throws IOException 746 * @deprecated use {@link #getServerDefaults(Path)} instead 747 */ 748 @Deprecated 749 public FsServerDefaults getServerDefaults() throws IOException { 750 Configuration conf = getConf(); 751 // CRC32 is chosen as default as it is available in all 752 // releases that support checksum. 753 // The client trash configuration is ignored. 754 return new FsServerDefaults(getDefaultBlockSize(), 755 conf.getInt("io.bytes.per.checksum", 512), 756 64 * 1024, 757 getDefaultReplication(), 758 conf.getInt("io.file.buffer.size", 4096), 759 false, 760 CommonConfigurationKeysPublic.FS_TRASH_INTERVAL_DEFAULT, 761 DataChecksum.Type.CRC32); 762 } 763 764 /** 765 * Return a set of server default configuration values 766 * @param p path is used to identify an FS since an FS could have 767 * another FS that it could be delegating the call to 768 * @return server default configuration values 769 * @throws IOException 770 */ 771 public FsServerDefaults getServerDefaults(Path p) throws IOException { 772 return getServerDefaults(); 773 } 774 775 /** 776 * Return the fully-qualified path of path f resolving the path 777 * through any symlinks or mount point 778 * @param p path to be resolved 779 * @return fully qualified path 780 * @throws FileNotFoundException 781 */ 782 public Path resolvePath(final Path p) throws IOException { 783 checkPath(p); 784 return getFileStatus(p).getPath(); 785 } 786 787 /** 788 * Opens an FSDataInputStream at the indicated Path. 789 * @param f the file name to open 790 * @param bufferSize the size of the buffer to be used. 791 */ 792 public abstract FSDataInputStream open(Path f, int bufferSize) 793 throws IOException; 794 795 /** 796 * Opens an FSDataInputStream at the indicated Path. 797 * @param f the file to open 798 */ 799 public FSDataInputStream open(Path f) throws IOException { 800 return open(f, getConf().getInt("io.file.buffer.size", 4096)); 801 } 802 803 /** 804 * Create an FSDataOutputStream at the indicated Path. 805 * Files are overwritten by default. 806 * @param f the file to create 807 */ 808 public FSDataOutputStream create(Path f) throws IOException { 809 return create(f, true); 810 } 811 812 /** 813 * Create an FSDataOutputStream at the indicated Path. 814 * @param f the file to create 815 * @param overwrite if a file with this name already exists, then if true, 816 * the file will be overwritten, and if false an exception will be thrown. 817 */ 818 public FSDataOutputStream create(Path f, boolean overwrite) 819 throws IOException { 820 return create(f, overwrite, 821 getConf().getInt("io.file.buffer.size", 4096), 822 getDefaultReplication(f), 823 getDefaultBlockSize(f)); 824 } 825 826 /** 827 * Create an FSDataOutputStream at the indicated Path with write-progress 828 * reporting. 829 * Files are overwritten by default. 830 * @param f the file to create 831 * @param progress to report progress 832 */ 833 public FSDataOutputStream create(Path f, Progressable progress) 834 throws IOException { 835 return create(f, true, 836 getConf().getInt("io.file.buffer.size", 4096), 837 getDefaultReplication(f), 838 getDefaultBlockSize(f), progress); 839 } 840 841 /** 842 * Create an FSDataOutputStream at the indicated Path. 843 * Files are overwritten by default. 844 * @param f the file to create 845 * @param replication the replication factor 846 */ 847 public FSDataOutputStream create(Path f, short replication) 848 throws IOException { 849 return create(f, true, 850 getConf().getInt("io.file.buffer.size", 4096), 851 replication, 852 getDefaultBlockSize(f)); 853 } 854 855 /** 856 * Create an FSDataOutputStream at the indicated Path with write-progress 857 * reporting. 858 * Files are overwritten by default. 859 * @param f the file to create 860 * @param replication the replication factor 861 * @param progress to report progress 862 */ 863 public FSDataOutputStream create(Path f, short replication, 864 Progressable progress) throws IOException { 865 return create(f, true, 866 getConf().getInt( 867 CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_KEY, 868 CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_DEFAULT), 869 replication, 870 getDefaultBlockSize(f), progress); 871 } 872 873 874 /** 875 * Create an FSDataOutputStream at the indicated Path. 876 * @param f the file name to create 877 * @param overwrite if a file with this name already exists, then if true, 878 * the file will be overwritten, and if false an error will be thrown. 879 * @param bufferSize the size of the buffer to be used. 880 */ 881 public FSDataOutputStream create(Path f, 882 boolean overwrite, 883 int bufferSize 884 ) throws IOException { 885 return create(f, overwrite, bufferSize, 886 getDefaultReplication(f), 887 getDefaultBlockSize(f)); 888 } 889 890 /** 891 * Create an FSDataOutputStream at the indicated Path with write-progress 892 * reporting. 893 * @param f the path of the file to open 894 * @param overwrite if a file with this name already exists, then if true, 895 * the file will be overwritten, and if false an error will be thrown. 896 * @param bufferSize the size of the buffer to be used. 897 */ 898 public FSDataOutputStream create(Path f, 899 boolean overwrite, 900 int bufferSize, 901 Progressable progress 902 ) throws IOException { 903 return create(f, overwrite, bufferSize, 904 getDefaultReplication(f), 905 getDefaultBlockSize(f), progress); 906 } 907 908 909 /** 910 * Create an FSDataOutputStream at the indicated Path. 911 * @param f the file name to open 912 * @param overwrite if a file with this name already exists, then if true, 913 * the file will be overwritten, and if false an error will be thrown. 914 * @param bufferSize the size of the buffer to be used. 915 * @param replication required block replication for the file. 916 */ 917 public FSDataOutputStream create(Path f, 918 boolean overwrite, 919 int bufferSize, 920 short replication, 921 long blockSize 922 ) throws IOException { 923 return create(f, overwrite, bufferSize, replication, blockSize, null); 924 } 925 926 /** 927 * Create an FSDataOutputStream at the indicated Path with write-progress 928 * reporting. 929 * @param f the file name to open 930 * @param overwrite if a file with this name already exists, then if true, 931 * the file will be overwritten, and if false an error will be thrown. 932 * @param bufferSize the size of the buffer to be used. 933 * @param replication required block replication for the file. 934 */ 935 public FSDataOutputStream create(Path f, 936 boolean overwrite, 937 int bufferSize, 938 short replication, 939 long blockSize, 940 Progressable progress 941 ) throws IOException { 942 return this.create(f, FsPermission.getFileDefault().applyUMask( 943 FsPermission.getUMask(getConf())), overwrite, bufferSize, 944 replication, blockSize, progress); 945 } 946 947 /** 948 * Create an FSDataOutputStream at the indicated Path with write-progress 949 * reporting. 950 * @param f the file name to open 951 * @param permission 952 * @param overwrite if a file with this name already exists, then if true, 953 * the file will be overwritten, and if false an error will be thrown. 954 * @param bufferSize the size of the buffer to be used. 955 * @param replication required block replication for the file. 956 * @param blockSize 957 * @param progress 958 * @throws IOException 959 * @see #setPermission(Path, FsPermission) 960 */ 961 public abstract FSDataOutputStream create(Path f, 962 FsPermission permission, 963 boolean overwrite, 964 int bufferSize, 965 short replication, 966 long blockSize, 967 Progressable progress) throws IOException; 968 969 /** 970 * Create an FSDataOutputStream at the indicated Path with write-progress 971 * reporting. 972 * @param f the file name to open 973 * @param permission 974 * @param flags {@link CreateFlag}s to use for this stream. 975 * @param bufferSize the size of the buffer to be used. 976 * @param replication required block replication for the file. 977 * @param blockSize 978 * @param progress 979 * @throws IOException 980 * @see #setPermission(Path, FsPermission) 981 */ 982 public FSDataOutputStream create(Path f, 983 FsPermission permission, 984 EnumSet<CreateFlag> flags, 985 int bufferSize, 986 short replication, 987 long blockSize, 988 Progressable progress) throws IOException { 989 return create(f, permission, flags, bufferSize, replication, 990 blockSize, progress, null); 991 } 992 993 /** 994 * Create an FSDataOutputStream at the indicated Path with a custom 995 * checksum option 996 * @param f the file name to open 997 * @param permission 998 * @param flags {@link CreateFlag}s to use for this stream. 999 * @param bufferSize the size of the buffer to be used. 1000 * @param replication required block replication for the file. 1001 * @param blockSize 1002 * @param progress 1003 * @param checksumOpt checksum parameter. If null, the values 1004 * found in conf will be used. 1005 * @throws IOException 1006 * @see #setPermission(Path, FsPermission) 1007 */ 1008 public FSDataOutputStream create(Path f, 1009 FsPermission permission, 1010 EnumSet<CreateFlag> flags, 1011 int bufferSize, 1012 short replication, 1013 long blockSize, 1014 Progressable progress, 1015 ChecksumOpt checksumOpt) throws IOException { 1016 // Checksum options are ignored by default. The file systems that 1017 // implement checksum need to override this method. The full 1018 // support is currently only available in DFS. 1019 return create(f, permission, flags.contains(CreateFlag.OVERWRITE), 1020 bufferSize, replication, blockSize, progress); 1021 } 1022 1023 /*. 1024 * This create has been added to support the FileContext that processes 1025 * the permission 1026 * with umask before calling this method. 1027 * This a temporary method added to support the transition from FileSystem 1028 * to FileContext for user applications. 1029 */ 1030 @Deprecated 1031 protected FSDataOutputStream primitiveCreate(Path f, 1032 FsPermission absolutePermission, EnumSet<CreateFlag> flag, int bufferSize, 1033 short replication, long blockSize, Progressable progress, 1034 ChecksumOpt checksumOpt) throws IOException { 1035 1036 boolean pathExists = exists(f); 1037 CreateFlag.validate(f, pathExists, flag); 1038 1039 // Default impl assumes that permissions do not matter and 1040 // nor does the bytesPerChecksum hence 1041 // calling the regular create is good enough. 1042 // FSs that implement permissions should override this. 1043 1044 if (pathExists && flag.contains(CreateFlag.APPEND)) { 1045 return append(f, bufferSize, progress); 1046 } 1047 1048 return this.create(f, absolutePermission, 1049 flag.contains(CreateFlag.OVERWRITE), bufferSize, replication, 1050 blockSize, progress); 1051 } 1052 1053 /** 1054 * This version of the mkdirs method assumes that the permission is absolute. 1055 * It has been added to support the FileContext that processes the permission 1056 * with umask before calling this method. 1057 * This a temporary method added to support the transition from FileSystem 1058 * to FileContext for user applications. 1059 */ 1060 @Deprecated 1061 protected boolean primitiveMkdir(Path f, FsPermission absolutePermission) 1062 throws IOException { 1063 // Default impl is to assume that permissions do not matter and hence 1064 // calling the regular mkdirs is good enough. 1065 // FSs that implement permissions should override this. 1066 return this.mkdirs(f, absolutePermission); 1067 } 1068 1069 1070 /** 1071 * This version of the mkdirs method assumes that the permission is absolute. 1072 * It has been added to support the FileContext that processes the permission 1073 * with umask before calling this method. 1074 * This a temporary method added to support the transition from FileSystem 1075 * to FileContext for user applications. 1076 */ 1077 @Deprecated 1078 protected void primitiveMkdir(Path f, FsPermission absolutePermission, 1079 boolean createParent) 1080 throws IOException { 1081 1082 if (!createParent) { // parent must exist. 1083 // since the this.mkdirs makes parent dirs automatically 1084 // we must throw exception if parent does not exist. 1085 final FileStatus stat = getFileStatus(f.getParent()); 1086 if (stat == null) { 1087 throw new FileNotFoundException("Missing parent:" + f); 1088 } 1089 if (!stat.isDirectory()) { 1090 throw new ParentNotDirectoryException("parent is not a dir"); 1091 } 1092 // parent does exist - go ahead with mkdir of leaf 1093 } 1094 // Default impl is to assume that permissions do not matter and hence 1095 // calling the regular mkdirs is good enough. 1096 // FSs that implement permissions should override this. 1097 if (!this.mkdirs(f, absolutePermission)) { 1098 throw new IOException("mkdir of "+ f + " failed"); 1099 } 1100 } 1101 1102 /** 1103 * Opens an FSDataOutputStream at the indicated Path with write-progress 1104 * reporting. Same as create(), except fails if parent directory doesn't 1105 * already exist. 1106 * @param f the file name to open 1107 * @param overwrite if a file with this name already exists, then if true, 1108 * the file will be overwritten, and if false an error will be thrown. 1109 * @param bufferSize the size of the buffer to be used. 1110 * @param replication required block replication for the file. 1111 * @param blockSize 1112 * @param progress 1113 * @throws IOException 1114 * @see #setPermission(Path, FsPermission) 1115 * @deprecated API only for 0.20-append 1116 */ 1117 @Deprecated 1118 public FSDataOutputStream createNonRecursive(Path f, 1119 boolean overwrite, 1120 int bufferSize, short replication, long blockSize, 1121 Progressable progress) throws IOException { 1122 return this.createNonRecursive(f, FsPermission.getFileDefault(), 1123 overwrite, bufferSize, replication, blockSize, progress); 1124 } 1125 1126 /** 1127 * Opens an FSDataOutputStream at the indicated Path with write-progress 1128 * reporting. Same as create(), except fails if parent directory doesn't 1129 * already exist. 1130 * @param f the file name to open 1131 * @param permission 1132 * @param overwrite if a file with this name already exists, then if true, 1133 * the file will be overwritten, and if false an error will be thrown. 1134 * @param bufferSize the size of the buffer to be used. 1135 * @param replication required block replication for the file. 1136 * @param blockSize 1137 * @param progress 1138 * @throws IOException 1139 * @see #setPermission(Path, FsPermission) 1140 * @deprecated API only for 0.20-append 1141 */ 1142 @Deprecated 1143 public FSDataOutputStream createNonRecursive(Path f, FsPermission permission, 1144 boolean overwrite, int bufferSize, short replication, long blockSize, 1145 Progressable progress) throws IOException { 1146 return createNonRecursive(f, permission, 1147 overwrite ? EnumSet.of(CreateFlag.CREATE, CreateFlag.OVERWRITE) 1148 : EnumSet.of(CreateFlag.CREATE), bufferSize, 1149 replication, blockSize, progress); 1150 } 1151 1152 /** 1153 * Opens an FSDataOutputStream at the indicated Path with write-progress 1154 * reporting. Same as create(), except fails if parent directory doesn't 1155 * already exist. 1156 * @param f the file name to open 1157 * @param permission 1158 * @param flags {@link CreateFlag}s to use for this stream. 1159 * @param bufferSize the size of the buffer to be used. 1160 * @param replication required block replication for the file. 1161 * @param blockSize 1162 * @param progress 1163 * @throws IOException 1164 * @see #setPermission(Path, FsPermission) 1165 * @deprecated API only for 0.20-append 1166 */ 1167 @Deprecated 1168 public FSDataOutputStream createNonRecursive(Path f, FsPermission permission, 1169 EnumSet<CreateFlag> flags, int bufferSize, short replication, long blockSize, 1170 Progressable progress) throws IOException { 1171 throw new IOException("createNonRecursive unsupported for this filesystem " 1172 + this.getClass()); 1173 } 1174 1175 /** 1176 * Creates the given Path as a brand-new zero-length file. If 1177 * create fails, or if it already existed, return false. 1178 * 1179 * @param f path to use for create 1180 */ 1181 public boolean createNewFile(Path f) throws IOException { 1182 if (exists(f)) { 1183 return false; 1184 } else { 1185 create(f, false, getConf().getInt("io.file.buffer.size", 4096)).close(); 1186 return true; 1187 } 1188 } 1189 1190 /** 1191 * Append to an existing file (optional operation). 1192 * Same as append(f, getConf().getInt("io.file.buffer.size", 4096), null) 1193 * @param f the existing file to be appended. 1194 * @throws IOException 1195 */ 1196 public FSDataOutputStream append(Path f) throws IOException { 1197 return append(f, getConf().getInt("io.file.buffer.size", 4096), null); 1198 } 1199 /** 1200 * Append to an existing file (optional operation). 1201 * Same as append(f, bufferSize, null). 1202 * @param f the existing file to be appended. 1203 * @param bufferSize the size of the buffer to be used. 1204 * @throws IOException 1205 */ 1206 public FSDataOutputStream append(Path f, int bufferSize) throws IOException { 1207 return append(f, bufferSize, null); 1208 } 1209 1210 /** 1211 * Append to an existing file (optional operation). 1212 * @param f the existing file to be appended. 1213 * @param bufferSize the size of the buffer to be used. 1214 * @param progress for reporting progress if it is not null. 1215 * @throws IOException 1216 */ 1217 public abstract FSDataOutputStream append(Path f, int bufferSize, 1218 Progressable progress) throws IOException; 1219 1220 /** 1221 * Concat existing files together. 1222 * @param trg the path to the target destination. 1223 * @param psrcs the paths to the sources to use for the concatenation. 1224 * @throws IOException 1225 */ 1226 public void concat(final Path trg, final Path [] psrcs) throws IOException { 1227 throw new UnsupportedOperationException("Not implemented by the " + 1228 getClass().getSimpleName() + " FileSystem implementation"); 1229 } 1230 1231 /** 1232 * Get replication. 1233 * 1234 * @deprecated Use getFileStatus() instead 1235 * @param src file name 1236 * @return file replication 1237 * @throws IOException 1238 */ 1239 @Deprecated 1240 public short getReplication(Path src) throws IOException { 1241 return getFileStatus(src).getReplication(); 1242 } 1243 1244 /** 1245 * Set replication for an existing file. 1246 * 1247 * @param src file name 1248 * @param replication new replication 1249 * @throws IOException 1250 * @return true if successful; 1251 * false if file does not exist or is a directory 1252 */ 1253 public boolean setReplication(Path src, short replication) 1254 throws IOException { 1255 return true; 1256 } 1257 1258 /** 1259 * Renames Path src to Path dst. Can take place on local fs 1260 * or remote DFS. 1261 * @param src path to be renamed 1262 * @param dst new path after rename 1263 * @throws IOException on failure 1264 * @return true if rename is successful 1265 */ 1266 public abstract boolean rename(Path src, Path dst) throws IOException; 1267 1268 /** 1269 * Renames Path src to Path dst 1270 * <ul> 1271 * <li 1272 * <li>Fails if src is a file and dst is a directory. 1273 * <li>Fails if src is a directory and dst is a file. 1274 * <li>Fails if the parent of dst does not exist or is a file. 1275 * </ul> 1276 * <p> 1277 * If OVERWRITE option is not passed as an argument, rename fails 1278 * if the dst already exists. 1279 * <p> 1280 * If OVERWRITE option is passed as an argument, rename overwrites 1281 * the dst if it is a file or an empty directory. Rename fails if dst is 1282 * a non-empty directory. 1283 * <p> 1284 * Note that atomicity of rename is dependent on the file system 1285 * implementation. Please refer to the file system documentation for 1286 * details. This default implementation is non atomic. 1287 * <p> 1288 * This method is deprecated since it is a temporary method added to 1289 * support the transition from FileSystem to FileContext for user 1290 * applications. 1291 * 1292 * @param src path to be renamed 1293 * @param dst new path after rename 1294 * @throws IOException on failure 1295 */ 1296 @Deprecated 1297 protected void rename(final Path src, final Path dst, 1298 final Rename... options) throws IOException { 1299 // Default implementation 1300 final FileStatus srcStatus = getFileLinkStatus(src); 1301 if (srcStatus == null) { 1302 throw new FileNotFoundException("rename source " + src + " not found."); 1303 } 1304 1305 boolean overwrite = false; 1306 if (null != options) { 1307 for (Rename option : options) { 1308 if (option == Rename.OVERWRITE) { 1309 overwrite = true; 1310 } 1311 } 1312 } 1313 1314 FileStatus dstStatus; 1315 try { 1316 dstStatus = getFileLinkStatus(dst); 1317 } catch (IOException e) { 1318 dstStatus = null; 1319 } 1320 if (dstStatus != null) { 1321 if (srcStatus.isDirectory() != dstStatus.isDirectory()) { 1322 throw new IOException("Source " + src + " Destination " + dst 1323 + " both should be either file or directory"); 1324 } 1325 if (!overwrite) { 1326 throw new FileAlreadyExistsException("rename destination " + dst 1327 + " already exists."); 1328 } 1329 // Delete the destination that is a file or an empty directory 1330 if (dstStatus.isDirectory()) { 1331 FileStatus[] list = listStatus(dst); 1332 if (list != null && list.length != 0) { 1333 throw new IOException( 1334 "rename cannot overwrite non empty destination directory " + dst); 1335 } 1336 } 1337 delete(dst, false); 1338 } else { 1339 final Path parent = dst.getParent(); 1340 final FileStatus parentStatus = getFileStatus(parent); 1341 if (parentStatus == null) { 1342 throw new FileNotFoundException("rename destination parent " + parent 1343 + " not found."); 1344 } 1345 if (!parentStatus.isDirectory()) { 1346 throw new ParentNotDirectoryException("rename destination parent " + parent 1347 + " is a file."); 1348 } 1349 } 1350 if (!rename(src, dst)) { 1351 throw new IOException("rename from " + src + " to " + dst + " failed."); 1352 } 1353 } 1354 1355 /** 1356 * Delete a file 1357 * @deprecated Use {@link #delete(Path, boolean)} instead. 1358 */ 1359 @Deprecated 1360 public boolean delete(Path f) throws IOException { 1361 return delete(f, true); 1362 } 1363 1364 /** Delete a file. 1365 * 1366 * @param f the path to delete. 1367 * @param recursive if path is a directory and set to 1368 * true, the directory is deleted else throws an exception. In 1369 * case of a file the recursive can be set to either true or false. 1370 * @return true if delete is successful else false. 1371 * @throws IOException 1372 */ 1373 public abstract boolean delete(Path f, boolean recursive) throws IOException; 1374 1375 /** 1376 * Mark a path to be deleted when FileSystem is closed. 1377 * When the JVM shuts down, 1378 * all FileSystem objects will be closed automatically. 1379 * Then, 1380 * the marked path will be deleted as a result of closing the FileSystem. 1381 * 1382 * The path has to exist in the file system. 1383 * 1384 * @param f the path to delete. 1385 * @return true if deleteOnExit is successful, otherwise false. 1386 * @throws IOException 1387 */ 1388 public boolean deleteOnExit(Path f) throws IOException { 1389 if (!exists(f)) { 1390 return false; 1391 } 1392 synchronized (deleteOnExit) { 1393 deleteOnExit.add(f); 1394 } 1395 return true; 1396 } 1397 1398 /** 1399 * Cancel the deletion of the path when the FileSystem is closed 1400 * @param f the path to cancel deletion 1401 */ 1402 public boolean cancelDeleteOnExit(Path f) { 1403 synchronized (deleteOnExit) { 1404 return deleteOnExit.remove(f); 1405 } 1406 } 1407 1408 /** 1409 * Delete all files that were marked as delete-on-exit. This recursively 1410 * deletes all files in the specified paths. 1411 */ 1412 protected void processDeleteOnExit() { 1413 synchronized (deleteOnExit) { 1414 for (Iterator<Path> iter = deleteOnExit.iterator(); iter.hasNext();) { 1415 Path path = iter.next(); 1416 try { 1417 if (exists(path)) { 1418 delete(path, true); 1419 } 1420 } 1421 catch (IOException e) { 1422 LOG.info("Ignoring failure to deleteOnExit for path " + path); 1423 } 1424 iter.remove(); 1425 } 1426 } 1427 } 1428 1429 /** Check if exists. 1430 * @param f source file 1431 */ 1432 public boolean exists(Path f) throws IOException { 1433 try { 1434 return getFileStatus(f) != null; 1435 } catch (FileNotFoundException e) { 1436 return false; 1437 } 1438 } 1439 1440 /** True iff the named path is a directory. 1441 * Note: Avoid using this method. Instead reuse the FileStatus 1442 * returned by getFileStatus() or listStatus() methods. 1443 * @param f path to check 1444 */ 1445 public boolean isDirectory(Path f) throws IOException { 1446 try { 1447 return getFileStatus(f).isDirectory(); 1448 } catch (FileNotFoundException e) { 1449 return false; // f does not exist 1450 } 1451 } 1452 1453 /** True iff the named path is a regular file. 1454 * Note: Avoid using this method. Instead reuse the FileStatus 1455 * returned by getFileStatus() or listStatus() methods. 1456 * @param f path to check 1457 */ 1458 public boolean isFile(Path f) throws IOException { 1459 try { 1460 return getFileStatus(f).isFile(); 1461 } catch (FileNotFoundException e) { 1462 return false; // f does not exist 1463 } 1464 } 1465 1466 /** The number of bytes in a file. */ 1467 /** @deprecated Use getFileStatus() instead */ 1468 @Deprecated 1469 public long getLength(Path f) throws IOException { 1470 return getFileStatus(f).getLen(); 1471 } 1472 1473 /** Return the {@link ContentSummary} of a given {@link Path}. 1474 * @param f path to use 1475 */ 1476 public ContentSummary getContentSummary(Path f) throws IOException { 1477 FileStatus status = getFileStatus(f); 1478 if (status.isFile()) { 1479 // f is a file 1480 return new ContentSummary(status.getLen(), 1, 0); 1481 } 1482 // f is a directory 1483 long[] summary = {0, 0, 1}; 1484 for(FileStatus s : listStatus(f)) { 1485 ContentSummary c = s.isDirectory() ? getContentSummary(s.getPath()) : 1486 new ContentSummary(s.getLen(), 1, 0); 1487 summary[0] += c.getLength(); 1488 summary[1] += c.getFileCount(); 1489 summary[2] += c.getDirectoryCount(); 1490 } 1491 return new ContentSummary(summary[0], summary[1], summary[2]); 1492 } 1493 1494 final private static PathFilter DEFAULT_FILTER = new PathFilter() { 1495 @Override 1496 public boolean accept(Path file) { 1497 return true; 1498 } 1499 }; 1500 1501 /** 1502 * List the statuses of the files/directories in the given path if the path is 1503 * a directory. 1504 * 1505 * @param f given path 1506 * @return the statuses of the files/directories in the given patch 1507 * @throws FileNotFoundException when the path does not exist; 1508 * IOException see specific implementation 1509 */ 1510 public abstract FileStatus[] listStatus(Path f) throws FileNotFoundException, 1511 IOException; 1512 1513 /* 1514 * Filter files/directories in the given path using the user-supplied path 1515 * filter. Results are added to the given array <code>results</code>. 1516 */ 1517 private void listStatus(ArrayList<FileStatus> results, Path f, 1518 PathFilter filter) throws FileNotFoundException, IOException { 1519 FileStatus listing[] = listStatus(f); 1520 if (listing == null) { 1521 throw new IOException("Error accessing " + f); 1522 } 1523 1524 for (int i = 0; i < listing.length; i++) { 1525 if (filter.accept(listing[i].getPath())) { 1526 results.add(listing[i]); 1527 } 1528 } 1529 } 1530 1531 /** 1532 * @return an iterator over the corrupt files under the given path 1533 * (may contain duplicates if a file has more than one corrupt block) 1534 * @throws IOException 1535 */ 1536 public RemoteIterator<Path> listCorruptFileBlocks(Path path) 1537 throws IOException { 1538 throw new UnsupportedOperationException(getClass().getCanonicalName() + 1539 " does not support" + 1540 " listCorruptFileBlocks"); 1541 } 1542 1543 /** 1544 * Filter files/directories in the given path using the user-supplied path 1545 * filter. 1546 * 1547 * @param f 1548 * a path name 1549 * @param filter 1550 * the user-supplied path filter 1551 * @return an array of FileStatus objects for the files under the given path 1552 * after applying the filter 1553 * @throws FileNotFoundException when the path does not exist; 1554 * IOException see specific implementation 1555 */ 1556 public FileStatus[] listStatus(Path f, PathFilter filter) 1557 throws FileNotFoundException, IOException { 1558 ArrayList<FileStatus> results = new ArrayList<FileStatus>(); 1559 listStatus(results, f, filter); 1560 return results.toArray(new FileStatus[results.size()]); 1561 } 1562 1563 /** 1564 * Filter files/directories in the given list of paths using default 1565 * path filter. 1566 * 1567 * @param files 1568 * a list of paths 1569 * @return a list of statuses for the files under the given paths after 1570 * applying the filter default Path filter 1571 * @throws FileNotFoundException when the path does not exist; 1572 * IOException see specific implementation 1573 */ 1574 public FileStatus[] listStatus(Path[] files) 1575 throws FileNotFoundException, IOException { 1576 return listStatus(files, DEFAULT_FILTER); 1577 } 1578 1579 /** 1580 * Filter files/directories in the given list of paths using user-supplied 1581 * path filter. 1582 * 1583 * @param files 1584 * a list of paths 1585 * @param filter 1586 * the user-supplied path filter 1587 * @return a list of statuses for the files under the given paths after 1588 * applying the filter 1589 * @throws FileNotFoundException when the path does not exist; 1590 * IOException see specific implementation 1591 */ 1592 public FileStatus[] listStatus(Path[] files, PathFilter filter) 1593 throws FileNotFoundException, IOException { 1594 ArrayList<FileStatus> results = new ArrayList<FileStatus>(); 1595 for (int i = 0; i < files.length; i++) { 1596 listStatus(results, files[i], filter); 1597 } 1598 return results.toArray(new FileStatus[results.size()]); 1599 } 1600 1601 /** 1602 * <p>Return all the files that match filePattern and are not checksum 1603 * files. Results are sorted by their names. 1604 * 1605 * <p> 1606 * A filename pattern is composed of <i>regular</i> characters and 1607 * <i>special pattern matching</i> characters, which are: 1608 * 1609 * <dl> 1610 * <dd> 1611 * <dl> 1612 * <p> 1613 * <dt> <tt> ? </tt> 1614 * <dd> Matches any single character. 1615 * 1616 * <p> 1617 * <dt> <tt> * </tt> 1618 * <dd> Matches zero or more characters. 1619 * 1620 * <p> 1621 * <dt> <tt> [<i>abc</i>] </tt> 1622 * <dd> Matches a single character from character set 1623 * <tt>{<i>a,b,c</i>}</tt>. 1624 * 1625 * <p> 1626 * <dt> <tt> [<i>a</i>-<i>b</i>] </tt> 1627 * <dd> Matches a single character from the character range 1628 * <tt>{<i>a...b</i>}</tt>. Note that character <tt><i>a</i></tt> must be 1629 * lexicographically less than or equal to character <tt><i>b</i></tt>. 1630 * 1631 * <p> 1632 * <dt> <tt> [^<i>a</i>] </tt> 1633 * <dd> Matches a single character that is not from character set or range 1634 * <tt>{<i>a</i>}</tt>. Note that the <tt>^</tt> character must occur 1635 * immediately to the right of the opening bracket. 1636 * 1637 * <p> 1638 * <dt> <tt> \<i>c</i> </tt> 1639 * <dd> Removes (escapes) any special meaning of character <i>c</i>. 1640 * 1641 * <p> 1642 * <dt> <tt> {ab,cd} </tt> 1643 * <dd> Matches a string from the string set <tt>{<i>ab, cd</i>} </tt> 1644 * 1645 * <p> 1646 * <dt> <tt> {ab,c{de,fh}} </tt> 1647 * <dd> Matches a string from the string set <tt>{<i>ab, cde, cfh</i>}</tt> 1648 * 1649 * </dl> 1650 * </dd> 1651 * </dl> 1652 * 1653 * @param pathPattern a regular expression specifying a pth pattern 1654 1655 * @return an array of paths that match the path pattern 1656 * @throws IOException 1657 */ 1658 public FileStatus[] globStatus(Path pathPattern) throws IOException { 1659 return new Globber(this, pathPattern, DEFAULT_FILTER).glob(); 1660 } 1661 1662 /** 1663 * Return an array of FileStatus objects whose path names match pathPattern 1664 * and is accepted by the user-supplied path filter. Results are sorted by 1665 * their path names. 1666 * Return null if pathPattern has no glob and the path does not exist. 1667 * Return an empty array if pathPattern has a glob and no path matches it. 1668 * 1669 * @param pathPattern 1670 * a regular expression specifying the path pattern 1671 * @param filter 1672 * a user-supplied path filter 1673 * @return an array of FileStatus objects 1674 * @throws IOException if any I/O error occurs when fetching file status 1675 */ 1676 public FileStatus[] globStatus(Path pathPattern, PathFilter filter) 1677 throws IOException { 1678 return new Globber(this, pathPattern, filter).glob(); 1679 } 1680 1681 /** 1682 * List the statuses of the files/directories in the given path if the path is 1683 * a directory. 1684 * Return the file's status and block locations If the path is a file. 1685 * 1686 * If a returned status is a file, it contains the file's block locations. 1687 * 1688 * @param f is the path 1689 * 1690 * @return an iterator that traverses statuses of the files/directories 1691 * in the given path 1692 * 1693 * @throws FileNotFoundException If <code>f</code> does not exist 1694 * @throws IOException If an I/O error occurred 1695 */ 1696 public RemoteIterator<LocatedFileStatus> listLocatedStatus(final Path f) 1697 throws FileNotFoundException, IOException { 1698 return listLocatedStatus(f, DEFAULT_FILTER); 1699 } 1700 1701 /** 1702 * Listing a directory 1703 * The returned results include its block location if it is a file 1704 * The results are filtered by the given path filter 1705 * @param f a path 1706 * @param filter a path filter 1707 * @return an iterator that traverses statuses of the files/directories 1708 * in the given path 1709 * @throws FileNotFoundException if <code>f</code> does not exist 1710 * @throws IOException if any I/O error occurred 1711 */ 1712 protected RemoteIterator<LocatedFileStatus> listLocatedStatus(final Path f, 1713 final PathFilter filter) 1714 throws FileNotFoundException, IOException { 1715 return new RemoteIterator<LocatedFileStatus>() { 1716 private final FileStatus[] stats = listStatus(f, filter); 1717 private int i = 0; 1718 1719 @Override 1720 public boolean hasNext() { 1721 return i<stats.length; 1722 } 1723 1724 @Override 1725 public LocatedFileStatus next() throws IOException { 1726 if (!hasNext()) { 1727 throw new NoSuchElementException("No more entry in " + f); 1728 } 1729 FileStatus result = stats[i++]; 1730 BlockLocation[] locs = result.isFile() ? 1731 getFileBlockLocations(result.getPath(), 0, result.getLen()) : 1732 null; 1733 return new LocatedFileStatus(result, locs); 1734 } 1735 }; 1736 } 1737 1738 /** 1739 * List the statuses and block locations of the files in the given path. 1740 * 1741 * If the path is a directory, 1742 * if recursive is false, returns files in the directory; 1743 * if recursive is true, return files in the subtree rooted at the path. 1744 * If the path is a file, return the file's status and block locations. 1745 * 1746 * @param f is the path 1747 * @param recursive if the subdirectories need to be traversed recursively 1748 * 1749 * @return an iterator that traverses statuses of the files 1750 * 1751 * @throws FileNotFoundException when the path does not exist; 1752 * IOException see specific implementation 1753 */ 1754 public RemoteIterator<LocatedFileStatus> listFiles( 1755 final Path f, final boolean recursive) 1756 throws FileNotFoundException, IOException { 1757 return new RemoteIterator<LocatedFileStatus>() { 1758 private Stack<RemoteIterator<LocatedFileStatus>> itors = 1759 new Stack<RemoteIterator<LocatedFileStatus>>(); 1760 private RemoteIterator<LocatedFileStatus> curItor = 1761 listLocatedStatus(f); 1762 private LocatedFileStatus curFile; 1763 1764 @Override 1765 public boolean hasNext() throws IOException { 1766 while (curFile == null) { 1767 if (curItor.hasNext()) { 1768 handleFileStat(curItor.next()); 1769 } else if (!itors.empty()) { 1770 curItor = itors.pop(); 1771 } else { 1772 return false; 1773 } 1774 } 1775 return true; 1776 } 1777 1778 /** 1779 * Process the input stat. 1780 * If it is a file, return the file stat. 1781 * If it is a directory, traverse the directory if recursive is true; 1782 * ignore it if recursive is false. 1783 * @param stat input status 1784 * @throws IOException if any IO error occurs 1785 */ 1786 private void handleFileStat(LocatedFileStatus stat) throws IOException { 1787 if (stat.isFile()) { // file 1788 curFile = stat; 1789 } else if (recursive) { // directory 1790 itors.push(curItor); 1791 curItor = listLocatedStatus(stat.getPath()); 1792 } 1793 } 1794 1795 @Override 1796 public LocatedFileStatus next() throws IOException { 1797 if (hasNext()) { 1798 LocatedFileStatus result = curFile; 1799 curFile = null; 1800 return result; 1801 } 1802 throw new java.util.NoSuchElementException("No more entry in " + f); 1803 } 1804 }; 1805 } 1806 1807 /** Return the current user's home directory in this filesystem. 1808 * The default implementation returns "/user/$USER/". 1809 */ 1810 public Path getHomeDirectory() { 1811 return this.makeQualified( 1812 new Path("/user/"+System.getProperty("user.name"))); 1813 } 1814 1815 1816 /** 1817 * Set the current working directory for the given file system. All relative 1818 * paths will be resolved relative to it. 1819 * 1820 * @param new_dir 1821 */ 1822 public abstract void setWorkingDirectory(Path new_dir); 1823 1824 /** 1825 * Get the current working directory for the given file system 1826 * @return the directory pathname 1827 */ 1828 public abstract Path getWorkingDirectory(); 1829 1830 1831 /** 1832 * Note: with the new FilesContext class, getWorkingDirectory() 1833 * will be removed. 1834 * The working directory is implemented in FilesContext. 1835 * 1836 * Some file systems like LocalFileSystem have an initial workingDir 1837 * that we use as the starting workingDir. For other file systems 1838 * like HDFS there is no built in notion of an initial workingDir. 1839 * 1840 * @return if there is built in notion of workingDir then it 1841 * is returned; else a null is returned. 1842 */ 1843 protected Path getInitialWorkingDirectory() { 1844 return null; 1845 } 1846 1847 /** 1848 * Call {@link #mkdirs(Path, FsPermission)} with default permission. 1849 */ 1850 public boolean mkdirs(Path f) throws IOException { 1851 return mkdirs(f, FsPermission.getDirDefault()); 1852 } 1853 1854 /** 1855 * Make the given file and all non-existent parents into 1856 * directories. Has the semantics of Unix 'mkdir -p'. 1857 * Existence of the directory hierarchy is not an error. 1858 * @param f path to create 1859 * @param permission to apply to f 1860 */ 1861 public abstract boolean mkdirs(Path f, FsPermission permission 1862 ) throws IOException; 1863 1864 /** 1865 * The src file is on the local disk. Add it to FS at 1866 * the given dst name and the source is kept intact afterwards 1867 * @param src path 1868 * @param dst path 1869 */ 1870 public void copyFromLocalFile(Path src, Path dst) 1871 throws IOException { 1872 copyFromLocalFile(false, src, dst); 1873 } 1874 1875 /** 1876 * The src files is on the local disk. Add it to FS at 1877 * the given dst name, removing the source afterwards. 1878 * @param srcs path 1879 * @param dst path 1880 */ 1881 public void moveFromLocalFile(Path[] srcs, Path dst) 1882 throws IOException { 1883 copyFromLocalFile(true, true, srcs, dst); 1884 } 1885 1886 /** 1887 * The src file is on the local disk. Add it to FS at 1888 * the given dst name, removing the source afterwards. 1889 * @param src path 1890 * @param dst path 1891 */ 1892 public void moveFromLocalFile(Path src, Path dst) 1893 throws IOException { 1894 copyFromLocalFile(true, src, dst); 1895 } 1896 1897 /** 1898 * The src file is on the local disk. Add it to FS at 1899 * the given dst name. 1900 * delSrc indicates if the source should be removed 1901 * @param delSrc whether to delete the src 1902 * @param src path 1903 * @param dst path 1904 */ 1905 public void copyFromLocalFile(boolean delSrc, Path src, Path dst) 1906 throws IOException { 1907 copyFromLocalFile(delSrc, true, src, dst); 1908 } 1909 1910 /** 1911 * The src files are on the local disk. Add it to FS at 1912 * the given dst name. 1913 * delSrc indicates if the source should be removed 1914 * @param delSrc whether to delete the src 1915 * @param overwrite whether to overwrite an existing file 1916 * @param srcs array of paths which are source 1917 * @param dst path 1918 */ 1919 public void copyFromLocalFile(boolean delSrc, boolean overwrite, 1920 Path[] srcs, Path dst) 1921 throws IOException { 1922 Configuration conf = getConf(); 1923 FileUtil.copy(getLocal(conf), srcs, this, dst, delSrc, overwrite, conf); 1924 } 1925 1926 /** 1927 * The src file is on the local disk. Add it to FS at 1928 * the given dst name. 1929 * delSrc indicates if the source should be removed 1930 * @param delSrc whether to delete the src 1931 * @param overwrite whether to overwrite an existing file 1932 * @param src path 1933 * @param dst path 1934 */ 1935 public void copyFromLocalFile(boolean delSrc, boolean overwrite, 1936 Path src, Path dst) 1937 throws IOException { 1938 Configuration conf = getConf(); 1939 FileUtil.copy(getLocal(conf), src, this, dst, delSrc, overwrite, conf); 1940 } 1941 1942 /** 1943 * The src file is under FS, and the dst is on the local disk. 1944 * Copy it from FS control to the local dst name. 1945 * @param src path 1946 * @param dst path 1947 */ 1948 public void copyToLocalFile(Path src, Path dst) throws IOException { 1949 copyToLocalFile(false, src, dst); 1950 } 1951 1952 /** 1953 * The src file is under FS, and the dst is on the local disk. 1954 * Copy it from FS control to the local dst name. 1955 * Remove the source afterwards 1956 * @param src path 1957 * @param dst path 1958 */ 1959 public void moveToLocalFile(Path src, Path dst) throws IOException { 1960 copyToLocalFile(true, src, dst); 1961 } 1962 1963 /** 1964 * The src file is under FS, and the dst is on the local disk. 1965 * Copy it from FS control to the local dst name. 1966 * delSrc indicates if the src will be removed or not. 1967 * @param delSrc whether to delete the src 1968 * @param src path 1969 * @param dst path 1970 */ 1971 public void copyToLocalFile(boolean delSrc, Path src, Path dst) 1972 throws IOException { 1973 copyToLocalFile(delSrc, src, dst, false); 1974 } 1975 1976 /** 1977 * The src file is under FS, and the dst is on the local disk. Copy it from FS 1978 * control to the local dst name. delSrc indicates if the src will be removed 1979 * or not. useRawLocalFileSystem indicates whether to use RawLocalFileSystem 1980 * as local file system or not. RawLocalFileSystem is non crc file system.So, 1981 * It will not create any crc files at local. 1982 * 1983 * @param delSrc 1984 * whether to delete the src 1985 * @param src 1986 * path 1987 * @param dst 1988 * path 1989 * @param useRawLocalFileSystem 1990 * whether to use RawLocalFileSystem as local file system or not. 1991 * 1992 * @throws IOException 1993 * - if any IO error 1994 */ 1995 public void copyToLocalFile(boolean delSrc, Path src, Path dst, 1996 boolean useRawLocalFileSystem) throws IOException { 1997 Configuration conf = getConf(); 1998 FileSystem local = null; 1999 if (useRawLocalFileSystem) { 2000 local = getLocal(conf).getRawFileSystem(); 2001 } else { 2002 local = getLocal(conf); 2003 } 2004 FileUtil.copy(this, src, local, dst, delSrc, conf); 2005 } 2006 2007 /** 2008 * Returns a local File that the user can write output to. The caller 2009 * provides both the eventual FS target name and the local working 2010 * file. If the FS is local, we write directly into the target. If 2011 * the FS is remote, we write into the tmp local area. 2012 * @param fsOutputFile path of output file 2013 * @param tmpLocalFile path of local tmp file 2014 */ 2015 public Path startLocalOutput(Path fsOutputFile, Path tmpLocalFile) 2016 throws IOException { 2017 return tmpLocalFile; 2018 } 2019 2020 /** 2021 * Called when we're all done writing to the target. A local FS will 2022 * do nothing, because we've written to exactly the right place. A remote 2023 * FS will copy the contents of tmpLocalFile to the correct target at 2024 * fsOutputFile. 2025 * @param fsOutputFile path of output file 2026 * @param tmpLocalFile path to local tmp file 2027 */ 2028 public void completeLocalOutput(Path fsOutputFile, Path tmpLocalFile) 2029 throws IOException { 2030 moveFromLocalFile(tmpLocalFile, fsOutputFile); 2031 } 2032 2033 /** 2034 * No more filesystem operations are needed. Will 2035 * release any held locks. 2036 */ 2037 @Override 2038 public void close() throws IOException { 2039 // delete all files that were marked as delete-on-exit. 2040 processDeleteOnExit(); 2041 CACHE.remove(this.key, this); 2042 } 2043 2044 /** Return the total size of all files in the filesystem.*/ 2045 public long getUsed() throws IOException{ 2046 long used = 0; 2047 FileStatus[] files = listStatus(new Path("/")); 2048 for(FileStatus file:files){ 2049 used += file.getLen(); 2050 } 2051 return used; 2052 } 2053 2054 /** 2055 * Get the block size for a particular file. 2056 * @param f the filename 2057 * @return the number of bytes in a block 2058 */ 2059 /** @deprecated Use getFileStatus() instead */ 2060 @Deprecated 2061 public long getBlockSize(Path f) throws IOException { 2062 return getFileStatus(f).getBlockSize(); 2063 } 2064 2065 /** 2066 * Return the number of bytes that large input files should be optimally 2067 * be split into to minimize i/o time. 2068 * @deprecated use {@link #getDefaultBlockSize(Path)} instead 2069 */ 2070 @Deprecated 2071 public long getDefaultBlockSize() { 2072 // default to 32MB: large enough to minimize the impact of seeks 2073 return getConf().getLong("fs.local.block.size", 32 * 1024 * 1024); 2074 } 2075 2076 /** Return the number of bytes that large input files should be optimally 2077 * be split into to minimize i/o time. The given path will be used to 2078 * locate the actual filesystem. The full path does not have to exist. 2079 * @param f path of file 2080 * @return the default block size for the path's filesystem 2081 */ 2082 public long getDefaultBlockSize(Path f) { 2083 return getDefaultBlockSize(); 2084 } 2085 2086 /** 2087 * Get the default replication. 2088 * @deprecated use {@link #getDefaultReplication(Path)} instead 2089 */ 2090 @Deprecated 2091 public short getDefaultReplication() { return 1; } 2092 2093 /** 2094 * Get the default replication for a path. The given path will be used to 2095 * locate the actual filesystem. The full path does not have to exist. 2096 * @param path of the file 2097 * @return default replication for the path's filesystem 2098 */ 2099 public short getDefaultReplication(Path path) { 2100 return getDefaultReplication(); 2101 } 2102 2103 /** 2104 * Return a file status object that represents the path. 2105 * @param f The path we want information from 2106 * @return a FileStatus object 2107 * @throws FileNotFoundException when the path does not exist; 2108 * IOException see specific implementation 2109 */ 2110 public abstract FileStatus getFileStatus(Path f) throws IOException; 2111 2112 /** 2113 * See {@link FileContext#fixRelativePart} 2114 */ 2115 protected Path fixRelativePart(Path p) { 2116 if (p.isUriPathAbsolute()) { 2117 return p; 2118 } else { 2119 return new Path(getWorkingDirectory(), p); 2120 } 2121 } 2122 2123 /** 2124 * See {@link FileContext#createSymlink(Path, Path, boolean)} 2125 */ 2126 public void createSymlink(final Path target, final Path link, 2127 final boolean createParent) throws AccessControlException, 2128 FileAlreadyExistsException, FileNotFoundException, 2129 ParentNotDirectoryException, UnsupportedFileSystemException, 2130 IOException { 2131 // Supporting filesystems should override this method 2132 throw new UnsupportedOperationException( 2133 "Filesystem does not support symlinks!"); 2134 } 2135 2136 /** 2137 * See {@link FileContext#getFileLinkStatus(Path)} 2138 */ 2139 public FileStatus getFileLinkStatus(final Path f) 2140 throws AccessControlException, FileNotFoundException, 2141 UnsupportedFileSystemException, IOException { 2142 // Supporting filesystems should override this method 2143 return getFileStatus(f); 2144 } 2145 2146 /** 2147 * See {@link AbstractFileSystem#supportsSymlinks()} 2148 */ 2149 public boolean supportsSymlinks() { 2150 return false; 2151 } 2152 2153 /** 2154 * See {@link FileContext#getLinkTarget(Path)} 2155 */ 2156 public Path getLinkTarget(Path f) throws IOException { 2157 // Supporting filesystems should override this method 2158 throw new UnsupportedOperationException( 2159 "Filesystem does not support symlinks!"); 2160 } 2161 2162 /** 2163 * See {@link AbstractFileSystem#getLinkTarget(Path)} 2164 */ 2165 protected Path resolveLink(Path f) throws IOException { 2166 // Supporting filesystems should override this method 2167 throw new UnsupportedOperationException( 2168 "Filesystem does not support symlinks!"); 2169 } 2170 2171 /** 2172 * Get the checksum of a file. 2173 * 2174 * @param f The file path 2175 * @return The file checksum. The default return value is null, 2176 * which indicates that no checksum algorithm is implemented 2177 * in the corresponding FileSystem. 2178 */ 2179 public FileChecksum getFileChecksum(Path f) throws IOException { 2180 return getFileChecksum(f, Long.MAX_VALUE); 2181 } 2182 2183 /** 2184 * Get the checksum of a file, from the beginning of the file till the 2185 * specific length. 2186 * @param f The file path 2187 * @param length The length of the file range for checksum calculation 2188 * @return The file checksum. 2189 */ 2190 public FileChecksum getFileChecksum(Path f, final long length) 2191 throws IOException { 2192 return null; 2193 } 2194 2195 /** 2196 * Set the verify checksum flag. This is only applicable if the 2197 * corresponding FileSystem supports checksum. By default doesn't do anything. 2198 * @param verifyChecksum 2199 */ 2200 public void setVerifyChecksum(boolean verifyChecksum) { 2201 //doesn't do anything 2202 } 2203 2204 /** 2205 * Set the write checksum flag. This is only applicable if the 2206 * corresponding FileSystem supports checksum. By default doesn't do anything. 2207 * @param writeChecksum 2208 */ 2209 public void setWriteChecksum(boolean writeChecksum) { 2210 //doesn't do anything 2211 } 2212 2213 /** 2214 * Returns a status object describing the use and capacity of the 2215 * file system. If the file system has multiple partitions, the 2216 * use and capacity of the root partition is reflected. 2217 * 2218 * @return a FsStatus object 2219 * @throws IOException 2220 * see specific implementation 2221 */ 2222 public FsStatus getStatus() throws IOException { 2223 return getStatus(null); 2224 } 2225 2226 /** 2227 * Returns a status object describing the use and capacity of the 2228 * file system. If the file system has multiple partitions, the 2229 * use and capacity of the partition pointed to by the specified 2230 * path is reflected. 2231 * @param p Path for which status should be obtained. null means 2232 * the default partition. 2233 * @return a FsStatus object 2234 * @throws IOException 2235 * see specific implementation 2236 */ 2237 public FsStatus getStatus(Path p) throws IOException { 2238 return new FsStatus(Long.MAX_VALUE, 0, Long.MAX_VALUE); 2239 } 2240 2241 /** 2242 * Set permission of a path. 2243 * @param p 2244 * @param permission 2245 */ 2246 public void setPermission(Path p, FsPermission permission 2247 ) throws IOException { 2248 } 2249 2250 /** 2251 * Set owner of a path (i.e. a file or a directory). 2252 * The parameters username and groupname cannot both be null. 2253 * @param p The path 2254 * @param username If it is null, the original username remains unchanged. 2255 * @param groupname If it is null, the original groupname remains unchanged. 2256 */ 2257 public void setOwner(Path p, String username, String groupname 2258 ) throws IOException { 2259 } 2260 2261 /** 2262 * Set access time of a file 2263 * @param p The path 2264 * @param mtime Set the modification time of this file. 2265 * The number of milliseconds since Jan 1, 1970. 2266 * A value of -1 means that this call should not set modification time. 2267 * @param atime Set the access time of this file. 2268 * The number of milliseconds since Jan 1, 1970. 2269 * A value of -1 means that this call should not set access time. 2270 */ 2271 public void setTimes(Path p, long mtime, long atime 2272 ) throws IOException { 2273 } 2274 2275 /** 2276 * Create a snapshot with a default name. 2277 * @param path The directory where snapshots will be taken. 2278 * @return the snapshot path. 2279 */ 2280 public final Path createSnapshot(Path path) throws IOException { 2281 return createSnapshot(path, null); 2282 } 2283 2284 /** 2285 * Create a snapshot 2286 * @param path The directory where snapshots will be taken. 2287 * @param snapshotName The name of the snapshot 2288 * @return the snapshot path. 2289 */ 2290 public Path createSnapshot(Path path, String snapshotName) 2291 throws IOException { 2292 throw new UnsupportedOperationException(getClass().getSimpleName() 2293 + " doesn't support createSnapshot"); 2294 } 2295 2296 /** 2297 * Rename a snapshot 2298 * @param path The directory path where the snapshot was taken 2299 * @param snapshotOldName Old name of the snapshot 2300 * @param snapshotNewName New name of the snapshot 2301 * @throws IOException 2302 */ 2303 public void renameSnapshot(Path path, String snapshotOldName, 2304 String snapshotNewName) throws IOException { 2305 throw new UnsupportedOperationException(getClass().getSimpleName() 2306 + " doesn't support renameSnapshot"); 2307 } 2308 2309 /** 2310 * Delete a snapshot of a directory 2311 * @param path The directory that the to-be-deleted snapshot belongs to 2312 * @param snapshotName The name of the snapshot 2313 */ 2314 public void deleteSnapshot(Path path, String snapshotName) 2315 throws IOException { 2316 throw new UnsupportedOperationException(getClass().getSimpleName() 2317 + " doesn't support deleteSnapshot"); 2318 } 2319 2320 /** 2321 * Modifies ACL entries of files and directories. This method can add new ACL 2322 * entries or modify the permissions on existing ACL entries. All existing 2323 * ACL entries that are not specified in this call are retained without 2324 * changes. (Modifications are merged into the current ACL.) 2325 * 2326 * @param path Path to modify 2327 * @param aclSpec List<AclEntry> describing modifications 2328 * @throws IOException if an ACL could not be modified 2329 */ 2330 public void modifyAclEntries(Path path, List<AclEntry> aclSpec) 2331 throws IOException { 2332 throw new UnsupportedOperationException(getClass().getSimpleName() 2333 + " doesn't support modifyAclEntries"); 2334 } 2335 2336 /** 2337 * Removes ACL entries from files and directories. Other ACL entries are 2338 * retained. 2339 * 2340 * @param path Path to modify 2341 * @param aclSpec List<AclEntry> describing entries to remove 2342 * @throws IOException if an ACL could not be modified 2343 */ 2344 public void removeAclEntries(Path path, List<AclEntry> aclSpec) 2345 throws IOException { 2346 throw new UnsupportedOperationException(getClass().getSimpleName() 2347 + " doesn't support removeAclEntries"); 2348 } 2349 2350 /** 2351 * Removes all default ACL entries from files and directories. 2352 * 2353 * @param path Path to modify 2354 * @throws IOException if an ACL could not be modified 2355 */ 2356 public void removeDefaultAcl(Path path) 2357 throws IOException { 2358 throw new UnsupportedOperationException(getClass().getSimpleName() 2359 + " doesn't support removeDefaultAcl"); 2360 } 2361 2362 /** 2363 * Removes all but the base ACL entries of files and directories. The entries 2364 * for user, group, and others are retained for compatibility with permission 2365 * bits. 2366 * 2367 * @param path Path to modify 2368 * @throws IOException if an ACL could not be removed 2369 */ 2370 public void removeAcl(Path path) 2371 throws IOException { 2372 throw new UnsupportedOperationException(getClass().getSimpleName() 2373 + " doesn't support removeAcl"); 2374 } 2375 2376 /** 2377 * Fully replaces ACL of files and directories, discarding all existing 2378 * entries. 2379 * 2380 * @param path Path to modify 2381 * @param aclSpec List<AclEntry> describing modifications, must include entries 2382 * for user, group, and others for compatibility with permission bits. 2383 * @throws IOException if an ACL could not be modified 2384 */ 2385 public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException { 2386 throw new UnsupportedOperationException(getClass().getSimpleName() 2387 + " doesn't support setAcl"); 2388 } 2389 2390 /** 2391 * Gets the ACL of a file or directory. 2392 * 2393 * @param path Path to get 2394 * @return AclStatus describing the ACL of the file or directory 2395 * @throws IOException if an ACL could not be read 2396 */ 2397 public AclStatus getAclStatus(Path path) throws IOException { 2398 throw new UnsupportedOperationException(getClass().getSimpleName() 2399 + " doesn't support getAclStatus"); 2400 } 2401 2402 /** 2403 * Set an xattr of a file or directory. 2404 * The name must be prefixed with user/trusted/security/system and 2405 * followed by ".". For example, "user.attr". 2406 * <p/> 2407 * A regular user can only set an xattr for the "user" namespace. 2408 * The super user can set an xattr of either the "user" or "trusted" namespaces. 2409 * The xattrs of the "security" and "system" namespaces are only used/exposed 2410 * internally by/to the FS impl. 2411 * <p/> 2412 * The access permissions of an xattr in the "user" namespace are 2413 * defined by the file and directory permission bits. 2414 * An xattr can only be set when the logged-in user has the correct permissions. 2415 * If the xattr exists, it will be replaced. 2416 * <p/> 2417 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2418 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2419 * 2420 * @param path Path to modify 2421 * @param name xattr name. 2422 * @param value xattr value. 2423 * @throws IOException 2424 */ 2425 public void setXAttr(Path path, String name, byte[] value) 2426 throws IOException { 2427 setXAttr(path, name, value, EnumSet.of(XAttrSetFlag.CREATE, 2428 XAttrSetFlag.REPLACE)); 2429 } 2430 2431 /** 2432 * Set an xattr of a file or directory. 2433 * The name must be prefixed with user/trusted/security/system and 2434 * followed by ".". For example, "user.attr". 2435 * <p/> 2436 * A regular user can only set an xattr for the "user" namespace. 2437 * The super user can set an xattr of either the "user" or "trusted" namespaces. 2438 * The xattrs of the "security" and "system" namespaces are only used/exposed 2439 * internally by/to the FS impl. 2440 * <p/> 2441 * The access permissions of an xattr in the "user" namespace are 2442 * defined by the file and directory permission bits. 2443 * An xattr can only be set if the logged-in user has the correct permissions. 2444 * If the xattr exists, it is replaced. 2445 * <p/> 2446 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2447 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2448 * 2449 * @param path Path to modify 2450 * @param name xattr name. 2451 * @param value xattr value. 2452 * @param flag xattr set flag 2453 * @throws IOException 2454 */ 2455 public void setXAttr(Path path, String name, byte[] value, 2456 EnumSet<XAttrSetFlag> flag) throws IOException { 2457 throw new UnsupportedOperationException(getClass().getSimpleName() 2458 + " doesn't support setXAttr"); 2459 } 2460 2461 /** 2462 * Get an xattr name and value for a file or directory. 2463 * The name must be prefixed with user/trusted/security/system and 2464 * followed by ".". For example, "user.attr". 2465 * <p/> 2466 * 2467 * A regular user can only get an xattr for the "user" namespace. 2468 * The super user can get an xattr of either the "user" or "trusted" namespaces. 2469 * The xattrs of the "security" and "system" namespaces are only used/exposed 2470 * internally by/to the FS impl. 2471 * <p/> 2472 * An xattr will only be returned if the logged-in user has the 2473 * correct permissions. 2474 * <p/> 2475 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2476 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2477 * 2478 * @param path Path to get extended attribute 2479 * @param name xattr name. 2480 * @return byte[] xattr value. 2481 * @throws IOException 2482 */ 2483 public byte[] getXAttr(Path path, String name) throws IOException { 2484 throw new UnsupportedOperationException(getClass().getSimpleName() 2485 + " doesn't support getXAttr"); 2486 } 2487 2488 /** 2489 * Get all of the xattr name/value pairs for a file or directory. 2490 * Only those xattrs which the logged-in user has permissions to view 2491 * are returned. 2492 * <p/> 2493 * A regular user can only get xattrs for the "user" namespace. 2494 * The super user can only get xattrs for "user" and "trusted" namespaces. 2495 * The xattrs of the "security" and "system" namespaces are only used/exposed 2496 * internally by/to the FS impl. 2497 * <p/> 2498 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2499 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2500 * 2501 * @param path Path to get extended attributes 2502 * @return Map<String, byte[]> describing the XAttrs of the file or directory 2503 * @throws IOException 2504 */ 2505 public Map<String, byte[]> getXAttrs(Path path) throws IOException { 2506 throw new UnsupportedOperationException(getClass().getSimpleName() 2507 + " doesn't support getXAttrs"); 2508 } 2509 2510 /** 2511 * Get all of the xattrs name/value pairs for a file or directory. 2512 * Only those xattrs which the logged-in user has permissions to view 2513 * are returned. 2514 * <p/> 2515 * A regular user can only get xattrs for the "user" namespace. 2516 * The super user can only get xattrs for "user" and "trusted" namespaces. 2517 * The xattrs of the "security" and "system" namespaces are only used/exposed 2518 * internally by/to the FS impl. 2519 * <p/> 2520 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2521 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2522 * 2523 * @param path Path to get extended attributes 2524 * @param names XAttr names. 2525 * @return Map<String, byte[]> describing the XAttrs of the file or directory 2526 * @throws IOException 2527 */ 2528 public Map<String, byte[]> getXAttrs(Path path, List<String> names) 2529 throws IOException { 2530 throw new UnsupportedOperationException(getClass().getSimpleName() 2531 + " doesn't support getXAttrs"); 2532 } 2533 2534 /** 2535 * Get all of the xattr names for a file or directory. 2536 * Only those xattr names which the logged-in user has permissions to view 2537 * are returned. 2538 * <p/> 2539 * A regular user can only get xattr names for the "user" namespace. 2540 * The super user can only get xattr names for "user" and "trusted" 2541 * namespaces. 2542 * The xattrs of the "security" and "system" namespaces are only 2543 * used/exposed internally by/to the FS impl. 2544 * <p/> 2545 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2546 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2547 * 2548 * @param path Path to get extended attributes 2549 * @return Map<String, byte[]> describing the XAttrs of the file or directory 2550 * @throws IOException 2551 */ 2552 public List<String> listXAttrs(Path path) throws IOException { 2553 throw new UnsupportedOperationException(getClass().getSimpleName() 2554 + " doesn't support listXAttrs"); 2555 } 2556 2557 /** 2558 * Remove an xattr of a file or directory. 2559 * The name must be prefixed with user/trusted/security/system and 2560 * followed by ".". For example, "user.attr". 2561 * <p/> 2562 * A regular user can only remove an xattr for the "user" namespace. 2563 * The super user can remove an xattr of either the "user" or "trusted" namespaces. 2564 * The xattrs of the "security" and "system" namespaces are only used/exposed 2565 * internally by/to the FS impl. 2566 * <p/> 2567 * The access permissions of an xattr in the "user" namespace are 2568 * defined by the file and directory permission bits. 2569 * An xattr can only be set when the logged-in user has the correct permissions. 2570 * If the xattr exists, it will be replaced. 2571 * <p/> 2572 * @see <a href="http://en.wikipedia.org/wiki/Extended_file_attributes"> 2573 * http://en.wikipedia.org/wiki/Extended_file_attributes</a> 2574 * 2575 * @param path Path to remove extended attribute 2576 * @param name xattr name 2577 * @throws IOException 2578 */ 2579 public void removeXAttr(Path path, String name) throws IOException { 2580 throw new UnsupportedOperationException(getClass().getSimpleName() 2581 + " doesn't support removeXAttr"); 2582 } 2583 2584 // making it volatile to be able to do a double checked locking 2585 private volatile static boolean FILE_SYSTEMS_LOADED = false; 2586 2587 private static final Map<String, Class<? extends FileSystem>> 2588 SERVICE_FILE_SYSTEMS = new HashMap<String, Class<? extends FileSystem>>(); 2589 2590 private static void loadFileSystems() { 2591 synchronized (FileSystem.class) { 2592 if (!FILE_SYSTEMS_LOADED) { 2593 ServiceLoader<FileSystem> serviceLoader = ServiceLoader.load(FileSystem.class); 2594 for (FileSystem fs : serviceLoader) { 2595 SERVICE_FILE_SYSTEMS.put(fs.getScheme(), fs.getClass()); 2596 } 2597 FILE_SYSTEMS_LOADED = true; 2598 } 2599 } 2600 } 2601 2602 public static Class<? extends FileSystem> getFileSystemClass(String scheme, 2603 Configuration conf) throws IOException { 2604 if (!FILE_SYSTEMS_LOADED) { 2605 loadFileSystems(); 2606 } 2607 Class<? extends FileSystem> clazz = null; 2608 if (conf != null) { 2609 clazz = (Class<? extends FileSystem>) conf.getClass("fs." + scheme + ".impl", null); 2610 } 2611 if (clazz == null) { 2612 clazz = SERVICE_FILE_SYSTEMS.get(scheme); 2613 } 2614 if (clazz == null) { 2615 throw new IOException("No FileSystem for scheme: " + scheme); 2616 } 2617 return clazz; 2618 } 2619 2620 private static FileSystem createFileSystem(URI uri, Configuration conf 2621 ) throws IOException { 2622 Class<?> clazz = getFileSystemClass(uri.getScheme(), conf); 2623 if (clazz == null) { 2624 throw new IOException("No FileSystem for scheme: " + uri.getScheme()); 2625 } 2626 FileSystem fs = (FileSystem)ReflectionUtils.newInstance(clazz, conf); 2627 fs.initialize(uri, conf); 2628 return fs; 2629 } 2630 2631 /** Caching FileSystem objects */ 2632 static class Cache { 2633 private final ClientFinalizer clientFinalizer = new ClientFinalizer(); 2634 2635 private final Map<Key, FileSystem> map = new HashMap<Key, FileSystem>(); 2636 private final Set<Key> toAutoClose = new HashSet<Key>(); 2637 2638 /** A variable that makes all objects in the cache unique */ 2639 private static AtomicLong unique = new AtomicLong(1); 2640 2641 FileSystem get(URI uri, Configuration conf) throws IOException{ 2642 Key key = new Key(uri, conf); 2643 return getInternal(uri, conf, key); 2644 } 2645 2646 /** The objects inserted into the cache using this method are all unique */ 2647 FileSystem getUnique(URI uri, Configuration conf) throws IOException{ 2648 Key key = new Key(uri, conf, unique.getAndIncrement()); 2649 return getInternal(uri, conf, key); 2650 } 2651 2652 private FileSystem getInternal(URI uri, Configuration conf, Key key) throws IOException{ 2653 FileSystem fs; 2654 synchronized (this) { 2655 fs = map.get(key); 2656 } 2657 if (fs != null) { 2658 return fs; 2659 } 2660 2661 fs = createFileSystem(uri, conf); 2662 synchronized (this) { // refetch the lock again 2663 FileSystem oldfs = map.get(key); 2664 if (oldfs != null) { // a file system is created while lock is releasing 2665 fs.close(); // close the new file system 2666 return oldfs; // return the old file system 2667 } 2668 2669 // now insert the new file system into the map 2670 if (map.isEmpty() 2671 && !ShutdownHookManager.get().isShutdownInProgress()) { 2672 ShutdownHookManager.get().addShutdownHook(clientFinalizer, SHUTDOWN_HOOK_PRIORITY); 2673 } 2674 fs.key = key; 2675 map.put(key, fs); 2676 if (conf.getBoolean("fs.automatic.close", true)) { 2677 toAutoClose.add(key); 2678 } 2679 return fs; 2680 } 2681 } 2682 2683 synchronized void remove(Key key, FileSystem fs) { 2684 if (map.containsKey(key) && fs == map.get(key)) { 2685 map.remove(key); 2686 toAutoClose.remove(key); 2687 } 2688 } 2689 2690 synchronized void closeAll() throws IOException { 2691 closeAll(false); 2692 } 2693 2694 /** 2695 * Close all FileSystem instances in the Cache. 2696 * @param onlyAutomatic only close those that are marked for automatic closing 2697 */ 2698 synchronized void closeAll(boolean onlyAutomatic) throws IOException { 2699 List<IOException> exceptions = new ArrayList<IOException>(); 2700 2701 // Make a copy of the keys in the map since we'll be modifying 2702 // the map while iterating over it, which isn't safe. 2703 List<Key> keys = new ArrayList<Key>(); 2704 keys.addAll(map.keySet()); 2705 2706 for (Key key : keys) { 2707 final FileSystem fs = map.get(key); 2708 2709 if (onlyAutomatic && !toAutoClose.contains(key)) { 2710 continue; 2711 } 2712 2713 //remove from cache 2714 remove(key, fs); 2715 2716 if (fs != null) { 2717 try { 2718 fs.close(); 2719 } 2720 catch(IOException ioe) { 2721 exceptions.add(ioe); 2722 } 2723 } 2724 } 2725 2726 if (!exceptions.isEmpty()) { 2727 throw MultipleIOException.createIOException(exceptions); 2728 } 2729 } 2730 2731 private class ClientFinalizer implements Runnable { 2732 @Override 2733 public synchronized void run() { 2734 try { 2735 closeAll(true); 2736 } catch (IOException e) { 2737 LOG.info("FileSystem.Cache.closeAll() threw an exception:\n" + e); 2738 } 2739 } 2740 } 2741 2742 synchronized void closeAll(UserGroupInformation ugi) throws IOException { 2743 List<FileSystem> targetFSList = new ArrayList<FileSystem>(); 2744 //Make a pass over the list and collect the filesystems to close 2745 //we cannot close inline since close() removes the entry from the Map 2746 for (Map.Entry<Key, FileSystem> entry : map.entrySet()) { 2747 final Key key = entry.getKey(); 2748 final FileSystem fs = entry.getValue(); 2749 if (ugi.equals(key.ugi) && fs != null) { 2750 targetFSList.add(fs); 2751 } 2752 } 2753 List<IOException> exceptions = new ArrayList<IOException>(); 2754 //now make a pass over the target list and close each 2755 for (FileSystem fs : targetFSList) { 2756 try { 2757 fs.close(); 2758 } 2759 catch(IOException ioe) { 2760 exceptions.add(ioe); 2761 } 2762 } 2763 if (!exceptions.isEmpty()) { 2764 throw MultipleIOException.createIOException(exceptions); 2765 } 2766 } 2767 2768 /** FileSystem.Cache.Key */ 2769 static class Key { 2770 final String scheme; 2771 final String authority; 2772 final UserGroupInformation ugi; 2773 final long unique; // an artificial way to make a key unique 2774 2775 Key(URI uri, Configuration conf) throws IOException { 2776 this(uri, conf, 0); 2777 } 2778 2779 Key(URI uri, Configuration conf, long unique) throws IOException { 2780 scheme = uri.getScheme()==null?"":uri.getScheme().toLowerCase(); 2781 authority = uri.getAuthority()==null?"":uri.getAuthority().toLowerCase(); 2782 this.unique = unique; 2783 2784 this.ugi = UserGroupInformation.getCurrentUser(); 2785 } 2786 2787 @Override 2788 public int hashCode() { 2789 return (scheme + authority).hashCode() + ugi.hashCode() + (int)unique; 2790 } 2791 2792 static boolean isEqual(Object a, Object b) { 2793 return a == b || (a != null && a.equals(b)); 2794 } 2795 2796 @Override 2797 public boolean equals(Object obj) { 2798 if (obj == this) { 2799 return true; 2800 } 2801 if (obj != null && obj instanceof Key) { 2802 Key that = (Key)obj; 2803 return isEqual(this.scheme, that.scheme) 2804 && isEqual(this.authority, that.authority) 2805 && isEqual(this.ugi, that.ugi) 2806 && (this.unique == that.unique); 2807 } 2808 return false; 2809 } 2810 2811 @Override 2812 public String toString() { 2813 return "("+ugi.toString() + ")@" + scheme + "://" + authority; 2814 } 2815 } 2816 } 2817 2818 /** 2819 * Tracks statistics about how many reads, writes, and so forth have been 2820 * done in a FileSystem. 2821 * 2822 * Since there is only one of these objects per FileSystem, there will 2823 * typically be many threads writing to this object. Almost every operation 2824 * on an open file will involve a write to this object. In contrast, reading 2825 * statistics is done infrequently by most programs, and not at all by others. 2826 * Hence, this is optimized for writes. 2827 * 2828 * Each thread writes to its own thread-local area of memory. This removes 2829 * contention and allows us to scale up to many, many threads. To read 2830 * statistics, the reader thread totals up the contents of all of the 2831 * thread-local data areas. 2832 */ 2833 public static final class Statistics { 2834 /** 2835 * Statistics data. 2836 * 2837 * There is only a single writer to thread-local StatisticsData objects. 2838 * Hence, volatile is adequate here-- we do not need AtomicLong or similar 2839 * to prevent lost updates. 2840 * The Java specification guarantees that updates to volatile longs will 2841 * be perceived as atomic with respect to other threads, which is all we 2842 * need. 2843 */ 2844 public static class StatisticsData { 2845 volatile long bytesRead; 2846 volatile long bytesWritten; 2847 volatile long readOps; 2848 volatile long largeReadOps; 2849 volatile long writeOps; 2850 /** 2851 * Stores a weak reference to the thread owning this StatisticsData. 2852 * This allows us to remove StatisticsData objects that pertain to 2853 * threads that no longer exist. 2854 */ 2855 final WeakReference<Thread> owner; 2856 2857 StatisticsData(WeakReference<Thread> owner) { 2858 this.owner = owner; 2859 } 2860 2861 /** 2862 * Add another StatisticsData object to this one. 2863 */ 2864 void add(StatisticsData other) { 2865 this.bytesRead += other.bytesRead; 2866 this.bytesWritten += other.bytesWritten; 2867 this.readOps += other.readOps; 2868 this.largeReadOps += other.largeReadOps; 2869 this.writeOps += other.writeOps; 2870 } 2871 2872 /** 2873 * Negate the values of all statistics. 2874 */ 2875 void negate() { 2876 this.bytesRead = -this.bytesRead; 2877 this.bytesWritten = -this.bytesWritten; 2878 this.readOps = -this.readOps; 2879 this.largeReadOps = -this.largeReadOps; 2880 this.writeOps = -this.writeOps; 2881 } 2882 2883 @Override 2884 public String toString() { 2885 return bytesRead + " bytes read, " + bytesWritten + " bytes written, " 2886 + readOps + " read ops, " + largeReadOps + " large read ops, " 2887 + writeOps + " write ops"; 2888 } 2889 2890 public long getBytesRead() { 2891 return bytesRead; 2892 } 2893 2894 public long getBytesWritten() { 2895 return bytesWritten; 2896 } 2897 2898 public int getReadOps() { 2899 return (int) readOps; 2900 } 2901 2902 public long getNumReadOps() { 2903 return readOps; 2904 } 2905 2906 public int getLargeReadOps() { 2907 return (int) largeReadOps; 2908 } 2909 2910 public long getNumLargeReadOps() { 2911 return largeReadOps; 2912 } 2913 2914 public int getWriteOps() { 2915 return (int) writeOps; 2916 } 2917 2918 public long getNumWriteOps() { 2919 return writeOps; 2920 } 2921 } 2922 2923 private interface StatisticsAggregator<T> { 2924 void accept(StatisticsData data); 2925 T aggregate(); 2926 } 2927 2928 private final String scheme; 2929 2930 /** 2931 * rootData is data that doesn't belong to any thread, but will be added 2932 * to the totals. This is useful for making copies of Statistics objects, 2933 * and for storing data that pertains to threads that have been garbage 2934 * collected. Protected by the Statistics lock. 2935 */ 2936 private final StatisticsData rootData; 2937 2938 /** 2939 * Thread-local data. 2940 */ 2941 private final ThreadLocal<StatisticsData> threadData; 2942 2943 /** 2944 * List of all thread-local data areas. Protected by the Statistics lock. 2945 */ 2946 private LinkedList<StatisticsData> allData; 2947 2948 public Statistics(String scheme) { 2949 this.scheme = scheme; 2950 this.rootData = new StatisticsData(null); 2951 this.threadData = new ThreadLocal<StatisticsData>(); 2952 this.allData = null; 2953 } 2954 2955 /** 2956 * Copy constructor. 2957 * 2958 * @param other The input Statistics object which is cloned. 2959 */ 2960 public Statistics(Statistics other) { 2961 this.scheme = other.scheme; 2962 this.rootData = new StatisticsData(null); 2963 other.visitAll(new StatisticsAggregator<Void>() { 2964 @Override 2965 public void accept(StatisticsData data) { 2966 rootData.add(data); 2967 } 2968 2969 public Void aggregate() { 2970 return null; 2971 } 2972 }); 2973 this.threadData = new ThreadLocal<StatisticsData>(); 2974 } 2975 2976 /** 2977 * Get or create the thread-local data associated with the current thread. 2978 */ 2979 public StatisticsData getThreadStatistics() { 2980 StatisticsData data = threadData.get(); 2981 if (data == null) { 2982 data = new StatisticsData( 2983 new WeakReference<Thread>(Thread.currentThread())); 2984 threadData.set(data); 2985 synchronized(this) { 2986 if (allData == null) { 2987 allData = new LinkedList<StatisticsData>(); 2988 } 2989 allData.add(data); 2990 } 2991 } 2992 return data; 2993 } 2994 2995 /** 2996 * Increment the bytes read in the statistics 2997 * @param newBytes the additional bytes read 2998 */ 2999 public void incrementBytesRead(long newBytes) { 3000 getThreadStatistics().bytesRead += newBytes; 3001 } 3002 3003 /** 3004 * Increment the bytes written in the statistics 3005 * @param newBytes the additional bytes written 3006 */ 3007 public void incrementBytesWritten(long newBytes) { 3008 getThreadStatistics().bytesWritten += newBytes; 3009 } 3010 3011 /** 3012 * Increment the number of read operations 3013 * @param count number of read operations 3014 */ 3015 public void incrementReadOps(int count) { 3016 getThreadStatistics().readOps += count; 3017 } 3018 3019 /** 3020 * Increment the number of large read operations 3021 * @param count number of large read operations 3022 */ 3023 public void incrementLargeReadOps(int count) { 3024 getThreadStatistics().largeReadOps += count; 3025 } 3026 3027 /** 3028 * Increment the number of write operations 3029 * @param count number of write operations 3030 */ 3031 public void incrementWriteOps(int count) { 3032 getThreadStatistics().writeOps += count; 3033 } 3034 3035 /** 3036 * Apply the given aggregator to all StatisticsData objects associated with 3037 * this Statistics object. 3038 * 3039 * For each StatisticsData object, we will call accept on the visitor. 3040 * Finally, at the end, we will call aggregate to get the final total. 3041 * 3042 * @param The visitor to use. 3043 * @return The total. 3044 */ 3045 private synchronized <T> T visitAll(StatisticsAggregator<T> visitor) { 3046 visitor.accept(rootData); 3047 if (allData != null) { 3048 for (Iterator<StatisticsData> iter = allData.iterator(); 3049 iter.hasNext(); ) { 3050 StatisticsData data = iter.next(); 3051 visitor.accept(data); 3052 if (data.owner.get() == null) { 3053 /* 3054 * If the thread that created this thread-local data no 3055 * longer exists, remove the StatisticsData from our list 3056 * and fold the values into rootData. 3057 */ 3058 rootData.add(data); 3059 iter.remove(); 3060 } 3061 } 3062 } 3063 return visitor.aggregate(); 3064 } 3065 3066 /** 3067 * Get the total number of bytes read 3068 * @return the number of bytes 3069 */ 3070 public long getBytesRead() { 3071 return visitAll(new StatisticsAggregator<Long>() { 3072 private long bytesRead = 0; 3073 3074 @Override 3075 public void accept(StatisticsData data) { 3076 bytesRead += data.bytesRead; 3077 } 3078 3079 public Long aggregate() { 3080 return bytesRead; 3081 } 3082 }); 3083 } 3084 3085 /** 3086 * Get the total number of bytes written 3087 * @return the number of bytes 3088 */ 3089 public long getBytesWritten() { 3090 return visitAll(new StatisticsAggregator<Long>() { 3091 private long bytesWritten = 0; 3092 3093 @Override 3094 public void accept(StatisticsData data) { 3095 bytesWritten += data.bytesWritten; 3096 } 3097 3098 public Long aggregate() { 3099 return bytesWritten; 3100 } 3101 }); 3102 } 3103 3104 /** 3105 * Get the number of file system read operations such as list files 3106 * @return number of read operations 3107 */ 3108 public int getReadOps() { 3109 return (int) getNumReadOps(); 3110 } 3111 3112 /** 3113 * Get the number of file system read operations such as list files 3114 * @return number of read operations as a long type 3115 */ 3116 public long getNumReadOps() { 3117 return visitAll(new StatisticsAggregator<Long>() { 3118 private long readOps = 0; 3119 3120 @Override 3121 public void accept(StatisticsData data) { 3122 readOps += data.readOps; 3123 readOps += data.largeReadOps; 3124 } 3125 3126 public Long aggregate() { 3127 return readOps; 3128 } 3129 }); 3130 } 3131 3132 /** 3133 * Get the number of large file system read operations such as list files 3134 * under a large directory 3135 * @return number of large read operations 3136 */ 3137 public int getLargeReadOps() { 3138 return (int) getNumLargeReadOps(); 3139 } 3140 3141 /** 3142 * Get the number of large file system read operations such as list files 3143 * under a large directory 3144 * @return number of large read operations as a long type 3145 */ 3146 public long getNumLargeReadOps() { 3147 return visitAll(new StatisticsAggregator<Long>() { 3148 private long largeReadOps = 0; 3149 3150 @Override 3151 public void accept(StatisticsData data) { 3152 largeReadOps += data.largeReadOps; 3153 } 3154 3155 public Long aggregate() { 3156 return largeReadOps; 3157 } 3158 }); 3159 } 3160 3161 /** 3162 * Get the number of file system write operations such as create, append 3163 * rename etc. 3164 * @return number of write operations 3165 */ 3166 public int getWriteOps() { 3167 return (int) getNumWriteOps(); 3168 } 3169 3170 /** 3171 * Get the number of file system write operations such as create, append 3172 * rename etc. 3173 * @return number of write operations as a long type 3174 */ 3175 public long getNumWriteOps() { 3176 return visitAll(new StatisticsAggregator<Long>() { 3177 private long writeOps = 0; 3178 3179 @Override 3180 public void accept(StatisticsData data) { 3181 writeOps += data.writeOps; 3182 } 3183 3184 public Long aggregate() { 3185 return writeOps; 3186 } 3187 }); 3188 } 3189 3190 3191 @Override 3192 public String toString() { 3193 return visitAll(new StatisticsAggregator<String>() { 3194 private StatisticsData total = new StatisticsData(null); 3195 3196 @Override 3197 public void accept(StatisticsData data) { 3198 total.add(data); 3199 } 3200 3201 public String aggregate() { 3202 return total.toString(); 3203 } 3204 }); 3205 } 3206 3207 /** 3208 * Resets all statistics to 0. 3209 * 3210 * In order to reset, we add up all the thread-local statistics data, and 3211 * set rootData to the negative of that. 3212 * 3213 * This may seem like a counterintuitive way to reset the statsitics. Why 3214 * can't we just zero out all the thread-local data? Well, thread-local 3215 * data can only be modified by the thread that owns it. If we tried to 3216 * modify the thread-local data from this thread, our modification might get 3217 * interleaved with a read-modify-write operation done by the thread that 3218 * owns the data. That would result in our update getting lost. 3219 * 3220 * The approach used here avoids this problem because it only ever reads 3221 * (not writes) the thread-local data. Both reads and writes to rootData 3222 * are done under the lock, so we're free to modify rootData from any thread 3223 * that holds the lock. 3224 */ 3225 public void reset() { 3226 visitAll(new StatisticsAggregator<Void>() { 3227 private StatisticsData total = new StatisticsData(null); 3228 3229 @Override 3230 public void accept(StatisticsData data) { 3231 total.add(data); 3232 } 3233 3234 public Void aggregate() { 3235 total.negate(); 3236 rootData.add(total); 3237 return null; 3238 } 3239 }); 3240 } 3241 3242 /** 3243 * Get the uri scheme associated with this statistics object. 3244 * @return the schema associated with this set of statistics 3245 */ 3246 public String getScheme() { 3247 return scheme; 3248 } 3249 } 3250 3251 /** 3252 * Get the Map of Statistics object indexed by URI Scheme. 3253 * @return a Map having a key as URI scheme and value as Statistics object 3254 * @deprecated use {@link #getAllStatistics} instead 3255 */ 3256 @Deprecated 3257 public static synchronized Map<String, Statistics> getStatistics() { 3258 Map<String, Statistics> result = new HashMap<String, Statistics>(); 3259 for(Statistics stat: statisticsTable.values()) { 3260 result.put(stat.getScheme(), stat); 3261 } 3262 return result; 3263 } 3264 3265 /** 3266 * Return the FileSystem classes that have Statistics 3267 */ 3268 public static synchronized List<Statistics> getAllStatistics() { 3269 return new ArrayList<Statistics>(statisticsTable.values()); 3270 } 3271 3272 /** 3273 * Get the statistics for a particular file system 3274 * @param cls the class to lookup 3275 * @return a statistics object 3276 */ 3277 public static synchronized 3278 Statistics getStatistics(String scheme, Class<? extends FileSystem> cls) { 3279 Statistics result = statisticsTable.get(cls); 3280 if (result == null) { 3281 result = new Statistics(scheme); 3282 statisticsTable.put(cls, result); 3283 } 3284 return result; 3285 } 3286 3287 /** 3288 * Reset all statistics for all file systems 3289 */ 3290 public static synchronized void clearStatistics() { 3291 for(Statistics stat: statisticsTable.values()) { 3292 stat.reset(); 3293 } 3294 } 3295 3296 /** 3297 * Print all statistics for all file systems 3298 */ 3299 public static synchronized 3300 void printStatistics() throws IOException { 3301 for (Map.Entry<Class<? extends FileSystem>, Statistics> pair: 3302 statisticsTable.entrySet()) { 3303 System.out.println(" FileSystem " + pair.getKey().getName() + 3304 ": " + pair.getValue()); 3305 } 3306 } 3307 3308 // But this causes issues for existing MR1 class TaskRunner which needs to 3309 // create symlink using local file system. So enabling symlinks. 3310 private static boolean symlinksEnabled = true; 3311 3312 private static Configuration conf = null; 3313 3314 @VisibleForTesting 3315 public static boolean areSymlinksEnabled() { 3316 return symlinksEnabled; 3317 } 3318 3319 @VisibleForTesting 3320 public static void enableSymlinks() { 3321 symlinksEnabled = true; 3322 } 3323 3324 /** 3325 * MapR addition: 3326 * Opens an FSDataInputStream at the indicated fid. 3327 * @param fid the fid to open 3328 * @param ips the list of ip/ports which this fid belongs to 3329 * @param chunkSize the chunkSize of the file corresponding to the fid 3330 * @param fileSize the size of the file corresponding to the fid 3331 */ 3332 public FSDataInputStream openFid(String fid, long[] ips, 3333 long chunkSize, long fileSize) throws IOException { 3334 throw new UnsupportedOperationException("See concrete FS for implementation"); 3335 } 3336 3337 /** 3338 * MapR addition: 3339 * Opens an FSDataInputStream at the indicated fid. 3340 * @param pfid the parent-fid of the file to open 3341 * @param file the file to be opened 3342 */ 3343 public FSDataInputStream openFid(String pfid, String file, long [] ips) 3344 throws IOException { 3345 throw new UnsupportedOperationException("See concrete FS for implementation"); 3346 } 3347 3348 /** 3349 * MapR - get Zookeeper connect string for the default cluster. 3350 */ 3351 public String getZkConnectString() throws IOException { 3352 throw new UnsupportedOperationException("See concrete FS for implementation"); 3353 } 3354 3355 /** 3356 * MapR - get jobTracker addresses given by cluster name 3357 * in mapred.job.tracker 3358 */ 3359 public InetSocketAddress[] getJobTrackerAddrs(Configuration conf) 3360 throws IOException { 3361 throw new UnsupportedOperationException("See concrete FS for implementation"); 3362 } 3363}