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 */
018package org.apache.hadoop.hbase.regionserver.wal;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertNull;
022
023import java.io.IOException;
024
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.fs.FileSystem;
027import org.apache.hadoop.fs.Path;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.client.Durability;
032import org.apache.hadoop.hbase.client.Put;
033import org.apache.hadoop.hbase.regionserver.ChunkCreator;
034import org.apache.hadoop.hbase.regionserver.HRegion;
035import org.apache.hadoop.hbase.regionserver.MemStoreLABImpl;
036import org.apache.hadoop.hbase.testclassification.MediumTests;
037import org.apache.hadoop.hbase.util.Bytes;
038import org.apache.hadoop.hbase.wal.WAL;
039import org.junit.Before;
040import org.junit.ClassRule;
041import org.junit.Rule;
042import org.junit.Test;
043import org.junit.experimental.categories.Category;
044import org.junit.rules.TestName;
045
046/**
047 * Tests for WAL write durability - hflush vs hsync
048 */
049@Category({ MediumTests.class })
050public class TestWALDurability {
051
052  @ClassRule
053  public static final HBaseClassTestRule CLASS_RULE =
054      HBaseClassTestRule.forClass(TestWALDurability.class);
055
056  private static final String COLUMN_FAMILY = "MyCF";
057  private static final byte[] COLUMN_FAMILY_BYTES = Bytes.toBytes(COLUMN_FAMILY);
058
059  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
060  private Configuration conf;
061  private String dir;
062  @Rule
063  public TestName name = new TestName();
064
065  // Test names
066  protected TableName tableName;
067
068  @Before
069  public void setup() throws IOException {
070    conf = TEST_UTIL.getConfiguration();
071    dir = TEST_UTIL.getDataTestDir("TestHRegion").toString();
072    tableName = TableName.valueOf(name.getMethodName());
073  }
074
075  @Test
076  public void testWALDurability() throws IOException {
077    class CustomFSLog extends FSHLog {
078      private Boolean syncFlag;
079
080      public CustomFSLog(FileSystem fs, Path root, String logDir, Configuration conf)
081          throws IOException {
082        super(fs, root, logDir, conf);
083      }
084
085      @Override
086      public void sync(boolean forceSync) throws IOException {
087        syncFlag = forceSync;
088        super.sync(forceSync);
089      }
090
091      @Override
092      public void sync(long txid, boolean forceSync) throws IOException {
093        syncFlag = forceSync;
094        super.sync(txid, forceSync);
095      }
096
097      private void resetSyncFlag() {
098        this.syncFlag = null;
099      }
100
101    }
102    // global hbase.wal.hsync false, no override in put call - hflush
103    conf.set(HRegion.WAL_HSYNC_CONF_KEY, "false");
104    FileSystem fs = FileSystem.get(conf);
105    Path rootDir = new Path(dir + getName());
106    CustomFSLog customFSLog = new CustomFSLog(fs, rootDir, getName(), conf);
107    HRegion region = initHRegion(tableName, null, null, customFSLog);
108    byte[] bytes = Bytes.toBytes(getName());
109    Put put = new Put(bytes);
110    put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("1"), bytes);
111
112    customFSLog.resetSyncFlag();
113    assertNull(customFSLog.syncFlag);
114    region.put(put);
115    assertEquals(customFSLog.syncFlag, false);
116
117    // global hbase.wal.hsync true, no override in put call
118    conf.set(HRegion.WAL_HSYNC_CONF_KEY, "true");
119    fs = FileSystem.get(conf);
120    customFSLog = new CustomFSLog(fs, rootDir, getName(), conf);
121    region = initHRegion(tableName, null, null, customFSLog);
122
123    customFSLog.resetSyncFlag();
124    assertNull(customFSLog.syncFlag);
125    region.put(put);
126    assertEquals(customFSLog.syncFlag, true);
127
128    // global hbase.wal.hsync true, durability set in put call - fsync
129    put.setDurability(Durability.FSYNC_WAL);
130    customFSLog.resetSyncFlag();
131    assertNull(customFSLog.syncFlag);
132    region.put(put);
133    assertEquals(customFSLog.syncFlag, true);
134
135    // global hbase.wal.hsync true, durability set in put call - sync
136    put = new Put(bytes);
137    put.addColumn(COLUMN_FAMILY_BYTES, Bytes.toBytes("1"), bytes);
138    put.setDurability(Durability.SYNC_WAL);
139    customFSLog.resetSyncFlag();
140    assertNull(customFSLog.syncFlag);
141    region.put(put);
142    assertEquals(customFSLog.syncFlag, false);
143
144    HBaseTestingUtility.closeRegionAndWAL(region);
145  }
146
147  private String getName() {
148    return name.getMethodName();
149  }
150
151  /**
152   * @return A region on which you must call {@link HBaseTestingUtility#closeRegionAndWAL(HRegion)}
153   *         when done.
154   */
155  public static HRegion initHRegion(TableName tableName, byte[] startKey, byte[] stopKey, WAL wal)
156      throws IOException {
157    ChunkCreator.initialize(MemStoreLABImpl.CHUNK_SIZE_DEFAULT, false, 0, 0, 0, null);
158    return TEST_UTIL.createLocalHRegion(tableName, startKey, stopKey, false, Durability.USE_DEFAULT,
159      wal, COLUMN_FAMILY_BYTES);
160  }
161}