You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by en...@apache.org on 2013/03/21 01:27:30 UTC
svn commit: r1459103 - in /hbase/branches/0.95/hbase-server/src:
main/java/org/apache/hadoop/hbase/master/
main/java/org/apache/hadoop/hbase/regionserver/
test/java/org/apache/hadoop/hbase/master/
test/java/org/apache/hadoop/hbase/util/
Author: enis
Date: Thu Mar 21 00:27:30 2013
New Revision: 1459103
URL: http://svn.apache.org/r1459103
Log:
HBASE-7546 Obtain a table read lock on region split operations
Modified:
hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableLockManager.java
hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitRequest.java
hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java
hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestTableLockManager.java
hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/util/MockRegionServerServices.java
Modified: hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableLockManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableLockManager.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableLockManager.java (original)
+++ hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/master/TableLockManager.java Thu Mar 21 00:27:30 2013
@@ -149,7 +149,7 @@ public abstract class TableLockManager {
* A null implementation
*/
@InterfaceAudience.Private
- static class NullTableLockManager extends TableLockManager {
+ public static class NullTableLockManager extends TableLockManager {
static class NullTableLock implements TableLock {
@Override
public void acquire() throws IOException {
Modified: hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java (original)
+++ hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java Thu Mar 21 00:27:30 2013
@@ -115,6 +115,7 @@ import org.apache.hadoop.hbase.ipc.RpcCl
import org.apache.hadoop.hbase.ipc.RpcServer;
import org.apache.hadoop.hbase.exceptions.ServerNotRunningYetException;
import org.apache.hadoop.hbase.ipc.ServerRpcController;
+import org.apache.hadoop.hbase.master.TableLockManager;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.ReplicationProtbufUtil;
import org.apache.hadoop.hbase.protobuf.RequestConverter;
@@ -437,6 +438,9 @@ public class HRegionServer implements Cl
/** Handle all the snapshot requests to this server */
RegionServerSnapshotManager snapshotManager;
+ // Table level lock manager for locking for region operations
+ private TableLockManager tableLockManager;
+
/**
* Starts a HRegionServer at the default location
*
@@ -634,6 +638,8 @@ public class HRegionServer implements Cl
} catch (KeeperException e) {
this.abort("Failed to reach zk cluster when creating snapshot handler.");
}
+ this.tableLockManager = TableLockManager.createTableLockManager(conf, zooKeeper,
+ new ServerName(isa.getHostName(), isa.getPort(), startcode));
}
/**
@@ -1130,6 +1136,11 @@ public class HRegionServer implements Cl
return regionServerAccounting;
}
+ @Override
+ public TableLockManager getTableLockManager() {
+ return tableLockManager;
+ }
+
/*
* @param r Region to get RegionLoad for.
*
Modified: hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java (original)
+++ hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RegionServerServices.java Thu Mar 21 00:27:30 2013
@@ -27,6 +27,7 @@ import org.apache.hadoop.hbase.HRegionIn
import org.apache.hadoop.hbase.catalog.CatalogTracker;
import org.apache.hadoop.hbase.executor.ExecutorService;
import org.apache.hadoop.hbase.ipc.RpcServer;
+import org.apache.hadoop.hbase.master.TableLockManager;
import org.apache.hadoop.hbase.regionserver.wal.HLog;
import org.apache.zookeeper.KeeperException;
@@ -60,6 +61,11 @@ public interface RegionServerServices ex
public RegionServerAccounting getRegionServerAccounting();
/**
+ * @return RegionServer's instance of {@link TableLockManager}
+ */
+ public TableLockManager getTableLockManager();
+
+ /**
* Tasks to perform after region open to complete deploy of region on
* regionserver
*
Modified: hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitRequest.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitRequest.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitRequest.java (original)
+++ hbase/branches/0.95/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/SplitRequest.java Thu Mar 21 00:27:30 2013
@@ -24,6 +24,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.RemoteExceptionHandler;
+import org.apache.hadoop.hbase.master.TableLockManager.TableLock;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.util.StringUtils;
@@ -38,6 +39,7 @@ class SplitRequest implements Runnable {
private final HRegion parent;
private final byte[] midKey;
private final HRegionServer server;
+ private TableLock tableLock;
SplitRequest(HRegion region, byte[] midKey, HRegionServer hrs) {
Preconditions.checkNotNull(hrs);
@@ -61,6 +63,18 @@ class SplitRequest implements Runnable {
try {
final long startTime = System.currentTimeMillis();
SplitTransaction st = new SplitTransaction(parent, midKey);
+
+ //acquire a shared read lock on the table, so that table schema modifications
+ //do not happen concurrently
+ tableLock = server.getTableLockManager().readLock(parent.getTableDesc().getName()
+ , "SPLIT_REGION:" + parent.getRegionNameAsString());
+ try {
+ tableLock.acquire();
+ } catch (IOException ex) {
+ tableLock = null;
+ throw ex;
+ }
+
// If prepare does not return true, for some reason -- logged inside in
// the prepare call -- we are not ready to split just now. Just return.
if (!st.prepare()) return;
@@ -110,6 +124,18 @@ class SplitRequest implements Runnable {
RemoteExceptionHandler.checkIOException(io));
}
}
+ releaseTableLock();
+ }
+ }
+
+ protected void releaseTableLock() {
+ if (this.tableLock != null) {
+ try {
+ this.tableLock.release();
+ } catch (IOException ex) {
+ LOG.warn("Could not release the table lock", ex);
+ //TODO: if we get here, and not abort RS, this lock will never be released
+ }
}
}
}
Modified: hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java (original)
+++ hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/MockRegionServer.java Thu Mar 21 00:27:30 2013
@@ -38,6 +38,7 @@ import org.apache.hadoop.hbase.client.Re
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.executor.ExecutorService;
import org.apache.hadoop.hbase.ipc.RpcServer;
+import org.apache.hadoop.hbase.master.TableLockManager.NullTableLockManager;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest;
import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionResponse;
@@ -148,7 +149,7 @@ class MockRegionServer implements AdminP
/**
* @param sn Name of this mock regionserver
- * @throws IOException
+ * @throws IOException
* @throws org.apache.hadoop.hbase.exceptions.ZooKeeperConnectionException
*/
MockRegionServer(final Configuration conf, final ServerName sn)
@@ -290,6 +291,10 @@ class MockRegionServer implements AdminP
return null;
}
+ public TableLockManager getTableLockManager() {
+ return new NullTableLockManager();
+ }
+
@Override
public void postOpenDeployTasks(HRegion r, CatalogTracker ct)
throws KeeperException, IOException {
Modified: hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestTableLockManager.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestTableLockManager.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestTableLockManager.java (original)
+++ hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/master/TestTableLockManager.java Thu Mar 21 00:27:30 2013
@@ -21,9 +21,12 @@ package org.apache.hadoop.hbase.master;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
+import java.util.List;
+import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@@ -34,10 +37,12 @@ import java.util.concurrent.Future;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Chore;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HRegionInfo;
import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.MediumTests;
+import org.apache.hadoop.hbase.LargeTests;
import org.apache.hadoop.hbase.ServerName;
import org.apache.hadoop.hbase.exceptions.LockTimeoutException;
import org.apache.hadoop.hbase.exceptions.TableNotDisabledException;
@@ -45,7 +50,10 @@ import org.apache.hadoop.hbase.client.HB
import org.apache.hadoop.hbase.coprocessor.BaseMasterObserver;
import org.apache.hadoop.hbase.coprocessor.MasterCoprocessorEnvironment;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
+import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.LoadTestTool;
+import org.apache.hadoop.hbase.util.StoppableImplementation;
import org.apache.hadoop.hbase.util.Threads;
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
@@ -56,7 +64,7 @@ import org.junit.experimental.categories
/**
* Tests the default table lock manager
*/
-@Category(MediumTests.class)
+@Category(LargeTests.class)
public class TestTableLockManager {
private static final Log LOG =
@@ -291,4 +299,103 @@ public class TestTableLockManager {
executor.shutdownNow();
}
+ @Test(timeout = 600000)
+ public void testTableReadLock() throws Exception {
+ // test plan: write some data to the table. Continuously alter the table and
+ // force splits
+ // concurrently until we have 10 regions. verify the data just in case.
+ // Every region should contain the same table descriptor
+ // This is not an exact test
+ prepareMiniCluster();
+ LoadTestTool loadTool = new LoadTestTool();
+ loadTool.setConf(TEST_UTIL.getConfiguration());
+ int numKeys = 10000;
+ final byte[] tableName = Bytes.toBytes("testTableReadLock");
+ final HBaseAdmin admin = TEST_UTIL.getHBaseAdmin();
+ final HTableDescriptor desc = new HTableDescriptor(tableName);
+ final byte[] family = Bytes.toBytes("test_cf");
+ desc.addFamily(new HColumnDescriptor(family));
+ admin.createTable(desc); // create with one region
+
+ // write some data, not much
+ int ret = loadTool.run(new String[] { "-tn", Bytes.toString(tableName), "-write",
+ String.format("%d:%d:%d", 1, 10, 10), "-num_keys", String.valueOf(numKeys), "-skip_init" });
+ if (0 != ret) {
+ String errorMsg = "Load failed with error code " + ret;
+ LOG.error(errorMsg);
+ fail(errorMsg);
+ }
+
+ int familyValues = admin.getTableDescriptor(tableName).getFamily(family).getValues().size();
+ StoppableImplementation stopper = new StoppableImplementation();
+
+ //alter table every 10 sec
+ Chore alterThread = new Chore("Alter Chore", 10000, stopper) {
+ @Override
+ protected void chore() {
+ Random random = new Random();
+ try {
+ HTableDescriptor htd = admin.getTableDescriptor(tableName);
+ String val = String.valueOf(random.nextInt());
+ htd.getFamily(family).setValue(val, val);
+ desc.getFamily(family).setValue(val, val); // save it for later
+ // control
+ admin.modifyTable(tableName, htd);
+ } catch (Exception ex) {
+ LOG.warn("Caught exception", ex);
+ fail(ex.getMessage());
+ }
+ }
+ };
+
+ //split table every 5 sec
+ Chore splitThread = new Chore("Split thread", 5000, stopper) {
+ @Override
+ public void chore() {
+ try {
+ Random random = new Random();
+ List<HRegionInfo> regions = admin.getTableRegions(tableName);
+ byte[] regionName = regions.get(random.nextInt(regions.size())).getRegionName();
+ admin.flush(regionName);
+ admin.compact(regionName);
+ admin.split(regionName);
+ } catch (Exception ex) {
+ LOG.warn("Caught exception", ex);
+ fail(ex.getMessage());
+ }
+ }
+ };
+
+ alterThread.start();
+ splitThread.start();
+ while (true) {
+ List<HRegionInfo> regions = admin.getTableRegions(tableName);
+ LOG.info(String.format("Table #regions: %d regions: %s:", regions.size(), regions));
+ assertEquals(admin.getTableDescriptor(tableName), desc);
+ for (HRegion region : TEST_UTIL.getMiniHBaseCluster().getRegions(tableName)) {
+ assertEquals(desc, region.getTableDesc());
+ }
+ if (regions.size() >= 10) {
+ break;
+ }
+ Threads.sleep(1000);
+ }
+ stopper.stop("test finished");
+
+ int newFamilyValues = admin.getTableDescriptor(tableName).getFamily(family).getValues().size();
+ LOG.info(String.format("Altered the table %d times", newFamilyValues - familyValues));
+ assertTrue(newFamilyValues > familyValues); // at least one alter went
+ // through
+
+ ret = loadTool.run(new String[] { "-tn", Bytes.toString(tableName), "-read", "100:10",
+ "-num_keys", String.valueOf(numKeys), "-skip_init" });
+ if (0 != ret) {
+ String errorMsg = "Verify failed with error code " + ret;
+ LOG.error(errorMsg);
+ fail(errorMsg);
+ }
+
+ admin.close();
+ }
+
}
Modified: hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/util/MockRegionServerServices.java
URL: http://svn.apache.org/viewvc/hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/util/MockRegionServerServices.java?rev=1459103&r1=1459102&r2=1459103&view=diff
==============================================================================
--- hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/util/MockRegionServerServices.java (original)
+++ hbase/branches/0.95/hbase-server/src/test/java/org/apache/hadoop/hbase/util/MockRegionServerServices.java Thu Mar 21 00:27:30 2013
@@ -31,6 +31,8 @@ import org.apache.hadoop.hbase.catalog.C
import org.apache.hadoop.hbase.executor.ExecutorService;
import org.apache.hadoop.hbase.fs.HFileSystem;
import org.apache.hadoop.hbase.ipc.RpcServer;
+import org.apache.hadoop.hbase.master.TableLockManager;
+import org.apache.hadoop.hbase.master.TableLockManager.NullTableLockManager;
import org.apache.hadoop.hbase.regionserver.CompactionRequestor;
import org.apache.hadoop.hbase.regionserver.FlushRequester;
import org.apache.hadoop.hbase.regionserver.HRegion;
@@ -131,6 +133,11 @@ public class MockRegionServerServices im
}
@Override
+ public TableLockManager getTableLockManager() {
+ return new NullTableLockManager();
+ }
+
+ @Override
public ServerName getServerName() {
return this.serverName;
}