HBASE-4744 enable test that log roll fails after split start.

Note that this changes testLogRollAfterSplitStart from a Large
test to a Medium test.

FSHLog changes:
* make logging in replaceWriter handle null newPath
* clean up javadoc for replaceWriter

TestHLogSplit changes:

* removed testLogRollAfterSplitStart

TestLogRollAbort

* added testLogRollAfterSplitStart
* remove @Ignore, add debug messages about test progress
* clean up check for proper failure from log roll
This commit is contained in:
Sean Busbey 2014-07-29 10:18:20 -05:00 committed by stack
parent aba9f5a7f4
commit aca2462ce3
3 changed files with 104 additions and 74 deletions

View File

@ -823,14 +823,21 @@ class FSHLog implements HLog, Syncable {
/**
* Cleans up current writer closing it and then puts in place the passed in
* <code>nextWriter</code>
* <code>nextWriter</code>.
*
* @param oldPath
* @param newPath
* @param nextWriter
* @param nextHdfsOut
* @return <code>newPath</code>
* @throws IOException
* In the case of creating a new WAL, oldPath will be null.
*
* In the case of rolling over from one file to the next, none of the params will be null.
*
* In the case of closing out this FSHLog with no further use newPath, nextWriter, and
* nextHdfsOut will be null.
*
* @param oldPath may be null
* @param newPath may be null
* @param nextWriter may be null
* @param nextHdfsOut may be null
* @return the passed in <code>newPath</code>
* @throws IOException if there is a problem flushing or closing the underlying FS
*/
Path replaceWriter(final Path oldPath, final Path newPath, FSHLog.Writer nextWriter,
final FSDataOutputStream nextHdfsOut)
@ -885,6 +892,7 @@ class FSHLog implements HLog, Syncable {
this.hdfs_out = nextHdfsOut;
int oldNumEntries = this.numEntries.get();
this.numEntries.set(0);
final String newPathString = (null == newPath ? null : FSUtils.getPath(newPath));
if (oldPath != null) {
this.byWalRegionSequenceIds.put(oldPath, this.highestRegionSequenceIds);
this.highestRegionSequenceIds = new HashMap<byte[], Long>();
@ -892,9 +900,9 @@ class FSHLog implements HLog, Syncable {
this.totalLogSize.addAndGet(oldFileLen);
LOG.info("Rolled WAL " + FSUtils.getPath(oldPath) + " with entries=" + oldNumEntries +
", filesize=" + StringUtils.byteDesc(oldFileLen) + "; new WAL " +
FSUtils.getPath(newPath));
newPathString);
} else {
LOG.info("New WAL " + FSUtils.getPath(newPath));
LOG.info("New WAL " + newPathString);
}
} catch (InterruptedException ie) {
// Perpetuate the interrupt

View File

@ -1072,70 +1072,6 @@ public class TestHLogSplit {
assertEquals(regions.size(), outputCounts.size());
}
// HBASE-2312: tests the case where a RegionServer enters a GC pause,
// comes back online after the master declared it dead and started to split.
// Want log rolling after a master split to fail
@Test (timeout=300000)
@Ignore("Need HADOOP-6886, HADOOP-6840, & HDFS-617 for this. HDFS 0.20.205.1+ should have this")
public void testLogRollAfterSplitStart() throws IOException {
HLog log = null;
String logName = "testLogRollAfterSplitStart";
Path thisTestsDir = new Path(HBASEDIR, logName);
try {
// put some entries in an HLog
TableName tableName =
TableName.valueOf(this.getClass().getName());
HRegionInfo regioninfo = new HRegionInfo(tableName,
HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
log = HLogFactory.createHLog(fs, HBASEDIR, logName, conf);
final AtomicLong sequenceId = new AtomicLong(1);
final int total = 20;
for (int i = 0; i < total; i++) {
WALEdit kvs = new WALEdit();
kvs.add(new KeyValue(Bytes.toBytes(i), tableName.getName(), tableName.getName()));
HTableDescriptor htd = new HTableDescriptor(tableName);
htd.addFamily(new HColumnDescriptor("column"));
log.append(regioninfo, tableName, kvs, System.currentTimeMillis(), htd, sequenceId);
}
// Send the data to HDFS datanodes and close the HDFS writer
log.sync();
((FSHLog) log).replaceWriter(((FSHLog)log).getOldPath(), null, null, null);
/* code taken from ProcessServerShutdown.process()
* handles RS shutdowns (as observed by the Master)
*/
// rename the directory so a rogue RS doesn't create more HLogs
Path rsSplitDir = new Path(thisTestsDir.getParent(),
thisTestsDir.getName() + "-splitting");
fs.rename(thisTestsDir, rsSplitDir);
LOG.debug("Renamed region directory: " + rsSplitDir);
// Process the old log files
HLogSplitter.split(HBASEDIR, rsSplitDir, OLDLOGDIR, fs, conf);
// Now, try to roll the HLog and verify failure
try {
log.rollWriter();
Assert.fail("rollWriter() did not throw any exception.");
} catch (IOException ioe) {
if (ioe.getCause().getMessage().contains("FileNotFound")) {
LOG.info("Got the expected exception: ", ioe.getCause());
} else {
Assert.fail("Unexpected exception: " + ioe);
}
}
} finally {
if (log != null) {
log.close();
}
if (fs.exists(thisTestsDir)) {
fs.delete(thisTestsDir, true);
}
}
}
/**
* This thread will keep adding new log files
* It simulates a region server that was considered dead but woke up and wrote

View File

@ -17,14 +17,24 @@
*/
package org.apache.hadoop.hbase.regionserver.wal;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
import static org.junit.Assert.assertTrue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.MediumTests;
import org.apache.hadoop.hbase.MiniHBaseCluster;
import org.apache.hadoop.hbase.TableName;
@ -53,6 +63,10 @@ public class TestLogRollAbort {
private static MiniHBaseCluster cluster;
private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
/* For the split-then-roll test */
private static final Path HBASEDIR = new Path("/hbase");
private static final Path OLDLOGDIR = new Path(HBASEDIR, "hlog.old");
// Need to override this setup so we can edit the config before it gets sent
// to the HDFS & HBase cluster startup.
@BeforeClass
@ -76,6 +90,9 @@ public class TestLogRollAbort {
TEST_UTIL.getConfiguration().setInt("dfs.client.block.write.retries", 10);
}
private Configuration conf;
private FileSystem fs;
@Before
public void setUp() throws Exception {
TEST_UTIL.startMiniCluster(2);
@ -83,6 +100,8 @@ public class TestLogRollAbort {
cluster = TEST_UTIL.getHBaseCluster();
dfsCluster = TEST_UTIL.getDFSCluster();
admin = TEST_UTIL.getHBaseAdmin();
conf = TEST_UTIL.getConfiguration();
fs = TEST_UTIL.getDFSCluster().getFileSystem();
// disable region rebalancing (interferes with log watching)
cluster.getMaster().balanceSwitch(false);
@ -148,4 +167,71 @@ public class TestLogRollAbort {
table.close();
}
}
/**
* Tests the case where a RegionServer enters a GC pause,
* comes back online after the master declared it dead and started to split.
* Want log rolling after a master split to fail. See HBASE-2312.
*/
@Test (timeout=300000)
public void testLogRollAfterSplitStart() throws IOException {
LOG.info("Verify wal roll after split starts will fail.");
HLog log = null;
String logName = "testLogRollAfterSplitStart";
Path thisTestsDir = new Path(HBASEDIR, logName);
try {
// put some entries in an HLog
TableName tableName =
TableName.valueOf(this.getClass().getName());
HRegionInfo regioninfo = new HRegionInfo(tableName,
HConstants.EMPTY_START_ROW, HConstants.EMPTY_END_ROW);
log = HLogFactory.createHLog(fs, HBASEDIR, logName, conf);
final AtomicLong sequenceId = new AtomicLong(1);
final int total = 20;
for (int i = 0; i < total; i++) {
WALEdit kvs = new WALEdit();
kvs.add(new KeyValue(Bytes.toBytes(i), tableName.getName(), tableName.getName()));
HTableDescriptor htd = new HTableDescriptor(tableName);
htd.addFamily(new HColumnDescriptor("column"));
log.append(regioninfo, tableName, kvs, System.currentTimeMillis(), htd, sequenceId);
}
// Send the data to HDFS datanodes and close the HDFS writer
log.sync();
((FSHLog) log).replaceWriter(((FSHLog)log).getOldPath(), null, null, null);
/* code taken from MasterFileSystem.getLogDirs(), which is called from MasterFileSystem.splitLog()
* handles RS shutdowns (as observed by the splitting process)
*/
// rename the directory so a rogue RS doesn't create more HLogs
Path rsSplitDir = thisTestsDir.suffix(HLog.SPLITTING_EXT);
if (!fs.rename(thisTestsDir, rsSplitDir)) {
throw new IOException("Failed fs.rename for log split: " + thisTestsDir);
}
LOG.debug("Renamed region directory: " + rsSplitDir);
LOG.debug("Processing the old log files.");
HLogSplitter.split(HBASEDIR, rsSplitDir, OLDLOGDIR, fs, conf);
LOG.debug("Trying to roll the HLog.");
try {
log.rollWriter();
Assert.fail("rollWriter() did not throw any exception.");
} catch (IOException ioe) {
if (ioe.getCause() instanceof FileNotFoundException) {
LOG.info("Got the expected exception: ", ioe.getCause());
} else {
Assert.fail("Unexpected exception: " + ioe);
}
}
} finally {
if (log != null) {
log.close();
}
if (fs.exists(thisTestsDir)) {
fs.delete(thisTestsDir, true);
}
}
}
}