columnName is redundant. Use {@link #addColumn(String, HColumnDescriptor)}
*/
public void modifyColumn(final String tableName, final String columnName,
- HColumnDescriptor descriptor)
+ HColumnDescriptor descriptor, boolean instantModify)
throws IOException {
- modifyColumn(tableName, descriptor);
+ modifyColumn(tableName, descriptor, instantModify);
}
/**
@@ -969,9 +969,10 @@
* @param descriptor new column descriptor to use
* @throws IOException if a remote or network exception occurs
*/
- public void modifyColumn(final String tableName, HColumnDescriptor descriptor)
+ public void modifyColumn(final String tableName, HColumnDescriptor descriptor,
+ boolean instantModify)
throws IOException {
- modifyColumn(Bytes.toBytes(tableName), descriptor);
+ modifyColumn(Bytes.toBytes(tableName), descriptor, instantModify);
}
/**
@@ -985,9 +986,9 @@
* @deprecated The columnName is redundant. Use {@link #modifyColumn(byte[], HColumnDescriptor)}
*/
public void modifyColumn(final byte [] tableName, final byte [] columnName,
- HColumnDescriptor descriptor)
+ HColumnDescriptor descriptor, boolean instantModify)
throws IOException {
- modifyColumn(tableName, descriptor);
+ modifyColumn(tableName, descriptor, instantModify);
}
/**
@@ -998,10 +999,11 @@
* @param descriptor new column descriptor to use
* @throws IOException if a remote or network exception occurs
*/
- public void modifyColumn(final byte [] tableName, HColumnDescriptor descriptor)
+ public void modifyColumn(final byte [] tableName, HColumnDescriptor descriptor,
+ boolean instantModify)
throws IOException {
try {
- getMaster().modifyColumn(tableName, descriptor);
+ getMaster().modifyColumn(tableName, descriptor, instantModify);
} catch (RemoteException re) {
// Convert RE exceptions in here; client shouldn't have to deal with them,
// at least w/ the type of exceptions that come out of this method:
@@ -1444,10 +1446,10 @@
* @param htd modified description of the table
* @throws IOException if a remote or network exception occurs
*/
- public void modifyTable(final byte [] tableName, HTableDescriptor htd)
+ public void modifyTable(final byte [] tableName, HTableDescriptor htd, boolean instantModify)
throws IOException {
try {
- getMaster().modifyTable(tableName, htd);
+ getMaster().modifyTable(tableName, htd, instantModify);
} catch (RemoteException re) {
// Convert RE exceptions in here; client shouldn't have to deal with them,
// at least w/ the type of exceptions that come out of this method:
Index: src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java
===================================================================
--- src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java (revision 483a54d3d0a6c9a89205b0541303c1aabf512913)
+++ src/test/java/org/apache/hadoop/hbase/coprocessor/TestMasterObserver.java (revision )
@@ -541,20 +541,20 @@
// modify table
htd.setMaxFileSize(512 * 1024 * 1024);
- admin.modifyTable(TEST_TABLE, htd);
+ admin.modifyTable(TEST_TABLE, htd, false);
// preModifyTable can't bypass default action.
assertTrue("Test table should have been modified",
cp.wasModifyTableCalled());
// add a column family
- admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2));
+ admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2), false);
assertTrue("New column family shouldn't have been added to test table",
cp.preAddColumnCalledOnly());
// modify a column family
HColumnDescriptor hcd1 = new HColumnDescriptor(TEST_FAMILY2);
hcd1.setMaxVersions(25);
- admin.modifyColumn(TEST_TABLE, hcd1);
+ admin.modifyColumn(TEST_TABLE, hcd1, false);
assertTrue("Second column family should be modified",
cp.preModifyColumnCalledOnly());
@@ -584,19 +584,19 @@
// modify table
htd.setMaxFileSize(512 * 1024 * 1024);
- admin.modifyTable(TEST_TABLE, htd);
+ admin.modifyTable(TEST_TABLE, htd, false);
assertTrue("Test table should have been modified",
cp.wasModifyTableCalled());
// add a column family
- admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2));
+ admin.addColumn(TEST_TABLE, new HColumnDescriptor(TEST_FAMILY2), false);
assertTrue("New column family should have been added to test table",
cp.wasAddColumnCalled());
// modify a column family
HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY2);
hcd.setMaxVersions(25);
- admin.modifyColumn(TEST_TABLE, hcd);
+ admin.modifyColumn(TEST_TABLE, hcd, false);
assertTrue("Second column family should be modified",
cp.wasModifyColumnCalled());
@@ -613,7 +613,7 @@
// delete column
assertFalse("No column family deleted yet", cp.wasDeleteColumnCalled());
- admin.deleteColumn(TEST_TABLE, TEST_FAMILY2);
+ admin.deleteColumn(TEST_TABLE, TEST_FAMILY2, false);
HTableDescriptor tableDesc = admin.getTableDescriptor(TEST_TABLE);
assertNull("'"+Bytes.toString(TEST_FAMILY2)+"' should have been removed",
tableDesc.getFamily(TEST_FAMILY2));
Index: src/main/java/org/apache/hadoop/hbase/executor/EventHandler.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/executor/EventHandler.java (revision 483a54d3d0a6c9a89205b0541303c1aabf512913)
+++ src/main/java/org/apache/hadoop/hbase/executor/EventHandler.java (revision )
@@ -140,14 +140,14 @@
* Constructor
*/
EventType(int value) {}
- public boolean isOnlineSchemaChangeSupported() {
+ public boolean isSchemaChangeEvent() {
return (
- this.equals(EventType.C_M_ADD_FAMILY) ||
- this.equals(EventType.C_M_DELETE_FAMILY) ||
- this.equals(EventType.C_M_MODIFY_FAMILY) ||
+ this.equals(EventType.C_M_ADD_FAMILY) ||
+ this.equals(EventType.C_M_DELETE_FAMILY) ||
+ this.equals(EventType.C_M_MODIFY_FAMILY) ||
- this.equals(EventType.C_M_MODIFY_TABLE)
- );
+ this.equals(EventType.C_M_MODIFY_TABLE));
}
+
}
/**
Index: src/main/java/org/apache/hadoop/hbase/regionserver/OnlineRegions.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/regionserver/OnlineRegions.java (revision 483a54d3d0a6c9a89205b0541303c1aabf512913)
+++ src/main/java/org/apache/hadoop/hbase/regionserver/OnlineRegions.java (revision )
@@ -21,6 +21,8 @@
import org.apache.hadoop.hbase.Server;
+import java.io.IOException;
+
/**
* Interface to Map of online regions. In the Map, the key is the region's
* encoded name and the value is an {@link HRegion} instance.
@@ -49,4 +51,11 @@
* null if named region is not member of the online regions.
*/
public HRegion getFromOnlineRegions(String encodedRegionName);
+
+ /**
+ * Refresh schema for online regions of a table.
+ * @param tableName
+ * @return
+ */
+ public void refreshSchema(byte[] tableName) throws IOException;
}
\ No newline at end of file
Index: src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java
===================================================================
--- src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java (revision 483a54d3d0a6c9a89205b0541303c1aabf512913)
+++ src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java (revision )
@@ -36,8 +36,10 @@
import org.apache.hadoop.hbase.executor.EventHandler;
import org.apache.hadoop.hbase.master.BulkReOpen;
import org.apache.hadoop.hbase.master.MasterServices;
+import org.apache.hadoop.hbase.ipc.HMasterInterface;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.zookeeper.KeeperException;
+import org.apache.hadoop.hbase.zookeeper.MasterSchemaChangeTracker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -52,8 +54,10 @@
public abstract class TableEventHandler extends EventHandler {
private static final Log LOG = LogFactory.getLog(TableEventHandler.class);
protected final MasterServices masterServices;
+ protected HMasterInterface master = null;
protected final byte [] tableName;
protected final String tableNameStr;
+ protected boolean instantAction = false;
public TableEventHandler(EventType eventType, byte [] tableName, Server server,
MasterServices masterServices)
@@ -61,19 +65,18 @@
super(server, eventType);
this.masterServices = masterServices;
this.tableName = tableName;
- try {
- this.masterServices.checkTableModifiable(tableName);
- } catch (TableNotDisabledException ex) {
- if (eventType.isOnlineSchemaChangeSupported()) {
- LOG.debug("Ignoring table not disabled exception " +
- "for supporting online schema changes.");
- } else {
- throw ex;
- }
- }
+ this.masterServices.checkTableModifiable(tableName, eventType);
this.tableNameStr = Bytes.toString(this.tableName);
}
+ public TableEventHandler(EventType eventType, byte [] tableName, Server server,
+ MasterServices masterServices, HMasterInterface masterInterface)
+ throws IOException {
+ this(eventType, tableName, server, masterServices);
+ this.instantAction = true;
+ this.master = masterInterface;
+ }
+
@Override
public void process() {
try {
@@ -83,23 +86,37 @@
MetaReader.getTableRegions(this.server.getCatalogTracker(),
tableName);
handleTableOperation(hris);
- if (eventType.isOnlineSchemaChangeSupported() && this.masterServices.
+ handleSchemaChanges(hris);
+ } catch (IOException e) {
+ LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
+ } catch (KeeperException e) {
+ LOG.error("Error manipulating table " + Bytes.toString(tableName), e);
+ }
+ }
+
+ private void handleSchemaChanges(List.META..
+ * Only returns online regions. If a region on this table has been
+ * closed during a disable, etc., it will not be included in the returned list.
+ * So, the returned list may not necessarily be ALL regions in this table, its
+ * all the ONLINE regions in the table.
+ * @param tableName
+ * @return Online regions from tableName
+ */
+ private ListAfter construction, use {@link #start} to kick off tracking.
+ *
+ * @param watcher
+ * @param node
+ * @param abortable
+ */
+ public MasterSchemaChangeTracker(ZooKeeperWatcher watcher,
+ Abortable abortable) {
+ super(watcher, watcher.schemaZNode, abortable);
+ }
+
+
+ @Override
+ public void start() {
+ try {
+ ZKUtil.listChildrenAndWatchThem(watcher, watcher.schemaZNode);
+ watcher.registerListener(this);
+ } catch (KeeperException e) {
+ LOG.error("MasterSchemaChangeTracker startup failed.", e);
+ }
+ }
+
+ /**
+ * Create a new schema change ZK node.
+ * @param tableName
+ * @throws KeeperException
+ */
+ public void createSchemaChangeNode(String tableName) throws KeeperException {
+ LOG.info("Creating schema change node for table = "
+ + tableName + " Path = "
+ + getSchemaChangeNodePathForTable(tableName));
+ if (isSchemaChangeNodeExists(tableName)) {
+ LOG.info("Schema change node already exists for table = " + tableName
+ + " Deleting the schema change node.");
+ deleteSchemaChangeNode(tableName);
+ }
+ ZKUtil.createAndFailSilent(this.watcher,
+ getSchemaChangeNodePathForTable(tableName));
+ int rsCount = ZKUtil.getNumberOfChildren(this.watcher, watcher.rsZNode);
+ ZKUtil.setData(this.watcher, getSchemaChangeNodePathForTable(tableName),
+ Bytes.toBytes(rsCount));
+ ZKUtil.listChildrenAndWatchThem(this.watcher,
+ getSchemaChangeNodePathForTable(tableName));
+ }
+
+ private void deleteSchemaChangeNode(String tableName) throws KeeperException {
+ ZKUtil.deleteNodeRecursively(watcher,
+ getSchemaChangeNodePathForTable(tableName));
+ }
+
+ /**
+ * Create a new schema change ZK node.
+ * @param tableName
+ * @throws KeeperException
+ */
+ public boolean isSchemaChangeNodeExists(String tableName)
+ throws KeeperException {
+ return ZKUtil.checkExists(watcher,
+ getSchemaChangeNodePathForTable(tableName)) != -1;
+ }
+
+
+ @Override
+ public void nodeChildrenChanged(String path) {
+ if (path.startsWith(watcher.schemaZNode)
+ && !path.equals(watcher.schemaZNode)) {
+ try {
+ List After construction, use {@link #start} to kick off tracking.
+ *
+ * @param watcher
+ * @param node
+ * @param abortable
+ */
+ public SchemaChangeTracker(ZooKeeperWatcher watcher,
+ Abortable abortable,
+ RegionServerServices regionServer) {
+ super(watcher, watcher.schemaZNode, abortable);
+ this.regionServer = regionServer;
+ }
+
+ @Override
+ public void start() {
+ try {
+ ZKUtil.listChildrenAndWatchThem(watcher, node);
+ watcher.registerListener(this);
+ } catch (KeeperException e) {
+ LOG.error("RegionServer SchemaChangeTracker startup failed with " +
+ "KeeperException.", e);
+ }
+ }
+
+ // whenever new schema change occur this event will get triggered
+ @Override
+ public void nodeChildrenChanged(String path) {
+ if (path.equals(watcher.schemaZNode)) {
+ try {
+ List