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