HBASE-8262 Add testcase to verify HBASE-7678's empty region split semantics change
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1464596 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
8465f20316
commit
f357ac700d
@ -49,18 +49,19 @@ import org.apache.hadoop.fs.PathFilter;
|
|||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hbase.ClusterId;
|
import org.apache.hadoop.hbase.ClusterId;
|
||||||
import org.apache.hadoop.hbase.exceptions.DeserializationException;
|
|
||||||
import org.apache.hadoop.hbase.HColumnDescriptor;
|
import org.apache.hadoop.hbase.HColumnDescriptor;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.HDFSBlocksDistribution;
|
import org.apache.hadoop.hbase.HDFSBlocksDistribution;
|
||||||
import org.apache.hadoop.hbase.HRegionInfo;
|
import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
import org.apache.hadoop.hbase.RemoteExceptionHandler;
|
||||||
|
import org.apache.hadoop.hbase.exceptions.DeserializationException;
|
||||||
import org.apache.hadoop.hbase.exceptions.FileSystemVersionException;
|
import org.apache.hadoop.hbase.exceptions.FileSystemVersionException;
|
||||||
import org.apache.hadoop.hbase.master.HMaster;
|
import org.apache.hadoop.hbase.master.HMaster;
|
||||||
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.protobuf.generated.FSProtos;
|
import org.apache.hadoop.hbase.protobuf.generated.FSProtos;
|
||||||
import org.apache.hadoop.hbase.regionserver.HRegion;
|
import org.apache.hadoop.hbase.regionserver.HRegion;
|
||||||
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
import org.apache.hadoop.hdfs.DistributedFileSystem;
|
||||||
|
import org.apache.hadoop.hdfs.protocol.FSConstants;
|
||||||
import org.apache.hadoop.io.IOUtils;
|
import org.apache.hadoop.io.IOUtils;
|
||||||
import org.apache.hadoop.io.SequenceFile;
|
import org.apache.hadoop.io.SequenceFile;
|
||||||
import org.apache.hadoop.security.AccessControlException;
|
import org.apache.hadoop.security.AccessControlException;
|
||||||
@ -1311,6 +1312,57 @@ public abstract class FSUtils {
|
|||||||
return getRootDir(conf).getFileSystem(conf);
|
return getRootDir(conf).getFileSystem(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs through the HBase rootdir/tablename and creates a reverse lookup map for
|
||||||
|
* table StoreFile names to the full Path.
|
||||||
|
* <br>
|
||||||
|
* Example...<br>
|
||||||
|
* Key = 3944417774205889744 <br>
|
||||||
|
* Value = hdfs://localhost:51169/user/userid/-ROOT-/70236052/info/3944417774205889744
|
||||||
|
*
|
||||||
|
* @param map map to add values. If null, this method will create and populate one to return
|
||||||
|
* @param fs The file system to use.
|
||||||
|
* @param hbaseRootDir The root directory to scan.
|
||||||
|
* @param tablename name of the table to scan.
|
||||||
|
* @return Map keyed by StoreFile name with a value of the full Path.
|
||||||
|
* @throws IOException When scanning the directory fails.
|
||||||
|
*/
|
||||||
|
public static Map<String, Path> getTableStoreFilePathMap(Map<String, Path> map,
|
||||||
|
final FileSystem fs, final Path hbaseRootDir, byte[] tablename)
|
||||||
|
throws IOException {
|
||||||
|
if (map == null) {
|
||||||
|
map = new HashMap<String, Path>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only include the directory paths to tables
|
||||||
|
Path tableDir = new Path(hbaseRootDir, Bytes.toString(tablename));
|
||||||
|
// Inside a table, there are compaction.dir directories to skip. Otherwise, all else
|
||||||
|
// should be regions.
|
||||||
|
PathFilter df = new BlackListDirFilter(fs, HConstants.HBASE_NON_TABLE_DIRS);
|
||||||
|
FileStatus[] regionDirs = fs.listStatus(tableDir);
|
||||||
|
for (FileStatus regionDir : regionDirs) {
|
||||||
|
Path dd = regionDir.getPath();
|
||||||
|
if (dd.getName().equals(HConstants.HREGION_COMPACTIONDIR_NAME)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// else its a region name, now look in region for families
|
||||||
|
FileStatus[] familyDirs = fs.listStatus(dd, df);
|
||||||
|
for (FileStatus familyDir : familyDirs) {
|
||||||
|
Path family = familyDir.getPath();
|
||||||
|
// now in family, iterate over the StoreFiles and
|
||||||
|
// put in map
|
||||||
|
FileStatus[] familyStatus = fs.listStatus(family);
|
||||||
|
for (FileStatus sfStatus : familyStatus) {
|
||||||
|
Path sf = sfStatus.getPath();
|
||||||
|
map.put( sf.getName(), sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs through the HBase rootdir and creates a reverse lookup map for
|
* Runs through the HBase rootdir and creates a reverse lookup map for
|
||||||
* table StoreFile names to the full Path.
|
* table StoreFile names to the full Path.
|
||||||
@ -1336,28 +1388,8 @@ public abstract class FSUtils {
|
|||||||
PathFilter df = new BlackListDirFilter(fs, HConstants.HBASE_NON_TABLE_DIRS);
|
PathFilter df = new BlackListDirFilter(fs, HConstants.HBASE_NON_TABLE_DIRS);
|
||||||
FileStatus [] tableDirs = fs.listStatus(hbaseRootDir, df);
|
FileStatus [] tableDirs = fs.listStatus(hbaseRootDir, df);
|
||||||
for (FileStatus tableDir : tableDirs) {
|
for (FileStatus tableDir : tableDirs) {
|
||||||
// Inside a table, there are compaction.dir directories to skip. Otherwise, all else
|
byte[] tablename = Bytes.toBytes(tableDir.getPath().getName());
|
||||||
// should be regions.
|
getTableStoreFilePathMap(map, fs, hbaseRootDir, tablename);
|
||||||
FileStatus[] regionDirs = fs.listStatus(tableDir.getPath(), df);
|
|
||||||
for (FileStatus regionDir : regionDirs) {
|
|
||||||
Path dd = regionDir.getPath();
|
|
||||||
if (dd.getName().equals(HConstants.HREGION_COMPACTIONDIR_NAME)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// else its a region name, now look in region for families
|
|
||||||
FileStatus[] familyDirs = fs.listStatus(dd, df);
|
|
||||||
for (FileStatus familyDir : familyDirs) {
|
|
||||||
Path family = familyDir.getPath();
|
|
||||||
// now in family, iterate over the StoreFiles and
|
|
||||||
// put in map
|
|
||||||
FileStatus[] familyStatus = fs.listStatus(family);
|
|
||||||
for (FileStatus sfStatus : familyStatus) {
|
|
||||||
Path sf = sfStatus.getPath();
|
|
||||||
map.put( sf.getName(), sf);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@ -34,6 +35,8 @@ import java.util.concurrent.CountDownLatch;
|
|||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
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.HBaseTestingUtility;
|
||||||
import org.apache.hadoop.hbase.HConstants;
|
import org.apache.hadoop.hbase.HConstants;
|
||||||
import org.apache.hadoop.hbase.HRegionInfo;
|
import org.apache.hadoop.hbase.HRegionInfo;
|
||||||
@ -59,6 +62,8 @@ import org.apache.hadoop.hbase.master.RegionStates;
|
|||||||
import org.apache.hadoop.hbase.master.handler.SplitRegionHandler;
|
import org.apache.hadoop.hbase.master.handler.SplitRegionHandler;
|
||||||
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
|
||||||
import org.apache.hadoop.hbase.util.Bytes;
|
import org.apache.hadoop.hbase.util.Bytes;
|
||||||
|
import org.apache.hadoop.hbase.util.FSUtils;
|
||||||
|
import org.apache.hadoop.hbase.util.HBaseFsck;
|
||||||
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
|
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
|
||||||
import org.apache.hadoop.hbase.util.Threads;
|
import org.apache.hadoop.hbase.util.Threads;
|
||||||
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
|
import org.apache.hadoop.hbase.zookeeper.ZKAssign;
|
||||||
@ -67,8 +72,8 @@ import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
|
|||||||
import org.apache.zookeeper.KeeperException;
|
import org.apache.zookeeper.KeeperException;
|
||||||
import org.apache.zookeeper.KeeperException.NodeExistsException;
|
import org.apache.zookeeper.KeeperException.NodeExistsException;
|
||||||
import org.apache.zookeeper.data.Stat;
|
import org.apache.zookeeper.data.Stat;
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -640,6 +645,67 @@ public class TestSplitTransactionOnCluster {
|
|||||||
admin.flush(tableName);
|
admin.flush(tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a table has regions that have no store files in a region, they should split successfully
|
||||||
|
* into two regions with no store files.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSplitRegionWithNoStoreFiles()
|
||||||
|
throws Exception {
|
||||||
|
final byte[] tableName = Bytes.toBytes("testSplitRegionWithNoStoreFiles");
|
||||||
|
// Create table then get the single region for our new table.
|
||||||
|
createTableAndWait(tableName, HConstants.CATALOG_FAMILY);
|
||||||
|
List<HRegion> regions = cluster.getRegions(tableName);
|
||||||
|
HRegionInfo hri = getAndCheckSingleTableRegion(regions);
|
||||||
|
ensureTableRegionNotOnSameServerAsMeta(admin, hri);
|
||||||
|
int regionServerIndex = cluster.getServerWith(regions.get(0).getRegionName());
|
||||||
|
HRegionServer regionServer = cluster.getRegionServer(regionServerIndex);
|
||||||
|
// Turn off balancer so it doesn't cut in and mess up our placements.
|
||||||
|
this.admin.setBalancerRunning(false, true);
|
||||||
|
// Turn off the meta scanner so it don't remove parent on us.
|
||||||
|
cluster.getMaster().setCatalogJanitorEnabled(false);
|
||||||
|
try {
|
||||||
|
// Precondition: we created a table with no data, no store files.
|
||||||
|
printOutRegions(regionServer, "Initial regions: ");
|
||||||
|
Configuration conf = cluster.getConfiguration();
|
||||||
|
HBaseFsck.debugLsr(conf, new Path("/"));
|
||||||
|
Path rootDir = FSUtils.getRootDir(conf);
|
||||||
|
FileSystem fs = TESTING_UTIL.getDFSCluster().getFileSystem();
|
||||||
|
Map<String, Path> storefiles =
|
||||||
|
FSUtils.getTableStoreFilePathMap(null, fs, rootDir, tableName);
|
||||||
|
assertEquals("Expected nothing but found " + storefiles.toString(), storefiles.size(), 0);
|
||||||
|
|
||||||
|
// find a splittable region. Refresh the regions list
|
||||||
|
regions = cluster.getRegions(tableName);
|
||||||
|
final HRegion region = findSplittableRegion(regions);
|
||||||
|
assertTrue("not able to find a splittable region", region != null);
|
||||||
|
|
||||||
|
// Now split.
|
||||||
|
SplitTransaction st = new MockedSplitTransaction(region, Bytes.toBytes("row2"));
|
||||||
|
try {
|
||||||
|
st.prepare();
|
||||||
|
st.execute(regionServer, regionServer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
fail("Split execution should have succeeded with no exceptions thrown");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Postcondition: split the table with no store files into two regions, but still have not
|
||||||
|
// store files
|
||||||
|
List<HRegion> daughters = cluster.getRegions(tableName);
|
||||||
|
assertTrue(daughters.size() == 2);
|
||||||
|
|
||||||
|
// check dirs
|
||||||
|
HBaseFsck.debugLsr(conf, new Path("/"));
|
||||||
|
Map<String, Path> storefilesAfter =
|
||||||
|
FSUtils.getTableStoreFilePathMap(null, fs, rootDir, tableName);
|
||||||
|
assertEquals("Expected nothing but found " + storefilesAfter.toString(),
|
||||||
|
storefilesAfter.size(), 0);
|
||||||
|
} finally {
|
||||||
|
admin.setBalancerRunning(true, false);
|
||||||
|
cluster.getMaster().setCatalogJanitorEnabled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void testSplitBeforeSettingSplittingInZKInternals() throws Exception {
|
private void testSplitBeforeSettingSplittingInZKInternals() throws Exception {
|
||||||
final byte[] tableName = Bytes.toBytes("testSplitBeforeSettingSplittingInZK");
|
final byte[] tableName = Bytes.toBytes("testSplitBeforeSettingSplittingInZK");
|
||||||
try {
|
try {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user