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    public void recoverFileLease(final FileSystem fs, final Path p, Configuration conf)
55    throws IOException{
56      if (!isAppendSupported(conf)) {
57        LOG.warn("Running on HDFS without append enabled may result in data loss");
58        return;
59      }
60      // lease recovery not needed for local file system case.
61      // currently, local file system doesn't implement append either.
62      if (!(fs instanceof DistributedFileSystem)) {
63        return;
64      }
65      LOG.info("Recovering file " + p);
66      long startWaiting = System.currentTimeMillis();
67  
68      // Trying recovery
69      boolean recovered = false;
70      while (!recovered) {
71        try {
72          try {
73            if (fs instanceof DistributedFileSystem) {
74              DistributedFileSystem dfs = (DistributedFileSystem)fs;
75              DistributedFileSystem.class.getMethod("recoverLease",
76                new Class[] {Path.class}).invoke(dfs, p);
77            } else {
78              throw new Exception("Not a DistributedFileSystem");
79            }
80          } catch (InvocationTargetException ite) {
81            // function was properly called, but threw it's own exception
82            throw (IOException) ite.getCause();
83          } catch (Exception e) {
84            LOG.debug("Failed fs.recoverLease invocation, " + e.toString() +
85              ", trying fs.append instead");
86            FSDataOutputStream out = fs.append(p);
87            out.close();
88          }
89          recovered = true;
90        } catch (IOException e) {
91          e = RemoteExceptionHandler.checkIOException(e);
92          if (e instanceof AlreadyBeingCreatedException) {
93            // We expect that we'll get this message while the lease is still
94            // within its soft limit, but if we get it past that, it means
95            // that the RS is holding onto the file even though it lost its
96            // znode. We could potentially abort after some time here.
97            long waitedFor = System.currentTimeMillis() - startWaiting;
98            if (waitedFor > LEASE_SOFTLIMIT_PERIOD) {
99              LOG.warn("Waited " + waitedFor + "ms for lease recovery on " + p +
100               ":" + e.getMessage());
101           }
102         } else if (e instanceof LeaseExpiredException &&
103             e.getMessage().contains("File does not exist")) {
104           // This exception comes out instead of FNFE, fix it
105           throw new FileNotFoundException(
106               "The given HLog wasn't found at " + p.toString());
107         } else {
108           throw new IOException("Failed to open " + p + " for append", e);
109         }
110       }
111       try {
112         Thread.sleep(1000);
113       } catch (InterruptedException ex) {
114         new InterruptedIOException().initCause(ex);
115       }
116     }
117     LOG.info("Finished lease recover attempt for " + p);
118   }
119 }