/// <summary> /// Queries datanodes for the blocks specified in <code>datanodeBlocks</code>, /// making one RPC to each datanode. /// </summary> /// <remarks> /// Queries datanodes for the blocks specified in <code>datanodeBlocks</code>, /// making one RPC to each datanode. These RPCs are made in parallel using a /// threadpool. /// </remarks> /// <param name="datanodeBlocks">Map of datanodes to the blocks present on the DN</param> /// <returns>metadatas Map of datanodes to block metadata of the DN</returns> /// <exception cref="Org.Apache.Hadoop.Hdfs.Security.Token.Block.InvalidBlockTokenException /// ">if client does not have read access on a requested block</exception> internal static IDictionary <DatanodeInfo, HdfsBlocksMetadata> QueryDatanodesForHdfsBlocksMetadata (Configuration conf, IDictionary <DatanodeInfo, IList <LocatedBlock> > datanodeBlocks , int poolsize, int timeoutMs, bool connectToDnViaHostname) { IList <BlockStorageLocationUtil.VolumeBlockLocationCallable> callables = CreateVolumeBlockLocationCallables (conf, datanodeBlocks, timeoutMs, connectToDnViaHostname, Trace.CurrentSpan()); // Use a thread pool to execute the Callables in parallel IList <Future <HdfsBlocksMetadata> > futures = new AList <Future <HdfsBlocksMetadata> > (); ExecutorService executor = new ScheduledThreadPoolExecutor(poolsize); try { futures = executor.InvokeAll(callables, timeoutMs, TimeUnit.Milliseconds); } catch (Exception) { } // Swallow the exception here, because we can return partial results executor.Shutdown(); IDictionary <DatanodeInfo, HdfsBlocksMetadata> metadatas = Maps.NewHashMapWithExpectedSize (datanodeBlocks.Count); // Fill in metadatas with results from DN RPCs, where possible for (int i = 0; i < futures.Count; i++) { BlockStorageLocationUtil.VolumeBlockLocationCallable callable = callables[i]; DatanodeInfo datanode = callable.GetDatanodeInfo(); Future <HdfsBlocksMetadata> future = futures[i]; try { HdfsBlocksMetadata metadata = future.Get(); metadatas[callable.GetDatanodeInfo()] = metadata; } catch (CancellationException e) { Log.Info("Cancelled while waiting for datanode " + datanode.GetIpcAddr(false) + ": " + e.ToString()); } catch (ExecutionException e) { Exception t = e.InnerException; if (t is InvalidBlockTokenException) { Log.Warn("Invalid access token when trying to retrieve " + "information from datanode " + datanode.GetIpcAddr(false)); throw (InvalidBlockTokenException)t; } else { if (t is NotSupportedException) { Log.Info("Datanode " + datanode.GetIpcAddr(false) + " does not support" + " required #getHdfsBlocksMetadata() API" ); throw (NotSupportedException)t; } else { Log.Info("Failed to query block locations on datanode " + datanode.GetIpcAddr(false ) + ": " + t); } } if (Log.IsDebugEnabled()) { Log.Debug("Could not fetch information from datanode", t); } } catch (Exception) { // Shouldn't happen, because invokeAll waits for all Futures to be ready Log.Info("Interrupted while fetching HdfsBlocksMetadata"); } } return(metadatas); }
/// <summary> /// Group the per-replica /// <see cref="Org.Apache.Hadoop.FS.VolumeId"/> /// info returned from /// <see cref="DFSClient#queryDatanodesForHdfsBlocksMetadata(Map)"/> /// to be /// associated /// with the corresponding /// <see cref="Org.Apache.Hadoop.Hdfs.Protocol.LocatedBlock"/> /// . /// </summary> /// <param name="blocks">Original LocatedBlock array</param> /// <param name="metadatas">VolumeId information for the replicas on each datanode</param> /// <returns> /// blockVolumeIds per-replica VolumeId information associated with the /// parent LocatedBlock /// </returns> internal static IDictionary <LocatedBlock, IList <VolumeId> > AssociateVolumeIdsWithBlocks (IList <LocatedBlock> blocks, IDictionary <DatanodeInfo, HdfsBlocksMetadata> metadatas ) { // Initialize mapping of ExtendedBlock to LocatedBlock. // Used to associate results from DN RPCs to the parent LocatedBlock IDictionary <long, LocatedBlock> blockIdToLocBlock = new Dictionary <long, LocatedBlock >(); foreach (LocatedBlock b in blocks) { blockIdToLocBlock[b.GetBlock().GetBlockId()] = b; } // Initialize the mapping of blocks -> list of VolumeIds, one per replica // This is filled out with real values from the DN RPCs IDictionary <LocatedBlock, IList <VolumeId> > blockVolumeIds = new Dictionary <LocatedBlock , IList <VolumeId> >(); foreach (LocatedBlock b_1 in blocks) { AList <VolumeId> l = new AList <VolumeId>(b_1.GetLocations().Length); for (int i = 0; i < b_1.GetLocations().Length; i++) { l.AddItem(null); } blockVolumeIds[b_1] = l; } // Iterate through the list of metadatas (one per datanode). // For each metadata, if it's valid, insert its volume location information // into the Map returned to the caller foreach (KeyValuePair <DatanodeInfo, HdfsBlocksMetadata> entry in metadatas) { DatanodeInfo datanode = entry.Key; HdfsBlocksMetadata metadata = entry.Value; // Check if metadata is valid if (metadata == null) { continue; } long[] metaBlockIds = metadata.GetBlockIds(); IList <byte[]> metaVolumeIds = metadata.GetVolumeIds(); IList <int> metaVolumeIndexes = metadata.GetVolumeIndexes(); // Add VolumeId for each replica in the HdfsBlocksMetadata for (int j = 0; j < metaBlockIds.Length; j++) { int volumeIndex = metaVolumeIndexes[j]; long blockId = metaBlockIds[j]; // Skip if block wasn't found, or not a valid index into metaVolumeIds // Also skip if the DN responded with a block we didn't ask for if (volumeIndex == int.MaxValue || volumeIndex >= metaVolumeIds.Count || !blockIdToLocBlock .Contains(blockId)) { if (Log.IsDebugEnabled()) { Log.Debug("No data for block " + blockId); } continue; } // Get the VolumeId by indexing into the list of VolumeIds // provided by the datanode byte[] volumeId = metaVolumeIds[volumeIndex]; HdfsVolumeId id = new HdfsVolumeId(volumeId); // Find out which index we are in the LocatedBlock's replicas LocatedBlock locBlock = blockIdToLocBlock[blockId]; DatanodeInfo[] dnInfos = locBlock.GetLocations(); int index = -1; for (int k = 0; k < dnInfos.Length; k++) { if (dnInfos[k].Equals(datanode)) { index = k; break; } } if (index < 0) { if (Log.IsDebugEnabled()) { Log.Debug("Datanode responded with a block volume id we did" + " not request, omitting." ); } continue; } // Place VolumeId at the same index as the DN's index in the list of // replicas IList <VolumeId> volumeIds = blockVolumeIds[locBlock]; volumeIds.Set(index, id); } } return(blockVolumeIds); }