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 */ 018 package org.apache.hadoop.hdfs; 019 020 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_BLOCK_SIZE_DEFAULT; 021 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_BLOCK_SIZE_KEY; 022 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_BYTES_PER_CHECKSUM_DEFAULT; 023 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_BYTES_PER_CHECKSUM_KEY; 024 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_BLOCK_WRITE_LOCATEFOLLOWINGBLOCK_RETRIES_DEFAULT; 025 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_BLOCK_WRITE_LOCATEFOLLOWINGBLOCK_RETRIES_KEY; 026 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_BLOCK_WRITE_RETRIES_DEFAULT; 027 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_BLOCK_WRITE_RETRIES_KEY; 028 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_CACHED_CONN_RETRY_DEFAULT; 029 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_CACHED_CONN_RETRY_KEY; 030 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_CACHE_DROP_BEHIND_READS; 031 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_CACHE_DROP_BEHIND_WRITES; 032 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_CACHE_READAHEAD; 033 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_DEFAULT; 034 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY; 035 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_DEFAULT; 036 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_KEY; 037 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_DEFAULT; 038 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_KEY; 039 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_DEFAULT; 040 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_MAX_ATTEMPTS_KEY; 041 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_MAX_BLOCK_ACQUIRE_FAILURES_DEFAULT; 042 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_MAX_BLOCK_ACQUIRE_FAILURES_KEY; 043 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_READ_PREFETCH_SIZE_KEY; 044 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_RETRY_WINDOW_BASE; 045 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_SOCKET_CACHE_CAPACITY_DEFAULT; 046 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_SOCKET_CACHE_CAPACITY_KEY; 047 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_SOCKET_CACHE_EXPIRY_MSEC_DEFAULT; 048 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_SOCKET_CACHE_EXPIRY_MSEC_KEY; 049 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_SOCKET_TIMEOUT_KEY; 050 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_USE_DN_HOSTNAME; 051 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_USE_DN_HOSTNAME_DEFAULT; 052 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_WRITE_EXCLUDE_NODES_CACHE_EXPIRY_INTERVAL; 053 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_WRITE_EXCLUDE_NODES_CACHE_EXPIRY_INTERVAL_DEFAULT; 054 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_WRITE_PACKET_SIZE_DEFAULT; 055 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_CLIENT_WRITE_PACKET_SIZE_KEY; 056 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_DATANODE_SOCKET_WRITE_TIMEOUT_KEY; 057 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_REPLICATION_DEFAULT; 058 import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_REPLICATION_KEY; 059 060 import java.io.BufferedOutputStream; 061 import java.io.DataInputStream; 062 import java.io.DataOutputStream; 063 import java.io.FileNotFoundException; 064 import java.io.IOException; 065 import java.io.InputStream; 066 import java.io.OutputStream; 067 import java.net.InetAddress; 068 import java.net.InetSocketAddress; 069 import java.net.NetworkInterface; 070 import java.net.Socket; 071 import java.net.SocketException; 072 import java.net.SocketAddress; 073 import java.net.URI; 074 import java.net.UnknownHostException; 075 import java.util.ArrayList; 076 import java.util.Collections; 077 import java.util.EnumSet; 078 import java.util.HashMap; 079 import java.util.LinkedHashMap; 080 import java.util.List; 081 import java.util.Map; 082 import java.util.Random; 083 084 import javax.net.SocketFactory; 085 086 import org.apache.commons.logging.Log; 087 import org.apache.commons.logging.LogFactory; 088 import org.apache.hadoop.classification.InterfaceAudience; 089 import org.apache.hadoop.conf.Configuration; 090 import org.apache.hadoop.fs.BlockLocation; 091 import org.apache.hadoop.fs.BlockStorageLocation; 092 import org.apache.hadoop.fs.CacheFlag; 093 import org.apache.hadoop.fs.CommonConfigurationKeysPublic; 094 import org.apache.hadoop.fs.ContentSummary; 095 import org.apache.hadoop.fs.CreateFlag; 096 import org.apache.hadoop.fs.FileAlreadyExistsException; 097 import org.apache.hadoop.fs.FileSystem; 098 import org.apache.hadoop.fs.FsServerDefaults; 099 import org.apache.hadoop.fs.FsStatus; 100 import org.apache.hadoop.fs.HdfsBlockLocation; 101 import org.apache.hadoop.fs.InvalidPathException; 102 import org.apache.hadoop.fs.MD5MD5CRC32CastagnoliFileChecksum; 103 import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum; 104 import org.apache.hadoop.fs.MD5MD5CRC32GzipFileChecksum; 105 import org.apache.hadoop.fs.Options; 106 import org.apache.hadoop.fs.RemoteIterator; 107 import org.apache.hadoop.fs.Options.ChecksumOpt; 108 import org.apache.hadoop.fs.ParentNotDirectoryException; 109 import org.apache.hadoop.fs.Path; 110 import org.apache.hadoop.fs.UnresolvedLinkException; 111 import org.apache.hadoop.fs.VolumeId; 112 import org.apache.hadoop.fs.permission.FsPermission; 113 import org.apache.hadoop.hdfs.client.ClientMmapManager; 114 import org.apache.hadoop.hdfs.client.HdfsDataInputStream; 115 import org.apache.hadoop.hdfs.client.HdfsDataOutputStream; 116 import org.apache.hadoop.hdfs.protocol.CacheDirectiveEntry; 117 import org.apache.hadoop.hdfs.protocol.CacheDirectiveIterator; 118 import org.apache.hadoop.hdfs.protocol.CachePoolEntry; 119 import org.apache.hadoop.hdfs.protocol.CachePoolInfo; 120 import org.apache.hadoop.hdfs.protocol.CachePoolIterator; 121 import org.apache.hadoop.hdfs.protocol.ClientProtocol; 122 import org.apache.hadoop.hdfs.protocol.CorruptFileBlocks; 123 import org.apache.hadoop.hdfs.protocol.DSQuotaExceededException; 124 import org.apache.hadoop.hdfs.protocol.DatanodeInfo; 125 import org.apache.hadoop.hdfs.protocol.DirectoryListing; 126 import org.apache.hadoop.hdfs.protocol.ExtendedBlock; 127 import org.apache.hadoop.hdfs.protocol.HdfsBlocksMetadata; 128 import org.apache.hadoop.hdfs.protocol.HdfsConstants; 129 import org.apache.hadoop.hdfs.protocol.CacheDirectiveInfo; 130 import org.apache.hadoop.hdfs.protocol.HdfsConstants.DatanodeReportType; 131 import org.apache.hadoop.hdfs.protocol.HdfsConstants.SafeModeAction; 132 import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; 133 import org.apache.hadoop.hdfs.protocol.LocatedBlock; 134 import org.apache.hadoop.hdfs.protocol.LocatedBlocks; 135 import org.apache.hadoop.hdfs.protocol.NSQuotaExceededException; 136 import org.apache.hadoop.hdfs.protocol.SnapshotAccessControlException; 137 import org.apache.hadoop.hdfs.protocol.SnapshotDiffReport; 138 import org.apache.hadoop.hdfs.protocol.SnapshottableDirectoryStatus; 139 import org.apache.hadoop.hdfs.protocol.UnresolvedPathException; 140 import org.apache.hadoop.hdfs.protocol.datatransfer.DataTransferEncryptor; 141 import org.apache.hadoop.hdfs.protocol.datatransfer.IOStreamPair; 142 import org.apache.hadoop.hdfs.protocol.datatransfer.Op; 143 import org.apache.hadoop.hdfs.protocol.datatransfer.ReplaceDatanodeOnFailure; 144 import org.apache.hadoop.hdfs.protocol.datatransfer.Sender; 145 import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.BlockOpResponseProto; 146 import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.OpBlockChecksumResponseProto; 147 import org.apache.hadoop.hdfs.protocol.proto.DataTransferProtos.Status; 148 import org.apache.hadoop.hdfs.security.token.block.DataEncryptionKey; 149 import org.apache.hadoop.hdfs.protocolPB.PBHelper; 150 import org.apache.hadoop.hdfs.security.token.block.InvalidBlockTokenException; 151 import org.apache.hadoop.hdfs.security.token.delegation.DelegationTokenIdentifier; 152 import org.apache.hadoop.hdfs.server.common.HdfsServerConstants; 153 import org.apache.hadoop.hdfs.server.datanode.CachingStrategy; 154 import org.apache.hadoop.hdfs.server.namenode.NameNode; 155 import org.apache.hadoop.hdfs.server.namenode.SafeModeException; 156 import org.apache.hadoop.io.DataOutputBuffer; 157 import org.apache.hadoop.io.EnumSetWritable; 158 import org.apache.hadoop.io.IOUtils; 159 import org.apache.hadoop.io.MD5Hash; 160 import org.apache.hadoop.io.Text; 161 import org.apache.hadoop.io.retry.LossyRetryInvocationHandler; 162 import org.apache.hadoop.ipc.Client; 163 import org.apache.hadoop.ipc.RPC; 164 import org.apache.hadoop.ipc.RemoteException; 165 import org.apache.hadoop.net.DNS; 166 import org.apache.hadoop.net.NetUtils; 167 import org.apache.hadoop.security.AccessControlException; 168 import org.apache.hadoop.security.UserGroupInformation; 169 import org.apache.hadoop.security.token.SecretManager.InvalidToken; 170 import org.apache.hadoop.security.token.Token; 171 import org.apache.hadoop.security.token.TokenRenewer; 172 import org.apache.hadoop.util.DataChecksum; 173 import org.apache.hadoop.util.DataChecksum.Type; 174 import org.apache.hadoop.util.Progressable; 175 import org.apache.hadoop.util.Time; 176 177 import com.google.common.annotations.VisibleForTesting; 178 import com.google.common.base.Joiner; 179 import com.google.common.base.Preconditions; 180 import com.google.common.net.InetAddresses; 181 182 /******************************************************** 183 * DFSClient can connect to a Hadoop Filesystem and 184 * perform basic file tasks. It uses the ClientProtocol 185 * to communicate with a NameNode daemon, and connects 186 * directly to DataNodes to read/write block data. 187 * 188 * Hadoop DFS users should obtain an instance of 189 * DistributedFileSystem, which uses DFSClient to handle 190 * filesystem tasks. 191 * 192 ********************************************************/ 193 @InterfaceAudience.Private 194 public class DFSClient implements java.io.Closeable { 195 public static final Log LOG = LogFactory.getLog(DFSClient.class); 196 public static final long SERVER_DEFAULTS_VALIDITY_PERIOD = 60 * 60 * 1000L; // 1 hour 197 static final int TCP_WINDOW_SIZE = 128 * 1024; // 128 KB 198 199 private final Configuration conf; 200 private final Conf dfsClientConf; 201 final ClientProtocol namenode; 202 /* The service used for delegation tokens */ 203 private Text dtService; 204 205 final UserGroupInformation ugi; 206 volatile boolean clientRunning = true; 207 volatile long lastLeaseRenewal; 208 private volatile FsServerDefaults serverDefaults; 209 private volatile long serverDefaultsLastUpdate; 210 final String clientName; 211 SocketFactory socketFactory; 212 final ReplaceDatanodeOnFailure dtpReplaceDatanodeOnFailure; 213 final FileSystem.Statistics stats; 214 private final String authority; 215 final PeerCache peerCache; 216 private Random r = new Random(); 217 private SocketAddress[] localInterfaceAddrs; 218 private DataEncryptionKey encryptionKey; 219 private boolean shouldUseLegacyBlockReaderLocal; 220 private final CachingStrategy defaultReadCachingStrategy; 221 private final CachingStrategy defaultWriteCachingStrategy; 222 private ClientMmapManager mmapManager; 223 224 private static final ClientMmapManagerFactory MMAP_MANAGER_FACTORY = 225 new ClientMmapManagerFactory(); 226 227 private static final class ClientMmapManagerFactory { 228 private ClientMmapManager mmapManager = null; 229 /** 230 * Tracks the number of users of mmapManager. 231 */ 232 private int refcnt = 0; 233 234 synchronized ClientMmapManager get(Configuration conf) { 235 if (refcnt++ == 0) { 236 mmapManager = ClientMmapManager.fromConf(conf); 237 } else { 238 String mismatches = mmapManager.verifyConfigurationMatches(conf); 239 if (!mismatches.isEmpty()) { 240 LOG.warn("The ClientMmapManager settings you specified " + 241 "have been ignored because another thread created the " + 242 "ClientMmapManager first. " + mismatches); 243 } 244 } 245 return mmapManager; 246 } 247 248 synchronized void unref(ClientMmapManager mmapManager) { 249 if (this.mmapManager != mmapManager) { 250 throw new IllegalArgumentException(); 251 } 252 if (--refcnt == 0) { 253 IOUtils.cleanup(LOG, mmapManager); 254 mmapManager = null; 255 } 256 } 257 } 258 259 /** 260 * DFSClient configuration 261 */ 262 public static class Conf { 263 final int hdfsTimeout; // timeout value for a DFS operation. 264 final int maxFailoverAttempts; 265 final int maxRetryAttempts; 266 final int failoverSleepBaseMillis; 267 final int failoverSleepMaxMillis; 268 final int maxBlockAcquireFailures; 269 final int confTime; 270 final int ioBufferSize; 271 final ChecksumOpt defaultChecksumOpt; 272 final int writePacketSize; 273 final int socketTimeout; 274 final int socketCacheCapacity; 275 final long socketCacheExpiry; 276 final long excludedNodesCacheExpiry; 277 /** Wait time window (in msec) if BlockMissingException is caught */ 278 final int timeWindow; 279 final int nCachedConnRetry; 280 final int nBlockWriteRetry; 281 final int nBlockWriteLocateFollowingRetry; 282 final long defaultBlockSize; 283 final long prefetchSize; 284 final short defaultReplication; 285 final String taskId; 286 final FsPermission uMask; 287 final boolean connectToDnViaHostname; 288 final boolean getHdfsBlocksMetadataEnabled; 289 final int getFileBlockStorageLocationsNumThreads; 290 final int getFileBlockStorageLocationsTimeout; 291 final int retryTimesForGetLastBlockLength; 292 final int retryIntervalForGetLastBlockLength; 293 294 final boolean useLegacyBlockReader; 295 final boolean useLegacyBlockReaderLocal; 296 final String domainSocketPath; 297 final boolean skipShortCircuitChecksums; 298 final int shortCircuitBufferSize; 299 final boolean shortCircuitLocalReads; 300 final boolean domainSocketDataTraffic; 301 final int shortCircuitStreamsCacheSize; 302 final long shortCircuitStreamsCacheExpiryMs; 303 304 public Conf(Configuration conf) { 305 // The hdfsTimeout is currently the same as the ipc timeout 306 hdfsTimeout = Client.getTimeout(conf); 307 308 maxFailoverAttempts = conf.getInt( 309 DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_KEY, 310 DFS_CLIENT_FAILOVER_MAX_ATTEMPTS_DEFAULT); 311 maxRetryAttempts = conf.getInt( 312 DFS_CLIENT_RETRY_MAX_ATTEMPTS_KEY, 313 DFS_CLIENT_RETRY_MAX_ATTEMPTS_DEFAULT); 314 failoverSleepBaseMillis = conf.getInt( 315 DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_KEY, 316 DFS_CLIENT_FAILOVER_SLEEPTIME_BASE_DEFAULT); 317 failoverSleepMaxMillis = conf.getInt( 318 DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_KEY, 319 DFS_CLIENT_FAILOVER_SLEEPTIME_MAX_DEFAULT); 320 321 maxBlockAcquireFailures = conf.getInt( 322 DFS_CLIENT_MAX_BLOCK_ACQUIRE_FAILURES_KEY, 323 DFS_CLIENT_MAX_BLOCK_ACQUIRE_FAILURES_DEFAULT); 324 confTime = conf.getInt(DFS_DATANODE_SOCKET_WRITE_TIMEOUT_KEY, 325 HdfsServerConstants.WRITE_TIMEOUT); 326 ioBufferSize = conf.getInt( 327 CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_KEY, 328 CommonConfigurationKeysPublic.IO_FILE_BUFFER_SIZE_DEFAULT); 329 defaultChecksumOpt = getChecksumOptFromConf(conf); 330 socketTimeout = conf.getInt(DFS_CLIENT_SOCKET_TIMEOUT_KEY, 331 HdfsServerConstants.READ_TIMEOUT); 332 /** dfs.write.packet.size is an internal config variable */ 333 writePacketSize = conf.getInt(DFS_CLIENT_WRITE_PACKET_SIZE_KEY, 334 DFS_CLIENT_WRITE_PACKET_SIZE_DEFAULT); 335 defaultBlockSize = conf.getLongBytes(DFS_BLOCK_SIZE_KEY, 336 DFS_BLOCK_SIZE_DEFAULT); 337 defaultReplication = (short) conf.getInt( 338 DFS_REPLICATION_KEY, DFS_REPLICATION_DEFAULT); 339 taskId = conf.get("mapreduce.task.attempt.id", "NONMAPREDUCE"); 340 socketCacheCapacity = conf.getInt(DFS_CLIENT_SOCKET_CACHE_CAPACITY_KEY, 341 DFS_CLIENT_SOCKET_CACHE_CAPACITY_DEFAULT); 342 socketCacheExpiry = conf.getLong(DFS_CLIENT_SOCKET_CACHE_EXPIRY_MSEC_KEY, 343 DFS_CLIENT_SOCKET_CACHE_EXPIRY_MSEC_DEFAULT); 344 excludedNodesCacheExpiry = conf.getLong( 345 DFS_CLIENT_WRITE_EXCLUDE_NODES_CACHE_EXPIRY_INTERVAL, 346 DFS_CLIENT_WRITE_EXCLUDE_NODES_CACHE_EXPIRY_INTERVAL_DEFAULT); 347 prefetchSize = conf.getLong(DFS_CLIENT_READ_PREFETCH_SIZE_KEY, 348 10 * defaultBlockSize); 349 timeWindow = conf.getInt(DFS_CLIENT_RETRY_WINDOW_BASE, 3000); 350 nCachedConnRetry = conf.getInt(DFS_CLIENT_CACHED_CONN_RETRY_KEY, 351 DFS_CLIENT_CACHED_CONN_RETRY_DEFAULT); 352 nBlockWriteRetry = conf.getInt(DFS_CLIENT_BLOCK_WRITE_RETRIES_KEY, 353 DFS_CLIENT_BLOCK_WRITE_RETRIES_DEFAULT); 354 nBlockWriteLocateFollowingRetry = conf.getInt( 355 DFS_CLIENT_BLOCK_WRITE_LOCATEFOLLOWINGBLOCK_RETRIES_KEY, 356 DFS_CLIENT_BLOCK_WRITE_LOCATEFOLLOWINGBLOCK_RETRIES_DEFAULT); 357 uMask = FsPermission.getUMask(conf); 358 connectToDnViaHostname = conf.getBoolean(DFS_CLIENT_USE_DN_HOSTNAME, 359 DFS_CLIENT_USE_DN_HOSTNAME_DEFAULT); 360 getHdfsBlocksMetadataEnabled = conf.getBoolean( 361 DFSConfigKeys.DFS_HDFS_BLOCKS_METADATA_ENABLED, 362 DFSConfigKeys.DFS_HDFS_BLOCKS_METADATA_ENABLED_DEFAULT); 363 getFileBlockStorageLocationsNumThreads = conf.getInt( 364 DFSConfigKeys.DFS_CLIENT_FILE_BLOCK_STORAGE_LOCATIONS_NUM_THREADS, 365 DFSConfigKeys.DFS_CLIENT_FILE_BLOCK_STORAGE_LOCATIONS_NUM_THREADS_DEFAULT); 366 getFileBlockStorageLocationsTimeout = conf.getInt( 367 DFSConfigKeys.DFS_CLIENT_FILE_BLOCK_STORAGE_LOCATIONS_TIMEOUT, 368 DFSConfigKeys.DFS_CLIENT_FILE_BLOCK_STORAGE_LOCATIONS_TIMEOUT_DEFAULT); 369 retryTimesForGetLastBlockLength = conf.getInt( 370 DFSConfigKeys.DFS_CLIENT_RETRY_TIMES_GET_LAST_BLOCK_LENGTH, 371 DFSConfigKeys.DFS_CLIENT_RETRY_TIMES_GET_LAST_BLOCK_LENGTH_DEFAULT); 372 retryIntervalForGetLastBlockLength = conf.getInt( 373 DFSConfigKeys.DFS_CLIENT_RETRY_INTERVAL_GET_LAST_BLOCK_LENGTH, 374 DFSConfigKeys.DFS_CLIENT_RETRY_INTERVAL_GET_LAST_BLOCK_LENGTH_DEFAULT); 375 376 useLegacyBlockReader = conf.getBoolean( 377 DFSConfigKeys.DFS_CLIENT_USE_LEGACY_BLOCKREADER, 378 DFSConfigKeys.DFS_CLIENT_USE_LEGACY_BLOCKREADER_DEFAULT); 379 useLegacyBlockReaderLocal = conf.getBoolean( 380 DFSConfigKeys.DFS_CLIENT_USE_LEGACY_BLOCKREADERLOCAL, 381 DFSConfigKeys.DFS_CLIENT_USE_LEGACY_BLOCKREADERLOCAL_DEFAULT); 382 shortCircuitLocalReads = conf.getBoolean( 383 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY, 384 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_DEFAULT); 385 domainSocketDataTraffic = conf.getBoolean( 386 DFSConfigKeys.DFS_CLIENT_DOMAIN_SOCKET_DATA_TRAFFIC, 387 DFSConfigKeys.DFS_CLIENT_DOMAIN_SOCKET_DATA_TRAFFIC_DEFAULT); 388 domainSocketPath = conf.getTrimmed( 389 DFSConfigKeys.DFS_DOMAIN_SOCKET_PATH_KEY, 390 DFSConfigKeys.DFS_DOMAIN_SOCKET_PATH_DEFAULT); 391 392 if (BlockReaderLocal.LOG.isDebugEnabled()) { 393 BlockReaderLocal.LOG.debug( 394 DFSConfigKeys.DFS_CLIENT_USE_LEGACY_BLOCKREADERLOCAL 395 + " = " + useLegacyBlockReaderLocal); 396 BlockReaderLocal.LOG.debug( 397 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_KEY 398 + " = " + shortCircuitLocalReads); 399 BlockReaderLocal.LOG.debug( 400 DFSConfigKeys.DFS_CLIENT_DOMAIN_SOCKET_DATA_TRAFFIC 401 + " = " + domainSocketDataTraffic); 402 BlockReaderLocal.LOG.debug( 403 DFSConfigKeys.DFS_DOMAIN_SOCKET_PATH_KEY 404 + " = " + domainSocketPath); 405 } 406 407 skipShortCircuitChecksums = conf.getBoolean( 408 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_KEY, 409 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_SKIP_CHECKSUM_DEFAULT); 410 shortCircuitBufferSize = conf.getInt( 411 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_BUFFER_SIZE_KEY, 412 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_BUFFER_SIZE_DEFAULT); 413 shortCircuitStreamsCacheSize = conf.getInt( 414 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_STREAMS_CACHE_SIZE_KEY, 415 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_STREAMS_CACHE_SIZE_DEFAULT); 416 shortCircuitStreamsCacheExpiryMs = conf.getLong( 417 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_STREAMS_CACHE_EXPIRY_MS_KEY, 418 DFSConfigKeys.DFS_CLIENT_READ_SHORTCIRCUIT_STREAMS_CACHE_EXPIRY_MS_DEFAULT); 419 } 420 421 private DataChecksum.Type getChecksumType(Configuration conf) { 422 final String checksum = conf.get( 423 DFSConfigKeys.DFS_CHECKSUM_TYPE_KEY, 424 DFSConfigKeys.DFS_CHECKSUM_TYPE_DEFAULT); 425 try { 426 return DataChecksum.Type.valueOf(checksum); 427 } catch(IllegalArgumentException iae) { 428 LOG.warn("Bad checksum type: " + checksum + ". Using default " 429 + DFSConfigKeys.DFS_CHECKSUM_TYPE_DEFAULT); 430 return DataChecksum.Type.valueOf( 431 DFSConfigKeys.DFS_CHECKSUM_TYPE_DEFAULT); 432 } 433 } 434 435 // Construct a checksum option from conf 436 private ChecksumOpt getChecksumOptFromConf(Configuration conf) { 437 DataChecksum.Type type = getChecksumType(conf); 438 int bytesPerChecksum = conf.getInt(DFS_BYTES_PER_CHECKSUM_KEY, 439 DFS_BYTES_PER_CHECKSUM_DEFAULT); 440 return new ChecksumOpt(type, bytesPerChecksum); 441 } 442 443 // create a DataChecksum with the default option. 444 private DataChecksum createChecksum() throws IOException { 445 return createChecksum(null); 446 } 447 448 private DataChecksum createChecksum(ChecksumOpt userOpt) 449 throws IOException { 450 // Fill in any missing field with the default. 451 ChecksumOpt myOpt = ChecksumOpt.processChecksumOpt( 452 defaultChecksumOpt, userOpt); 453 DataChecksum dataChecksum = DataChecksum.newDataChecksum( 454 myOpt.getChecksumType(), 455 myOpt.getBytesPerChecksum()); 456 if (dataChecksum == null) { 457 throw new IOException("Invalid checksum type specified: " 458 + myOpt.getChecksumType().name()); 459 } 460 return dataChecksum; 461 } 462 } 463 464 public Conf getConf() { 465 return dfsClientConf; 466 } 467 468 Configuration getConfiguration() { 469 return conf; 470 } 471 472 /** 473 * A map from file names to {@link DFSOutputStream} objects 474 * that are currently being written by this client. 475 * Note that a file can only be written by a single client. 476 */ 477 private final Map<String, DFSOutputStream> filesBeingWritten 478 = new HashMap<String, DFSOutputStream>(); 479 480 private final DomainSocketFactory domainSocketFactory; 481 482 /** 483 * Same as this(NameNode.getAddress(conf), conf); 484 * @see #DFSClient(InetSocketAddress, Configuration) 485 * @deprecated Deprecated at 0.21 486 */ 487 @Deprecated 488 public DFSClient(Configuration conf) throws IOException { 489 this(NameNode.getAddress(conf), conf); 490 } 491 492 public DFSClient(InetSocketAddress address, Configuration conf) throws IOException { 493 this(NameNode.getUri(address), conf); 494 } 495 496 /** 497 * Same as this(nameNodeUri, conf, null); 498 * @see #DFSClient(URI, Configuration, FileSystem.Statistics) 499 */ 500 public DFSClient(URI nameNodeUri, Configuration conf 501 ) throws IOException { 502 this(nameNodeUri, conf, null); 503 } 504 505 /** 506 * Same as this(nameNodeUri, null, conf, stats); 507 * @see #DFSClient(URI, ClientProtocol, Configuration, FileSystem.Statistics) 508 */ 509 public DFSClient(URI nameNodeUri, Configuration conf, 510 FileSystem.Statistics stats) 511 throws IOException { 512 this(nameNodeUri, null, conf, stats); 513 } 514 515 /** 516 * Create a new DFSClient connected to the given nameNodeUri or rpcNamenode. 517 * If HA is enabled and a positive value is set for 518 * {@link DFSConfigKeys#DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY} in the 519 * configuration, the DFSClient will use {@link LossyRetryInvocationHandler} 520 * as its RetryInvocationHandler. Otherwise one of nameNodeUri or rpcNamenode 521 * must be null. 522 */ 523 @VisibleForTesting 524 public DFSClient(URI nameNodeUri, ClientProtocol rpcNamenode, 525 Configuration conf, FileSystem.Statistics stats) 526 throws IOException { 527 // Copy only the required DFSClient configuration 528 this.dfsClientConf = new Conf(conf); 529 this.shouldUseLegacyBlockReaderLocal = 530 this.dfsClientConf.useLegacyBlockReaderLocal; 531 if (this.dfsClientConf.useLegacyBlockReaderLocal) { 532 LOG.debug("Using legacy short-circuit local reads."); 533 } 534 this.conf = conf; 535 this.stats = stats; 536 this.socketFactory = NetUtils.getSocketFactory(conf, ClientProtocol.class); 537 this.dtpReplaceDatanodeOnFailure = ReplaceDatanodeOnFailure.get(conf); 538 539 this.ugi = UserGroupInformation.getCurrentUser(); 540 541 this.authority = nameNodeUri == null? "null": nameNodeUri.getAuthority(); 542 this.clientName = "DFSClient_" + dfsClientConf.taskId + "_" + 543 DFSUtil.getRandom().nextInt() + "_" + Thread.currentThread().getId(); 544 545 int numResponseToDrop = conf.getInt( 546 DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY, 547 DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_DEFAULT); 548 NameNodeProxies.ProxyAndInfo<ClientProtocol> proxyInfo = null; 549 if (numResponseToDrop > 0) { 550 // This case is used for testing. 551 LOG.warn(DFSConfigKeys.DFS_CLIENT_TEST_DROP_NAMENODE_RESPONSE_NUM_KEY 552 + " is set to " + numResponseToDrop 553 + ", this hacked client will proactively drop responses"); 554 proxyInfo = NameNodeProxies.createProxyWithLossyRetryHandler(conf, 555 nameNodeUri, ClientProtocol.class, numResponseToDrop); 556 } 557 558 if (proxyInfo != null) { 559 this.dtService = proxyInfo.getDelegationTokenService(); 560 this.namenode = proxyInfo.getProxy(); 561 } else if (rpcNamenode != null) { 562 // This case is used for testing. 563 Preconditions.checkArgument(nameNodeUri == null); 564 this.namenode = rpcNamenode; 565 dtService = null; 566 } else { 567 Preconditions.checkArgument(nameNodeUri != null, 568 "null URI"); 569 proxyInfo = NameNodeProxies.createProxy(conf, nameNodeUri, 570 ClientProtocol.class); 571 this.dtService = proxyInfo.getDelegationTokenService(); 572 this.namenode = proxyInfo.getProxy(); 573 } 574 575 // read directly from the block file if configured. 576 this.domainSocketFactory = new DomainSocketFactory(dfsClientConf); 577 578 String localInterfaces[] = 579 conf.getTrimmedStrings(DFSConfigKeys.DFS_CLIENT_LOCAL_INTERFACES); 580 localInterfaceAddrs = getLocalInterfaceAddrs(localInterfaces); 581 if (LOG.isDebugEnabled() && 0 != localInterfaces.length) { 582 LOG.debug("Using local interfaces [" + 583 Joiner.on(',').join(localInterfaces)+ "] with addresses [" + 584 Joiner.on(',').join(localInterfaceAddrs) + "]"); 585 } 586 587 this.peerCache = PeerCache.getInstance(dfsClientConf.socketCacheCapacity, dfsClientConf.socketCacheExpiry); 588 Boolean readDropBehind = (conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_READS) == null) ? 589 null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_READS, false); 590 Long readahead = (conf.get(DFS_CLIENT_CACHE_READAHEAD) == null) ? 591 null : conf.getLong(DFS_CLIENT_CACHE_READAHEAD, 0); 592 Boolean writeDropBehind = (conf.get(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES) == null) ? 593 null : conf.getBoolean(DFS_CLIENT_CACHE_DROP_BEHIND_WRITES, false); 594 this.defaultReadCachingStrategy = 595 new CachingStrategy(readDropBehind, readahead); 596 this.defaultWriteCachingStrategy = 597 new CachingStrategy(writeDropBehind, readahead); 598 this.mmapManager = MMAP_MANAGER_FACTORY.get(conf); 599 } 600 601 /** 602 * Return the socket addresses to use with each configured 603 * local interface. Local interfaces may be specified by IP 604 * address, IP address range using CIDR notation, interface 605 * name (e.g. eth0) or sub-interface name (e.g. eth0:0). 606 * The socket addresses consist of the IPs for the interfaces 607 * and the ephemeral port (port 0). If an IP, IP range, or 608 * interface name matches an interface with sub-interfaces 609 * only the IP of the interface is used. Sub-interfaces can 610 * be used by specifying them explicitly (by IP or name). 611 * 612 * @return SocketAddresses for the configured local interfaces, 613 * or an empty array if none are configured 614 * @throws UnknownHostException if a given interface name is invalid 615 */ 616 private static SocketAddress[] getLocalInterfaceAddrs( 617 String interfaceNames[]) throws UnknownHostException { 618 List<SocketAddress> localAddrs = new ArrayList<SocketAddress>(); 619 for (String interfaceName : interfaceNames) { 620 if (InetAddresses.isInetAddress(interfaceName)) { 621 localAddrs.add(new InetSocketAddress(interfaceName, 0)); 622 } else if (NetUtils.isValidSubnet(interfaceName)) { 623 for (InetAddress addr : NetUtils.getIPs(interfaceName, false)) { 624 localAddrs.add(new InetSocketAddress(addr, 0)); 625 } 626 } else { 627 for (String ip : DNS.getIPs(interfaceName, false)) { 628 localAddrs.add(new InetSocketAddress(ip, 0)); 629 } 630 } 631 } 632 return localAddrs.toArray(new SocketAddress[localAddrs.size()]); 633 } 634 635 /** 636 * Select one of the configured local interfaces at random. We use a random 637 * interface because other policies like round-robin are less effective 638 * given that we cache connections to datanodes. 639 * 640 * @return one of the local interface addresses at random, or null if no 641 * local interfaces are configured 642 */ 643 SocketAddress getRandomLocalInterfaceAddr() { 644 if (localInterfaceAddrs.length == 0) { 645 return null; 646 } 647 final int idx = r.nextInt(localInterfaceAddrs.length); 648 final SocketAddress addr = localInterfaceAddrs[idx]; 649 if (LOG.isDebugEnabled()) { 650 LOG.debug("Using local interface " + addr); 651 } 652 return addr; 653 } 654 655 /** 656 * Return the number of times the client should go back to the namenode 657 * to retrieve block locations when reading. 658 */ 659 int getMaxBlockAcquireFailures() { 660 return dfsClientConf.maxBlockAcquireFailures; 661 } 662 663 /** 664 * Return the timeout that clients should use when writing to datanodes. 665 * @param numNodes the number of nodes in the pipeline. 666 */ 667 int getDatanodeWriteTimeout(int numNodes) { 668 return (dfsClientConf.confTime > 0) ? 669 (dfsClientConf.confTime + HdfsServerConstants.WRITE_TIMEOUT_EXTENSION * numNodes) : 0; 670 } 671 672 int getDatanodeReadTimeout(int numNodes) { 673 return dfsClientConf.socketTimeout > 0 ? 674 (HdfsServerConstants.READ_TIMEOUT_EXTENSION * numNodes + 675 dfsClientConf.socketTimeout) : 0; 676 } 677 678 int getHdfsTimeout() { 679 return dfsClientConf.hdfsTimeout; 680 } 681 682 @VisibleForTesting 683 public String getClientName() { 684 return clientName; 685 } 686 687 void checkOpen() throws IOException { 688 if (!clientRunning) { 689 IOException result = new IOException("Filesystem closed"); 690 throw result; 691 } 692 } 693 694 /** Return the lease renewer instance. The renewer thread won't start 695 * until the first output stream is created. The same instance will 696 * be returned until all output streams are closed. 697 */ 698 public LeaseRenewer getLeaseRenewer() throws IOException { 699 return LeaseRenewer.getInstance(authority, ugi, this); 700 } 701 702 /** Get a lease and start automatic renewal */ 703 private void beginFileLease(final String src, final DFSOutputStream out) 704 throws IOException { 705 getLeaseRenewer().put(src, out, this); 706 } 707 708 /** Stop renewal of lease for the file. */ 709 void endFileLease(final String src) throws IOException { 710 getLeaseRenewer().closeFile(src, this); 711 } 712 713 714 /** Put a file. Only called from LeaseRenewer, where proper locking is 715 * enforced to consistently update its local dfsclients array and 716 * client's filesBeingWritten map. 717 */ 718 void putFileBeingWritten(final String src, final DFSOutputStream out) { 719 synchronized(filesBeingWritten) { 720 filesBeingWritten.put(src, out); 721 // update the last lease renewal time only when there was no 722 // writes. once there is one write stream open, the lease renewer 723 // thread keeps it updated well with in anyone's expiration time. 724 if (lastLeaseRenewal == 0) { 725 updateLastLeaseRenewal(); 726 } 727 } 728 } 729 730 /** Remove a file. Only called from LeaseRenewer. */ 731 void removeFileBeingWritten(final String src) { 732 synchronized(filesBeingWritten) { 733 filesBeingWritten.remove(src); 734 if (filesBeingWritten.isEmpty()) { 735 lastLeaseRenewal = 0; 736 } 737 } 738 } 739 740 /** Is file-being-written map empty? */ 741 boolean isFilesBeingWrittenEmpty() { 742 synchronized(filesBeingWritten) { 743 return filesBeingWritten.isEmpty(); 744 } 745 } 746 747 /** @return true if the client is running */ 748 boolean isClientRunning() { 749 return clientRunning; 750 } 751 752 long getLastLeaseRenewal() { 753 return lastLeaseRenewal; 754 } 755 756 void updateLastLeaseRenewal() { 757 synchronized(filesBeingWritten) { 758 if (filesBeingWritten.isEmpty()) { 759 return; 760 } 761 lastLeaseRenewal = Time.now(); 762 } 763 } 764 765 /** 766 * Renew leases. 767 * @return true if lease was renewed. May return false if this 768 * client has been closed or has no files open. 769 **/ 770 boolean renewLease() throws IOException { 771 if (clientRunning && !isFilesBeingWrittenEmpty()) { 772 try { 773 namenode.renewLease(clientName); 774 updateLastLeaseRenewal(); 775 return true; 776 } catch (IOException e) { 777 // Abort if the lease has already expired. 778 final long elapsed = Time.now() - getLastLeaseRenewal(); 779 if (elapsed > HdfsConstants.LEASE_HARDLIMIT_PERIOD) { 780 LOG.warn("Failed to renew lease for " + clientName + " for " 781 + (elapsed/1000) + " seconds (>= hard-limit =" 782 + (HdfsConstants.LEASE_HARDLIMIT_PERIOD/1000) + " seconds.) " 783 + "Closing all files being written ...", e); 784 closeAllFilesBeingWritten(true); 785 } else { 786 // Let the lease renewer handle it and retry. 787 throw e; 788 } 789 } 790 } 791 return false; 792 } 793 794 /** 795 * Close connections the Namenode. 796 */ 797 void closeConnectionToNamenode() { 798 RPC.stopProxy(namenode); 799 } 800 801 /** Abort and release resources held. Ignore all errors. */ 802 void abort() { 803 if (mmapManager != null) { 804 MMAP_MANAGER_FACTORY.unref(mmapManager); 805 mmapManager = null; 806 } 807 clientRunning = false; 808 closeAllFilesBeingWritten(true); 809 try { 810 // remove reference to this client and stop the renewer, 811 // if there is no more clients under the renewer. 812 getLeaseRenewer().closeClient(this); 813 } catch (IOException ioe) { 814 LOG.info("Exception occurred while aborting the client " + ioe); 815 } 816 closeConnectionToNamenode(); 817 } 818 819 /** Close/abort all files being written. */ 820 private void closeAllFilesBeingWritten(final boolean abort) { 821 for(;;) { 822 final String src; 823 final DFSOutputStream out; 824 synchronized(filesBeingWritten) { 825 if (filesBeingWritten.isEmpty()) { 826 return; 827 } 828 src = filesBeingWritten.keySet().iterator().next(); 829 out = filesBeingWritten.remove(src); 830 } 831 if (out != null) { 832 try { 833 if (abort) { 834 out.abort(); 835 } else { 836 out.close(); 837 } 838 } catch(IOException ie) { 839 LOG.error("Failed to " + (abort? "abort": "close") + " file " + src, 840 ie); 841 } 842 } 843 } 844 } 845 846 /** 847 * Close the file system, abandoning all of the leases and files being 848 * created and close connections to the namenode. 849 */ 850 @Override 851 public synchronized void close() throws IOException { 852 if (mmapManager != null) { 853 MMAP_MANAGER_FACTORY.unref(mmapManager); 854 mmapManager = null; 855 } 856 if(clientRunning) { 857 closeAllFilesBeingWritten(false); 858 clientRunning = false; 859 getLeaseRenewer().closeClient(this); 860 // close connections to the namenode 861 closeConnectionToNamenode(); 862 } 863 } 864 865 /** 866 * Get the default block size for this cluster 867 * @return the default block size in bytes 868 */ 869 public long getDefaultBlockSize() { 870 return dfsClientConf.defaultBlockSize; 871 } 872 873 /** 874 * @see ClientProtocol#getPreferredBlockSize(String) 875 */ 876 public long getBlockSize(String f) throws IOException { 877 try { 878 return namenode.getPreferredBlockSize(f); 879 } catch (IOException ie) { 880 LOG.warn("Problem getting block size", ie); 881 throw ie; 882 } 883 } 884 885 /** 886 * Get server default values for a number of configuration params. 887 * @see ClientProtocol#getServerDefaults() 888 */ 889 public FsServerDefaults getServerDefaults() throws IOException { 890 long now = Time.now(); 891 if (now - serverDefaultsLastUpdate > SERVER_DEFAULTS_VALIDITY_PERIOD) { 892 serverDefaults = namenode.getServerDefaults(); 893 serverDefaultsLastUpdate = now; 894 } 895 return serverDefaults; 896 } 897 898 /** 899 * Get a canonical token service name for this client's tokens. Null should 900 * be returned if the client is not using tokens. 901 * @return the token service for the client 902 */ 903 @InterfaceAudience.LimitedPrivate( { "HDFS" }) 904 public String getCanonicalServiceName() { 905 return (dtService != null) ? dtService.toString() : null; 906 } 907 908 /** 909 * @see ClientProtocol#getDelegationToken(Text) 910 */ 911 public Token<DelegationTokenIdentifier> getDelegationToken(Text renewer) 912 throws IOException { 913 assert dtService != null; 914 Token<DelegationTokenIdentifier> token = 915 namenode.getDelegationToken(renewer); 916 917 if (token != null) { 918 token.setService(this.dtService); 919 LOG.info("Created " + DelegationTokenIdentifier.stringifyToken(token)); 920 } else { 921 LOG.info("Cannot get delegation token from " + renewer); 922 } 923 return token; 924 925 } 926 927 /** 928 * Renew a delegation token 929 * @param token the token to renew 930 * @return the new expiration time 931 * @throws InvalidToken 932 * @throws IOException 933 * @deprecated Use Token.renew instead. 934 */ 935 @Deprecated 936 public long renewDelegationToken(Token<DelegationTokenIdentifier> token) 937 throws InvalidToken, IOException { 938 LOG.info("Renewing " + DelegationTokenIdentifier.stringifyToken(token)); 939 try { 940 return token.renew(conf); 941 } catch (InterruptedException ie) { 942 throw new RuntimeException("caught interrupted", ie); 943 } catch (RemoteException re) { 944 throw re.unwrapRemoteException(InvalidToken.class, 945 AccessControlException.class); 946 } 947 } 948 949 private static Map<String, Boolean> localAddrMap = Collections 950 .synchronizedMap(new HashMap<String, Boolean>()); 951 952 static boolean isLocalAddress(InetSocketAddress targetAddr) { 953 InetAddress addr = targetAddr.getAddress(); 954 Boolean cached = localAddrMap.get(addr.getHostAddress()); 955 if (cached != null) { 956 if (LOG.isTraceEnabled()) { 957 LOG.trace("Address " + targetAddr + 958 (cached ? " is local" : " is not local")); 959 } 960 return cached; 961 } 962 963 boolean local = NetUtils.isLocalAddress(addr); 964 965 if (LOG.isTraceEnabled()) { 966 LOG.trace("Address " + targetAddr + 967 (local ? " is local" : " is not local")); 968 } 969 localAddrMap.put(addr.getHostAddress(), local); 970 return local; 971 } 972 973 /** 974 * Should the block access token be refetched on an exception 975 * 976 * @param ex Exception received 977 * @param targetAddr Target datanode address from where exception was received 978 * @return true if block access token has expired or invalid and it should be 979 * refetched 980 */ 981 private static boolean tokenRefetchNeeded(IOException ex, 982 InetSocketAddress targetAddr) { 983 /* 984 * Get a new access token and retry. Retry is needed in 2 cases. 1) When 985 * both NN and DN re-started while DFSClient holding a cached access token. 986 * 2) In the case that NN fails to update its access key at pre-set interval 987 * (by a wide margin) and subsequently restarts. In this case, DN 988 * re-registers itself with NN and receives a new access key, but DN will 989 * delete the old access key from its memory since it's considered expired 990 * based on the estimated expiration date. 991 */ 992 if (ex instanceof InvalidBlockTokenException || ex instanceof InvalidToken) { 993 LOG.info("Access token was invalid when connecting to " + targetAddr 994 + " : " + ex); 995 return true; 996 } 997 return false; 998 } 999 1000 /** 1001 * Cancel a delegation token 1002 * @param token the token to cancel 1003 * @throws InvalidToken 1004 * @throws IOException 1005 * @deprecated Use Token.cancel instead. 1006 */ 1007 @Deprecated 1008 public void cancelDelegationToken(Token<DelegationTokenIdentifier> token) 1009 throws InvalidToken, IOException { 1010 LOG.info("Cancelling " + DelegationTokenIdentifier.stringifyToken(token)); 1011 try { 1012 token.cancel(conf); 1013 } catch (InterruptedException ie) { 1014 throw new RuntimeException("caught interrupted", ie); 1015 } catch (RemoteException re) { 1016 throw re.unwrapRemoteException(InvalidToken.class, 1017 AccessControlException.class); 1018 } 1019 } 1020 1021 @InterfaceAudience.Private 1022 public static class Renewer extends TokenRenewer { 1023 1024 static { 1025 //Ensure that HDFS Configuration files are loaded before trying to use 1026 // the renewer. 1027 HdfsConfiguration.init(); 1028 } 1029 1030 @Override 1031 public boolean handleKind(Text kind) { 1032 return DelegationTokenIdentifier.HDFS_DELEGATION_KIND.equals(kind); 1033 } 1034 1035 @SuppressWarnings("unchecked") 1036 @Override 1037 public long renew(Token<?> token, Configuration conf) throws IOException { 1038 Token<DelegationTokenIdentifier> delToken = 1039 (Token<DelegationTokenIdentifier>) token; 1040 ClientProtocol nn = getNNProxy(delToken, conf); 1041 try { 1042 return nn.renewDelegationToken(delToken); 1043 } catch (RemoteException re) { 1044 throw re.unwrapRemoteException(InvalidToken.class, 1045 AccessControlException.class); 1046 } 1047 } 1048 1049 @SuppressWarnings("unchecked") 1050 @Override 1051 public void cancel(Token<?> token, Configuration conf) throws IOException { 1052 Token<DelegationTokenIdentifier> delToken = 1053 (Token<DelegationTokenIdentifier>) token; 1054 LOG.info("Cancelling " + 1055 DelegationTokenIdentifier.stringifyToken(delToken)); 1056 ClientProtocol nn = getNNProxy(delToken, conf); 1057 try { 1058 nn.cancelDelegationToken(delToken); 1059 } catch (RemoteException re) { 1060 throw re.unwrapRemoteException(InvalidToken.class, 1061 AccessControlException.class); 1062 } 1063 } 1064 1065 private static ClientProtocol getNNProxy( 1066 Token<DelegationTokenIdentifier> token, Configuration conf) 1067 throws IOException { 1068 URI uri = HAUtil.getServiceUriFromToken(token); 1069 if (HAUtil.isTokenForLogicalUri(token) && 1070 !HAUtil.isLogicalUri(conf, uri)) { 1071 // If the token is for a logical nameservice, but the configuration 1072 // we have disagrees about that, we can't actually renew it. 1073 // This can be the case in MR, for example, if the RM doesn't 1074 // have all of the HA clusters configured in its configuration. 1075 throw new IOException("Unable to map logical nameservice URI '" + 1076 uri + "' to a NameNode. Local configuration does not have " + 1077 "a failover proxy provider configured."); 1078 } 1079 1080 NameNodeProxies.ProxyAndInfo<ClientProtocol> info = 1081 NameNodeProxies.createProxy(conf, uri, ClientProtocol.class); 1082 assert info.getDelegationTokenService().equals(token.getService()) : 1083 "Returned service '" + info.getDelegationTokenService().toString() + 1084 "' doesn't match expected service '" + 1085 token.getService().toString() + "'"; 1086 1087 return info.getProxy(); 1088 } 1089 1090 @Override 1091 public boolean isManaged(Token<?> token) throws IOException { 1092 return true; 1093 } 1094 1095 } 1096 1097 /** 1098 * Report corrupt blocks that were discovered by the client. 1099 * @see ClientProtocol#reportBadBlocks(LocatedBlock[]) 1100 */ 1101 public void reportBadBlocks(LocatedBlock[] blocks) throws IOException { 1102 namenode.reportBadBlocks(blocks); 1103 } 1104 1105 public short getDefaultReplication() { 1106 return dfsClientConf.defaultReplication; 1107 } 1108 1109 public LocatedBlocks getLocatedBlocks(String src, long start) 1110 throws IOException { 1111 return getLocatedBlocks(src, start, dfsClientConf.prefetchSize); 1112 } 1113 1114 /* 1115 * This is just a wrapper around callGetBlockLocations, but non-static so that 1116 * we can stub it out for tests. 1117 */ 1118 @VisibleForTesting 1119 public LocatedBlocks getLocatedBlocks(String src, long start, long length) 1120 throws IOException { 1121 return callGetBlockLocations(namenode, src, start, length); 1122 } 1123 1124 /** 1125 * @see ClientProtocol#getBlockLocations(String, long, long) 1126 */ 1127 static LocatedBlocks callGetBlockLocations(ClientProtocol namenode, 1128 String src, long start, long length) 1129 throws IOException { 1130 try { 1131 return namenode.getBlockLocations(src, start, length); 1132 } catch(RemoteException re) { 1133 throw re.unwrapRemoteException(AccessControlException.class, 1134 FileNotFoundException.class, 1135 UnresolvedPathException.class); 1136 } 1137 } 1138 1139 /** 1140 * Recover a file's lease 1141 * @param src a file's path 1142 * @return true if the file is already closed 1143 * @throws IOException 1144 */ 1145 boolean recoverLease(String src) throws IOException { 1146 checkOpen(); 1147 1148 try { 1149 return namenode.recoverLease(src, clientName); 1150 } catch (RemoteException re) { 1151 throw re.unwrapRemoteException(FileNotFoundException.class, 1152 AccessControlException.class, 1153 UnresolvedPathException.class); 1154 } 1155 } 1156 1157 /** 1158 * Get block location info about file 1159 * 1160 * getBlockLocations() returns a list of hostnames that store 1161 * data for a specific file region. It returns a set of hostnames 1162 * for every block within the indicated region. 1163 * 1164 * This function is very useful when writing code that considers 1165 * data-placement when performing operations. For example, the 1166 * MapReduce system tries to schedule tasks on the same machines 1167 * as the data-block the task processes. 1168 */ 1169 public BlockLocation[] getBlockLocations(String src, long start, 1170 long length) throws IOException, UnresolvedLinkException { 1171 LocatedBlocks blocks = getLocatedBlocks(src, start, length); 1172 BlockLocation[] locations = DFSUtil.locatedBlocks2Locations(blocks); 1173 HdfsBlockLocation[] hdfsLocations = new HdfsBlockLocation[locations.length]; 1174 for (int i = 0; i < locations.length; i++) { 1175 hdfsLocations[i] = new HdfsBlockLocation(locations[i], blocks.get(i)); 1176 } 1177 return hdfsLocations; 1178 } 1179 1180 /** 1181 * Get block location information about a list of {@link HdfsBlockLocation}. 1182 * Used by {@link DistributedFileSystem#getFileBlockStorageLocations(List)} to 1183 * get {@link BlockStorageLocation}s for blocks returned by 1184 * {@link DistributedFileSystem#getFileBlockLocations(org.apache.hadoop.fs.FileStatus, long, long)} 1185 * . 1186 * 1187 * This is done by making a round of RPCs to the associated datanodes, asking 1188 * the volume of each block replica. The returned array of 1189 * {@link BlockStorageLocation} expose this information as a 1190 * {@link VolumeId}. 1191 * 1192 * @param blockLocations 1193 * target blocks on which to query volume location information 1194 * @return volumeBlockLocations original block array augmented with additional 1195 * volume location information for each replica. 1196 */ 1197 public BlockStorageLocation[] getBlockStorageLocations( 1198 List<BlockLocation> blockLocations) throws IOException, 1199 UnsupportedOperationException, InvalidBlockTokenException { 1200 if (!getConf().getHdfsBlocksMetadataEnabled) { 1201 throw new UnsupportedOperationException("Datanode-side support for " + 1202 "getVolumeBlockLocations() must also be enabled in the client " + 1203 "configuration."); 1204 } 1205 // Downcast blockLocations and fetch out required LocatedBlock(s) 1206 List<LocatedBlock> blocks = new ArrayList<LocatedBlock>(); 1207 for (BlockLocation loc : blockLocations) { 1208 if (!(loc instanceof HdfsBlockLocation)) { 1209 throw new ClassCastException("DFSClient#getVolumeBlockLocations " + 1210 "expected to be passed HdfsBlockLocations"); 1211 } 1212 HdfsBlockLocation hdfsLoc = (HdfsBlockLocation) loc; 1213 blocks.add(hdfsLoc.getLocatedBlock()); 1214 } 1215 1216 // Re-group the LocatedBlocks to be grouped by datanodes, with the values 1217 // a list of the LocatedBlocks on the datanode. 1218 Map<DatanodeInfo, List<LocatedBlock>> datanodeBlocks = 1219 new LinkedHashMap<DatanodeInfo, List<LocatedBlock>>(); 1220 for (LocatedBlock b : blocks) { 1221 for (DatanodeInfo info : b.getLocations()) { 1222 if (!datanodeBlocks.containsKey(info)) { 1223 datanodeBlocks.put(info, new ArrayList<LocatedBlock>()); 1224 } 1225 List<LocatedBlock> l = datanodeBlocks.get(info); 1226 l.add(b); 1227 } 1228 } 1229 1230 // Make RPCs to the datanodes to get volume locations for its replicas 1231 List<HdfsBlocksMetadata> metadatas = BlockStorageLocationUtil 1232 .queryDatanodesForHdfsBlocksMetadata(conf, datanodeBlocks, 1233 getConf().getFileBlockStorageLocationsNumThreads, 1234 getConf().getFileBlockStorageLocationsTimeout, 1235 getConf().connectToDnViaHostname); 1236 1237 // Regroup the returned VolumeId metadata to again be grouped by 1238 // LocatedBlock rather than by datanode 1239 Map<LocatedBlock, List<VolumeId>> blockVolumeIds = BlockStorageLocationUtil 1240 .associateVolumeIdsWithBlocks(blocks, datanodeBlocks, metadatas); 1241 1242 // Combine original BlockLocations with new VolumeId information 1243 BlockStorageLocation[] volumeBlockLocations = BlockStorageLocationUtil 1244 .convertToVolumeBlockLocations(blocks, blockVolumeIds); 1245 1246 return volumeBlockLocations; 1247 } 1248 1249 public DFSInputStream open(String src) 1250 throws IOException, UnresolvedLinkException { 1251 return open(src, dfsClientConf.ioBufferSize, true, null); 1252 } 1253 1254 /** 1255 * Create an input stream that obtains a nodelist from the 1256 * namenode, and then reads from all the right places. Creates 1257 * inner subclass of InputStream that does the right out-of-band 1258 * work. 1259 * @deprecated Use {@link #open(String, int, boolean)} instead. 1260 */ 1261 @Deprecated 1262 public DFSInputStream open(String src, int buffersize, boolean verifyChecksum, 1263 FileSystem.Statistics stats) 1264 throws IOException, UnresolvedLinkException { 1265 return open(src, buffersize, verifyChecksum); 1266 } 1267 1268 1269 /** 1270 * Create an input stream that obtains a nodelist from the 1271 * namenode, and then reads from all the right places. Creates 1272 * inner subclass of InputStream that does the right out-of-band 1273 * work. 1274 */ 1275 public DFSInputStream open(String src, int buffersize, boolean verifyChecksum) 1276 throws IOException, UnresolvedLinkException { 1277 checkOpen(); 1278 // Get block info from namenode 1279 return new DFSInputStream(this, src, buffersize, verifyChecksum); 1280 } 1281 1282 /** 1283 * Get the namenode associated with this DFSClient object 1284 * @return the namenode associated with this DFSClient object 1285 */ 1286 public ClientProtocol getNamenode() { 1287 return namenode; 1288 } 1289 1290 /** 1291 * Call {@link #create(String, boolean, short, long, Progressable)} with 1292 * default <code>replication</code> and <code>blockSize<code> and null <code> 1293 * progress</code>. 1294 */ 1295 public OutputStream create(String src, boolean overwrite) 1296 throws IOException { 1297 return create(src, overwrite, dfsClientConf.defaultReplication, 1298 dfsClientConf.defaultBlockSize, null); 1299 } 1300 1301 /** 1302 * Call {@link #create(String, boolean, short, long, Progressable)} with 1303 * default <code>replication</code> and <code>blockSize<code>. 1304 */ 1305 public OutputStream create(String src, 1306 boolean overwrite, 1307 Progressable progress) throws IOException { 1308 return create(src, overwrite, dfsClientConf.defaultReplication, 1309 dfsClientConf.defaultBlockSize, progress); 1310 } 1311 1312 /** 1313 * Call {@link #create(String, boolean, short, long, Progressable)} with 1314 * null <code>progress</code>. 1315 */ 1316 public OutputStream create(String src, 1317 boolean overwrite, 1318 short replication, 1319 long blockSize) throws IOException { 1320 return create(src, overwrite, replication, blockSize, null); 1321 } 1322 1323 /** 1324 * Call {@link #create(String, boolean, short, long, Progressable, int)} 1325 * with default bufferSize. 1326 */ 1327 public OutputStream create(String src, boolean overwrite, short replication, 1328 long blockSize, Progressable progress) throws IOException { 1329 return create(src, overwrite, replication, blockSize, progress, 1330 dfsClientConf.ioBufferSize); 1331 } 1332 1333 /** 1334 * Call {@link #create(String, FsPermission, EnumSet, short, long, 1335 * Progressable, int, ChecksumOpt)} with default <code>permission</code> 1336 * {@link FsPermission#getFileDefault()}. 1337 * 1338 * @param src File name 1339 * @param overwrite overwrite an existing file if true 1340 * @param replication replication factor for the file 1341 * @param blockSize maximum block size 1342 * @param progress interface for reporting client progress 1343 * @param buffersize underlying buffersize 1344 * 1345 * @return output stream 1346 */ 1347 public OutputStream create(String src, 1348 boolean overwrite, 1349 short replication, 1350 long blockSize, 1351 Progressable progress, 1352 int buffersize) 1353 throws IOException { 1354 return create(src, FsPermission.getFileDefault(), 1355 overwrite ? EnumSet.of(CreateFlag.CREATE, CreateFlag.OVERWRITE) 1356 : EnumSet.of(CreateFlag.CREATE), replication, blockSize, progress, 1357 buffersize, null); 1358 } 1359 1360 /** 1361 * Call {@link #create(String, FsPermission, EnumSet, boolean, short, 1362 * long, Progressable, int, ChecksumOpt)} with <code>createParent</code> 1363 * set to true. 1364 */ 1365 public DFSOutputStream create(String src, 1366 FsPermission permission, 1367 EnumSet<CreateFlag> flag, 1368 short replication, 1369 long blockSize, 1370 Progressable progress, 1371 int buffersize, 1372 ChecksumOpt checksumOpt) 1373 throws IOException { 1374 return create(src, permission, flag, true, 1375 replication, blockSize, progress, buffersize, checksumOpt, null); 1376 } 1377 1378 /** 1379 * Create a new dfs file with the specified block replication 1380 * with write-progress reporting and return an output stream for writing 1381 * into the file. 1382 * 1383 * @param src File name 1384 * @param permission The permission of the directory being created. 1385 * If null, use default permission {@link FsPermission#getFileDefault()} 1386 * @param flag indicates create a new file or create/overwrite an 1387 * existing file or append to an existing file 1388 * @param createParent create missing parent directory if true 1389 * @param replication block replication 1390 * @param blockSize maximum block size 1391 * @param progress interface for reporting client progress 1392 * @param buffersize underlying buffer size 1393 * @param checksumOpt checksum options 1394 * 1395 * @return output stream 1396 * 1397 * @see ClientProtocol#create(String, FsPermission, String, EnumSetWritable, 1398 * boolean, short, long) for detailed description of exceptions thrown 1399 */ 1400 public DFSOutputStream create(String src, 1401 FsPermission permission, 1402 EnumSet<CreateFlag> flag, 1403 boolean createParent, 1404 short replication, 1405 long blockSize, 1406 Progressable progress, 1407 int buffersize, 1408 ChecksumOpt checksumOpt) throws IOException { 1409 return create(src, permission, flag, createParent, replication, blockSize, 1410 progress, buffersize, checksumOpt, null); 1411 } 1412 1413 /** 1414 * Same as {@link #create(String, FsPermission, EnumSet, boolean, short, long, 1415 * Progressable, int, ChecksumOpt)} with the addition of favoredNodes that is 1416 * a hint to where the namenode should place the file blocks. 1417 * The favored nodes hint is not persisted in HDFS. Hence it may be honored 1418 * at the creation time only. HDFS could move the blocks during balancing or 1419 * replication, to move the blocks from favored nodes. A value of null means 1420 * no favored nodes for this create 1421 */ 1422 public DFSOutputStream create(String src, 1423 FsPermission permission, 1424 EnumSet<CreateFlag> flag, 1425 boolean createParent, 1426 short replication, 1427 long blockSize, 1428 Progressable progress, 1429 int buffersize, 1430 ChecksumOpt checksumOpt, 1431 InetSocketAddress[] favoredNodes) throws IOException { 1432 checkOpen(); 1433 if (permission == null) { 1434 permission = FsPermission.getFileDefault(); 1435 } 1436 FsPermission masked = permission.applyUMask(dfsClientConf.uMask); 1437 if(LOG.isDebugEnabled()) { 1438 LOG.debug(src + ": masked=" + masked); 1439 } 1440 String[] favoredNodeStrs = null; 1441 if (favoredNodes != null) { 1442 favoredNodeStrs = new String[favoredNodes.length]; 1443 for (int i = 0; i < favoredNodes.length; i++) { 1444 favoredNodeStrs[i] = 1445 favoredNodes[i].getHostName() + ":" 1446 + favoredNodes[i].getPort(); 1447 } 1448 } 1449 final DFSOutputStream result = DFSOutputStream.newStreamForCreate(this, 1450 src, masked, flag, createParent, replication, blockSize, progress, 1451 buffersize, dfsClientConf.createChecksum(checksumOpt), favoredNodeStrs); 1452 beginFileLease(src, result); 1453 return result; 1454 } 1455 1456 /** 1457 * Append to an existing file if {@link CreateFlag#APPEND} is present 1458 */ 1459 private DFSOutputStream primitiveAppend(String src, EnumSet<CreateFlag> flag, 1460 int buffersize, Progressable progress) throws IOException { 1461 if (flag.contains(CreateFlag.APPEND)) { 1462 HdfsFileStatus stat = getFileInfo(src); 1463 if (stat == null) { // No file to append to 1464 // New file needs to be created if create option is present 1465 if (!flag.contains(CreateFlag.CREATE)) { 1466 throw new FileNotFoundException("failed to append to non-existent file " 1467 + src + " on client " + clientName); 1468 } 1469 return null; 1470 } 1471 return callAppend(stat, src, buffersize, progress); 1472 } 1473 return null; 1474 } 1475 1476 /** 1477 * Same as {{@link #create(String, FsPermission, EnumSet, short, long, 1478 * Progressable, int, ChecksumOpt)} except that the permission 1479 * is absolute (ie has already been masked with umask. 1480 */ 1481 public DFSOutputStream primitiveCreate(String src, 1482 FsPermission absPermission, 1483 EnumSet<CreateFlag> flag, 1484 boolean createParent, 1485 short replication, 1486 long blockSize, 1487 Progressable progress, 1488 int buffersize, 1489 ChecksumOpt checksumOpt) 1490 throws IOException, UnresolvedLinkException { 1491 checkOpen(); 1492 CreateFlag.validate(flag); 1493 DFSOutputStream result = primitiveAppend(src, flag, buffersize, progress); 1494 if (result == null) { 1495 DataChecksum checksum = dfsClientConf.createChecksum(checksumOpt); 1496 result = DFSOutputStream.newStreamForCreate(this, src, absPermission, 1497 flag, createParent, replication, blockSize, progress, buffersize, 1498 checksum); 1499 } 1500 beginFileLease(src, result); 1501 return result; 1502 } 1503 1504 /** 1505 * Creates a symbolic link. 1506 * 1507 * @see ClientProtocol#createSymlink(String, String,FsPermission, boolean) 1508 */ 1509 public void createSymlink(String target, String link, boolean createParent) 1510 throws IOException { 1511 try { 1512 FsPermission dirPerm = 1513 FsPermission.getDefault().applyUMask(dfsClientConf.uMask); 1514 namenode.createSymlink(target, link, dirPerm, createParent); 1515 } catch (RemoteException re) { 1516 throw re.unwrapRemoteException(AccessControlException.class, 1517 FileAlreadyExistsException.class, 1518 FileNotFoundException.class, 1519 ParentNotDirectoryException.class, 1520 NSQuotaExceededException.class, 1521 DSQuotaExceededException.class, 1522 UnresolvedPathException.class, 1523 SnapshotAccessControlException.class); 1524 } 1525 } 1526 1527 /** 1528 * Resolve the *first* symlink, if any, in the path. 1529 * 1530 * @see ClientProtocol#getLinkTarget(String) 1531 */ 1532 public String getLinkTarget(String path) throws IOException { 1533 checkOpen(); 1534 try { 1535 return namenode.getLinkTarget(path); 1536 } catch (RemoteException re) { 1537 throw re.unwrapRemoteException(AccessControlException.class, 1538 FileNotFoundException.class); 1539 } 1540 } 1541 1542 /** Method to get stream returned by append call */ 1543 private DFSOutputStream callAppend(HdfsFileStatus stat, String src, 1544 int buffersize, Progressable progress) throws IOException { 1545 LocatedBlock lastBlock = null; 1546 try { 1547 lastBlock = namenode.append(src, clientName); 1548 } catch(RemoteException re) { 1549 throw re.unwrapRemoteException(AccessControlException.class, 1550 FileNotFoundException.class, 1551 SafeModeException.class, 1552 DSQuotaExceededException.class, 1553 UnsupportedOperationException.class, 1554 UnresolvedPathException.class, 1555 SnapshotAccessControlException.class); 1556 } 1557 return DFSOutputStream.newStreamForAppend(this, src, buffersize, progress, 1558 lastBlock, stat, dfsClientConf.createChecksum()); 1559 } 1560 1561 /** 1562 * Append to an existing HDFS file. 1563 * 1564 * @param src file name 1565 * @param buffersize buffer size 1566 * @param progress for reporting write-progress; null is acceptable. 1567 * @param statistics file system statistics; null is acceptable. 1568 * @return an output stream for writing into the file 1569 * 1570 * @see ClientProtocol#append(String, String) 1571 */ 1572 public HdfsDataOutputStream append(final String src, final int buffersize, 1573 final Progressable progress, final FileSystem.Statistics statistics 1574 ) throws IOException { 1575 final DFSOutputStream out = append(src, buffersize, progress); 1576 return new HdfsDataOutputStream(out, statistics, out.getInitialLen()); 1577 } 1578 1579 private DFSOutputStream append(String src, int buffersize, Progressable progress) 1580 throws IOException { 1581 checkOpen(); 1582 HdfsFileStatus stat = getFileInfo(src); 1583 if (stat == null) { // No file found 1584 throw new FileNotFoundException("failed to append to non-existent file " 1585 + src + " on client " + clientName); 1586 } 1587 final DFSOutputStream result = callAppend(stat, src, buffersize, progress); 1588 beginFileLease(src, result); 1589 return result; 1590 } 1591 1592 /** 1593 * Set replication for an existing file. 1594 * @param src file name 1595 * @param replication 1596 * 1597 * @see ClientProtocol#setReplication(String, short) 1598 */ 1599 public boolean setReplication(String src, short replication) 1600 throws IOException { 1601 try { 1602 return namenode.setReplication(src, replication); 1603 } catch(RemoteException re) { 1604 throw re.unwrapRemoteException(AccessControlException.class, 1605 FileNotFoundException.class, 1606 SafeModeException.class, 1607 DSQuotaExceededException.class, 1608 UnresolvedPathException.class, 1609 SnapshotAccessControlException.class); 1610 } 1611 } 1612 1613 /** 1614 * Rename file or directory. 1615 * @see ClientProtocol#rename(String, String) 1616 * @deprecated Use {@link #rename(String, String, Options.Rename...)} instead. 1617 */ 1618 @Deprecated 1619 public boolean rename(String src, String dst) throws IOException { 1620 checkOpen(); 1621 try { 1622 return namenode.rename(src, dst); 1623 } catch(RemoteException re) { 1624 throw re.unwrapRemoteException(AccessControlException.class, 1625 NSQuotaExceededException.class, 1626 DSQuotaExceededException.class, 1627 UnresolvedPathException.class, 1628 SnapshotAccessControlException.class); 1629 } 1630 } 1631 1632 /** 1633 * Move blocks from src to trg and delete src 1634 * See {@link ClientProtocol#concat(String, String [])}. 1635 */ 1636 public void concat(String trg, String [] srcs) throws IOException { 1637 checkOpen(); 1638 try { 1639 namenode.concat(trg, srcs); 1640 } catch(RemoteException re) { 1641 throw re.unwrapRemoteException(AccessControlException.class, 1642 UnresolvedPathException.class, 1643 SnapshotAccessControlException.class); 1644 } 1645 } 1646 /** 1647 * Rename file or directory. 1648 * @see ClientProtocol#rename2(String, String, Options.Rename...) 1649 */ 1650 public void rename(String src, String dst, Options.Rename... options) 1651 throws IOException { 1652 checkOpen(); 1653 try { 1654 namenode.rename2(src, dst, options); 1655 } catch(RemoteException re) { 1656 throw re.unwrapRemoteException(AccessControlException.class, 1657 DSQuotaExceededException.class, 1658 FileAlreadyExistsException.class, 1659 FileNotFoundException.class, 1660 ParentNotDirectoryException.class, 1661 SafeModeException.class, 1662 NSQuotaExceededException.class, 1663 UnresolvedPathException.class, 1664 SnapshotAccessControlException.class); 1665 } 1666 } 1667 /** 1668 * Delete file or directory. 1669 * See {@link ClientProtocol#delete(String, boolean)}. 1670 */ 1671 @Deprecated 1672 public boolean delete(String src) throws IOException { 1673 checkOpen(); 1674 return namenode.delete(src, true); 1675 } 1676 1677 /** 1678 * delete file or directory. 1679 * delete contents of the directory if non empty and recursive 1680 * set to true 1681 * 1682 * @see ClientProtocol#delete(String, boolean) 1683 */ 1684 public boolean delete(String src, boolean recursive) throws IOException { 1685 checkOpen(); 1686 try { 1687 return namenode.delete(src, recursive); 1688 } catch(RemoteException re) { 1689 throw re.unwrapRemoteException(AccessControlException.class, 1690 FileNotFoundException.class, 1691 SafeModeException.class, 1692 UnresolvedPathException.class, 1693 SnapshotAccessControlException.class); 1694 } 1695 } 1696 1697 /** Implemented using getFileInfo(src) 1698 */ 1699 public boolean exists(String src) throws IOException { 1700 checkOpen(); 1701 return getFileInfo(src) != null; 1702 } 1703 1704 /** 1705 * Get a partial listing of the indicated directory 1706 * No block locations need to be fetched 1707 */ 1708 public DirectoryListing listPaths(String src, byte[] startAfter) 1709 throws IOException { 1710 return listPaths(src, startAfter, false); 1711 } 1712 1713 /** 1714 * Get a partial listing of the indicated directory 1715 * 1716 * Recommend to use HdfsFileStatus.EMPTY_NAME as startAfter 1717 * if the application wants to fetch a listing starting from 1718 * the first entry in the directory 1719 * 1720 * @see ClientProtocol#getListing(String, byte[], boolean) 1721 */ 1722 public DirectoryListing listPaths(String src, byte[] startAfter, 1723 boolean needLocation) 1724 throws IOException { 1725 checkOpen(); 1726 try { 1727 return namenode.getListing(src, startAfter, needLocation); 1728 } catch(RemoteException re) { 1729 throw re.unwrapRemoteException(AccessControlException.class, 1730 FileNotFoundException.class, 1731 UnresolvedPathException.class); 1732 } 1733 } 1734 1735 /** 1736 * Get the file info for a specific file or directory. 1737 * @param src The string representation of the path to the file 1738 * @return object containing information regarding the file 1739 * or null if file not found 1740 * 1741 * @see ClientProtocol#getFileInfo(String) for description of exceptions 1742 */ 1743 public HdfsFileStatus getFileInfo(String src) throws IOException { 1744 checkOpen(); 1745 try { 1746 return namenode.getFileInfo(src); 1747 } catch(RemoteException re) { 1748 throw re.unwrapRemoteException(AccessControlException.class, 1749 FileNotFoundException.class, 1750 UnresolvedPathException.class); 1751 } 1752 } 1753 1754 /** 1755 * Close status of a file 1756 * @return true if file is already closed 1757 */ 1758 public boolean isFileClosed(String src) throws IOException{ 1759 checkOpen(); 1760 try { 1761 return namenode.isFileClosed(src); 1762 } catch(RemoteException re) { 1763 throw re.unwrapRemoteException(AccessControlException.class, 1764 FileNotFoundException.class, 1765 UnresolvedPathException.class); 1766 } 1767 } 1768 1769 /** 1770 * Get the file info for a specific file or directory. If src 1771 * refers to a symlink then the FileStatus of the link is returned. 1772 * @param src path to a file or directory. 1773 * 1774 * For description of exceptions thrown 1775 * @see ClientProtocol#getFileLinkInfo(String) 1776 */ 1777 public HdfsFileStatus getFileLinkInfo(String src) throws IOException { 1778 checkOpen(); 1779 try { 1780 return namenode.getFileLinkInfo(src); 1781 } catch(RemoteException re) { 1782 throw re.unwrapRemoteException(AccessControlException.class, 1783 UnresolvedPathException.class); 1784 } 1785 } 1786 1787 /** 1788 * Get the checksum of a file. 1789 * @param src The file path 1790 * @return The checksum 1791 * @see DistributedFileSystem#getFileChecksum(Path) 1792 */ 1793 public MD5MD5CRC32FileChecksum getFileChecksum(String src) throws IOException { 1794 checkOpen(); 1795 return getFileChecksum(src, clientName, namenode, socketFactory, 1796 dfsClientConf.socketTimeout, getDataEncryptionKey(), 1797 dfsClientConf.connectToDnViaHostname); 1798 } 1799 1800 @InterfaceAudience.Private 1801 public void clearDataEncryptionKey() { 1802 LOG.debug("Clearing encryption key"); 1803 synchronized (this) { 1804 encryptionKey = null; 1805 } 1806 } 1807 1808 /** 1809 * @return true if data sent between this client and DNs should be encrypted, 1810 * false otherwise. 1811 * @throws IOException in the event of error communicating with the NN 1812 */ 1813 boolean shouldEncryptData() throws IOException { 1814 FsServerDefaults d = getServerDefaults(); 1815 return d == null ? false : d.getEncryptDataTransfer(); 1816 } 1817 1818 @InterfaceAudience.Private 1819 public DataEncryptionKey getDataEncryptionKey() 1820 throws IOException { 1821 if (shouldEncryptData()) { 1822 synchronized (this) { 1823 if (encryptionKey == null || 1824 encryptionKey.expiryDate < Time.now()) { 1825 LOG.debug("Getting new encryption token from NN"); 1826 encryptionKey = namenode.getDataEncryptionKey(); 1827 } 1828 return encryptionKey; 1829 } 1830 } else { 1831 return null; 1832 } 1833 } 1834 1835 /** 1836 * Get the checksum of a file. 1837 * @param src The file path 1838 * @param clientName the name of the client requesting the checksum. 1839 * @param namenode the RPC proxy for the namenode 1840 * @param socketFactory to create sockets to connect to DNs 1841 * @param socketTimeout timeout to use when connecting and waiting for a response 1842 * @param encryptionKey the key needed to communicate with DNs in this cluster 1843 * @param connectToDnViaHostname whether the client should use hostnames instead of IPs 1844 * @return The checksum 1845 */ 1846 private static MD5MD5CRC32FileChecksum getFileChecksum(String src, 1847 String clientName, 1848 ClientProtocol namenode, SocketFactory socketFactory, int socketTimeout, 1849 DataEncryptionKey encryptionKey, boolean connectToDnViaHostname) 1850 throws IOException { 1851 //get all block locations 1852 LocatedBlocks blockLocations = callGetBlockLocations(namenode, src, 0, Long.MAX_VALUE); 1853 if (null == blockLocations) { 1854 throw new FileNotFoundException("File does not exist: " + src); 1855 } 1856 List<LocatedBlock> locatedblocks = blockLocations.getLocatedBlocks(); 1857 final DataOutputBuffer md5out = new DataOutputBuffer(); 1858 int bytesPerCRC = -1; 1859 DataChecksum.Type crcType = DataChecksum.Type.DEFAULT; 1860 long crcPerBlock = 0; 1861 boolean refetchBlocks = false; 1862 int lastRetriedIndex = -1; 1863 1864 //get block checksum for each block 1865 for(int i = 0; i < locatedblocks.size(); i++) { 1866 if (refetchBlocks) { // refetch to get fresh tokens 1867 blockLocations = callGetBlockLocations(namenode, src, 0, Long.MAX_VALUE); 1868 if (null == blockLocations) { 1869 throw new FileNotFoundException("File does not exist: " + src); 1870 } 1871 locatedblocks = blockLocations.getLocatedBlocks(); 1872 refetchBlocks = false; 1873 } 1874 LocatedBlock lb = locatedblocks.get(i); 1875 final ExtendedBlock block = lb.getBlock(); 1876 final DatanodeInfo[] datanodes = lb.getLocations(); 1877 1878 //try each datanode location of the block 1879 final int timeout = 3000 * datanodes.length + socketTimeout; 1880 boolean done = false; 1881 for(int j = 0; !done && j < datanodes.length; j++) { 1882 DataOutputStream out = null; 1883 DataInputStream in = null; 1884 1885 try { 1886 //connect to a datanode 1887 IOStreamPair pair = connectToDN(socketFactory, connectToDnViaHostname, 1888 encryptionKey, datanodes[j], timeout); 1889 out = new DataOutputStream(new BufferedOutputStream(pair.out, 1890 HdfsConstants.SMALL_BUFFER_SIZE)); 1891 in = new DataInputStream(pair.in); 1892 1893 if (LOG.isDebugEnabled()) { 1894 LOG.debug("write to " + datanodes[j] + ": " 1895 + Op.BLOCK_CHECKSUM + ", block=" + block); 1896 } 1897 // get block MD5 1898 new Sender(out).blockChecksum(block, lb.getBlockToken()); 1899 1900 final BlockOpResponseProto reply = 1901 BlockOpResponseProto.parseFrom(PBHelper.vintPrefixed(in)); 1902 1903 if (reply.getStatus() != Status.SUCCESS) { 1904 if (reply.getStatus() == Status.ERROR_ACCESS_TOKEN) { 1905 throw new InvalidBlockTokenException(); 1906 } else { 1907 throw new IOException("Bad response " + reply + " for block " 1908 + block + " from datanode " + datanodes[j]); 1909 } 1910 } 1911 1912 OpBlockChecksumResponseProto checksumData = 1913 reply.getChecksumResponse(); 1914 1915 //read byte-per-checksum 1916 final int bpc = checksumData.getBytesPerCrc(); 1917 if (i == 0) { //first block 1918 bytesPerCRC = bpc; 1919 } 1920 else if (bpc != bytesPerCRC) { 1921 throw new IOException("Byte-per-checksum not matched: bpc=" + bpc 1922 + " but bytesPerCRC=" + bytesPerCRC); 1923 } 1924 1925 //read crc-per-block 1926 final long cpb = checksumData.getCrcPerBlock(); 1927 if (locatedblocks.size() > 1 && i == 0) { 1928 crcPerBlock = cpb; 1929 } 1930 1931 //read md5 1932 final MD5Hash md5 = new MD5Hash( 1933 checksumData.getMd5().toByteArray()); 1934 md5.write(md5out); 1935 1936 // read crc-type 1937 final DataChecksum.Type ct; 1938 if (checksumData.hasCrcType()) { 1939 ct = PBHelper.convert(checksumData 1940 .getCrcType()); 1941 } else { 1942 LOG.debug("Retrieving checksum from an earlier-version DataNode: " + 1943 "inferring checksum by reading first byte"); 1944 ct = inferChecksumTypeByReading( 1945 clientName, socketFactory, socketTimeout, lb, datanodes[j], 1946 encryptionKey, connectToDnViaHostname); 1947 } 1948 1949 if (i == 0) { // first block 1950 crcType = ct; 1951 } else if (crcType != DataChecksum.Type.MIXED 1952 && crcType != ct) { 1953 // if crc types are mixed in a file 1954 crcType = DataChecksum.Type.MIXED; 1955 } 1956 1957 done = true; 1958 1959 if (LOG.isDebugEnabled()) { 1960 if (i == 0) { 1961 LOG.debug("set bytesPerCRC=" + bytesPerCRC 1962 + ", crcPerBlock=" + crcPerBlock); 1963 } 1964 LOG.debug("got reply from " + datanodes[j] + ": md5=" + md5); 1965 } 1966 } catch (InvalidBlockTokenException ibte) { 1967 if (i > lastRetriedIndex) { 1968 if (LOG.isDebugEnabled()) { 1969 LOG.debug("Got access token error in response to OP_BLOCK_CHECKSUM " 1970 + "for file " + src + " for block " + block 1971 + " from datanode " + datanodes[j] 1972 + ". Will retry the block once."); 1973 } 1974 lastRetriedIndex = i; 1975 done = true; // actually it's not done; but we'll retry 1976 i--; // repeat at i-th block 1977 refetchBlocks = true; 1978 break; 1979 } 1980 } catch (IOException ie) { 1981 LOG.warn("src=" + src + ", datanodes["+j+"]=" + datanodes[j], ie); 1982 } finally { 1983 IOUtils.closeStream(in); 1984 IOUtils.closeStream(out); 1985 } 1986 } 1987 1988 if (!done) { 1989 throw new IOException("Fail to get block MD5 for " + block); 1990 } 1991 } 1992 1993 //compute file MD5 1994 final MD5Hash fileMD5 = MD5Hash.digest(md5out.getData()); 1995 switch (crcType) { 1996 case CRC32: 1997 return new MD5MD5CRC32GzipFileChecksum(bytesPerCRC, 1998 crcPerBlock, fileMD5); 1999 case CRC32C: 2000 return new MD5MD5CRC32CastagnoliFileChecksum(bytesPerCRC, 2001 crcPerBlock, fileMD5); 2002 default: 2003 // If there is no block allocated for the file, 2004 // return one with the magic entry that matches what previous 2005 // hdfs versions return. 2006 if (locatedblocks.size() == 0) { 2007 return new MD5MD5CRC32GzipFileChecksum(0, 0, fileMD5); 2008 } 2009 2010 // we should never get here since the validity was checked 2011 // when getCrcType() was called above. 2012 return null; 2013 } 2014 } 2015 2016 /** 2017 * Connect to the given datanode's datantrasfer port, and return 2018 * the resulting IOStreamPair. This includes encryption wrapping, etc. 2019 */ 2020 private static IOStreamPair connectToDN( 2021 SocketFactory socketFactory, boolean connectToDnViaHostname, 2022 DataEncryptionKey encryptionKey, DatanodeInfo dn, int timeout) 2023 throws IOException 2024 { 2025 boolean success = false; 2026 Socket sock = null; 2027 try { 2028 sock = socketFactory.createSocket(); 2029 String dnAddr = dn.getXferAddr(connectToDnViaHostname); 2030 if (LOG.isDebugEnabled()) { 2031 LOG.debug("Connecting to datanode " + dnAddr); 2032 } 2033 NetUtils.connect(sock, NetUtils.createSocketAddr(dnAddr), timeout); 2034 sock.setSoTimeout(timeout); 2035 2036 OutputStream unbufOut = NetUtils.getOutputStream(sock); 2037 InputStream unbufIn = NetUtils.getInputStream(sock); 2038 IOStreamPair ret; 2039 if (encryptionKey != null) { 2040 ret = DataTransferEncryptor.getEncryptedStreams( 2041 unbufOut, unbufIn, encryptionKey); 2042 } else { 2043 ret = new IOStreamPair(unbufIn, unbufOut); 2044 } 2045 success = true; 2046 return ret; 2047 } finally { 2048 if (!success) { 2049 IOUtils.closeSocket(sock); 2050 } 2051 } 2052 } 2053 2054 /** 2055 * Infer the checksum type for a replica by sending an OP_READ_BLOCK 2056 * for the first byte of that replica. This is used for compatibility 2057 * with older HDFS versions which did not include the checksum type in 2058 * OpBlockChecksumResponseProto. 2059 * 2060 * @param in input stream from datanode 2061 * @param out output stream to datanode 2062 * @param lb the located block 2063 * @param clientName the name of the DFSClient requesting the checksum 2064 * @param dn the connected datanode 2065 * @return the inferred checksum type 2066 * @throws IOException if an error occurs 2067 */ 2068 private static Type inferChecksumTypeByReading( 2069 String clientName, SocketFactory socketFactory, int socketTimeout, 2070 LocatedBlock lb, DatanodeInfo dn, 2071 DataEncryptionKey encryptionKey, boolean connectToDnViaHostname) 2072 throws IOException { 2073 IOStreamPair pair = connectToDN(socketFactory, connectToDnViaHostname, 2074 encryptionKey, dn, socketTimeout); 2075 2076 try { 2077 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(pair.out, 2078 HdfsConstants.SMALL_BUFFER_SIZE)); 2079 DataInputStream in = new DataInputStream(pair.in); 2080 2081 new Sender(out).readBlock(lb.getBlock(), lb.getBlockToken(), clientName, 2082 0, 1, true, CachingStrategy.newDefaultStrategy()); 2083 final BlockOpResponseProto reply = 2084 BlockOpResponseProto.parseFrom(PBHelper.vintPrefixed(in)); 2085 2086 if (reply.getStatus() != Status.SUCCESS) { 2087 if (reply.getStatus() == Status.ERROR_ACCESS_TOKEN) { 2088 throw new InvalidBlockTokenException(); 2089 } else { 2090 throw new IOException("Bad response " + reply + " trying to read " 2091 + lb.getBlock() + " from datanode " + dn); 2092 } 2093 } 2094 2095 return PBHelper.convert(reply.getReadOpChecksumInfo().getChecksum().getType()); 2096 } finally { 2097 IOUtils.cleanup(null, pair.in, pair.out); 2098 } 2099 } 2100 2101 /** 2102 * Set permissions to a file or directory. 2103 * @param src path name. 2104 * @param permission 2105 * 2106 * @see ClientProtocol#setPermission(String, FsPermission) 2107 */ 2108 public void setPermission(String src, FsPermission permission) 2109 throws IOException { 2110 checkOpen(); 2111 try { 2112 namenode.setPermission(src, permission); 2113 } catch(RemoteException re) { 2114 throw re.unwrapRemoteException(AccessControlException.class, 2115 FileNotFoundException.class, 2116 SafeModeException.class, 2117 UnresolvedPathException.class, 2118 SnapshotAccessControlException.class); 2119 } 2120 } 2121 2122 /** 2123 * Set file or directory owner. 2124 * @param src path name. 2125 * @param username user id. 2126 * @param groupname user group. 2127 * 2128 * @see ClientProtocol#setOwner(String, String, String) 2129 */ 2130 public void setOwner(String src, String username, String groupname) 2131 throws IOException { 2132 checkOpen(); 2133 try { 2134 namenode.setOwner(src, username, groupname); 2135 } catch(RemoteException re) { 2136 throw re.unwrapRemoteException(AccessControlException.class, 2137 FileNotFoundException.class, 2138 SafeModeException.class, 2139 UnresolvedPathException.class, 2140 SnapshotAccessControlException.class); 2141 } 2142 } 2143 2144 /** 2145 * @see ClientProtocol#getStats() 2146 */ 2147 public FsStatus getDiskStatus() throws IOException { 2148 long rawNums[] = namenode.getStats(); 2149 return new FsStatus(rawNums[0], rawNums[1], rawNums[2]); 2150 } 2151 2152 /** 2153 * Returns count of blocks with no good replicas left. Normally should be 2154 * zero. 2155 * @throws IOException 2156 */ 2157 public long getMissingBlocksCount() throws IOException { 2158 return namenode.getStats()[ClientProtocol.GET_STATS_MISSING_BLOCKS_IDX]; 2159 } 2160 2161 /** 2162 * Returns count of blocks with one of more replica missing. 2163 * @throws IOException 2164 */ 2165 public long getUnderReplicatedBlocksCount() throws IOException { 2166 return namenode.getStats()[ClientProtocol.GET_STATS_UNDER_REPLICATED_IDX]; 2167 } 2168 2169 /** 2170 * Returns count of blocks with at least one replica marked corrupt. 2171 * @throws IOException 2172 */ 2173 public long getCorruptBlocksCount() throws IOException { 2174 return namenode.getStats()[ClientProtocol.GET_STATS_CORRUPT_BLOCKS_IDX]; 2175 } 2176 2177 /** 2178 * @return a list in which each entry describes a corrupt file/block 2179 * @throws IOException 2180 */ 2181 public CorruptFileBlocks listCorruptFileBlocks(String path, 2182 String cookie) 2183 throws IOException { 2184 return namenode.listCorruptFileBlocks(path, cookie); 2185 } 2186 2187 public DatanodeInfo[] datanodeReport(DatanodeReportType type) 2188 throws IOException { 2189 return namenode.getDatanodeReport(type); 2190 } 2191 2192 /** 2193 * Enter, leave or get safe mode. 2194 * 2195 * @see ClientProtocol#setSafeMode(HdfsConstants.SafeModeAction,boolean) 2196 */ 2197 public boolean setSafeMode(SafeModeAction action) throws IOException { 2198 return setSafeMode(action, false); 2199 } 2200 2201 /** 2202 * Enter, leave or get safe mode. 2203 * 2204 * @param action 2205 * One of SafeModeAction.GET, SafeModeAction.ENTER and 2206 * SafeModeActiob.LEAVE 2207 * @param isChecked 2208 * If true, then check only active namenode's safemode status, else 2209 * check first namenode's status. 2210 * @see ClientProtocol#setSafeMode(HdfsConstants.SafeModeAction, boolean) 2211 */ 2212 public boolean setSafeMode(SafeModeAction action, boolean isChecked) throws IOException{ 2213 return namenode.setSafeMode(action, isChecked); 2214 } 2215 2216 /** 2217 * Create one snapshot. 2218 * 2219 * @param snapshotRoot The directory where the snapshot is to be taken 2220 * @param snapshotName Name of the snapshot 2221 * @return the snapshot path. 2222 * @see ClientProtocol#createSnapshot(String, String) 2223 */ 2224 public String createSnapshot(String snapshotRoot, String snapshotName) 2225 throws IOException { 2226 checkOpen(); 2227 try { 2228 return namenode.createSnapshot(snapshotRoot, snapshotName); 2229 } catch(RemoteException re) { 2230 throw re.unwrapRemoteException(); 2231 } 2232 } 2233 2234 /** 2235 * Delete a snapshot of a snapshottable directory. 2236 * 2237 * @param snapshotRoot The snapshottable directory that the 2238 * to-be-deleted snapshot belongs to 2239 * @param snapshotName The name of the to-be-deleted snapshot 2240 * @throws IOException 2241 * @see ClientProtocol#deleteSnapshot(String, String) 2242 */ 2243 public void deleteSnapshot(String snapshotRoot, String snapshotName) 2244 throws IOException { 2245 try { 2246 namenode.deleteSnapshot(snapshotRoot, snapshotName); 2247 } catch(RemoteException re) { 2248 throw re.unwrapRemoteException(); 2249 } 2250 } 2251 2252 /** 2253 * Rename a snapshot. 2254 * @param snapshotDir The directory path where the snapshot was taken 2255 * @param snapshotOldName Old name of the snapshot 2256 * @param snapshotNewName New name of the snapshot 2257 * @throws IOException 2258 * @see ClientProtocol#renameSnapshot(String, String, String) 2259 */ 2260 public void renameSnapshot(String snapshotDir, String snapshotOldName, 2261 String snapshotNewName) throws IOException { 2262 checkOpen(); 2263 try { 2264 namenode.renameSnapshot(snapshotDir, snapshotOldName, snapshotNewName); 2265 } catch(RemoteException re) { 2266 throw re.unwrapRemoteException(); 2267 } 2268 } 2269 2270 /** 2271 * Get all the current snapshottable directories. 2272 * @return All the current snapshottable directories 2273 * @throws IOException 2274 * @see ClientProtocol#getSnapshottableDirListing() 2275 */ 2276 public SnapshottableDirectoryStatus[] getSnapshottableDirListing() 2277 throws IOException { 2278 checkOpen(); 2279 try { 2280 return namenode.getSnapshottableDirListing(); 2281 } catch(RemoteException re) { 2282 throw re.unwrapRemoteException(); 2283 } 2284 } 2285 2286 /** 2287 * Allow snapshot on a directory. 2288 * 2289 * @see ClientProtocol#allowSnapshot(String snapshotRoot) 2290 */ 2291 public void allowSnapshot(String snapshotRoot) throws IOException { 2292 checkOpen(); 2293 try { 2294 namenode.allowSnapshot(snapshotRoot); 2295 } catch (RemoteException re) { 2296 throw re.unwrapRemoteException(); 2297 } 2298 } 2299 2300 /** 2301 * Disallow snapshot on a directory. 2302 * 2303 * @see ClientProtocol#disallowSnapshot(String snapshotRoot) 2304 */ 2305 public void disallowSnapshot(String snapshotRoot) throws IOException { 2306 checkOpen(); 2307 try { 2308 namenode.disallowSnapshot(snapshotRoot); 2309 } catch (RemoteException re) { 2310 throw re.unwrapRemoteException(); 2311 } 2312 } 2313 2314 /** 2315 * Get the difference between two snapshots, or between a snapshot and the 2316 * current tree of a directory. 2317 * @see ClientProtocol#getSnapshotDiffReport(String, String, String) 2318 */ 2319 public SnapshotDiffReport getSnapshotDiffReport(String snapshotDir, 2320 String fromSnapshot, String toSnapshot) throws IOException { 2321 checkOpen(); 2322 try { 2323 return namenode.getSnapshotDiffReport(snapshotDir, 2324 fromSnapshot, toSnapshot); 2325 } catch(RemoteException re) { 2326 throw re.unwrapRemoteException(); 2327 } 2328 } 2329 2330 public long addCacheDirective( 2331 CacheDirectiveInfo info, EnumSet<CacheFlag> flags) throws IOException { 2332 checkOpen(); 2333 try { 2334 return namenode.addCacheDirective(info, flags); 2335 } catch (RemoteException re) { 2336 throw re.unwrapRemoteException(); 2337 } 2338 } 2339 2340 public void modifyCacheDirective( 2341 CacheDirectiveInfo info, EnumSet<CacheFlag> flags) throws IOException { 2342 checkOpen(); 2343 try { 2344 namenode.modifyCacheDirective(info, flags); 2345 } catch (RemoteException re) { 2346 throw re.unwrapRemoteException(); 2347 } 2348 } 2349 2350 public void removeCacheDirective(long id) 2351 throws IOException { 2352 checkOpen(); 2353 try { 2354 namenode.removeCacheDirective(id); 2355 } catch (RemoteException re) { 2356 throw re.unwrapRemoteException(); 2357 } 2358 } 2359 2360 public RemoteIterator<CacheDirectiveEntry> listCacheDirectives( 2361 CacheDirectiveInfo filter) throws IOException { 2362 return new CacheDirectiveIterator(namenode, filter); 2363 } 2364 2365 public void addCachePool(CachePoolInfo info) throws IOException { 2366 checkOpen(); 2367 try { 2368 namenode.addCachePool(info); 2369 } catch (RemoteException re) { 2370 throw re.unwrapRemoteException(); 2371 } 2372 } 2373 2374 public void modifyCachePool(CachePoolInfo info) throws IOException { 2375 checkOpen(); 2376 try { 2377 namenode.modifyCachePool(info); 2378 } catch (RemoteException re) { 2379 throw re.unwrapRemoteException(); 2380 } 2381 } 2382 2383 public void removeCachePool(String poolName) throws IOException { 2384 checkOpen(); 2385 try { 2386 namenode.removeCachePool(poolName); 2387 } catch (RemoteException re) { 2388 throw re.unwrapRemoteException(); 2389 } 2390 } 2391 2392 public RemoteIterator<CachePoolEntry> listCachePools() throws IOException { 2393 return new CachePoolIterator(namenode); 2394 } 2395 2396 /** 2397 * Save namespace image. 2398 * 2399 * @see ClientProtocol#saveNamespace() 2400 */ 2401 void saveNamespace() throws AccessControlException, IOException { 2402 try { 2403 namenode.saveNamespace(); 2404 } catch(RemoteException re) { 2405 throw re.unwrapRemoteException(AccessControlException.class); 2406 } 2407 } 2408 2409 /** 2410 * Rolls the edit log on the active NameNode. 2411 * @return the txid of the new log segment 2412 * 2413 * @see ClientProtocol#rollEdits() 2414 */ 2415 long rollEdits() throws AccessControlException, IOException { 2416 try { 2417 return namenode.rollEdits(); 2418 } catch(RemoteException re) { 2419 throw re.unwrapRemoteException(AccessControlException.class); 2420 } 2421 } 2422 2423 @VisibleForTesting 2424 ExtendedBlock getPreviousBlock(String file) { 2425 return filesBeingWritten.get(file).getBlock(); 2426 } 2427 2428 /** 2429 * enable/disable restore failed storage. 2430 * 2431 * @see ClientProtocol#restoreFailedStorage(String arg) 2432 */ 2433 boolean restoreFailedStorage(String arg) 2434 throws AccessControlException, IOException{ 2435 return namenode.restoreFailedStorage(arg); 2436 } 2437 2438 /** 2439 * Refresh the hosts and exclude files. (Rereads them.) 2440 * See {@link ClientProtocol#refreshNodes()} 2441 * for more details. 2442 * 2443 * @see ClientProtocol#refreshNodes() 2444 */ 2445 public void refreshNodes() throws IOException { 2446 namenode.refreshNodes(); 2447 } 2448 2449 /** 2450 * Dumps DFS data structures into specified file. 2451 * 2452 * @see ClientProtocol#metaSave(String) 2453 */ 2454 public void metaSave(String pathname) throws IOException { 2455 namenode.metaSave(pathname); 2456 } 2457 2458 /** 2459 * Requests the namenode to tell all datanodes to use a new, non-persistent 2460 * bandwidth value for dfs.balance.bandwidthPerSec. 2461 * See {@link ClientProtocol#setBalancerBandwidth(long)} 2462 * for more details. 2463 * 2464 * @see ClientProtocol#setBalancerBandwidth(long) 2465 */ 2466 public void setBalancerBandwidth(long bandwidth) throws IOException { 2467 namenode.setBalancerBandwidth(bandwidth); 2468 } 2469 2470 /** 2471 * @see ClientProtocol#finalizeUpgrade() 2472 */ 2473 public void finalizeUpgrade() throws IOException { 2474 namenode.finalizeUpgrade(); 2475 } 2476 2477 /** 2478 */ 2479 @Deprecated 2480 public boolean mkdirs(String src) throws IOException { 2481 return mkdirs(src, null, true); 2482 } 2483 2484 /** 2485 * Create a directory (or hierarchy of directories) with the given 2486 * name and permission. 2487 * 2488 * @param src The path of the directory being created 2489 * @param permission The permission of the directory being created. 2490 * If permission == null, use {@link FsPermission#getDefault()}. 2491 * @param createParent create missing parent directory if true 2492 * 2493 * @return True if the operation success. 2494 * 2495 * @see ClientProtocol#mkdirs(String, FsPermission, boolean) 2496 */ 2497 public boolean mkdirs(String src, FsPermission permission, 2498 boolean createParent) throws IOException { 2499 if (permission == null) { 2500 permission = FsPermission.getDefault(); 2501 } 2502 FsPermission masked = permission.applyUMask(dfsClientConf.uMask); 2503 return primitiveMkdir(src, masked, createParent); 2504 } 2505 2506 /** 2507 * Same {{@link #mkdirs(String, FsPermission, boolean)} except 2508 * that the permissions has already been masked against umask. 2509 */ 2510 public boolean primitiveMkdir(String src, FsPermission absPermission) 2511 throws IOException { 2512 return primitiveMkdir(src, absPermission, true); 2513 } 2514 2515 /** 2516 * Same {{@link #mkdirs(String, FsPermission, boolean)} except 2517 * that the permissions has already been masked against umask. 2518 */ 2519 public boolean primitiveMkdir(String src, FsPermission absPermission, 2520 boolean createParent) 2521 throws IOException { 2522 checkOpen(); 2523 if (absPermission == null) { 2524 absPermission = 2525 FsPermission.getDefault().applyUMask(dfsClientConf.uMask); 2526 } 2527 2528 if(LOG.isDebugEnabled()) { 2529 LOG.debug(src + ": masked=" + absPermission); 2530 } 2531 try { 2532 return namenode.mkdirs(src, absPermission, createParent); 2533 } catch(RemoteException re) { 2534 throw re.unwrapRemoteException(AccessControlException.class, 2535 InvalidPathException.class, 2536 FileAlreadyExistsException.class, 2537 FileNotFoundException.class, 2538 ParentNotDirectoryException.class, 2539 SafeModeException.class, 2540 NSQuotaExceededException.class, 2541 DSQuotaExceededException.class, 2542 UnresolvedPathException.class, 2543 SnapshotAccessControlException.class); 2544 } 2545 } 2546 2547 /** 2548 * Get {@link ContentSummary} rooted at the specified directory. 2549 * @param path The string representation of the path 2550 * 2551 * @see ClientProtocol#getContentSummary(String) 2552 */ 2553 ContentSummary getContentSummary(String src) throws IOException { 2554 try { 2555 return namenode.getContentSummary(src); 2556 } catch(RemoteException re) { 2557 throw re.unwrapRemoteException(AccessControlException.class, 2558 FileNotFoundException.class, 2559 UnresolvedPathException.class); 2560 } 2561 } 2562 2563 /** 2564 * Sets or resets quotas for a directory. 2565 * @see ClientProtocol#setQuota(String, long, long) 2566 */ 2567 void setQuota(String src, long namespaceQuota, long diskspaceQuota) 2568 throws IOException { 2569 // sanity check 2570 if ((namespaceQuota <= 0 && namespaceQuota != HdfsConstants.QUOTA_DONT_SET && 2571 namespaceQuota != HdfsConstants.QUOTA_RESET) || 2572 (diskspaceQuota <= 0 && diskspaceQuota != HdfsConstants.QUOTA_DONT_SET && 2573 diskspaceQuota != HdfsConstants.QUOTA_RESET)) { 2574 throw new IllegalArgumentException("Invalid values for quota : " + 2575 namespaceQuota + " and " + 2576 diskspaceQuota); 2577 2578 } 2579 try { 2580 namenode.setQuota(src, namespaceQuota, diskspaceQuota); 2581 } catch(RemoteException re) { 2582 throw re.unwrapRemoteException(AccessControlException.class, 2583 FileNotFoundException.class, 2584 NSQuotaExceededException.class, 2585 DSQuotaExceededException.class, 2586 UnresolvedPathException.class, 2587 SnapshotAccessControlException.class); 2588 } 2589 } 2590 2591 /** 2592 * set the modification and access time of a file 2593 * 2594 * @see ClientProtocol#setTimes(String, long, long) 2595 */ 2596 public void setTimes(String src, long mtime, long atime) throws IOException { 2597 checkOpen(); 2598 try { 2599 namenode.setTimes(src, mtime, atime); 2600 } catch(RemoteException re) { 2601 throw re.unwrapRemoteException(AccessControlException.class, 2602 FileNotFoundException.class, 2603 UnresolvedPathException.class, 2604 SnapshotAccessControlException.class); 2605 } 2606 } 2607 2608 /** 2609 * @deprecated use {@link HdfsDataInputStream} instead. 2610 */ 2611 @Deprecated 2612 public static class DFSDataInputStream extends HdfsDataInputStream { 2613 2614 public DFSDataInputStream(DFSInputStream in) throws IOException { 2615 super(in); 2616 } 2617 } 2618 2619 void reportChecksumFailure(String file, ExtendedBlock blk, DatanodeInfo dn) { 2620 DatanodeInfo [] dnArr = { dn }; 2621 LocatedBlock [] lblocks = { new LocatedBlock(blk, dnArr) }; 2622 reportChecksumFailure(file, lblocks); 2623 } 2624 2625 // just reports checksum failure and ignores any exception during the report. 2626 void reportChecksumFailure(String file, LocatedBlock lblocks[]) { 2627 try { 2628 reportBadBlocks(lblocks); 2629 } catch (IOException ie) { 2630 LOG.info("Found corruption while reading " + file 2631 + ". Error repairing corrupt blocks. Bad blocks remain.", ie); 2632 } 2633 } 2634 2635 @Override 2636 public String toString() { 2637 return getClass().getSimpleName() + "[clientName=" + clientName 2638 + ", ugi=" + ugi + "]"; 2639 } 2640 2641 public DomainSocketFactory getDomainSocketFactory() { 2642 return domainSocketFactory; 2643 } 2644 2645 public void disableLegacyBlockReaderLocal() { 2646 shouldUseLegacyBlockReaderLocal = false; 2647 } 2648 2649 public boolean useLegacyBlockReaderLocal() { 2650 return shouldUseLegacyBlockReaderLocal; 2651 } 2652 2653 public CachingStrategy getDefaultReadCachingStrategy() { 2654 return defaultReadCachingStrategy; 2655 } 2656 2657 public CachingStrategy getDefaultWriteCachingStrategy() { 2658 return defaultWriteCachingStrategy; 2659 } 2660 2661 @VisibleForTesting 2662 public ClientMmapManager getMmapManager() { 2663 return mmapManager; 2664 } 2665 }