HBASE-7537 .regioninfo not created by createHRegion()

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1433514 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
mbertozzi 2013-01-15 16:51:44 +00:00
parent 7fb425daf4
commit 21ebbdae06
2 changed files with 99 additions and 19 deletions

View File

@ -753,27 +753,49 @@ public class HRegion implements HeapSize { // , Writable{
return this.memstoreSize.getAndAdd(memStoreSize); return this.memstoreSize.getAndAdd(memStoreSize);
} }
/* /**
* Write out an info file under the region directory. Useful recovering * Write out an info file under the stored region directory. Useful recovering mangled regions.
* mangled regions.
* @throws IOException * @throws IOException
*/ */
private void checkRegioninfoOnFilesystem() throws IOException { private void checkRegioninfoOnFilesystem() throws IOException {
Path regioninfoPath = new Path(this.regiondir, REGIONINFO_FILE); checkRegioninfoOnFilesystem(this.regiondir);
// Compose the content of the file so we can compare to length in filesystem. If not same, }
// rewrite it (it may have been written in the old format using Writables instead of pb). The
/**
* Write out an info file under the region directory. Useful recovering mangled regions.
* @param regiondir directory under which to write out the region info
* @throws IOException
*/
private void checkRegioninfoOnFilesystem(Path regiondir) throws IOException {
writeRegioninfoOnFilesystem(regionInfo, regiondir, getFilesystem(), conf);
}
/**
* Write out an info file under the region directory. Useful recovering mangled regions. If the
* regioninfo already exists on disk and there is information in the file, then we fast exit.
* @param regionInfo information about the region
* @param regiondir directory under which to write out the region info
* @param fs {@link FileSystem} on which to write the region info
* @param conf {@link Configuration} from which to extract specific file locations
* @throws IOException on unexpected error.
*/
public static void writeRegioninfoOnFilesystem(HRegionInfo regionInfo, Path regiondir,
FileSystem fs, Configuration conf) throws IOException {
Path regioninfoPath = new Path(regiondir, REGIONINFO_FILE);
// Compose the content of the file so we can compare to length in filesystem. If not same,
// rewrite it (it may have been written in the old format using Writables instead of pb). The
// pb version is much shorter -- we write now w/o the toString version -- so checking length // pb version is much shorter -- we write now w/o the toString version -- so checking length
// only should be sufficient. I don't want to read the file every time to check if it pb // only should be sufficient. I don't want to read the file every time to check if it pb
// serialized. // serialized.
byte [] content = getDotRegionInfoFileContent(this.getRegionInfo()); byte[] content = getDotRegionInfoFileContent(regionInfo);
boolean exists = this.fs.exists(regioninfoPath); boolean exists = fs.exists(regioninfoPath);
FileStatus status = exists? this.fs.getFileStatus(regioninfoPath): null; FileStatus status = exists ? fs.getFileStatus(regioninfoPath) : null;
if (status != null && status.getLen() == content.length) { if (status != null && status.getLen() == content.length) {
// Then assume the content good and move on. // Then assume the content good and move on.
return; return;
} }
// Create in tmpdir and then move into place in case we crash after // Create in tmpdir and then move into place in case we crash after
// create but before close. If we don't successfully close the file, // create but before close. If we don't successfully close the file,
// subsequent region reopens will fail the below because create is // subsequent region reopens will fail the below because create is
// registered in NN. // registered in NN.
@ -781,7 +803,7 @@ public class HRegion implements HeapSize { // , Writable{
FsPermission perms = FSUtils.getFilePermissions(fs, conf, HConstants.DATA_FILE_UMASK_KEY); FsPermission perms = FSUtils.getFilePermissions(fs, conf, HConstants.DATA_FILE_UMASK_KEY);
// And then create the file // And then create the file
Path tmpPath = new Path(getTmpDir(), REGIONINFO_FILE); Path tmpPath = new Path(getTmpDir(regiondir), REGIONINFO_FILE);
// If datanode crashes or if the RS goes down just before the close is called while trying to // If datanode crashes or if the RS goes down just before the close is called while trying to
// close the created regioninfo file in the .tmp directory then on next // close the created regioninfo file in the .tmp directory then on next
@ -1227,7 +1249,15 @@ public class HRegion implements HeapSize { // , Writable{
* will have its contents removed when the region is reopened. * will have its contents removed when the region is reopened.
*/ */
Path getTmpDir() { Path getTmpDir() {
return new Path(getRegionDir(), REGION_TEMP_SUBDIR); return getTmpDir(getRegionDir());
}
/**
* Get the temporary directory for the specified region. This directory
* will have its contents removed when the region is reopened.
*/
static Path getTmpDir(Path regionDir) {
return new Path(regionDir, REGION_TEMP_SUBDIR);
} }
void triggerMajorCompaction() { void triggerMajorCompaction() {
@ -3924,6 +3954,8 @@ public class HRegion implements HeapSize { // , Writable{
Path regionDir = HRegion.getRegionDir(tableDir, info.getEncodedName()); Path regionDir = HRegion.getRegionDir(tableDir, info.getEncodedName());
FileSystem fs = FileSystem.get(conf); FileSystem fs = FileSystem.get(conf);
fs.mkdirs(regionDir); fs.mkdirs(regionDir);
// Write HRI to a file in case we need to recover .META.
writeRegioninfoOnFilesystem(info, regionDir, fs, conf);
HLog effectiveHLog = hlog; HLog effectiveHLog = hlog;
if (hlog == null && !ignoreHLog) { if (hlog == null && !ignoreHLog) {
effectiveHLog = HLogFactory.createHLog(fs, regionDir, effectiveHLog = HLogFactory.createHLog(fs, regionDir,
@ -4004,15 +4036,15 @@ public class HRegion implements HeapSize { // , Writable{
return r.openHRegion(reporter); return r.openHRegion(reporter);
} }
public static HRegion openHRegion(Path tableDir, final HRegionInfo info, public static HRegion openHRegion(Path rootDir, final HRegionInfo info,
final HTableDescriptor htd, final HLog wal, final Configuration conf) final HTableDescriptor htd, final HLog wal, final Configuration conf)
throws IOException { throws IOException {
return openHRegion(tableDir, info, htd, wal, conf, null, null); return openHRegion(rootDir, info, htd, wal, conf, null, null);
} }
/** /**
* Open a Region. * Open a Region.
* @param tableDir Table directory * @param rootDir Root directory for HBase instance
* @param info Info for region to be opened. * @param info Info for region to be opened.
* @param wal HLog for region to use. This method will call * @param wal HLog for region to use. This method will call
* HLog#setSequenceNumber(long) passing the result of the call to * HLog#setSequenceNumber(long) passing the result of the call to
@ -4024,7 +4056,7 @@ public class HRegion implements HeapSize { // , Writable{
* *
* @throws IOException * @throws IOException
*/ */
public static HRegion openHRegion(final Path tableDir, final HRegionInfo info, public static HRegion openHRegion(final Path rootDir, final HRegionInfo info,
final HTableDescriptor htd, final HLog wal, final Configuration conf, final HTableDescriptor htd, final HLog wal, final Configuration conf,
final RegionServerServices rsServices, final RegionServerServices rsServices,
final CancelableProgressable reporter) final CancelableProgressable reporter)
@ -4034,7 +4066,7 @@ public class HRegion implements HeapSize { // , Writable{
if (LOG.isDebugEnabled()) { if (LOG.isDebugEnabled()) {
LOG.debug("Opening region: " + info); LOG.debug("Opening region: " + info);
} }
Path dir = HTableDescriptor.getTableDir(tableDir, info.getTableName()); Path dir = HTableDescriptor.getTableDir(rootDir, info.getTableName());
HRegion r = HRegion.newHRegion(dir, wal, FileSystem.get(conf), conf, info, htd, rsServices); HRegion r = HRegion.newHRegion(dir, wal, FileSystem.get(conf), conf, info, htd, rsServices);
return r.openHRegion(reporter); return r.openHRegion(reporter);
} }

View File

@ -3506,7 +3506,55 @@ public class TestHRegion extends HBaseTestCase {
HRegion.closeHRegion(region); HRegion.closeHRegion(region);
} }
} }
/**
* Verifies that the .regioninfo file is written on region creation
* and that is recreated if missing during region opening.
*/
public void testRegionInfoFileCreation() throws IOException {
Path rootDir = new Path(DIR + "testRegionInfoFileCreation");
Configuration conf = HBaseConfiguration.create(this.conf);
HTableDescriptor htd = new HTableDescriptor("testtb");
htd.addFamily(new HColumnDescriptor("cf"));
HRegionInfo hri = new HRegionInfo(htd.getName());
// Create a region and skip the initialization (like CreateTableHandler)
HRegion region = HRegion.createHRegion(hri, rootDir, conf, htd, null, false, true);
Path regionDir = region.getRegionDir();
FileSystem fs = region.getFilesystem();
HRegion.closeHRegion(region);
Path regionInfoFile = new Path(regionDir, HRegion.REGIONINFO_FILE);
// Verify that the .regioninfo file is present
assertTrue(HRegion.REGIONINFO_FILE + " should be present in the region dir",
fs.exists(regionInfoFile));
// Try to open the region
region = HRegion.openHRegion(rootDir, hri, htd, null, conf);
assertEquals(regionDir, region.getRegionDir());
HRegion.closeHRegion(region);
// Verify that the .regioninfo file is still there
assertTrue(HRegion.REGIONINFO_FILE + " should be present in the region dir",
fs.exists(regionInfoFile));
// Remove the .regioninfo file and verify is recreated on region open
fs.delete(regionInfoFile);
assertFalse(HRegion.REGIONINFO_FILE + " should be removed from the region dir",
fs.exists(regionInfoFile));
region = HRegion.openHRegion(rootDir, hri, htd, null, conf);
assertEquals(regionDir, region.getRegionDir());
HRegion.closeHRegion(region);
// Verify that the .regioninfo file is still there
assertTrue(HRegion.REGIONINFO_FILE + " should be present in the region dir",
fs.exists(new Path(regionDir, HRegion.REGIONINFO_FILE)));
}
/** /**
* TestCase for increment * TestCase for increment
* *