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, Closeable, 038 ByteBufferReadable, HasFileDescriptor, CanSetDropBehind, CanSetReadahead, 039 HasEnhancedByteBufferAccess { 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 throws IOException { 062 super(in); 063 if( !(in instanceof Seekable) || !(in instanceof PositionedReadable) ) { 064 throw new IllegalArgumentException( 065 "In is not an instance of Seekable or PositionedReadable"); 066 } 067 } 068 069 /** 070 * Seek to the given offset. 071 * 072 * @param desired offset to seek to 073 */ 074 @Override 075 public synchronized void seek(long desired) throws IOException { 076 ((Seekable)in).seek(desired); 077 } 078 079 /** 080 * Get the current position in the input stream. 081 * 082 * @return current position in the input stream 083 */ 084 @Override 085 public long getPos() throws IOException { 086 return ((Seekable)in).getPos(); 087 } 088 089 /** 090 * Read bytes from the given position in the stream to the given buffer. 091 * 092 * @param position position in the input stream to seek 093 * @param buffer buffer into which data is read 094 * @param offset offset into the buffer in which data is written 095 * @param length maximum number of bytes to read 096 * @return total number of bytes read into the buffer, or <code>-1</code> 097 * if there is no more data because the end of the stream has been 098 * reached 099 */ 100 @Override 101 public int read(long position, byte[] buffer, int offset, int length) 102 throws IOException { 103 return ((PositionedReadable)in).read(position, buffer, offset, length); 104 } 105 106 /** 107 * Read bytes from the given position in the stream to the given buffer. 108 * Continues to read until <code>length</code> bytes have been read. 109 * 110 * @param position position in the input stream to seek 111 * @param buffer buffer into which data is read 112 * @param offset offset into the buffer in which data is written 113 * @param length the number of bytes to read 114 * @throws EOFException If the end of stream is reached while reading. 115 * If an exception is thrown an undetermined number 116 * of bytes in the buffer may have been written. 117 */ 118 @Override 119 public void readFully(long position, byte[] buffer, int offset, int length) 120 throws IOException { 121 ((PositionedReadable)in).readFully(position, buffer, offset, length); 122 } 123 124 /** 125 * See {@link #readFully(long, byte[], int, int)}. 126 */ 127 @Override 128 public void readFully(long position, byte[] buffer) 129 throws IOException { 130 ((PositionedReadable)in).readFully(position, buffer, 0, buffer.length); 131 } 132 133 /** 134 * Seek to the given position on an alternate copy of the data. 135 * 136 * @param targetPos position to seek to 137 * @return true if a new source is found, false otherwise 138 */ 139 @Override 140 public boolean seekToNewSource(long targetPos) throws IOException { 141 return ((Seekable)in).seekToNewSource(targetPos); 142 } 143 144 /** 145 * Get a reference to the wrapped input stream. Used by unit tests. 146 * 147 * @return the underlying input stream 148 */ 149 @InterfaceAudience.LimitedPrivate({"HDFS"}) 150 public InputStream getWrappedStream() { 151 return in; 152 } 153 154 @Override 155 public int read(ByteBuffer buf) throws IOException { 156 if (in instanceof ByteBufferReadable) { 157 return ((ByteBufferReadable)in).read(buf); 158 } 159 160 throw new UnsupportedOperationException("Byte-buffer read unsupported by input stream"); 161 } 162 163 @Override 164 public FileDescriptor getFileDescriptor() throws IOException { 165 if (in instanceof HasFileDescriptor) { 166 return ((HasFileDescriptor) in).getFileDescriptor(); 167 } else if (in instanceof FileInputStream) { 168 return ((FileInputStream) in).getFD(); 169 } else { 170 return null; 171 } 172 } 173 174 @Override 175 public void setReadahead(Long readahead) 176 throws IOException, UnsupportedOperationException { 177 try { 178 ((CanSetReadahead)in).setReadahead(readahead); 179 } catch (ClassCastException e) { 180 throw new UnsupportedOperationException( 181 "this stream does not support setting the readahead " + 182 "caching strategy."); 183 } 184 } 185 186 @Override 187 public void setDropBehind(Boolean dropBehind) 188 throws IOException, UnsupportedOperationException { 189 try { 190 ((CanSetDropBehind)in).setDropBehind(dropBehind); 191 } catch (ClassCastException e) { 192 throw new UnsupportedOperationException("this stream does not " + 193 "support setting the drop-behind caching setting."); 194 } 195 } 196 197 @Override 198 public ByteBuffer read(ByteBufferPool bufferPool, int maxLength, 199 EnumSet<ReadOption> opts) 200 throws IOException, UnsupportedOperationException { 201 try { 202 return ((HasEnhancedByteBufferAccess)in).read(bufferPool, 203 maxLength, opts); 204 } 205 catch (ClassCastException e) { 206 ByteBuffer buffer = ByteBufferUtil. 207 fallbackRead(this, bufferPool, maxLength); 208 if (buffer != null) { 209 extendedReadBuffers.put(buffer, bufferPool); 210 } 211 return buffer; 212 } 213 } 214 215 private static final EnumSet<ReadOption> EMPTY_READ_OPTIONS_SET = 216 EnumSet.noneOf(ReadOption.class); 217 218 final public ByteBuffer read(ByteBufferPool bufferPool, int maxLength) 219 throws IOException, UnsupportedOperationException { 220 return read(bufferPool, maxLength, EMPTY_READ_OPTIONS_SET); 221 } 222 223 @Override 224 public void releaseBuffer(ByteBuffer buffer) { 225 try { 226 ((HasEnhancedByteBufferAccess)in).releaseBuffer(buffer); 227 } 228 catch (ClassCastException e) { 229 ByteBufferPool bufferPool = extendedReadBuffers.remove( buffer); 230 if (bufferPool == null) { 231 throw new IllegalArgumentException("tried to release a buffer " + 232 "that was not created by this stream."); 233 } 234 bufferPool.putBuffer(buffer); 235 } 236 } 237 238 /** 239 * Specifies the kind of advise to provide for this stream and the file 240 * offsets to which they apply. 241 * 242 * The default implementation does nothing. Sub classes can override this 243 * behavior. 244 * 245 * @param type advise type 246 * @param offset starting file offset 247 * @param count number of bytes starting from the offset 248 */ 249 @MapRModified 250 public void adviseFile(FadviseType type, long offset, long count) 251 throws IOException { 252 } 253 254 /** 255 * Returns the file length. 256 * 257 * @return file length 258 */ 259 @MapRModified 260 public long getFileLength() throws IOException { 261 throw new UnsupportedOperationException(); 262 } 263 264 /** 265 * Returns the file id as string. 266 * 267 * @return file id as string 268 */ 269 @MapRModified 270 public String getFidStr() { 271 throw new UnsupportedOperationException(); 272 } 273 274 /** 275 * Returns the server IPs in which the file is stored. Each IP is stored in a 276 * long. For e.g., the first 4 bytes can be used to store the IP in 277 * hexadecimal format and the last 4 bytes to store the port number. 278 * 279 * @return array of server IPs in which the file is stored 280 */ 281 @MapRModified 282 public long[] getFidServers() { 283 throw new UnsupportedOperationException(); 284 } 285 286 /** 287 * Returns the file chunk size. 288 * 289 * @return file chunk size 290 */ 291 @MapRModified 292 public long getChunkSize() { 293 throw new UnsupportedOperationException(); 294 } 295}