/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hdfs.protocol; import com.facebook.swift.codec.ThriftConstructor; import com.facebook.swift.codec.ThriftField; import com.facebook.swift.codec.ThriftStruct; import org.apache.hadoop.fs.ContentSummary; import org.apache.hadoop.fs.OpenFileInfo; import org.apache.hadoop.io.CompatibleWritable; import org.apache.hadoop.io.Writable; import javax.validation.constraints.NotNull; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_CAPACITY_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_CORRUPT_BLOCKS_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_MISSING_BLOCKS_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_REMAINING_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_UNDER_REPLICATED_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProtocol.GET_STATS_USED_IDX; import static org.apache.hadoop.hdfs.protocol.ClientProxyRequests.readStrings; import static org.apache.hadoop.hdfs.protocol.ClientProxyRequests.writeStrings; public class ClientProxyResponses { /** A wrapper around any Writable, allows wrapped value to be null */ public static abstract class WrapperWritable<T extends Writable> implements Writable { private T value; public void set(T value) { this.value = value; } public T get() { return value; } @Override public void write(DataOutput out) throws IOException { if (value == null) { out.writeBoolean(false); } else { out.writeBoolean(true); // We know that runtime type of serialized value representation is T create(value).write(out); } } @Override public void readFields(DataInput in) throws IOException { if (in.readBoolean()) { value = create(); // We know that runtime type of value is T value.readFields(in); } else { value = null; } } /** Returns a new object of runtime type T */ protected abstract T create(); /** * Returns an object whose runtime type is T and contains information stored in the argument. * Despite misleading name there is no need to create a new object. * Example: let B extend A, B contains additional field which is serialized therefore we * cannot serialize A and deserialize B (or the other way around) without corrupting stream, * since static type that should be sent on wire is A we have to convert B to A (runtime types) * before serializing. * Note: if A is a final class then we know that there is no such B, * as a consequence we are safe to return passed object (we have V == T == object.getClass()). */ protected <V extends T> T create(@NotNull V object) { return object; } } //////////////////////////////////////// // Wrapping responses //////////////////////////////////////// @ThriftStruct public static class BlockLocationsResponse extends WrapperWritable<LocatedBlocks> { @Override protected LocatedBlocks create() { return new LocatedBlocks(); } @Override protected <V extends LocatedBlocks> LocatedBlocks create(@NotNull V object) { return new LocatedBlocks(object); } @SuppressWarnings("unused") public BlockLocationsResponse() { } @ThriftConstructor public BlockLocationsResponse(@ThriftField(1) LocatedBlocks blocks) { set(blocks); } @ThriftField(1) public LocatedBlocks getBlocks() { return get(); } } @ThriftStruct public static class OpenResponse extends WrapperWritable<LocatedBlocksWithMetaInfo> { @Override protected LocatedBlocksWithMetaInfo create() { return new LocatedBlocksWithMetaInfo(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public OpenResponse() { } @ThriftConstructor public OpenResponse(@ThriftField(1) LocatedBlocksWithMetaInfo blocks) { set(blocks); } @ThriftField(1) public LocatedBlocksWithMetaInfo getBlocks() { return get(); } } @ThriftStruct public static class AppendResponse extends WrapperWritable<LocatedBlockWithOldGS> { @Override protected LocatedBlockWithOldGS create() { return new LocatedBlockWithOldGS(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public AppendResponse() { } @ThriftConstructor public AppendResponse(@ThriftField(1) LocatedBlockWithOldGS block) { set(block); } @ThriftField(1) public LocatedBlockWithOldGS getBlock() { return get(); } } @ThriftStruct public static class AddBlockResponse extends WrapperWritable<LocatedBlockWithMetaInfo> { @Override protected LocatedBlockWithMetaInfo create() { return new LocatedBlockWithMetaInfo(); } @Override protected <V extends LocatedBlockWithMetaInfo> LocatedBlockWithMetaInfo create( @NotNull V object) { return new LocatedBlockWithMetaInfo(object); } @SuppressWarnings("unused") public AddBlockResponse() { } @ThriftConstructor public AddBlockResponse(@ThriftField(1) LocatedBlockWithMetaInfo block) { set(block); } @ThriftField(1) public LocatedBlockWithMetaInfo getBlock() { return get(); } } @ThriftStruct public static class PartialListingResponse extends WrapperWritable<DirectoryListing> { @Override protected DirectoryListing create() { return new DirectoryListing(); } @Override protected <V extends DirectoryListing> DirectoryListing create(@NotNull V object) { return new DirectoryListing(object); } @SuppressWarnings("unused") public PartialListingResponse() { } @ThriftConstructor public PartialListingResponse(@ThriftField(1) DirectoryListing listing) { set(listing); } @ThriftField(1) public DirectoryListing getListing() { return get(); } } @ThriftStruct public static class LocatedPartialListingResponse extends WrapperWritable<LocatedDirectoryListing> { @Override protected LocatedDirectoryListing create() { return new LocatedDirectoryListing(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public LocatedPartialListingResponse() { } @ThriftConstructor public LocatedPartialListingResponse(@ThriftField(1) LocatedDirectoryListing listing) { set(listing); } @ThriftField(1) public LocatedDirectoryListing getListing() { return get(); } } @ThriftStruct public static class CorruptFileBlocksResponse extends WrapperWritable<CorruptFileBlocks> { @Override protected CorruptFileBlocks create() { return new CorruptFileBlocks(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public CorruptFileBlocksResponse() { } @ThriftConstructor public CorruptFileBlocksResponse(@ThriftField(1) CorruptFileBlocks blocks) { set(blocks); } @ThriftField(1) public CorruptFileBlocks getBlocks() { return get(); } } @ThriftStruct public static class FileInfoResponse extends WrapperWritable<HdfsFileStatus> { @Override protected HdfsFileStatus create() { return new HdfsFileStatus(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public FileInfoResponse() { } @ThriftConstructor public FileInfoResponse(@ThriftField(1) HdfsFileStatus status) { set(status); } @ThriftField(1) public HdfsFileStatus getStatus() { return get(); } } @ThriftStruct public static class ContentSummaryResponse extends WrapperWritable<ContentSummary> { @Override protected ContentSummary create() { return new ContentSummary(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public ContentSummaryResponse() { } @ThriftConstructor public ContentSummaryResponse(@ThriftField(1) ContentSummary summary) { set(summary); } @ThriftField(1) public ContentSummary getSummary() { return get(); } } @ThriftStruct public static class BlockInfoResponse extends WrapperWritable<LocatedBlockWithFileName> { @Override protected LocatedBlockWithFileName create() { return new LocatedBlockWithFileName(); } // Wrapped class is final, no create(V object) needed @SuppressWarnings("unused") public BlockInfoResponse() { } @ThriftConstructor public BlockInfoResponse(@ThriftField(1) LocatedBlockWithFileName block) { set(block); } @ThriftField(1) public LocatedBlockWithFileName getBlock() { return get(); } } //////////////////////////////////////// // Aggregate responses //////////////////////////////////////// @ThriftStruct public static class StatsResponse extends CompatibleWritable { /** Estimated size of structure on wire */ private static final int SERIALIZED_SIZE = 2 * Long.SIZE * (new StatsResponse() .asArray().length); @ThriftField(1) public long capacity; @ThriftField(2) public long used; @ThriftField(3) public long remaining; @ThriftField(4) public long underReplicatedBlocks; @ThriftField(5) public long corruptBlocks; @ThriftField(6) public long missingBlocks; @ThriftField(7) public long usedNS; @SuppressWarnings("unused") public StatsResponse() { } public StatsResponse(long capacity, long used, long remaining, long underReplicatedBlocks, long corruptBlocks, long missingBlocks, long usedNS) { this.capacity = capacity; this.used = used; this.remaining = remaining; this.underReplicatedBlocks = underReplicatedBlocks; this.corruptBlocks = corruptBlocks; this.missingBlocks = missingBlocks; this.usedNS = usedNS; } public StatsResponse(long[] stats) { capacity = stats[GET_STATS_CAPACITY_IDX]; used = stats[GET_STATS_USED_IDX]; remaining = stats[GET_STATS_REMAINING_IDX]; underReplicatedBlocks = stats[GET_STATS_UNDER_REPLICATED_IDX]; corruptBlocks = stats[GET_STATS_CORRUPT_BLOCKS_IDX]; missingBlocks = stats[GET_STATS_MISSING_BLOCKS_IDX]; if (stats.length > 5) { usedNS = stats[6]; } } @Override protected int getSizeEstimate() { return SERIALIZED_SIZE; } @Override protected byte[] getBuffer(int size) { return new byte[size]; } @Override protected void freeBuffer(byte[] buffer) { // We do not cache buffers for this class } @Override public void writeCompatible(DataOutput out) throws IOException { out.writeLong(capacity); out.writeLong(used); out.writeLong(remaining); out.writeLong(underReplicatedBlocks); out.writeLong(corruptBlocks); out.writeLong(missingBlocks); out.writeLong(usedNS); } @Override public void readCompatible(CompatibleDataInput in) throws IOException { capacity = in.readLong(); used = in.readLong(); remaining = in.readLong(); underReplicatedBlocks = in.readLong(); corruptBlocks = in.readLong(); missingBlocks = in.readLong(); usedNS = in.readLong(); } public long[] asArray() { return new long[]{capacity, used, remaining, underReplicatedBlocks, corruptBlocks, missingBlocks, usedNS}; } } @ThriftStruct public static class HardLinkedFilesResponse implements Writable { private List<String> paths; @SuppressWarnings("unused") public HardLinkedFilesResponse() { } @ThriftConstructor public HardLinkedFilesResponse(@ThriftField(1) List<String> paths) { this.paths = paths; } @Override public void write(DataOutput out) throws IOException { writeStrings(out, paths); } @Override public void readFields(DataInput in) throws IOException { paths = readStrings(in); } @ThriftField(1) public List<String> getPaths() { return paths; } } @ThriftStruct public static class IterativeGetOpenFilesResponse implements Writable { private List<OpenFileInfo> files; @SuppressWarnings("unused") public IterativeGetOpenFilesResponse() { } @ThriftConstructor public IterativeGetOpenFilesResponse(@ThriftField(1) List<OpenFileInfo> files) { this.files = files; } @Override public void write(DataOutput out) throws IOException { if (files != null) { out.writeInt(files.size()); for (OpenFileInfo elem : files) { OpenFileInfo.write(out, elem); } } else { out.writeInt(-1); } } @Override public void readFields(DataInput in) throws IOException { final int fileSize = in.readInt(); files = (fileSize < 0) ? null : new ArrayList<OpenFileInfo>(fileSize); for (int i = 0; i < fileSize; i++) { files.add(OpenFileInfo.read(in)); } } @ThriftField(1) public List<OpenFileInfo> getFiles() { return files; } } @ThriftStruct public static class PingResponse implements Writable { private long response; @SuppressWarnings("unused") public PingResponse() { } @ThriftConstructor public PingResponse(@ThriftField(1) long response) { this.response = response; } @Override public void write(DataOutput out) throws IOException { out.writeLong(response); } @Override public void readFields(DataInput in) throws IOException { response = in.readLong(); } @ThriftField(1) public long getResponse() { return response; } } }