|
| 1 | +/** |
| 2 | + * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | + * or more contributor license agreements. See the NOTICE file |
| 4 | + * distributed with this work for additional information |
| 5 | + * regarding copyright ownership. The ASF licenses this file |
| 6 | + * to you under the Apache License, Version 2.0 (the |
| 7 | + * "License"); you may not use this file except in compliance |
| 8 | + * with the License. You may obtain a copy of the License at |
| 9 | + * |
| 10 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | + * |
| 12 | + * Unless required by applicable law or agreed to in writing, software |
| 13 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 14 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 15 | + * See the License for the specific language governing permissions and |
| 16 | + * limitations under the License. |
| 17 | + */ |
| 18 | +package org.apache.hadoop.hdfs.server.federation.async; |
| 19 | + |
| 20 | +import org.apache.hadoop.fs.StorageType; |
| 21 | +import org.apache.hadoop.hdfs.protocol.DatanodeInfo; |
| 22 | +import org.apache.hadoop.hdfs.protocol.HdfsConstants; |
| 23 | +import org.apache.hadoop.hdfs.security.token.block.ExportedBlockKeys; |
| 24 | +import org.apache.hadoop.hdfs.server.federation.router.RemoteMethod; |
| 25 | +import org.apache.hadoop.hdfs.server.federation.router.RouterNamenodeProtocol; |
| 26 | +import org.apache.hadoop.hdfs.server.federation.router.RouterRpcClient; |
| 27 | +import org.apache.hadoop.hdfs.server.federation.router.RouterRpcServer; |
| 28 | +import org.apache.hadoop.hdfs.server.federation.router.async.AsyncApplyFunction; |
| 29 | +import org.apache.hadoop.hdfs.server.namenode.NNStorage; |
| 30 | +import org.apache.hadoop.hdfs.server.namenode.NameNode; |
| 31 | +import org.apache.hadoop.hdfs.server.protocol.BlocksWithLocations; |
| 32 | +import org.apache.hadoop.hdfs.server.protocol.DatanodeStorageReport; |
| 33 | +import org.apache.hadoop.hdfs.server.protocol.NamenodeProtocol; |
| 34 | +import org.apache.hadoop.hdfs.server.protocol.NamespaceInfo; |
| 35 | +import java.io.IOException; |
| 36 | +import java.util.Map; |
| 37 | + |
| 38 | +import static org.apache.hadoop.hdfs.server.federation.router.async.AsyncUtil.asyncApply; |
| 39 | +import static org.apache.hadoop.hdfs.server.federation.router.async.AsyncUtil.asyncComplete; |
| 40 | +import static org.apache.hadoop.hdfs.server.federation.router.async.AsyncUtil.asyncReturn; |
| 41 | + |
| 42 | +/** |
| 43 | + * Module that implements all the asynchronous RPC calls in {@link NamenodeProtocol} in the |
| 44 | + * {@link RouterRpcServer}. |
| 45 | + */ |
| 46 | +public class RouterAsyncNamenodeProtocol extends RouterNamenodeProtocol { |
| 47 | + |
| 48 | + /** RPC server to receive client calls. */ |
| 49 | + private final RouterRpcServer rpcServer; |
| 50 | + /** RPC clients to connect to the Namenodes. */ |
| 51 | + private final RouterRpcClient rpcClient; |
| 52 | + |
| 53 | + public RouterAsyncNamenodeProtocol(RouterRpcServer server) { |
| 54 | + super(server); |
| 55 | + this.rpcServer = server; |
| 56 | + this.rpcClient = this.rpcServer.getRPCClient(); |
| 57 | + } |
| 58 | + |
| 59 | + /** |
| 60 | + * Asynchronously get a list of blocks belonging to <code>datanode</code> |
| 61 | + * whose total size equals <code>size</code>. |
| 62 | + * |
| 63 | + * @see org.apache.hadoop.hdfs.server.balancer.Balancer |
| 64 | + * @param datanode a data node |
| 65 | + * @param size requested size |
| 66 | + * @param minBlockSize each block should be of this minimum Block Size |
| 67 | + * @param hotBlockTimeInterval prefer to get blocks which are belong to |
| 68 | + * the cold files accessed before the time interval |
| 69 | + * @param storageType the given storage type {@link StorageType} |
| 70 | + * @return BlocksWithLocations a list of blocks & their locations |
| 71 | + * @throws IOException if size is less than or equal to 0 or |
| 72 | + datanode does not exist |
| 73 | + */ |
| 74 | + @Override |
| 75 | + public BlocksWithLocations getBlocks( |
| 76 | + DatanodeInfo datanode, long size, |
| 77 | + long minBlockSize, long hotBlockTimeInterval, StorageType storageType) throws IOException { |
| 78 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 79 | + |
| 80 | + // Get the namespace where the datanode is located |
| 81 | + rpcServer.getDatanodeStorageReportMapAsync(HdfsConstants.DatanodeReportType.ALL); |
| 82 | + asyncApply((AsyncApplyFunction<Map<String, DatanodeStorageReport[]>, Object>) map -> { |
| 83 | + String nsId = null; |
| 84 | + for (Map.Entry<String, DatanodeStorageReport[]> entry : map.entrySet()) { |
| 85 | + DatanodeStorageReport[] dns = entry.getValue(); |
| 86 | + for (DatanodeStorageReport dn : dns) { |
| 87 | + DatanodeInfo dnInfo = dn.getDatanodeInfo(); |
| 88 | + if (dnInfo.getDatanodeUuid().equals(datanode.getDatanodeUuid())) { |
| 89 | + nsId = entry.getKey(); |
| 90 | + break; |
| 91 | + } |
| 92 | + } |
| 93 | + // Break the loop if already found |
| 94 | + if (nsId != null) { |
| 95 | + break; |
| 96 | + } |
| 97 | + } |
| 98 | + // Forward to the proper namenode |
| 99 | + if (nsId != null) { |
| 100 | + RemoteMethod method = new RemoteMethod( |
| 101 | + NamenodeProtocol.class, "getBlocks", new Class<?>[] |
| 102 | + {DatanodeInfo.class, long.class, long.class, long.class, StorageType.class}, |
| 103 | + datanode, size, minBlockSize, hotBlockTimeInterval, storageType); |
| 104 | + rpcClient.invokeSingle(nsId, method, BlocksWithLocations.class); |
| 105 | + } else { |
| 106 | + asyncComplete(null); |
| 107 | + } |
| 108 | + }); |
| 109 | + return asyncReturn(BlocksWithLocations.class); |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * Asynchronously get the current block keys. |
| 114 | + * |
| 115 | + * @return ExportedBlockKeys containing current block keys |
| 116 | + * @throws IOException if there is no namespace available or other ioExceptions. |
| 117 | + */ |
| 118 | + @Override |
| 119 | + public ExportedBlockKeys getBlockKeys() throws IOException { |
| 120 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 121 | + |
| 122 | + RemoteMethod method = |
| 123 | + new RemoteMethod(NamenodeProtocol.class, "getBlockKeys"); |
| 124 | + rpcServer.invokeAtAvailableNsAsync(method, ExportedBlockKeys.class); |
| 125 | + return asyncReturn(ExportedBlockKeys.class); |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * Asynchronously get the most recent transaction ID. |
| 130 | + * |
| 131 | + * @return The most recent transaction ID that has been synced to |
| 132 | + * persistent storage, or applied from persistent storage in the |
| 133 | + * case of a non-active node. |
| 134 | + * @throws IOException if there is no namespace available or other ioExceptions. |
| 135 | + */ |
| 136 | + @Override |
| 137 | + public long getTransactionID() throws IOException { |
| 138 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 139 | + |
| 140 | + RemoteMethod method = |
| 141 | + new RemoteMethod(NamenodeProtocol.class, "getTransactionID"); |
| 142 | + rpcServer.invokeAtAvailableNsAsync(method, long.class); |
| 143 | + return asyncReturn(Long.class); |
| 144 | + } |
| 145 | + |
| 146 | + /** |
| 147 | + * Asynchronously get the transaction ID of the most recent checkpoint. |
| 148 | + * |
| 149 | + * @return The transaction ID of the most recent checkpoint. |
| 150 | + * @throws IOException if there is no namespace available or other ioExceptions. |
| 151 | + */ |
| 152 | + @Override |
| 153 | + public long getMostRecentCheckpointTxId() throws IOException { |
| 154 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 155 | + |
| 156 | + RemoteMethod method = |
| 157 | + new RemoteMethod(NamenodeProtocol.class, "getMostRecentCheckpointTxId"); |
| 158 | + rpcServer.invokeAtAvailableNsAsync(method, long.class); |
| 159 | + return asyncReturn(Long.class); |
| 160 | + } |
| 161 | + |
| 162 | + /** |
| 163 | + * Asynchronously get the transaction ID of the most recent checkpoint |
| 164 | + * for the given NameNodeFile. |
| 165 | + * |
| 166 | + * @return The transaction ID of the most recent checkpoint |
| 167 | + * for the given NameNodeFile. |
| 168 | + * @throws IOException if there is no namespace available or other ioExceptions. |
| 169 | + */ |
| 170 | + @Override |
| 171 | + public long getMostRecentNameNodeFileTxId(NNStorage.NameNodeFile nnf) |
| 172 | + throws IOException { |
| 173 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 174 | + |
| 175 | + RemoteMethod method = |
| 176 | + new RemoteMethod(NamenodeProtocol.class, "getMostRecentNameNodeFileTxId", |
| 177 | + new Class<?>[] {NNStorage.NameNodeFile.class}, nnf); |
| 178 | + rpcServer.invokeAtAvailableNsAsync(method, long.class); |
| 179 | + return asyncReturn(Long.class); |
| 180 | + } |
| 181 | + |
| 182 | + /** |
| 183 | + * Asynchronously request name-node version and storage information. |
| 184 | + * |
| 185 | + * @return {@link NamespaceInfo} identifying versions and storage information |
| 186 | + * of the name-node. |
| 187 | + * @throws IOException if there is no namespace available or other ioExceptions. |
| 188 | + */ |
| 189 | + @Override |
| 190 | + public NamespaceInfo versionRequest() throws IOException { |
| 191 | + rpcServer.checkOperation(NameNode.OperationCategory.READ); |
| 192 | + |
| 193 | + RemoteMethod method = |
| 194 | + new RemoteMethod(NamenodeProtocol.class, "versionRequest"); |
| 195 | + rpcServer.invokeAtAvailableNsAsync(method, NamespaceInfo.class); |
| 196 | + return asyncReturn(NamespaceInfo.class); |
| 197 | + } |
| 198 | +} |
0 commit comments