org.apache.hadoop.hbase.regionserver.wal.HLogFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.regionserver.wal.HLogFactory.java

Source

/**
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.hadoop.hbase.regionserver.wal;

import java.io.IOException;
import java.util.Arrays;
import java.io.InterruptedIOException;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.regionserver.wal.HLog.Reader;
import org.apache.hadoop.hbase.regionserver.wal.HLog.Writer;
import org.apache.hadoop.hbase.util.CancelableProgressable;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;

public class HLogFactory {
    private static final Log LOG = LogFactory.getLog(HLogFactory.class);

    public static HLog createHLog(final FileSystem fs, final Path root, final String logName,
            final Configuration conf) throws IOException {
        return new FSHLog(fs, root, logName, conf);
    }

    public static HLog createHLog(final FileSystem fs, final Path root, final String logName,
            final String oldLogName, final Configuration conf) throws IOException {
        return new FSHLog(fs, root, logName, oldLogName, conf, null, true, null, false);
    }

    public static HLog createHLog(final FileSystem fs, final Path root, final String logName,
            final Configuration conf, final List<WALActionsListener> listeners, final String prefix)
            throws IOException {
        return new FSHLog(fs, root, logName, HConstants.HREGION_OLDLOGDIR_NAME, conf, listeners, true, prefix,
                false);
    }

    public static HLog createMetaHLog(final FileSystem fs, final Path root, final String logName,
            final Configuration conf, final List<WALActionsListener> listeners, final String prefix)
            throws IOException {
        return new FSHLog(fs, root, logName, HConstants.HREGION_OLDLOGDIR_NAME, conf, listeners, false, prefix,
                true);
    }

    /*
     * WAL Reader
     */
    private static Class<? extends Reader> logReaderClass;

    static void resetLogReaderClass() {
        logReaderClass = null;
    }

    public static HLog.Reader createReader(final FileSystem fs, final Path path, Configuration conf)
            throws IOException {
        return createReader(fs, path, conf, null);
    }

    /**
     * Create a reader for the WAL. If you are reading from a file that's being written to
     * and need to reopen it multiple times, use {@link HLog.Reader#reset()} instead of this method
     * then just seek back to the last known good position.
     * @return A WAL reader.  Close when done with it.
     * @throws IOException
     */
    public static HLog.Reader createReader(final FileSystem fs, final Path path, Configuration conf,
            CancelableProgressable reporter) throws IOException {
        return createReader(fs, path, conf, reporter, true);
    }

    public static HLog.Reader createReader(final FileSystem fs, final Path path, Configuration conf,
            CancelableProgressable reporter, boolean allowCustom) throws IOException {
        if (allowCustom && (logReaderClass == null)) {
            logReaderClass = conf.getClass("hbase.regionserver.hlog.reader.impl", ProtobufLogReader.class,
                    Reader.class);
        }
        Class<? extends Reader> lrClass = allowCustom ? logReaderClass : ProtobufLogReader.class;

        try {
            // A hlog file could be under recovery, so it may take several
            // tries to get it open. Instead of claiming it is corrupted, retry
            // to open it up to 5 minutes by default.
            long startWaiting = EnvironmentEdgeManager.currentTimeMillis();
            long openTimeout = conf.getInt("hbase.hlog.open.timeout", 300000) + startWaiting;
            int nbAttempt = 0;
            while (true) {
                try {
                    if (lrClass != ProtobufLogReader.class) {
                        // User is overriding the WAL reader, let them.
                        HLog.Reader reader = lrClass.newInstance();
                        reader.init(fs, path, conf, null);
                        return reader;
                    } else {
                        FSDataInputStream stream = fs.open(path);
                        // Note that zero-length file will fail to read PB magic, and attempt to create
                        // a non-PB reader and fail the same way existing code expects it to. If we get
                        // rid of the old reader entirely, we need to handle 0-size files differently from
                        // merely non-PB files.
                        byte[] magic = new byte[ProtobufLogReader.PB_WAL_MAGIC.length];
                        boolean isPbWal = (stream.read(magic) == magic.length)
                                && Arrays.equals(magic, ProtobufLogReader.PB_WAL_MAGIC);
                        HLog.Reader reader = isPbWal ? new ProtobufLogReader() : new SequenceFileLogReader();
                        reader.init(fs, path, conf, stream);
                        return reader;
                    }
                } catch (IOException e) {
                    String msg = e.getMessage();
                    if (msg != null && (msg.contains("Cannot obtain block length")
                            || msg.contains("Could not obtain the last block")
                            || msg.matches("Blocklist for [^ ]* has changed.*"))) {
                        if (++nbAttempt == 1) {
                            LOG.warn("Lease should have recovered. This is not expected. Will retry", e);
                        }
                        if (reporter != null && !reporter.progress()) {
                            throw new InterruptedIOException("Operation is cancelled");
                        }
                        if (nbAttempt > 2 && openTimeout < EnvironmentEdgeManager.currentTimeMillis()) {
                            LOG.error("Can't open after " + nbAttempt + " attempts and "
                                    + (EnvironmentEdgeManager.currentTimeMillis() - startWaiting) + "ms " + " for "
                                    + path);
                        } else {
                            try {
                                Thread.sleep(nbAttempt < 3 ? 500 : 1000);
                                continue; // retry
                            } catch (InterruptedException ie) {
                                InterruptedIOException iioe = new InterruptedIOException();
                                iioe.initCause(ie);
                                throw iioe;
                            }
                        }
                    }
                    throw e;
                }
            }
        } catch (IOException ie) {
            throw ie;
        } catch (Exception e) {
            throw new IOException("Cannot get log reader", e);
        }
    }

    /*
     * WAL writer
     */
    private static Class<? extends Writer> logWriterClass;

    /**
     * Create a writer for the WAL.
     * @return A WAL writer.  Close when done with it.
     * @throws IOException
     */
    public static HLog.Writer createWALWriter(final FileSystem fs, final Path path, Configuration conf)
            throws IOException {
        return createWriter(fs, path, conf, false);
    }

    public static HLog.Writer createRecoveredEditsWriter(final FileSystem fs, final Path path, Configuration conf)
            throws IOException {
        return createWriter(fs, path, conf, true);
    }

    private static HLog.Writer createWriter(final FileSystem fs, final Path path, Configuration conf,
            boolean overwritable) throws IOException {
        try {
            if (logWriterClass == null) {
                logWriterClass = conf.getClass("hbase.regionserver.hlog.writer.impl", ProtobufLogWriter.class,
                        Writer.class);
            }
            HLog.Writer writer = (HLog.Writer) logWriterClass.newInstance();
            writer.init(fs, path, conf, overwritable);
            return writer;
        } catch (Exception e) {
            throw new IOException("cannot get log writer", e);
        }
    }
}