001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package org.apache.hadoop.hdfs.server.datanode;
019    
020    
021    import java.io.Closeable;
022    import java.io.File;
023    import java.io.FilterInputStream;
024    import java.io.IOException;
025    import java.io.InputStream;
026    import java.io.OutputStream;
027    import java.util.List;
028    import java.util.Map;
029    
030    import org.apache.hadoop.classification.InterfaceAudience;
031    import org.apache.hadoop.conf.Configuration;
032    import org.apache.hadoop.hdfs.DFSConfigKeys;
033    import org.apache.hadoop.hdfs.protocol.Block;
034    import org.apache.hadoop.hdfs.protocol.BlockListAsLongs;
035    import org.apache.hadoop.hdfs.protocol.BlockLocalPathInfo;
036    import org.apache.hadoop.hdfs.protocol.ExtendedBlock;
037    import org.apache.hadoop.hdfs.server.datanode.metrics.FSDatasetMBean;
038    import org.apache.hadoop.hdfs.server.protocol.BlockRecoveryCommand.RecoveringBlock;
039    import org.apache.hadoop.hdfs.server.protocol.ReplicaRecoveryInfo;
040    import org.apache.hadoop.io.IOUtils;
041    import org.apache.hadoop.util.DataChecksum;
042    import org.apache.hadoop.util.ReflectionUtils;
043    import org.apache.hadoop.util.DiskChecker.DiskErrorException;
044    
045    /**
046     * This is an interface for the underlying storage that stores blocks for
047     * a data node. 
048     * Examples are the FSDataset (which stores blocks on dirs)  and 
049     * SimulatedFSDataset (which simulates data).
050     *
051     */
052    @InterfaceAudience.Private
053    public interface FSDatasetInterface extends FSDatasetMBean {
054      /**
055       * A factory for creating FSDatasetInterface objects.
056       */
057      public abstract class Factory {
058        /** @return the configured factory. */
059        public static Factory getFactory(Configuration conf) {
060          final Class<? extends Factory> clazz = conf.getClass(
061              DFSConfigKeys.DFS_DATANODE_FSDATASET_FACTORY_KEY,
062              FSDataset.Factory.class,
063              Factory.class);
064          return ReflectionUtils.newInstance(clazz, conf);
065        }
066    
067        /** Create a FSDatasetInterface object. */
068        public abstract FSDatasetInterface createFSDatasetInterface(
069            DataNode datanode, DataStorage storage, Configuration conf
070            ) throws IOException;
071    
072        /** Does the factory create simulated objects? */
073        public boolean isSimulated() {
074          return false;
075        }
076      }
077    
078      /**
079       * This is an interface for the underlying volume.
080       * @see org.apache.hadoop.hdfs.server.datanode.FSDataset.FSVolume
081       */
082      interface FSVolumeInterface {
083        /** @return a list of block pools. */
084        public String[] getBlockPoolList();
085    
086        /** @return the available storage space in bytes. */
087        public long getAvailable() throws IOException;
088    
089        /** @return the directory for the block pool. */
090        public File getDirectory(String bpid) throws IOException;
091    
092        /** @return the directory for the finalized blocks in the block pool. */
093        public File getFinalizedDir(String bpid) throws IOException;
094      }
095    
096      /** @return a list of volumes. */
097      public List<FSVolumeInterface> getVolumes();
098    
099      /** @return a volume information map (name => info). */
100      public Map<String, Object> getVolumeInfoMap();
101    
102      /** @return a list of block pools. */
103      public String[] getBlockPoolList();
104    
105      /** @return a list of finalized blocks for the given block pool. */
106      public List<Block> getFinalizedBlocks(String bpid);
107    
108      /**
109       * Check whether the in-memory block record matches the block on the disk,
110       * and, in case that they are not matched, update the record or mark it
111       * as corrupted.
112       */
113      public void checkAndUpdate(String bpid, long blockId, File diskFile,
114          File diskMetaFile, FSVolumeInterface vol);
115    
116      /**
117       * Returns the length of the metadata file of the specified block
118       * @param b - the block for which the metadata length is desired
119       * @return the length of the metadata file for the specified block.
120       * @throws IOException
121       */
122      public long getMetaDataLength(ExtendedBlock b) throws IOException;
123      
124      /**
125       * This class provides the input stream and length of the metadata
126       * of a block
127       *
128       */
129      static class MetaDataInputStream extends FilterInputStream {
130        MetaDataInputStream(InputStream stream, long len) {
131          super(stream);
132          length = len;
133        }
134        private long length;
135        
136        public long getLength() {
137          return length;
138        }
139      }
140      
141      /**
142       * Returns metaData of block b as an input stream (and its length)
143       * @param b - the block
144       * @return the metadata input stream; 
145       * @throws IOException
146       */
147      public MetaDataInputStream getMetaDataInputStream(ExtendedBlock b)
148            throws IOException;
149      
150      /**
151       * Does the meta file exist for this block?
152       * @param b - the block
153       * @return true of the metafile for specified block exits
154       * @throws IOException
155       */
156      public boolean metaFileExists(ExtendedBlock b) throws IOException;
157    
158    
159      /**
160       * Returns the specified block's on-disk length (excluding metadata)
161       * @param b
162       * @return   the specified block's on-disk length (excluding metadta)
163       * @throws IOException
164       */
165      public long getLength(ExtendedBlock b) throws IOException;
166    
167      /**
168       * Get reference to the replica meta info in the replicasMap. 
169       * To be called from methods that are synchronized on {@link FSDataset}
170       * @param blockId
171       * @return replica from the replicas map
172       */
173      @Deprecated
174      public Replica getReplica(String bpid, long blockId);
175    
176      /**
177       * @return replica meta information
178       */
179      public String getReplicaString(String bpid, long blockId);
180    
181      /**
182       * @return the generation stamp stored with the block.
183       */
184      public Block getStoredBlock(String bpid, long blkid)
185          throws IOException;
186    
187      /**
188       * Returns an input stream to read the contents of the specified block
189       * @param b
190       * @return an input stream to read the contents of the specified block
191       * @throws IOException
192       */
193      public InputStream getBlockInputStream(ExtendedBlock b) throws IOException;
194      
195      /**
196       * Returns an input stream at specified offset of the specified block
197       * @param b
198       * @param seekOffset
199       * @return an input stream to read the contents of the specified block,
200       *  starting at the offset
201       * @throws IOException
202       */
203      public InputStream getBlockInputStream(ExtendedBlock b, long seekOffset)
204                throws IOException;
205    
206      /**
207       * Returns an input stream at specified offset of the specified block
208       * The block is still in the tmp directory and is not finalized
209       * @param b
210       * @param blkoff
211       * @param ckoff
212       * @return an input stream to read the contents of the specified block,
213       *  starting at the offset
214       * @throws IOException
215       */
216      public BlockInputStreams getTmpInputStreams(ExtendedBlock b, long blkoff,
217          long ckoff) throws IOException;
218    
219         /**
220          * 
221          * This class contains the output streams for the data and checksum
222          * of a block
223          *
224          */
225         static class BlockWriteStreams {
226          OutputStream dataOut;
227          OutputStream checksumOut;
228          DataChecksum checksum;
229          
230          BlockWriteStreams(OutputStream dOut, OutputStream cOut,
231              DataChecksum checksum) {
232            dataOut = dOut;
233            checksumOut = cOut;
234            this.checksum = checksum;
235          }
236          
237          void close() throws IOException {
238            IOUtils.closeStream(dataOut);
239            IOUtils.closeStream(checksumOut);
240          }
241          
242          DataChecksum getChecksum() {
243            return checksum;
244          }
245        }
246    
247      /**
248       * This class contains the input streams for the data and checksum
249       * of a block
250       */
251      static class BlockInputStreams implements Closeable {
252        final InputStream dataIn;
253        final InputStream checksumIn;
254    
255        BlockInputStreams(InputStream dataIn, InputStream checksumIn) {
256          this.dataIn = dataIn;
257          this.checksumIn = checksumIn;
258        }
259    
260        /** {@inheritDoc} */
261        public void close() {
262          IOUtils.closeStream(dataIn);
263          IOUtils.closeStream(checksumIn);
264        }
265      }
266        
267      /**
268       * Creates a temporary replica and returns the meta information of the replica
269       * 
270       * @param b block
271       * @return the meta info of the replica which is being written to
272       * @throws IOException if an error occurs
273       */
274      public ReplicaInPipelineInterface createTemporary(ExtendedBlock b)
275      throws IOException;
276    
277      /**
278       * Creates a RBW replica and returns the meta info of the replica
279       * 
280       * @param b block
281       * @return the meta info of the replica which is being written to
282       * @throws IOException if an error occurs
283       */
284      public ReplicaInPipelineInterface createRbw(ExtendedBlock b) throws IOException;
285    
286      /**
287       * Recovers a RBW replica and returns the meta info of the replica
288       * 
289       * @param b block
290       * @param newGS the new generation stamp for the replica
291       * @param minBytesRcvd the minimum number of bytes that the replica could have
292       * @param maxBytesRcvd the maximum number of bytes that the replica could have
293       * @return the meta info of the replica which is being written to
294       * @throws IOException if an error occurs
295       */
296      public ReplicaInPipelineInterface recoverRbw(ExtendedBlock b, 
297          long newGS, long minBytesRcvd, long maxBytesRcvd)
298      throws IOException;
299    
300      /**
301       * Covert a temporary replica to a RBW.
302       * @param temporary the temporary replica being converted
303       * @return the result RBW
304       */
305      public ReplicaInPipelineInterface convertTemporaryToRbw(
306          ExtendedBlock temporary) throws IOException;
307    
308      /**
309       * Append to a finalized replica and returns the meta info of the replica
310       * 
311       * @param b block
312       * @param newGS the new generation stamp for the replica
313       * @param expectedBlockLen the number of bytes the replica is expected to have
314       * @return the meata info of the replica which is being written to
315       * @throws IOException
316       */
317      public ReplicaInPipelineInterface append(ExtendedBlock b, 
318          long newGS, long expectedBlockLen) throws IOException;
319    
320      /**
321       * Recover a failed append to a finalized replica
322       * and returns the meta info of the replica
323       * 
324       * @param b block
325       * @param newGS the new generation stamp for the replica
326       * @param expectedBlockLen the number of bytes the replica is expected to have
327       * @return the meta info of the replica which is being written to
328       * @throws IOException
329       */
330      public ReplicaInPipelineInterface recoverAppend(ExtendedBlock b,
331          long newGS, long expectedBlockLen) throws IOException;
332      
333      /**
334       * Recover a failed pipeline close
335       * It bumps the replica's generation stamp and finalize it if RBW replica
336       * 
337       * @param b block
338       * @param newGS the new generation stamp for the replica
339       * @param expectedBlockLen the number of bytes the replica is expected to have
340       * @throws IOException
341       */
342      public void recoverClose(ExtendedBlock b,
343          long newGS, long expectedBlockLen) throws IOException;
344      
345      /**
346       * Finalizes the block previously opened for writing using writeToBlock.
347       * The block size is what is in the parameter b and it must match the amount
348       *  of data written
349       * @param b
350       * @throws IOException
351       */
352      public void finalizeBlock(ExtendedBlock b) throws IOException;
353    
354      /**
355       * Unfinalizes the block previously opened for writing using writeToBlock.
356       * The temporary file associated with this block is deleted.
357       * @param b
358       * @throws IOException
359       */
360      public void unfinalizeBlock(ExtendedBlock b) throws IOException;
361    
362      /**
363       * Returns the block report - the full list of blocks stored under a 
364       * block pool
365       * @param bpid Block Pool Id
366       * @return - the block report - the full list of blocks stored
367       */
368      public BlockListAsLongs getBlockReport(String bpid);
369    
370      /** Does the dataset contain the block? */
371      public boolean contains(ExtendedBlock block);
372    
373      /**
374       * Is the block valid?
375       * @param b
376       * @return - true if the specified block is valid
377       */
378      public boolean isValidBlock(ExtendedBlock b);
379    
380      /**
381       * Is the block a valid RBW?
382       * @param b
383       * @return - true if the specified block is a valid RBW
384       */
385      public boolean isValidRbw(ExtendedBlock b);
386    
387      /**
388       * Invalidates the specified blocks
389       * @param bpid Block pool Id
390       * @param invalidBlks - the blocks to be invalidated
391       * @throws IOException
392       */
393      public void invalidate(String bpid, Block invalidBlks[]) throws IOException;
394    
395        /**
396         * Check if all the data directories are healthy
397         * @throws DiskErrorException
398         */
399      public void checkDataDir() throws DiskErrorException;
400          
401        /**
402         * Stringifies the name of the storage
403         */
404      public String toString();
405      
406      /**
407       * Shutdown the FSDataset
408       */
409      public void shutdown();
410    
411      /**
412       * Sets the file pointer of the checksum stream so that the last checksum
413       * will be overwritten
414       * @param b block
415       * @param stream The stream for the data file and checksum file
416       * @param checksumSize number of bytes each checksum has
417       * @throws IOException
418       */
419      public void adjustCrcChannelPosition(ExtendedBlock b, BlockWriteStreams stream, 
420          int checksumSize) throws IOException;
421    
422      /**
423       * Checks how many valid storage volumes there are in the DataNode.
424       * @return true if more than the minimum number of valid volumes are left 
425       * in the FSDataSet.
426       */
427      public boolean hasEnoughResource();
428    
429      /**
430       * Get visible length of the specified replica.
431       */
432      long getReplicaVisibleLength(final ExtendedBlock block) throws IOException;
433    
434      /**
435       * Initialize a replica recovery.
436       * @return actual state of the replica on this data-node or 
437       * null if data-node does not have the replica.
438       */
439      public ReplicaRecoveryInfo initReplicaRecovery(RecoveringBlock rBlock)
440          throws IOException;
441    
442      /**
443       * Update replica's generation stamp and length and finalize it.
444       */
445      public ReplicaInfo updateReplicaUnderRecovery(
446                                              ExtendedBlock oldBlock,
447                                              long recoveryId,
448                                              long newLength) throws IOException;
449      /**
450       * add new block pool ID
451       * @param bpid Block pool Id
452       * @param conf Configuration
453       */
454      public void addBlockPool(String bpid, Configuration conf) throws IOException;
455      
456      /**
457       * Shutdown and remove the block pool from underlying storage.
458       * @param bpid Block pool Id to be removed
459       */
460      public void shutdownBlockPool(String bpid) ;
461      
462      /**
463       * Deletes the block pool directories. If force is false, directories are 
464       * deleted only if no block files exist for the block pool. If force 
465       * is true entire directory for the blockpool is deleted along with its
466       * contents.
467       * @param bpid BlockPool Id to be deleted.
468       * @param force If force is false, directories are deleted only if no
469       *        block files exist for the block pool, otherwise entire 
470       *        directory for the blockpool is deleted along with its contents.
471       * @throws IOException
472       */
473      public void deleteBlockPool(String bpid, boolean force) throws IOException;
474      
475      /**
476       * Get {@link BlockLocalPathInfo} for the given block.
477       **/
478      public BlockLocalPathInfo getBlockLocalPathInfo(ExtendedBlock b) throws IOException;
479    }