/** * Copyright 2009 The Apache Software Foundation 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.transactional; import java.io.IOException; import java.util.List; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.regionserver.transactional.TransactionState.WriteAction; import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogReader; import org.apache.hadoop.hbase.regionserver.wal.SequenceFileLogWriter; import org.apache.hadoop.hbase.regionserver.wal.WALActionsListener; import org.apache.hadoop.hbase.regionserver.wal.WALEdit; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; /** * Add support for transactional operations to the regionserver's * write-ahead-log. */ public class THLog extends HLog { static final String THLOG_DATFILE = "thlog.dat."; /** Name of old log file for reconstruction */ static final String HREGION_OLD_THLOGFILE_NAME = "oldthlogfile.log"; public THLog(final FileSystem fs, final Path dir, final Path oldLogDir, final Configuration conf, final List<WALActionsListener> listeners) throws IOException { super(fs, dir, oldLogDir, conf, listeners, false, null); } /** * Get a writer for the WAL. * * @param path * @param conf * @return A WAL writer. Close when done with it. * @throws IOException */ public static Writer createWriter(final FileSystem fs, final Path path, final Configuration conf) throws IOException { try { HLog.Writer writer = new SequenceFileLogWriter(THLogKey.class); writer.init(fs, path, conf); return writer; } catch (Exception e) { IOException ie = new IOException("cannot get log writer"); ie.initCause(e); throw ie; } } @Override protected Writer createWriterInstance(final FileSystem fs, final Path path, final Configuration conf) throws IOException { return createWriter(fs, path, conf); } /** * This is a convenience method that computes a new filename with a given * file-number. * * @param fn * @return Path */ @Override protected Path computeFilename() { // REVIEW : Use prefix ? return new Path(getDir(), THLOG_DATFILE + getFilenum()); } /** * Get a reader for the WAL. * * @param fs * @param path * @param conf * @return A WAL reader. Close when done with it. * @throws IOException */ public static Reader getReader(final FileSystem fs, final Path path, final Configuration conf) throws IOException { try { HLog.Reader reader = new SequenceFileLogReader(THLogKey.class); reader.init(fs, path, conf); return reader; } catch (Exception e) { IOException ie = new IOException("cannot get log reader"); ie.initCause(e); throw ie; } } protected THLogKey makeKey(final byte[] regionName, final byte[] tableName, final long seqnum, final long now) { return new THLogKey(regionName, tableName, seqnum, now, null, -1); } /** * Write a transactional state to the log after we have decide that it can * be committed. At this time we are still waiting for the final vote (from * other regions), so the commit may not be processed. */ public void writeCommitResuestToLog(final HRegionInfo regionInfo, final TransactionState transactionState) throws IOException { this.appendCommitRequest(regionInfo, EnvironmentEdgeManager.currentTimeMillis(), transactionState); } /** * @param regionInfo * @param transactionId * @throws IOException */ public void writeCommitToLog(final HRegionInfo regionInfo, final long transactionId) throws IOException { this.append(regionInfo, EnvironmentEdgeManager.currentTimeMillis(), THLogKey.TrxOp.COMMIT, transactionId); } /** * @param regionInfo * @param transactionId * @throws IOException */ public void writeAbortToLog(final HRegionInfo regionInfo, final long transactionId) throws IOException { this.append(regionInfo, EnvironmentEdgeManager.currentTimeMillis(), THLogKey.TrxOp.ABORT, transactionId); } /** * Write a general transaction op to the log. This covers: start, commit, * and abort. * * @param regionInfo * @param now * @param txOp * @param transactionId * @throws IOException */ private void append(final HRegionInfo regionInfo, final long now, final THLogKey.TrxOp txOp, final long transactionId) throws IOException { @SuppressWarnings("deprecation") THLogKey key = new THLogKey(regionInfo.getRegionName(), regionInfo .getTableDesc().getName(), -1, now, txOp, transactionId); WALEdit e = new WALEdit(); e.add(new KeyValue(new byte[0], 0, 0)); // Empty KeyValue super.append(regionInfo, key, e, null, false); } /** * Write a transactional state to the log for a commit request. * * @param regionInfo * @param update * @param transactionId * @throws IOException */ private void appendCommitRequest(final HRegionInfo regionInfo, final long now, final TransactionState transactionState) throws IOException { @SuppressWarnings("deprecation") THLogKey key = new THLogKey(regionInfo.getRegionName(), regionInfo .getTableDesc().getName(), -1, now, THLogKey.TrxOp.COMMIT_REQUEST, transactionState.getTransactionId()); WALEdit e = new WALEdit(); for (WriteAction write : transactionState.getWriteOrdering()) { for (KeyValue value : write.getKeyValues()) { e.add(value); } } super.append(regionInfo, key, e, null, false); } }