View Javadoc

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  
19  package org.apache.hadoop.hbase.util;
20  
21  import java.io.FileNotFoundException;
22  import java.io.IOException;
23  import java.io.InterruptedIOException;
24  import java.lang.reflect.InvocationTargetException;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.conf.Configuration;
29  import org.apache.hadoop.fs.FSDataOutputStream;
30  import org.apache.hadoop.fs.FileSystem;
31  import org.apache.hadoop.fs.Path;
32  import org.apache.hadoop.hbase.RemoteExceptionHandler;
33  import org.apache.hadoop.hdfs.DistributedFileSystem;
34  import org.apache.hadoop.hdfs.protocol.AlreadyBeingCreatedException;
35  import org.apache.hadoop.hdfs.server.namenode.LeaseExpiredException;
36  
37  
38  /**
39   * Implementation for hdfs
40   */
41  public class FSHDFSUtils extends FSUtils{
42    private static final Log LOG = LogFactory.getLog(FSHDFSUtils.class);
43  
44    /**
45     * Lease timeout constant, sourced from HDFS upstream.
46     * The upstream constant is defined in a private interface, so we
47     * can't reuse for compatibility reasons.
48     * NOTE: On versions earlier than Hadoop 0.23, the constant is in
49     * o.a.h.hdfs.protocol.FSConstants, while for 0.23 and above it is
50     * in o.a.h.hdfs.protocol.HdfsConstants cause of HDFS-1620.
51     */
52    public static final long LEASE_SOFTLIMIT_PERIOD = 60 * 1000;
53  
54    @Override
55    public void recoverFileLease(final FileSystem fs, final Path p, Configuration conf)
56    throws IOException{
57      if (!isAppendSupported(conf)) {
58        LOG.warn("Running on HDFS without append enabled may result in data loss");
59        return;
60      }
61      // lease recovery not needed for local file system case.
62      // currently, local file system doesn't implement append either.
63      if (!(fs instanceof DistributedFileSystem)) {
64        return;
65      }
66      LOG.info("Recovering file " + p);
67      long startWaiting = System.currentTimeMillis();
68  
69      // Trying recovery
70      boolean recovered = false;
71      while (!recovered) {
72        try {
73          try {
74            if (fs instanceof DistributedFileSystem) {
75              DistributedFileSystem dfs = (DistributedFileSystem)fs;
76              DistributedFileSystem.class.getMethod("recoverLease",
77                new Class[] {Path.class}).invoke(dfs, p);
78            } else {
79              throw new Exception("Not a DistributedFileSystem");
80            }
81          } catch (InvocationTargetException ite) {
82            // function was properly called, but threw it's own exception
83            throw (IOException) ite.getCause();
84          } catch (Exception e) {
85            LOG.debug("Failed fs.recoverLease invocation, " + e.toString() +
86              ", trying fs.append instead");
87            FSDataOutputStream out = fs.append(p);
88            out.close();
89          }
90          recovered = true;
91        } catch (IOException e) {
92          e = RemoteExceptionHandler.checkIOException(e);
93          if (e instanceof AlreadyBeingCreatedException) {
94            // We expect that we'll get this message while the lease is still
95            // within its soft limit, but if we get it past that, it means
96            // that the RS is holding onto the file even though it lost its
97            // znode. We could potentially abort after some time here.
98            long waitedFor = System.currentTimeMillis() - startWaiting;
99            if (waitedFor > LEASE_SOFTLIMIT_PERIOD) {
100             LOG.warn("Waited " + waitedFor + "ms for lease recovery on " + p +
101               ":" + e.getMessage());
102           }
103         } else if (e instanceof LeaseExpiredException &&
104             e.getMessage().contains("File does not exist")) {
105           // This exception comes out instead of FNFE, fix it
106           throw new FileNotFoundException(
107               "The given HLog wasn't found at " + p.toString());
108         } else {
109           throw new IOException("Failed to open " + p + " for append", e);
110         }
111       }
112       try {
113         Thread.sleep(1000);
114       } catch (InterruptedException ex) {
115         InterruptedIOException iioe = new InterruptedIOException();
116         iioe.initCause(ex);
117         throw iioe;
118       }
119     }
120     LOG.info("Finished lease recover attempt for " + p);
121   }
122 }