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:
parent
7fb425daf4
commit
21ebbdae06
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue