001/** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.fs; 020 021import java.io.*; 022import java.nio.ByteBuffer; 023import java.util.EnumSet; 024 025import org.apache.hadoop.classification.InterfaceAudience; 026import org.apache.hadoop.classification.InterfaceStability; 027import org.apache.hadoop.classification.MapRModified; 028import org.apache.hadoop.io.ByteBufferPool; 029import org.apache.hadoop.fs.ByteBufferUtil; 030import org.apache.hadoop.util.IdentityHashStore; 031 032/** Utility that wraps a {@link FSInputStream} in a {@link DataInputStream} 033 * and buffers input through a {@link BufferedInputStream}. */ 034@InterfaceAudience.Public 035@InterfaceStability.Stable 036public class FSDataInputStream extends DataInputStream 037 implements Seekable, PositionedReadable, 038 ByteBufferReadable, HasFileDescriptor, CanSetDropBehind, CanSetReadahead, 039 HasEnhancedByteBufferAccess, CanUnbuffer { 040 /** 041 * Map ByteBuffers that we have handed out to readers to ByteBufferPool 042 * objects 043 */ 044 private final IdentityHashStore<ByteBuffer, ByteBufferPool> 045 extendedReadBuffers 046 = new IdentityHashStore<ByteBuffer, ByteBufferPool>(0); 047 048 /** 049 * Type of file advise to be passed on to the underlying file system. This 050 * information can be used to make optimizations such as reclaiming buffers 051 * for files that are no longer needed by the application, etc. 052 */ 053 @MapRModified 054 public static enum FadviseType { 055 FILE_DONTNEED, 056 FILE_RANDOM, 057 FILE_SEQUENTIAL; 058 } 059 060 public FSDataInputStream(InputStream in) { 061 super(in); 062 if( !(in instanceof Seekable) || !(in instanceof PositionedReadable) ) { 063 throw new IllegalArgumentException( 064 "In is not an instance of Seekable or PositionedReadable"); 065 } 066 } 067 068 /** 069 * Seek to the given offset. 070 * 071 * @param desired offset to seek to 072 */ 073 @Override 074 public void seek(long desired) throws IOException { 075 ((Seekable)in).seek(desired); 076 } 077 078 /** 079 * Get the current position in the input stream. 080 * 081 * @return current position in the input stream 082 */ 083 @Override 084 public long getPos() throws IOException { 085 return ((Seekable)in).getPos(); 086 } 087 088 /** 089 * Read bytes from the given position in the stream to the given buffer. 090 * 091 * @param position position in the input stream to seek 092 * @param buffer buffer into which data is read 093 * @param offset offset into the buffer in which data is written 094 * @param length maximum number of bytes to read 095 * @return total number of bytes read into the buffer, or <code>-1</code> 096 * if there is no more data because the end of the stream has been 097 * reached 098 */ 099 @Override 100 public int read(long position, byte[] buffer, int offset, int length) 101 throws IOException { 102 return ((PositionedReadable)in).read(position, buffer, offset, length); 103 } 104 105 /** 106 * Read bytes from the given position in the stream to the given buffer. 107 * Continues to read until <code>length</code> bytes have been read. 108 * 109 * @param position position in the input stream to seek 110 * @param buffer buffer into which data is read 111 * @param offset offset into the buffer in which data is written 112 * @param length the number of bytes to read 113 * @throws EOFException If the end of stream is reached while reading. 114 * If an exception is thrown an undetermined number 115 * of bytes in the buffer may have been written. 116 */ 117 @Override 118 public void readFully(long position, byte[] buffer, int offset, int length) 119 throws IOException { 120 ((PositionedReadable)in).readFully(position, buffer, offset, length); 121 } 122 123 /** 124 * See {@link #readFully(long, byte[], int, int)}. 125 */ 126 @Override 127 public void readFully(long position, byte[] buffer) 128 throws IOException { 129 ((PositionedReadable)in).readFully(position, buffer, 0, buffer.length); 130 } 131 132 /** 133 * Seek to the given position on an alternate copy of the data. 134 * 135 * @param targetPos position to seek to 136 * @return true if a new source is found, false otherwise 137 */ 138 @Override 139 public boolean seekToNewSource(long targetPos) throws IOException { 140 return ((Seekable)in).seekToNewSource(targetPos); 141 } 142 143 /** 144 * Get a reference to the wrapped input stream. Used by unit tests. 145 * 146 * @return the underlying input stream 147 */ 148 @InterfaceAudience.LimitedPrivate({"HDFS"}) 149 public InputStream getWrappedStream() { 150 return in; 151 } 152 153 @Override 154 public int read(ByteBuffer buf) throws IOException { 155 if (in instanceof ByteBufferReadable) { 156 return ((ByteBufferReadable)in).read(buf); 157 } 158 159 throw new UnsupportedOperationException("Byte-buffer read unsupported by input stream"); 160 } 161 162 @Override 163 public FileDescriptor getFileDescriptor() throws IOException { 164 if (in instanceof HasFileDescriptor) { 165 return ((HasFileDescriptor) in).getFileDescriptor(); 166 } else if (in instanceof FileInputStream) { 167 return ((FileInputStream) in).getFD(); 168 } else { 169 return null; 170 } 171 } 172 173 @Override 174 public void setReadahead(Long readahead) 175 throws IOException, UnsupportedOperationException { 176 try { 177 ((CanSetReadahead)in).setReadahead(readahead); 178 } catch (ClassCastException e) { 179 throw new UnsupportedOperationException( 180 "this stream does not support setting the readahead " + 181 "caching strategy."); 182 } 183 } 184 185 @Override 186 public void setDropBehind(Boolean dropBehind) 187 throws IOException, UnsupportedOperationException { 188 try { 189 ((CanSetDropBehind)in).setDropBehind(dropBehind); 190 } catch (ClassCastException e) { 191 throw new UnsupportedOperationException("this stream does not " + 192 "support setting the drop-behind caching setting."); 193 } 194 } 195 196 @Override 197 public ByteBuffer read(ByteBufferPool bufferPool, int maxLength, 198 EnumSet<ReadOption> opts) 199 throws IOException, UnsupportedOperationException { 200 try { 201 return ((HasEnhancedByteBufferAccess)in).read(bufferPool, 202 maxLength, opts); 203 } 204 catch (ClassCastException e) { 205 ByteBuffer buffer = ByteBufferUtil. 206 fallbackRead(this, bufferPool, maxLength); 207 if (buffer != null) { 208 extendedReadBuffers.put(buffer, bufferPool); 209 } 210 return buffer; 211 } 212 } 213 214 private static final EnumSet<ReadOption> EMPTY_READ_OPTIONS_SET = 215 EnumSet.noneOf(ReadOption.class); 216 217 final public ByteBuffer read(ByteBufferPool bufferPool, int maxLength) 218 throws IOException, UnsupportedOperationException { 219 return read(bufferPool, maxLength, EMPTY_READ_OPTIONS_SET); 220 } 221 222 @Override 223 public void releaseBuffer(ByteBuffer buffer) { 224 try { 225 ((HasEnhancedByteBufferAccess)in).releaseBuffer(buffer); 226 } 227 catch (ClassCastException e) { 228 ByteBufferPool bufferPool = extendedReadBuffers.remove( buffer); 229 if (bufferPool == null) { 230 throw new IllegalArgumentException("tried to release a buffer " + 231 "that was not created by this stream."); 232 } 233 bufferPool.putBuffer(buffer); 234 } 235 } 236 237 @Override 238 public void unbuffer() { 239 try { 240 ((CanUnbuffer)in).unbuffer(); 241 } catch (ClassCastException e) { 242 throw new UnsupportedOperationException("this stream does not " + 243 "support unbuffering."); 244 } 245 } 246 247 /** 248 * Specifies the kind of advise to provide for this stream and the file 249 * offsets to which they apply. 250 * 251 * The default implementation does nothing. Sub classes can override this 252 * behavior. 253 * 254 * @param type advise type 255 * @param offset starting file offset 256 * @param count number of bytes starting from the offset 257 */ 258 @MapRModified 259 public void adviseFile(FadviseType type, long offset, long count) 260 throws IOException { 261 } 262 263 /** 264 * Returns the file length. 265 * 266 * @return file length 267 */ 268 @MapRModified 269 public long getFileLength() throws IOException { 270 throw new UnsupportedOperationException(); 271 } 272 273 /** 274 * Returns the file id as string. 275 * 276 * @return file id as string 277 */ 278 @MapRModified 279 public String getFidStr() { 280 throw new UnsupportedOperationException(); 281 } 282 283 /** 284 * Returns the server IPs in which the file is stored. Each IP is stored in a 285 * long. For e.g., the first 4 bytes can be used to store the IP in 286 * hexadecimal format and the last 4 bytes to store the port number. 287 * 288 * @return array of server IPs in which the file is stored 289 */ 290 @MapRModified 291 public long[] getFidServers() { 292 throw new UnsupportedOperationException(); 293 } 294 295 /** 296 * Returns the file chunk size. 297 * 298 * @return file chunk size 299 */ 300 @MapRModified 301 public long getChunkSize() { 302 throw new UnsupportedOperationException(); 303 } 304}