commit 9056364d6434930643bcb93c510084d4b824c6da Author: Virag Kothari Date: Thu Oct 9 11:48:37 2014 -0700 First root commit diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java index 49f31d6..c3ee645 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HRegionInfo.java @@ -206,6 +206,10 @@ public class HRegionInfo implements Comparable { /** HRegionInfo for first meta region */ public static final HRegionInfo FIRST_META_REGIONINFO = new HRegionInfo(1L, TableName.META_TABLE_NAME); + + /** HRegionInfo for root region */ + public static final HRegionInfo ROOT_REGIONINFO = + new HRegionInfo(0L, TableName.ROOT_TABLE_NAME); private void setHashCode() { int result = Arrays.hashCode(this.regionName); @@ -716,6 +720,11 @@ public class HRegionInfo implements Comparable { public boolean isMetaRegion() { return tableName.equals(HRegionInfo.FIRST_META_REGIONINFO.getTable()); } + + /** @return true if this region is a root region */ + public boolean isRootRegion() { + return tableName.equals(HRegionInfo.ROOT_REGIONINFO.getTable()); + } /** * @return True if has been split and has daughters. @@ -865,7 +874,7 @@ public class HRegionInfo implements Comparable { * @return Comparator to use comparing {@link KeyValue}s. */ public KVComparator getComparator() { - return isMetaRegion()? + return (isMetaRegion() || isRootRegion()) ? KeyValue.META_COMPARATOR: KeyValue.COMPARATOR; } @@ -913,6 +922,8 @@ public class HRegionInfo implements Comparable { ProtobufUtil.toTableName(proto.getTableName()); if (tableName.equals(TableName.META_TABLE_NAME)) { return FIRST_META_REGIONINFO; + } else if (tableName.equals(TableName.ROOT_TABLE_NAME)) { + return ROOT_REGIONINFO; } long regionId = proto.getRegionId(); int replicaId = proto.hasReplicaId() ? proto.getReplicaId() : DEFAULT_REPLICA_ID; @@ -1076,7 +1087,7 @@ public class HRegionInfo implements Comparable { */ public static byte[] getRegionNameForDisplay(HRegionInfo hri, Configuration conf) { boolean displayKey = conf.getBoolean(DISPLAY_KEYS_KEY, true); - if (displayKey || hri.getTable().equals(TableName.META_TABLE_NAME)) { + if (displayKey || hri.getTable().equals(TableName.META_TABLE_NAME) || hri.getTable().equals(TableName.ROOT_TABLE_NAME)) { return hri.getRegionName(); } else { // create a modified regionname with the startkey replaced but preserving diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java index 058819b..484bc37 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/HTableDescriptor.java @@ -349,7 +349,7 @@ public class HTableDescriptor implements Comparable { * @param name */ private void setMetaFlags(final TableName name) { - setMetaRegion(isRootRegion() || + setMetaRegion(TableName.ROOT_TABLE_NAME.equals(name) || name.equals(TableName.META_TABLE_NAME)); } @@ -1260,7 +1260,7 @@ public class HTableDescriptor implements Comparable { return new Path(rootdir, new Path(HConstants.BASE_NAMESPACE_DIR, new Path(name.getNamespaceAsString(), new Path(name.getQualifierAsString())))); } - + /** Table descriptor for hbase:meta catalog table * Deprecated, use TableDescriptors#get(TableName.META_TABLE) or * Admin#getTableDescriptor(TableName.META_TABLE) instead. diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java index 45a561a..5c2f822 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/MetaTableAccessor.java @@ -36,6 +36,8 @@ import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.ipc.CoprocessorRpcChannel; +import org.apache.hadoop.hbase.master.RegionState; +import org.apache.hadoop.hbase.master.RegionState.State; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; import org.apache.hadoop.hbase.protobuf.generated.ClientProtos; import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos; @@ -44,6 +46,7 @@ import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.PairOfSameType; import org.apache.hadoop.hbase.util.Threads; +import org.apache.hadoop.hbase.zookeeper.MetaTableLocator; import java.io.IOException; import java.io.InterruptedIOException; @@ -136,9 +139,23 @@ public class MetaTableAccessor { public static List fullScanOfMeta(Connection connection) throws IOException { CollectAllVisitor v = new CollectAllVisitor(); - fullScan(connection, v, null); + fullScan(connection, v, null, false); return v.getResults(); } + + /** + * Performs a full scan of a hbase:root table. + * @return List of {@link Result} + * @throws IOException + */ + public static List fullScanOfRoot(Connection connection) + throws IOException { + CollectAllVisitor v = new CollectAllVisitor(); + fullScan(connection, v, null, true); + return v.getResults(); + } + + /** * Performs a full scan of hbase:meta. @@ -149,7 +166,7 @@ public class MetaTableAccessor { public static void fullScan(Connection connection, final Visitor visitor) throws IOException { - fullScan(connection, visitor, null); + fullScan(connection, visitor, null, false); } /** @@ -161,7 +178,7 @@ public class MetaTableAccessor { public static List fullScan(Connection connection) throws IOException { CollectAllVisitor v = new CollectAllVisitor(); - fullScan(connection, v, null); + fullScan(connection, v, null, false); return v.getResults(); } @@ -182,6 +199,29 @@ public class MetaTableAccessor { } return new HTable(tableName, connection); } + + private static Table getCatalogTable(final Connection connection, byte[] row) + throws IOException { + return isRootTableRow(row)? + getRootHTable(connection): + getMetaHTable(connection); + } + + /** + * Check if row belongs to root tables + * @param row + * @return True if row is row of hbase:root table. + */ + private static boolean isRootTableRow(final byte[] row) { + if (row.length < META_REGION_PREFIX.length + 2 /* ',', + '1' */) { + // Can't be meta table region. + return false; + } + // Compare the prefix of row. If it matches META_REGION_PREFIX prefix, + // then this is row from hbase:root table. + return Bytes.equals(row, 0, META_REGION_PREFIX.length, META_REGION_PREFIX, 0, + META_REGION_PREFIX.length); + } /** * Callers should call close on the returned {@link HTable} instance. @@ -193,6 +233,18 @@ public class MetaTableAccessor { throws IOException { return getHTable(connection, TableName.META_TABLE_NAME); } + + /** + * Get a root htable instance. + * Callers should call close on the returned {@link HTable} instance. + * @param connection connection we're using to access Root + * @return An {@link HTable} for hbase:root + * @throws IOException + */ + private static Table getRootHTable(final Connection connection) + throws IOException { + return getHTable(connection, TableName.ROOT_TABLE_NAME); + } /** * @param t Table to use (will be closed when done). @@ -226,7 +278,7 @@ public class MetaTableAccessor { } /** - * Returns the HRegionLocation from meta for the given region + * Returns the HRegionLocation from meta or root for the given region * @param connection connection we're using * @param regionName region we're looking for * @return HRegionLocation for the given region @@ -236,7 +288,7 @@ public class MetaTableAccessor { byte[] regionName) throws IOException { byte[] row = regionName; HRegionInfo parsedInfo = null; - try { + try { parsedInfo = parseRegionInfoFromRegionName(regionName); row = getMetaKeyForRegion(parsedInfo); } catch (Exception parseEx) { @@ -244,15 +296,48 @@ public class MetaTableAccessor { } Get get = new Get(row); get.addFamily(HConstants.CATALOG_FAMILY); - Result r = get(getMetaHTable(connection), get); + Result r = get(getCatalogTable(connection, regionName), get); RegionLocations locations = getRegionLocations(r); return locations == null ? null : locations.getRegionLocation(parsedInfo == null ? 0 : parsedInfo.getReplicaId()); } + + /** + * Returns the Regionstate from meta or root for the given region + * @param connection connection we're using + * @param regionName region we're looking for + * @return RegionState for the given region + * @throws IOException + */ + public static RegionState getRegionState(Connection connection, byte[] regionName) + throws IOException { + Result r = getRegionResult(connection, regionName); + RegionLocations locations = getRegionLocations(r); + HRegionInfo parsedInfo = null; + try { + parsedInfo = parseRegionInfoFromRegionName(regionName); + } catch (Exception parseEx) { + // Ignore. This is used with tableName passed as regionName. + } + int replicaId = parsedInfo == null ? 0 : parsedInfo.getReplicaId(); + HRegionLocation location = locations == null ? null : locations.getRegionLocation(replicaId); + Cell cell = r.getColumnLatestCell(HConstants.CATALOG_FAMILY, getStateColumn(replicaId)); + State state = + (cell != null && cell.getValueLength() != 0) ? State.valueOf(Bytes.toString( + cell.getValueArray(), cell.getValueOffset(), cell.getValueLength())) : null; + return new RegionState(parsedInfo, state, location != null ? location.getServerName() : null); + } + + private static byte[] getStateColumn(int replicaId) { + return replicaId == 0 + ? HConstants.STATE_QUALIFIER + : Bytes.toBytes(HConstants.STATE_QUALIFIER_STR + META_REPLICA_ID_DELIMITER + + String.format(HRegionInfo.REPLICA_ID_FORMAT, replicaId)); + } /** - * Returns the HRegionLocation from meta for the given region + * Returns the HRegionLocation from meta or root for the given region * @param connection connection we're using * @param regionInfo region information * @return HRegionLocation for the given region @@ -263,7 +348,7 @@ public class MetaTableAccessor { byte[] row = getMetaKeyForRegion(regionInfo); Get get = new Get(row); get.addFamily(HConstants.CATALOG_FAMILY); - Result r = get(getMetaHTable(connection), get); + Result r = get(getCatalogTable(connection, regionInfo.getRegionName()), get); return getRegionLocation(r, regionInfo, regionInfo.getReplicaId()); } @@ -278,6 +363,9 @@ public class MetaTableAccessor { */ protected static HRegionInfo parseRegionInfoFromRegionName(byte[] regionName) throws IOException { + if (Bytes.compareTo(MetaTableLocator.META_REGION_NAME, regionName) == 0) { + return HRegionInfo.FIRST_META_REGIONINFO; + } byte[][] fields = HRegionInfo.parseRegionName(regionName); long regionId = Long.parseLong(Bytes.toString(fields[2])); int replicaId = fields.length > 3 ? Integer.parseInt(Bytes.toString(fields[3]), 16) : 0; @@ -296,7 +384,7 @@ public class MetaTableAccessor { byte[] regionName) throws IOException { Get get = new Get(regionName); get.addFamily(HConstants.CATALOG_FAMILY); - return get(getMetaHTable(connection), get); + return get(getCatalogTable(connection,regionName), get); } /** @@ -326,7 +414,7 @@ public class MetaTableAccessor { public static boolean tableExists(Connection connection, final TableName tableName) throws IOException { - if (tableName.equals(TableName.META_TABLE_NAME)) { + if (tableName.equals(TableName.META_TABLE_NAME) || tableName.equals(TableName.ROOT_TABLE_NAME)) { // Catalog tables always exist. return true; } @@ -359,7 +447,7 @@ public class MetaTableAccessor { this.results.add(this.current); } }; - fullScan(connection, visitor, getTableStartRowForMeta(tableName)); + fullScan(connection, visitor, getTableStartRowForMeta(tableName), false); // If visitor has results >= 1 then table exists. return visitor.getResults().size() >= 1; } @@ -468,7 +556,7 @@ public class MetaTableAccessor { } /** - * Do not use this method to get meta table regions, use methods in MetaTableLocator instead. + * Do not use this method to get root table regions, use methods in MetaTableLocator instead. * @param connection connection we're using * @param tableName table to work with * @return Return list of regioninfos and server addresses. @@ -478,8 +566,8 @@ public class MetaTableAccessor { public static List> getTableRegionsAndLocations( Connection connection, final TableName tableName, final boolean excludeOfflinedSplitParents) throws IOException, InterruptedException { - if (tableName.equals(TableName.META_TABLE_NAME)) { - throw new IOException("This method can't be used to locate meta regions;" + if (tableName.equals(TableName.ROOT_TABLE_NAME)) { + throw new IOException("This method can't be used to locate root regions;" + " use MetaTableLocator instead"); } // Make a version of CollectingVisitor that collects HRegionInfo and ServerAddress @@ -514,7 +602,8 @@ public class MetaTableAccessor { } } }; - fullScan(connection, visitor, getTableStartRowForMeta(tableName)); + fullScan(connection, visitor, getTableStartRowForMeta(tableName), + TableName.META_TABLE_NAME.equals(tableName) ? true : false); return visitor.getResults(); } @@ -576,11 +665,11 @@ public class MetaTableAccessor { * @param visitor Visitor invoked against each row. * @param startrow Where to start the scan. Pass null if want to begin scan * at first row. - * hbase:meta, the default (pass false to scan hbase:meta) + * @param scanRoot pass false to scan hbase:meta and true to scan hbase:root * @throws IOException */ public static void fullScan(Connection connection, - final Visitor visitor, final byte [] startrow) + final Visitor visitor, final byte [] startrow, boolean scanRoot) throws IOException { Scan scan = new Scan(); if (startrow != null) scan.setStartRow(startrow); @@ -590,10 +679,10 @@ public class MetaTableAccessor { scan.setCaching(caching); } scan.addFamily(HConstants.CATALOG_FAMILY); - Table metaTable = getMetaHTable(connection); + Table catalogTable = scanRoot ? getRootHTable(connection) : getMetaHTable(connection); ResultScanner scanner = null; try { - scanner = metaTable.getScanner(scan); + scanner = catalogTable.getScanner(scan); Result data; while((data = scanner.next()) != null) { if (data.isEmpty()) continue; @@ -602,7 +691,7 @@ public class MetaTableAccessor { } } finally { if (scanner != null) scanner.close(); - metaTable.close(); + catalogTable.close(); } } @@ -745,7 +834,6 @@ public class MetaTableAccessor { locations.add(getRegionLocation(r, regionInfo, replicaId)); } - return new RegionLocations(locations); } @@ -946,6 +1034,17 @@ public class MetaTableAccessor { throws IOException { put(getMetaHTable(connection), p); } + + /** + * Put the passed p to a catalog table. + * @param ct CatalogTracker on whose back we will ride the edit. + * @param p Put to add + * @throws IOException + */ + private static void putToCatalogTable(final Connection connection, final Put p) + throws IOException { + put(getCatalogTable(connection, p.getRow()), p); + } /** * @param t Table to use (will be closed when done). @@ -1303,7 +1402,7 @@ public class MetaTableAccessor { // region replicas are kept in the primary region's row Put put = new Put(getMetaKeyForRegion(regionInfo)); addLocation(put, sn, openSeqNum, regionInfo.getReplicaId()); - putToMetaTable(connection, put); + putToCatalogTable(connection, put); LOG.info("Updated row " + regionInfo.getRegionNameAsString() + " with server=" + sn); } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java index 1da1320..22f8933 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java @@ -1058,7 +1058,8 @@ class ConnectionManager { // Since this is an explicit request not to use any caching, finding // disabled tables should not be desirable. This will ensure that an exception is thrown when // the first time a disabled table is interacted with. - if (!tableName.equals(TableName.META_TABLE_NAME) && isTableDisabled(tableName)) { + if (!(tableName.equals(TableName.META_TABLE_NAME) || tableName + .equals(TableName.ROOT_TABLE_NAME)) && isTableDisabled(tableName)) { throw new TableNotEnabledException(tableName.getNameAsString() + " is disabled."); } @@ -1087,15 +1088,19 @@ class ConnectionManager { throw new IllegalArgumentException( "table name cannot be null or zero length"); } - if (tableName.equals(TableName.META_TABLE_NAME)) { - return locateMeta(tableName, useCache, replicaId); + if (tableName.equals(TableName.ROOT_TABLE_NAME)) { + return locateRoot(tableName, useCache, replicaId); + } else if (tableName.equals(TableName.META_TABLE_NAME)) { + return locateRegionInMeta(TableName.ROOT_TABLE_NAME, tableName, row, useCache, retry, + replicaId); } else { // Region not in the cache - have to go to the meta RS - return locateRegionInMeta(tableName, row, useCache, retry, replicaId); + return locateRegionInMeta(TableName.META_TABLE_NAME, tableName, row, useCache, retry, + replicaId); } } - private RegionLocations locateMeta(final TableName tableName, + private RegionLocations locateRoot(final TableName tableName, boolean useCache, int replicaId) throws IOException { // HBASE-10785: We cache the location of the META itself, so that we are not overloading // zookeeper with one request for every region lookup. We cache the META with empty row @@ -1119,9 +1124,10 @@ class ConnectionManager { return locations; } } + // // Look up from zookeeper - locations = this.registry.getMetaRegionLocation(); + locations = this.registry.getRootRegionLocation(); if (locations != null) { cacheLocation(tableName, locations); } @@ -1133,8 +1139,8 @@ class ConnectionManager { * Search the hbase:meta table for the HRegionLocation * info that contains the table and row we're seeking. */ - private RegionLocations locateRegionInMeta(TableName tableName, byte[] row, - boolean useCache, boolean retry, int replicaId) throws IOException { + private RegionLocations locateRegionInMeta(TableName parentTable, TableName tableName, + byte[] row, boolean useCache, boolean retry, int replicaId) throws IOException { // If we are supposed to be using the cache, look in the cache to see if // we already have the region. @@ -1180,7 +1186,7 @@ class ConnectionManager { Result regionInfoRow = null; ReversedClientScanner rcs = null; try { - rcs = new ClientSmallReversedScanner(conf, s, TableName.META_TABLE_NAME, this, + rcs = new ClientSmallReversedScanner(conf, s, parentTable, this, rpcCallerFactory, rpcControllerFactory, getBatchPool(), 0); regionInfoRow = rcs.next(); } finally { @@ -1202,7 +1208,7 @@ class ConnectionManager { HRegionInfo regionInfo = locations.getRegionLocation(replicaId).getRegionInfo(); if (regionInfo == null) { throw new IOException("HRegionInfo was null or empty in " + - TableName.META_TABLE_NAME + ", row=" + regionInfoRow); + parentTable + ", row=" + regionInfoRow); } // possible we got a region of a different table... @@ -1226,13 +1232,13 @@ class ConnectionManager { ServerName serverName = locations.getRegionLocation(replicaId).getServerName(); if (serverName == null) { throw new NoServerForRegionException("No server address listed " + - "in " + TableName.META_TABLE_NAME + " for region " + + "in " + parentTable + " for region " + regionInfo.getRegionNameAsString() + " containing row " + Bytes.toStringBinary(row)); } if (isDeadServer(serverName)){ - throw new RegionServerStoppedException("hbase:meta says the region "+ + throw new RegionServerStoppedException(parentTable + " says the region "+ regionInfo.getRegionNameAsString()+" is managed by the server " + serverName + ", but it is dead."); } @@ -1253,7 +1259,7 @@ class ConnectionManager { if (tries < localNumRetries - 1) { if (LOG.isDebugEnabled()) { LOG.debug("locateRegionInMeta parentTable=" + - TableName.META_TABLE_NAME + ", metaLocation=" + + parentTable + ", metaLocation=" + ", attempt=" + tries + " of " + localNumRetries + " failed; retrying after sleep of " + ConnectionUtils.getPauseTime(this.pause, tries) + " because: " + e.getMessage()); @@ -1264,7 +1270,7 @@ class ConnectionManager { // Only relocate the parent region if necessary if(!(e instanceof RegionOfflineException || e instanceof NoServerForRegionException)) { - relocateRegion(TableName.META_TABLE_NAME, metaKey, replicaId); + relocateRegion(parentTable, metaKey, replicaId); } } try{ diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index 79c2eb1..9ab9b4d 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -1728,8 +1728,8 @@ public class HBaseAdmin implements Admin { zookeeper = new ZooKeeperWatcher(conf, ZK_IDENTIFIER_PREFIX + connection.toString(), new ThrowableAbortable()); List> pairs; - if (TableName.META_TABLE_NAME.equals(tableName)) { - pairs = new MetaTableLocator().getMetaRegionsAndLocations(zookeeper); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + pairs = new MetaTableLocator().getRootRegionsAndLocations(zookeeper); } else { pairs = MetaTableAccessor.getTableRegionsAndLocations(connection, tableName); } @@ -2086,8 +2086,8 @@ public class HBaseAdmin implements Admin { zookeeper = new ZooKeeperWatcher(conf, ZK_IDENTIFIER_PREFIX + connection.toString(), new ThrowableAbortable()); List> pairs; - if (TableName.META_TABLE_NAME.equals(tableName)) { - pairs = new MetaTableLocator().getMetaRegionsAndLocations(zookeeper); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + pairs = new MetaTableLocator().getRootRegionsAndLocations(zookeeper); } else { pairs = MetaTableAccessor.getTableRegionsAndLocations(connection, tableName); } @@ -2572,8 +2572,8 @@ public class HBaseAdmin implements Admin { new ThrowableAbortable()); List regions = null; try { - if (TableName.META_TABLE_NAME.equals(tableName)) { - regions = new MetaTableLocator().getMetaRegions(zookeeper); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + regions = new MetaTableLocator().getRootRegions(zookeeper); } else { regions = MetaTableAccessor.getTableRegions(connection, tableName, true); } @@ -2680,8 +2680,8 @@ public class HBaseAdmin implements Admin { try { checkTableExists(tableName); List> pairs; - if (TableName.META_TABLE_NAME.equals(tableName)) { - pairs = new MetaTableLocator().getMetaRegionsAndLocations(zookeeper); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + pairs = new MetaTableLocator().getRootRegionsAndLocations(zookeeper); } else { pairs = MetaTableAccessor.getTableRegionsAndLocations(connection, tableName); } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java index cd494a4..2a46004 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/Registry.java @@ -36,7 +36,7 @@ interface Registry { * @return Meta region location * @throws IOException */ - RegionLocations getMetaRegionLocation() throws IOException; + RegionLocations getRootRegionLocation() throws IOException; /** * @return Cluster id. diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java index 7cab2cc..14840b4 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ZooKeeperRegistry.java @@ -49,20 +49,20 @@ class ZooKeeperRegistry implements Registry { } @Override - public RegionLocations getMetaRegionLocation() throws IOException { + public RegionLocations getRootRegionLocation() throws IOException { ZooKeeperKeepAliveConnection zkw = hci.getKeepAliveZooKeeperWatcher(); try { if (LOG.isTraceEnabled()) { - LOG.trace("Looking up meta region location in ZK," + " connection=" + this); + LOG.trace("Looking up root region location in ZK," + " connection=" + this); } ServerName servername = new MetaTableLocator().blockUntilAvailable(zkw, hci.rpcTimeout); if (LOG.isTraceEnabled()) { - LOG.trace("Looked up meta region location, connection=" + this + + LOG.trace("Looked up root region location, connection=" + this + "; serverName=" + ((servername == null) ? "null" : servername)); } if (servername == null) return null; - HRegionLocation loc = new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, servername, 0); + HRegionLocation loc = new HRegionLocation(HRegionInfo.ROOT_REGIONINFO, servername, 0); return new RegionLocations(new HRegionLocation[] {loc}); } catch (InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/EventType.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/EventType.java index 9764efd..f2e9446 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/EventType.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/EventType.java @@ -224,10 +224,18 @@ public enum EventType { * Master is processing shutdown of a RS */ M_SERVER_SHUTDOWN (70, ExecutorType.MASTER_SERVER_OPERATIONS), + + /** + * Master controlled events to be executed on the master.
+ * M_ROOT_SERVER_SHUTDOWN
+ * Master is processing shutdown of RS hosting a root region. + */ + M_ROOT_SERVER_SHUTDOWN (71, ExecutorType.MASTER_ROOT_OPERATIONS), + /** * Master controlled events to be executed on the master.
* M_META_SERVER_SHUTDOWN
- * Master is processing shutdown of RS hosting a meta region (-ROOT- or hbase:meta). + * Master is processing shutdown of RS hosting a hbase:meta region */ M_META_SERVER_SHUTDOWN (72, ExecutorType.MASTER_META_SERVER_OPERATIONS), /** diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/ExecutorType.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/ExecutorType.java index 5590b0a..10cd604 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/ExecutorType.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/executor/ExecutorType.java @@ -36,6 +36,7 @@ public enum ExecutorType { MASTER_RS_SHUTDOWN (5), MASTER_META_SERVER_OPERATIONS (6), M_LOG_REPLAY_OPS (7), + MASTER_ROOT_OPERATIONS (8), // RegionServer executor services RS_OPEN_REGION (20), diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/MetaTableLocator.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/MetaTableLocator.java index 98a25d3..c4fecbb 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/MetaTableLocator.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/MetaTableLocator.java @@ -34,8 +34,11 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HRegionLocation; +import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.HConnection; import org.apache.hadoop.hbase.client.RetriesExhaustedException; import org.apache.hadoop.hbase.exceptions.DeserializationException; @@ -58,56 +61,58 @@ import com.google.common.base.Stopwatch; import com.google.protobuf.InvalidProtocolBufferException; /** - * Utility class to perform operation (get/wait for/verify/set/delete) on znode in ZooKeeper - * which keeps hbase:meta region server location. + * Utility class to perform operation (get/wait for/verify/set) on hbase:root and hbase:meta * * Stateless class with a bunch of static methods. Doesn't manage resources passed in * (e.g. HConnection, ZooKeeperWatcher etc). * - * Meta region location is set by RegionServerServices. + * Root region location is set by RegionServerServices. * This class doesn't use ZK watchers, rather accesses ZK directly. * * This class it stateless. The only reason it's not made a non-instantiable util class * with a collection of static methods is that it'd be rather hard to mock properly in tests. - * + * * TODO: rewrite using RPC calls to master to find out about hbase:meta. */ @InterfaceAudience.Private public class MetaTableLocator { private static final Log LOG = LogFactory.getLog(MetaTableLocator.class); - static final byte [] META_REGION_NAME = - HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); + private static final byte [] ROOT_REGION_NAME = + HRegionInfo.ROOT_REGIONINFO.getRegionName(); + + public static final byte [] META_REGION_NAME = + HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); // only needed to allow non-timeout infinite waits to stop when cluster shuts down private volatile boolean stopped = false; /** - * Checks if the meta region location is available. - * @return true if meta region location is available, false if not + * Checks if the root region location is available. + * @return true if root region location is available, false if not */ - public boolean isLocationAvailable(ZooKeeperWatcher zkw) { - return getMetaRegionLocation(zkw) != null; + public boolean isRootLocationAvailable(ZooKeeperWatcher zkw) { + return getRootRegionLocation(zkw) != null; } /** * @param zkw ZooKeeper watcher to be used - * @return meta table regions and their locations. + * @return root table regions and their locations. */ - public List> getMetaRegionsAndLocations(ZooKeeperWatcher zkw) { - ServerName serverName = new MetaTableLocator().getMetaRegionLocation(zkw); + public List> getRootRegionsAndLocations(ZooKeeperWatcher zkw) { + ServerName serverName = getRootRegionLocation(zkw); List> list = new ArrayList<>(); - list.add(new Pair<>(HRegionInfo.FIRST_META_REGIONINFO, serverName)); + list.add(new Pair<>(HRegionInfo.ROOT_REGIONINFO, serverName)); return list; } /** * @param zkw ZooKeeper watcher to be used - * @return List of meta regions + * @return List of root regions */ - public List getMetaRegions(ZooKeeperWatcher zkw) { + public List getRootRegions(ZooKeeperWatcher zkw) { List> result; - result = getMetaRegionsAndLocations(zkw); + result = getRootRegionsAndLocations(zkw); return getListOfHRegionInfos(result); } @@ -122,14 +127,14 @@ public class MetaTableLocator { } /** - * Gets the meta region location, if available. Does not block. + * Gets the root region location, if available. Does not block. * @param zkw zookeeper connection to use * @return server name or null if we failed to get the data. */ @Nullable - public ServerName getMetaRegionLocation(final ZooKeeperWatcher zkw) { + public ServerName getRootRegionLocation(final ZooKeeperWatcher zkw) { try { - RegionState state = getMetaRegionState(zkw); + RegionState state = getRootRegionState(zkw); return state.isOpened() ? state.getServerName() : null; } catch (KeeperException ke) { return null; @@ -137,16 +142,15 @@ public class MetaTableLocator { } /** - * Gets the meta region location, if available, and waits for up to the + * Gets the root region location, if available, and waits for up to the * specified timeout if not immediately available. - * Given the zookeeper notification could be delayed, we will try to - * get the latest data. + * @param zkw the zookeeper watcher * @param timeout maximum time to wait, in millis - * @return server name for server hosting meta region formatted as per + * @return server name for server hosting root region formatted as per * {@link ServerName}, or null if none available * @throws InterruptedException if interrupted while waiting */ - public ServerName waitMetaRegionLocation(ZooKeeperWatcher zkw, long timeout) + public ServerName waitRootRegionLocation(ZooKeeperWatcher zkw, long timeout) throws InterruptedException, NotAllMetaRegionsOnlineException { try { if (ZKUtil.checkExists(zkw, zkw.baseZNode) == -1) { @@ -168,21 +172,23 @@ public class MetaTableLocator { } /** - * Waits indefinitely for availability of hbase:meta. Used during - * cluster startup. Does not verify meta, just that something has been + * Waits indefinitely for availability of hbase:root. Used during + * cluster startup. Does not verify root, just that something has been * set up in zk. - * @see #waitMetaRegionLocation(org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher, long) + * @see #waitRootRegionLocation(org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher, long) * @throws InterruptedException if interrupted while waiting */ - public void waitMetaRegionLocation(ZooKeeperWatcher zkw) throws InterruptedException { + public void waitRootRegionLocation(ZooKeeperWatcher zkw) throws InterruptedException { Stopwatch stopwatch = new Stopwatch().start(); while (!stopped) { try { - if (waitMetaRegionLocation(zkw, 100) != null) break; + if (waitRootRegionLocation(zkw, 100) != null) { + break; + } long sleepTime = stopwatch.elapsedMillis(); // +1 in case sleepTime=0 if ((sleepTime + 1) % 10000 == 0) { - LOG.warn("Have been waiting for meta to be assigned for " + sleepTime + "ms"); + LOG.warn("Have been waiting for root to be assigned for " + sleepTime + "ms"); } } catch (NotAllMetaRegionsOnlineException e) { if (LOG.isTraceEnabled()) { @@ -192,21 +198,45 @@ public class MetaTableLocator { } } } + + /** + * Waits indefinitely for availability of hbase:meta. Used during cluster startup. + * Does not verify meta, just that the location has been set up in root table + * @throws InterruptedException if interrupted while waiting + */ + public void waitMetaRegionLocation(Connection connection) throws IOException, + InterruptedException { + Stopwatch stopwatch = new Stopwatch().start(); + while (!stopped) { + if (waitMetaRegionLocation(connection, 100) != null) { + break; + } + long sleepTime = stopwatch.elapsedMillis(); + // +1 in case sleepTime=0 + if ((sleepTime + 1) % 10000 == 0) { + LOG.warn("Have been waiting for meta to be assigned for " + sleepTime + "ms"); + } + } + } /** - * Verify hbase:meta is deployed and accessible. - * @param timeout How long to wait on zk for meta address (passed through to - * the internal call to {@link #getMetaServerConnection}. - * @return True if the hbase:meta location is healthy. + * Verify hbase:root is deployed and accessible. + * @param hConnection the HConnection used to verify root location + * @return True if the hbase:root location is healthy. * @throws java.io.IOException * @throws InterruptedException */ - public boolean verifyMetaRegionLocation(HConnection hConnection, + public boolean verifyRootRegionLocation(HConnection hConnection, ZooKeeperWatcher zkw, final long timeout) throws InterruptedException, IOException { AdminProtos.AdminService.BlockingInterface service = null; + ServerName serverName = null; try { - service = getMetaServerConnection(hConnection, zkw, timeout); + serverName = waitRootRegionLocation(zkw, timeout); + if (serverName == null) { + return false; + } + service = getCachedConnection(hConnection, serverName); } catch (NotAllMetaRegionsOnlineException e) { // Pass } catch (ServerNotRunningYetException e) { @@ -217,7 +247,7 @@ public class MetaTableLocator { // Pass -- server name sends us to a server that is dying or already dead. } return (service != null) && verifyRegionLocation(service, - getMetaRegionLocation(zkw), META_REGION_NAME); + serverName, ROOT_REGION_NAME); } /** @@ -270,22 +300,6 @@ public class MetaTableLocator { } /** - * Gets a connection to the server hosting meta, as reported by ZooKeeper, - * waiting up to the specified timeout for availability. - *

WARNING: Does not retry. Use an {@link org.apache.hadoop.hbase.client.HTable} instead. - * @param timeout How long to wait on meta location - * @return connection to server hosting meta - * @throws InterruptedException - * @throws NotAllMetaRegionsOnlineException if timed out waiting - * @throws IOException - */ - private AdminService.BlockingInterface getMetaServerConnection(HConnection hConnection, - ZooKeeperWatcher zkw, long timeout) - throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { - return getCachedConnection(hConnection, waitMetaRegionLocation(zkw, timeout)); - } - - /** * @param sn ServerName to get a connection against. * @return The AdminProtocol we got when we connected to sn * May have come from cache, may not be good, may have been setup by this @@ -338,35 +352,37 @@ public class MetaTableLocator { } /** - * Sets the location of hbase:meta in ZooKeeper to the + * Sets the location of hbase:root in ZooKeeper to the * specified server address. * @param zookeeper zookeeper reference - * @param serverName The server hosting hbase:meta + * @param serverName The server hosting hbase:root * @param state The region transition state * @throws KeeperException unexpected zookeeper exception */ - public static void setMetaLocation(ZooKeeperWatcher zookeeper, + public static void setRootLocation(ZooKeeperWatcher zookeeper, ServerName serverName, RegionState.State state) throws KeeperException { - LOG.info("Setting hbase:meta region location in ZooKeeper as " + serverName); + LOG.info("Setting hbase:root region location in ZooKeeper as " + serverName); // Make the MetaRegionServer pb and then get its bytes and save this as // the znode content. MetaRegionServer pbrsr = MetaRegionServer.newBuilder() .setServer(ProtobufUtil.toServerName(serverName)) .setRpcVersion(HConstants.RPC_CURRENT_VERSION) - .setState(state.convert()).build(); + .setState(state.convert()) + .setIsRoot(true) + .setRootVersion(HConstants.ROOT_SCHEMA_VERSION).build(); byte[] data = ProtobufUtil.prependPBMagic(pbrsr.toByteArray()); try { ZKUtil.setData(zookeeper, zookeeper.metaServerZNode, data); } catch(KeeperException.NoNodeException nne) { - LOG.debug("META region location doesn't existed, create it"); + LOG.debug("hbase:root region location didn't exist, create it"); ZKUtil.createAndWatch(zookeeper, zookeeper.metaServerZNode, data); } } /** - * Load the meta region state from the meta server ZNode. + * Load the root region state from the meta server ZNode. */ - public static RegionState getMetaRegionState(ZooKeeperWatcher zkw) throws KeeperException { + public static RegionState getRootRegionState(ZooKeeperWatcher zkw) throws KeeperException { RegionState.State state = RegionState.State.OPEN; ServerName serverName = null; try { @@ -384,7 +400,7 @@ public class MetaTableLocator { serverName = ServerName.valueOf( sn.getHostName(), sn.getPort(), sn.getStartCode()); } catch (InvalidProtocolBufferException e) { - throw new DeserializationException("Unable to parse meta region location"); + throw new DeserializationException("Unable to parse root region location"); } } else { // old style of meta region location? @@ -398,18 +414,18 @@ public class MetaTableLocator { if (serverName == null) { state = RegionState.State.OFFLINE; } - return new RegionState(HRegionInfo.FIRST_META_REGIONINFO, + return new RegionState(HRegionInfo.ROOT_REGIONINFO, state, serverName); } /** - * Deletes the location of hbase:meta in ZooKeeper. + * Deletes the location of hbase:root in ZooKeeper. * @param zookeeper zookeeper reference * @throws KeeperException unexpected zookeeper exception */ - public void deleteMetaLocation(ZooKeeperWatcher zookeeper) + public void deleteRootLocation(ZooKeeperWatcher zookeeper) throws KeeperException { - LOG.info("Deleting hbase:meta region location in ZooKeeper"); + LOG.info("Deleting hbase:root region location in ZooKeeper"); try { // Just delete the node. Don't need any watches. ZKUtil.deleteNode(zookeeper, zookeeper.metaServerZNode); @@ -434,7 +450,7 @@ public class MetaTableLocator { ServerName sn = null; try { while (true) { - sn = getMetaRegionLocation(zkw); + sn = getRootRegionLocation(zkw); if (sn != null || sw.elapsedMillis() > timeout - HConstants.SOCKET_RETRY_WAIT_MS) { break; @@ -446,6 +462,34 @@ public class MetaTableLocator { } return sn; } + + /** + * Wait for meta to be available. This only checks whether meta is set in root. Doesn't try + * to verify the meta location + * @param conn the Connection + * @param timeout the timeout after which we stop retry + * @return ServerName the server holding meta + * @throws IOException + * @throws InterruptedException + */ + public ServerName waitMetaRegionLocation(final Connection conn, final long timeout) + throws IOException, InterruptedException { + if (timeout < 0) throw new IllegalArgumentException(); + Stopwatch sw = new Stopwatch().start(); + ServerName sn = null; + try { + while (true) { + sn = getMetaRegionLocation(conn); + if (sn != null || sw.elapsedMillis() > timeout - HConstants.SOCKET_RETRY_WAIT_MS) { + break; + } + Thread.sleep(HConstants.SOCKET_RETRY_WAIT_MS); + } + } finally { + sw.stop(); + } + return sn; + } /** * Stop working. @@ -457,4 +501,60 @@ public class MetaTableLocator { stopped = true; } } + + + /** + * Finds location of meta by reading hbase:root + * @return {@link ServerName} for server hosting hbase:meta or if null, we'll read + * the location that is up in hbase:root table (which could be null or just + * plain stale). + * @throws IOException + */ + public ServerName getMetaRegionLocation(Connection connection) throws IOException { + HRegionLocation regionLocation; + regionLocation = MetaTableAccessor.getRegionLocation(connection, META_REGION_NAME); + return regionLocation == null ? null : regionLocation.getServerName(); + } + + /** + * Finds location of meta by reading hbase:root + * @return {@link ServerName} for server hosting hbase:meta or if null, we'll read + * the location that is up in hbase:root table (which could be null or just + * plain stale). + * @throws IOException + */ + public RegionState getMetaRegionState(Connection connection) throws IOException { + return MetaTableAccessor.getRegionState(connection, META_REGION_NAME); + } + + /** + * Verify hbase:meta is deployed and accessible. + * @param hConnection the HConnection used to verify the meta location + * @return True if the hbase:meta location is healthy. + * @throws java.io.IOException + * @throws InterruptedException + */ + public boolean verifyMetaRegionLocation(HConnection hConnection) throws IOException { + AdminProtos.AdminService.BlockingInterface service = null; + ServerName serverName = null; + try { + serverName = getMetaRegionLocation(hConnection); + if (serverName == null) { + return false; + } + service = getCachedConnection(hConnection, serverName); + } catch (NotAllMetaRegionsOnlineException e) { + // Pass + } catch (ServerNotRunningYetException e) { + // Pass -- remote server is not up so can't be carrying root + } catch (UnknownHostException e) { + // Pass -- server name doesn't resolve so it can't be assigned anything. + } catch (RegionServerStoppedException e) { + // Pass -- server name sends us to a server that is dying or already dead. + } + return (service != null) && verifyRegionLocation(service, + serverName, META_REGION_NAME); + } + + } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java index 4d4eba3..a82c4a8 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java @@ -1588,8 +1588,8 @@ public class ZKUtil { zkw.backupMasterAddressesZNode)) { sb.append("\n ").append(child); } - sb.append("\nRegion server holding hbase:meta: " - + new MetaTableLocator().getMetaRegionLocation(zkw)); + sb.append("\nRegion server holding hbase:root: " + + new MetaTableLocator().getRootRegionLocation(zkw)); sb.append("\nRegion servers:"); for (String child : listChildrenNoWatch(zkw, zkw.rsZNode)) { sb.append("\n ").append(child); diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java index b9f1ede..e47b97a 100644 --- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestClientNoCluster.java @@ -22,6 +22,7 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.net.SocketTimeoutException; +import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.Map; @@ -119,9 +120,9 @@ public class TestClientNoCluster extends Configured implements Tool { } @Override - public RegionLocations getMetaRegionLocation() throws IOException { + public RegionLocations getRootRegionLocation() throws IOException { return new RegionLocations( - new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, META_HOST)); + new HRegionLocation(HRegionInfo.ROOT_REGIONINFO, META_HOST)); } @Override @@ -145,7 +146,7 @@ public class TestClientNoCluster extends Configured implements Tool { Configuration localConfig = HBaseConfiguration.create(this.conf); // This override mocks up our exists/get call to throw a RegionServerStoppedException. localConfig.set("hbase.client.connection.impl", RpcTimeoutConnection.class.getName()); - Table table = new HTable(localConfig, TableName.META_TABLE_NAME); + Table table = new HTable(localConfig, TableName.ROOT_TABLE_NAME); Throwable t = null; LOG.info("Start"); try { @@ -182,7 +183,7 @@ public class TestClientNoCluster extends Configured implements Tool { // and it has expired. Otherwise, if this functionality is broke, all retries will be run -- // all ten of them -- and we'll get the RetriesExhaustedException exception. localConfig.setInt(HConstants.HBASE_CLIENT_META_OPERATION_TIMEOUT, pause - 1); - Table table = new HTable(localConfig, TableName.META_TABLE_NAME); + Table table = new HTable(localConfig, TableName.ROOT_TABLE_NAME); Throwable t = null; try { // An exists call turns into a get w/ a flag. @@ -214,7 +215,7 @@ public class TestClientNoCluster extends Configured implements Tool { // Go against meta else we will try to find first region for the table on construction which // means we'll have to do a bunch more mocking. Tests that go against meta only should be // good for a bit of testing. - Table table = new HTable(this.conf, TableName.META_TABLE_NAME); + Table table = new HTable(this.conf, TableName.ROOT_TABLE_NAME); ResultScanner scanner = table.getScanner(HConstants.CATALOG_FAMILY); try { Result result = null; @@ -234,7 +235,7 @@ public class TestClientNoCluster extends Configured implements Tool { // Go against meta else we will try to find first region for the table on construction which // means we'll have to do a bunch more mocking. Tests that go against meta only should be // good for a bit of testing. - Table table = new HTable(this.conf, TableName.META_TABLE_NAME); + Table table = new HTable(this.conf, TableName.ROOT_TABLE_NAME); ResultScanner scanner = table.getScanner(HConstants.CATALOG_FAMILY); try { Result result = null; @@ -304,6 +305,28 @@ public class TestClientNoCluster extends Configured implements Tool { throw new IOException(e); } } + + // Override this so client doesn't try to scan root to find meta. + // This is required for testDoNotRetryMetaScanner() + @Override + public RegionLocations locateRegion(final TableName tableName, + final byte [] row, boolean useCache, boolean retry, int replicaId) throws IOException { + if (tableName.equals(TableName.META_TABLE_NAME)) { + return new RegionLocations(Arrays.asList(new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, META_SERVERNAME, 0))); + } else { + return super.locateRegion(tableName, row, useCache, retry, replicaId); + } + } + + @Override + public HRegionLocation locateRegion( + final TableName tableName, final byte[] row) throws IOException{ + if (tableName.equals(TableName.META_TABLE_NAME)) { + return new HRegionLocation(HRegionInfo.FIRST_META_REGIONINFO, META_SERVERNAME); + } else { + return super.relocateRegion(tableName, row); + } + } @Override public BlockingInterface getClient(ServerName sn) throws IOException { diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java index 1f23828..ac89546 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/HConstants.java @@ -189,6 +189,11 @@ public final class HConstants { public static final String ZOOKEEPER_ZNODE_PARENT = "zookeeper.znode.parent"; public static final String DEFAULT_ZOOKEEPER_ZNODE_PARENT = "/hbase"; + + /** + * The current root schema version. + */ + public static final byte ROOT_SCHEMA_VERSION = 0; /** * Parameter name for the limit on concurrent client-side zookeeper @@ -668,7 +673,7 @@ public final class HConstants { /** * Default value of {@link #HBASE_CLIENT_RETRIES_NUMBER}. */ - public static int DEFAULT_HBASE_CLIENT_RETRIES_NUMBER = 31; + public static int DEFAULT_HBASE_CLIENT_RETRIES_NUMBER = 35; /** * Parameter name to set the default scanner caching for all clients. @@ -952,7 +957,7 @@ public final class HConstants { /** Directories that are not HBase user table directories */ public static final List HBASE_NON_USER_TABLE_DIRS = Collections.unmodifiableList(Arrays.asList((String[])ArrayUtils.addAll( - new String[] { TableName.META_TABLE_NAME.getNameAsString() }, + new String[] { TableName.META_TABLE_NAME.getNameAsString(), TableName.ROOT_TABLE_NAME.getNameAsString() }, HBASE_NON_TABLE_DIRS.toArray()))); /** Health script related settings. */ diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java index 802319e..8f3fae0 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/TableName.java @@ -81,6 +81,10 @@ public final class TableName implements Comparable { /** The hbase:meta table's name. */ public static final TableName META_TABLE_NAME = valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "meta"); + + /** The hbase:root table's name. */ + public static final TableName ROOT_TABLE_NAME = + valueOf(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "root"); /** The Namespace table's name. */ public static final TableName NAMESPACE_TABLE_NAME = @@ -271,7 +275,8 @@ public final class TableName implements Comparable { this.qualifierAsString = Bytes.toString(this.qualifier); if (qualifierAsString.equals(OLD_ROOT_STR)) { - throw new IllegalArgumentException(OLD_ROOT_STR + " has been deprecated."); + throw new IllegalArgumentException(OLD_ROOT_STR + " no longer exists. The table has been " + + "renamed to " + ROOT_TABLE_NAME); } if (qualifierAsString.equals(OLD_META_STR)) { throw new IllegalArgumentException(OLD_META_STR + " no longer exists. The table has been " + @@ -501,7 +506,7 @@ public final class TableName implements Comparable { * @return The comparator. */ public KVComparator getRowComparator() { - if(TableName.META_TABLE_NAME.equals(this)) { + if(TableName.META_TABLE_NAME.equals(this) || TableName.ROOT_TABLE_NAME.equals(this)) { return KeyValue.META_COMPARATOR; } return KeyValue.COMPARATOR; diff --git a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystemSource.java b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystemSource.java index 2307599..d746068 100644 --- a/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystemSource.java +++ b/hbase-hadoop-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystemSource.java @@ -44,18 +44,26 @@ public interface MetricsMasterFileSystemSource extends BaseSource { String META_SPLIT_TIME_NAME = "metaHlogSplitTime"; String META_SPLIT_SIZE_NAME = "metaHlogSplitSize"; + String ROOT_SPLIT_TIME_NAME = "rootHlogSplitTime"; + String ROOT_SPLIT_SIZE_NAME = "rootHlogSplitSize"; String SPLIT_TIME_NAME = "hlogSplitTime"; String SPLIT_SIZE_NAME = "hlogSplitSize"; String META_SPLIT_TIME_DESC = "Time it takes to finish splitMetaLog()"; String META_SPLIT_SIZE_DESC = "Size of hbase:meta HLog files being split"; + String ROOT_SPLIT_TIME_DESC = "Time it takes to finish splitRootLog()"; + String ROOT_SPLIT_SIZE_DESC = "Size of hbase:root HLog files being split"; String SPLIT_TIME_DESC = "Time it takes to finish HLog.splitLog()"; String SPLIT_SIZE_DESC = "Size of HLog files being split"; void updateMetaWALSplitTime(long time); + + void updateRootWALSplitTime(long time); void updateMetaWALSplitSize(long size); + + void updateRootWALSplitSize(long size); void updateSplitTime(long time); diff --git a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFilesystemSourceImpl.java b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFilesystemSourceImpl.java index 1644207..2deed98 100644 --- a/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFilesystemSourceImpl.java +++ b/hbase-hadoop2-compat/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFilesystemSourceImpl.java @@ -29,6 +29,8 @@ public class MetricsMasterFilesystemSourceImpl extends BaseSourceImpl implements private MutableHistogram splitTimeHisto; private MutableHistogram metaSplitTimeHisto; private MutableHistogram metaSplitSizeHisto; + private MutableHistogram rootSplitTimeHisto; + private MutableHistogram rootSplitSizeHisto; public MetricsMasterFilesystemSourceImpl() { this(METRICS_NAME, METRICS_DESCRIPTION, METRICS_CONTEXT, METRICS_JMX_CONTEXT); @@ -46,6 +48,8 @@ public class MetricsMasterFilesystemSourceImpl extends BaseSourceImpl implements splitTimeHisto = metricsRegistry.newHistogram(SPLIT_TIME_NAME, SPLIT_TIME_DESC); metaSplitTimeHisto = metricsRegistry.newHistogram(META_SPLIT_TIME_NAME, META_SPLIT_TIME_DESC); metaSplitSizeHisto = metricsRegistry.newHistogram(META_SPLIT_SIZE_NAME, META_SPLIT_SIZE_DESC); + rootSplitTimeHisto = metricsRegistry.newHistogram(ROOT_SPLIT_TIME_NAME, ROOT_SPLIT_TIME_DESC); + rootSplitSizeHisto = metricsRegistry.newHistogram(META_SPLIT_SIZE_NAME, ROOT_SPLIT_SIZE_DESC); } @Override @@ -68,4 +72,14 @@ public class MetricsMasterFilesystemSourceImpl extends BaseSourceImpl implements public void updateMetaWALSplitSize(long size) { metaSplitSizeHisto.add(size); } + + @Override + public void updateRootWALSplitTime(long time) { + rootSplitTimeHisto.add(time); + } + + @Override + public void updateRootWALSplitSize(long size) { + rootSplitSizeHisto.add(size); + } } diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ZooKeeperProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ZooKeeperProtos.java index a86c4a6..6e3bf2a 100644 --- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ZooKeeperProtos.java +++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/ZooKeeperProtos.java @@ -79,6 +79,44 @@ public final class ZooKeeperProtos { * */ org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionState.State getState(); + + // optional bool is_root = 101; + /** + * optional bool is_root = 101; + * + *

+     * Whether the zookeeper location holds meta or root. 
+     * This would be required for migration from 0.98/branch-1
+     * 
+ */ + boolean hasIsRoot(); + /** + * optional bool is_root = 101; + * + *
+     * Whether the zookeeper location holds meta or root. 
+     * This would be required for migration from 0.98/branch-1
+     * 
+ */ + boolean getIsRoot(); + + // optional uint32 root_version = 102; + /** + * optional uint32 root_version = 102; + * + *
+     * Version of root schema/compartor
+     * 
+ */ + boolean hasRootVersion(); + /** + * optional uint32 root_version = 102; + * + *
+     * Version of root schema/compartor
+     * 
+ */ + int getRootVersion(); } /** * Protobuf type {@code MetaRegionServer} @@ -165,6 +203,16 @@ public final class ZooKeeperProtos { } break; } + case 808: { + bitField0_ |= 0x00000008; + isRoot_ = input.readBool(); + break; + } + case 816: { + bitField0_ |= 0x00000010; + rootVersion_ = input.readUInt32(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -294,10 +342,62 @@ public final class ZooKeeperProtos { return state_; } + // optional bool is_root = 101; + public static final int IS_ROOT_FIELD_NUMBER = 101; + private boolean isRoot_; + /** + * optional bool is_root = 101; + * + *
+     * Whether the zookeeper location holds meta or root. 
+     * This would be required for migration from 0.98/branch-1
+     * 
+ */ + public boolean hasIsRoot() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bool is_root = 101; + * + *
+     * Whether the zookeeper location holds meta or root. 
+     * This would be required for migration from 0.98/branch-1
+     * 
+ */ + public boolean getIsRoot() { + return isRoot_; + } + + // optional uint32 root_version = 102; + public static final int ROOT_VERSION_FIELD_NUMBER = 102; + private int rootVersion_; + /** + * optional uint32 root_version = 102; + * + *
+     * Version of root schema/compartor
+     * 
+ */ + public boolean hasRootVersion() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional uint32 root_version = 102; + * + *
+     * Version of root schema/compartor
+     * 
+ */ + public int getRootVersion() { + return rootVersion_; + } + private void initFields() { server_ = org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ServerName.getDefaultInstance(); rpcVersion_ = 0; state_ = org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionState.State.OFFLINE; + isRoot_ = false; + rootVersion_ = 0; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -328,6 +428,12 @@ public final class ZooKeeperProtos { if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeEnum(3, state_.getNumber()); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBool(101, isRoot_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeUInt32(102, rootVersion_); + } getUnknownFields().writeTo(output); } @@ -349,6 +455,14 @@ public final class ZooKeeperProtos { size += com.google.protobuf.CodedOutputStream .computeEnumSize(3, state_.getNumber()); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(101, isRoot_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(102, rootVersion_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -387,6 +501,16 @@ public final class ZooKeeperProtos { result = result && (getState() == other.getState()); } + result = result && (hasIsRoot() == other.hasIsRoot()); + if (hasIsRoot()) { + result = result && (getIsRoot() + == other.getIsRoot()); + } + result = result && (hasRootVersion() == other.hasRootVersion()); + if (hasRootVersion()) { + result = result && (getRootVersion() + == other.getRootVersion()); + } result = result && getUnknownFields().equals(other.getUnknownFields()); return result; @@ -412,6 +536,14 @@ public final class ZooKeeperProtos { hash = (37 * hash) + STATE_FIELD_NUMBER; hash = (53 * hash) + hashEnum(getState()); } + if (hasIsRoot()) { + hash = (37 * hash) + IS_ROOT_FIELD_NUMBER; + hash = (53 * hash) + hashBoolean(getIsRoot()); + } + if (hasRootVersion()) { + hash = (37 * hash) + ROOT_VERSION_FIELD_NUMBER; + hash = (53 * hash) + getRootVersion(); + } hash = (29 * hash) + getUnknownFields().hashCode(); memoizedHashCode = hash; return hash; @@ -537,6 +669,10 @@ public final class ZooKeeperProtos { bitField0_ = (bitField0_ & ~0x00000002); state_ = org.apache.hadoop.hbase.protobuf.generated.ClusterStatusProtos.RegionState.State.OFFLINE; bitField0_ = (bitField0_ & ~0x00000004); + isRoot_ = false; + bitField0_ = (bitField0_ & ~0x00000008); + rootVersion_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); return this; } @@ -581,6 +717,14 @@ public final class ZooKeeperProtos { to_bitField0_ |= 0x00000004; } result.state_ = state_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.isRoot_ = isRoot_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.rootVersion_ = rootVersion_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -606,6 +750,12 @@ public final class ZooKeeperProtos { if (other.hasState()) { setState(other.getState()); } + if (other.hasIsRoot()) { + setIsRoot(other.getIsRoot()); + } + if (other.hasRootVersion()) { + setRootVersion(other.getRootVersion()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -912,6 +1062,108 @@ public final class ZooKeeperProtos { return this; } + // optional bool is_root = 101; + private boolean isRoot_ ; + /** + * optional bool is_root = 101; + * + *
+       * Whether the zookeeper location holds meta or root. 
+       * This would be required for migration from 0.98/branch-1
+       * 
+ */ + public boolean hasIsRoot() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional bool is_root = 101; + * + *
+       * Whether the zookeeper location holds meta or root. 
+       * This would be required for migration from 0.98/branch-1
+       * 
+ */ + public boolean getIsRoot() { + return isRoot_; + } + /** + * optional bool is_root = 101; + * + *
+       * Whether the zookeeper location holds meta or root. 
+       * This would be required for migration from 0.98/branch-1
+       * 
+ */ + public Builder setIsRoot(boolean value) { + bitField0_ |= 0x00000008; + isRoot_ = value; + onChanged(); + return this; + } + /** + * optional bool is_root = 101; + * + *
+       * Whether the zookeeper location holds meta or root. 
+       * This would be required for migration from 0.98/branch-1
+       * 
+ */ + public Builder clearIsRoot() { + bitField0_ = (bitField0_ & ~0x00000008); + isRoot_ = false; + onChanged(); + return this; + } + + // optional uint32 root_version = 102; + private int rootVersion_ ; + /** + * optional uint32 root_version = 102; + * + *
+       * Version of root schema/compartor
+       * 
+ */ + public boolean hasRootVersion() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + /** + * optional uint32 root_version = 102; + * + *
+       * Version of root schema/compartor
+       * 
+ */ + public int getRootVersion() { + return rootVersion_; + } + /** + * optional uint32 root_version = 102; + * + *
+       * Version of root schema/compartor
+       * 
+ */ + public Builder setRootVersion(int value) { + bitField0_ |= 0x00000010; + rootVersion_ = value; + onChanged(); + return this; + } + /** + * optional uint32 root_version = 102; + * + *
+       * Version of root schema/compartor
+       * 
+ */ + public Builder clearRootVersion() { + bitField0_ = (bitField0_ & ~0x00000010); + rootVersion_ = 0; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:MetaRegionServer) } @@ -9563,15 +9815,16 @@ public final class ZooKeeperProtos { static { java.lang.String[] descriptorData = { "\n\017ZooKeeper.proto\032\013HBase.proto\032\023ClusterS" + - "tatus.proto\"g\n\020MetaRegionServer\022\033\n\006serve" + - "r\030\001 \002(\0132\013.ServerName\022\023\n\013rpc_version\030\002 \001(" + - "\r\022!\n\005state\030\003 \001(\0162\022.RegionState.State\":\n\006" + + "tatus.proto\"\216\001\n\020MetaRegionServer\022\033\n\006serv" + + "er\030\001 \002(\0132\013.ServerName\022\023\n\013rpc_version\030\002 \001" + + "(\r\022!\n\005state\030\003 \001(\0162\022.RegionState.State\022\017\n" + + "\007is_root\030e \001(\010\022\024\n\014root_version\030f \001(\r\":\n\006" + "Master\022\033\n\006master\030\001 \002(\0132\013.ServerName\022\023\n\013r" + "pc_version\030\002 \001(\r\"\037\n\tClusterUp\022\022\n\nstart_d" + "ate\030\001 \002(\t\"\214\002\n\014SplitLogTask\022\"\n\005state\030\001 \002(" + "\0162\023.SplitLogTask.State\022 \n\013server_name\030\002 " + - "\002(\0132\013.ServerName\0221\n\004mode\030\003 \001(\0162\032.SplitLo" + - "gTask.RecoveryMode:\007UNKNOWN\"C\n\005State\022\016\n\n", + "\002(\0132\013.ServerName\0221\n\004mode\030\003 \001(\0162\032.SplitLo", + "gTask.RecoveryMode:\007UNKNOWN\"C\n\005State\022\016\n\n" + "UNASSIGNED\020\000\022\t\n\005OWNED\020\001\022\014\n\010RESIGNED\020\002\022\010\n" + "\004DONE\020\003\022\007\n\003ERR\020\004\">\n\014RecoveryMode\022\013\n\007UNKN" + "OWN\020\000\022\021\n\rLOG_SPLITTING\020\001\022\016\n\nLOG_REPLAY\020\002" + @@ -9580,8 +9833,8 @@ public final class ZooKeeperProtos { "\n\005State\022\013\n\007ENABLED\020\000\022\014\n\010DISABLED\020\001\022\r\n\tDI" + "SABLING\020\002\022\014\n\010ENABLING\020\003\"\215\001\n\017ReplicationP" + "eer\022\022\n\nclusterkey\030\001 \002(\t\022\037\n\027replicationEn" + - "dpointImpl\030\002 \001(\t\022\035\n\004data\030\003 \003(\0132\017.BytesBy" + - "tesPair\022&\n\rconfiguration\030\004 \003(\0132\017.NameStr", + "dpointImpl\030\002 \001(\t\022\035\n\004data\030\003 \003(\0132\017.BytesBy", + "tesPair\022&\n\rconfiguration\030\004 \003(\0132\017.NameStr" + "ingPair\"^\n\020ReplicationState\022&\n\005state\030\001 \002" + "(\0162\027.ReplicationState.State\"\"\n\005State\022\013\n\007" + "ENABLED\020\000\022\014\n\010DISABLED\020\001\"+\n\027ReplicationHL" + @@ -9590,8 +9843,8 @@ public final class ZooKeeperProtos { "k\022\036\n\ntable_name\030\001 \001(\0132\n.TableName\022\037\n\nloc" + "k_owner\030\002 \001(\0132\013.ServerName\022\021\n\tthread_id\030" + "\003 \001(\003\022\021\n\tis_shared\030\004 \001(\010\022\017\n\007purpose\030\005 \001(" + - "\t\022\023\n\013create_time\030\006 \001(\003\";\n\017StoreSequenceI" + - "d\022\023\n\013family_name\030\001 \002(\014\022\023\n\013sequence_id\030\002 ", + "\t\022\023\n\013create_time\030\006 \001(\003\";\n\017StoreSequenceI", + "d\022\023\n\013family_name\030\001 \002(\014\022\023\n\013sequence_id\030\002 " + "\002(\004\"g\n\026RegionStoreSequenceIds\022 \n\030last_fl" + "ushed_sequence_id\030\001 \002(\004\022+\n\021store_sequenc" + "e_id\030\002 \003(\0132\020.StoreSequenceIdBE\n*org.apac" + @@ -9608,7 +9861,7 @@ public final class ZooKeeperProtos { internal_static_MetaRegionServer_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_MetaRegionServer_descriptor, - new java.lang.String[] { "Server", "RpcVersion", "State", }); + new java.lang.String[] { "Server", "RpcVersion", "State", "IsRoot", "RootVersion", }); internal_static_Master_descriptor = getDescriptor().getMessageTypes().get(1); internal_static_Master_fieldAccessorTable = new diff --git a/hbase-protocol/src/main/protobuf/ZooKeeper.proto b/hbase-protocol/src/main/protobuf/ZooKeeper.proto index c40fa77..e7d339a 100644 --- a/hbase-protocol/src/main/protobuf/ZooKeeper.proto +++ b/hbase-protocol/src/main/protobuf/ZooKeeper.proto @@ -42,6 +42,11 @@ message MetaRegionServer { // State of the region transition. OPEN means fully operational 'hbase:meta' optional RegionState.State state = 3; + // Whether the zookeeper location holds meta or root. + // This would be required for migration from 0.98/branch-1 + optional bool is_root = 101; + // Version of root schema/compartor + optional uint32 root_version=102; } /** diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/TableDescriptor.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/TableDescriptor.java index d27bfb7..404813f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/TableDescriptor.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/TableDescriptor.java @@ -178,5 +178,23 @@ public class TableDescriptor { null, Coprocessor.PRIORITY_SYSTEM, null); return metaDescriptor; } + + public static HTableDescriptor rootTableDescriptor(final Configuration conf) throws IOException { + return new HTableDescriptor(TableName.ROOT_TABLE_NAME, + new HColumnDescriptor[] { new HColumnDescriptor(HConstants.CATALOG_FAMILY) + // For now, lets use the same config for meta versions + .setMaxVersions( + conf.getInt(HConstants.HBASE_META_VERSIONS, HConstants.DEFAULT_HBASE_META_VERSIONS)) + .setInMemory(true) + .setBlocksize( + conf.getInt(HConstants.HBASE_META_BLOCK_SIZE, + HConstants.DEFAULT_HBASE_META_BLOCK_SIZE)) + .setScope(HConstants.REPLICATION_SCOPE_LOCAL) + // Disable blooms for meta. Needs work. Seems to mess w/ getClosestOrBefore. + .setBloomFilterType(BloomType.NONE) + // Enable cache of data blocks in L1 if more than one caching tier deployed: + // e.g. if using CombinedBlockCache (BucketCache). + .setCacheDataInL1(true) }); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/SplitLogManagerCoordination.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/SplitLogManagerCoordination.java index 9186867..00fd63c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/SplitLogManagerCoordination.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/SplitLogManagerCoordination.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.master.MasterFileSystem; import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.hadoop.hbase.master.SplitLogManager; import org.apache.hadoop.hbase.master.SplitLogManager.ResubmitDirective; import org.apache.hadoop.hbase.master.SplitLogManager.Task; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode; @@ -140,7 +141,7 @@ public interface SplitLogManagerCoordination { * @param isMetaRecovery whether current recovery is for the meta region on * serverNames */ - void removeRecoveringRegions(Set serverNames, Boolean isMetaRecovery) throws IOException; + void removeRecoveringRegions(Set serverNames, SplitLogManager.RecoveryMode recoveryMode) throws IOException; /** * Return the number of remaining tasks diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/ZKSplitLogManagerCoordination.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/ZKSplitLogManagerCoordination.java index 0fb5c59..25eda0e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/ZKSplitLogManagerCoordination.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/coordination/ZKSplitLogManagerCoordination.java @@ -297,9 +297,10 @@ public class ZKSplitLogManagerCoordination extends ZooKeeperListener implements */ @Override public void removeRecoveringRegions(final Set recoveredServerNameSet, - Boolean isMetaRecovery) + SplitLogManager.RecoveryMode recoveryMode) throws IOException { final String metaEncodeRegionName = HRegionInfo.FIRST_META_REGIONINFO.getEncodedName(); + final String rootRegionName = HRegionInfo.ROOT_REGIONINFO.getEncodedName(); int count = 0; try { List tasks = ZKUtil.listChildrenNoWatch(watcher, watcher.splitLogZNode); @@ -325,15 +326,21 @@ public class ZKSplitLogManagerCoordination extends ZooKeeperListener implements int listSize = regions.size(); if (LOG.isDebugEnabled()) { LOG.debug("Processing recovering " + regions + " and servers " + - recoveredServerNameSet + ", isMetaRecovery=" + isMetaRecovery); + recoveredServerNameSet + ", Recovery for=" + recoveryMode); } for (int i = 0; i < listSize; i++) { String region = regions.get(i); - if (isMetaRecovery != null) { - if ((isMetaRecovery && !region.equalsIgnoreCase(metaEncodeRegionName)) - || (!isMetaRecovery && region.equalsIgnoreCase(metaEncodeRegionName))) { + if(recoveryMode != null) { + if ((recoveryMode == SplitLogManager.RecoveryMode.META && !region.equalsIgnoreCase(metaEncodeRegionName)) + || (recoveryMode != SplitLogManager.RecoveryMode.META && region.equalsIgnoreCase(metaEncodeRegionName))) { // skip non-meta regions when recovering the meta region or - // skip the meta region when recovering user regions + // skip the meta region when recovering non-meta regions + continue; + } + if ((recoveryMode == SplitLogManager.RecoveryMode.ROOT && !region.equalsIgnoreCase(rootRegionName)) + || (recoveryMode != SplitLogManager.RecoveryMode.ROOT && region.equalsIgnoreCase(rootRegionName))) { + // skip non-root regions when recovering the root region or + // skip the root region when recovering non-root regions continue; } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 7c7f0b6..86361ee 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -337,8 +337,8 @@ public class AssignmentManager { public Pair getReopenStatus(TableName tableName) throws IOException { List hris; - if (TableName.META_TABLE_NAME.equals(tableName)) { - hris = new MetaTableLocator().getMetaRegions(server.getZooKeeper()); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + hris = new MetaTableLocator().getRootRegions(server.getZooKeeper()); } else { hris = MetaTableAccessor.getTableRegions(server.getShortCircuitConnection(), tableName, true); } @@ -439,7 +439,7 @@ public class AssignmentManager { for (Map.Entry en: regionStates.getRegionAssignments().entrySet()) { HRegionInfo hri = en.getKey(); - if (!hri.isMetaTable() + if (!hri.isMetaTable() && !hri.isRootRegion() && onlineServers.contains(en.getValue())) { LOG.debug("Found " + hri + " out on cluster"); failover = true; @@ -451,7 +451,7 @@ public class AssignmentManager { Map regionsInTransition = regionStates.getRegionsInTransition(); if (!regionsInTransition.isEmpty()) { for (RegionState regionState: regionsInTransition.values()) { - if (!regionState.getRegion().isMetaRegion() + if (!regionState.getRegion().isMetaRegion() && !regionState.getRegion().isRootRegion() && onlineServers.contains(regionState.getServerName())) { LOG.debug("Found " + regionState + " in RITs"); failover = true; @@ -983,13 +983,13 @@ public class AssignmentManager { } if (plan == null) { LOG.warn("Unable to determine a plan to assign " + region); - if (region.isMetaRegion()) { + if (region.isMetaRegion() || region.isRootRegion()) { try { Thread.sleep(this.sleepTimeBeforeRetryingMetaAssignment); if (i == maximumAttempts) i = 1; continue; } catch (InterruptedException e) { - LOG.error("Got exception while waiting for hbase:meta assignment"); + LOG.error("Got exception while waiting for assignment of "+ region.getRegionNameAsString()); Thread.currentThread().interrupt(); } } @@ -1190,7 +1190,7 @@ public class AssignmentManager { newPlan = true; randomPlan = new RegionPlan(region, null, balancer.randomAssignment(region, destServers)); - if (!region.isMetaTable() && shouldAssignRegionsWithFavoredNodes) { + if (!region.isMetaTable() && !region.isRootRegion() && shouldAssignRegionsWithFavoredNodes) { List regions = new ArrayList(1); regions.add(region); try { @@ -1351,10 +1351,21 @@ public class AssignmentManager { * Assumes that hbase:meta is currently closed and is not being actively served by * any RegionServer. */ - public void assignMeta() throws KeeperException { + public void assignMeta() { regionStates.updateRegionState(HRegionInfo.FIRST_META_REGIONINFO, State.OFFLINE); assign(HRegionInfo.FIRST_META_REGIONINFO); } + + /** + * Assigns the hbase:root region. + *

+ * Assumes that hbase:root is currently closed and is not being actively served by + * any RegionServer. + */ + public void assignRoot() { + regionStates.updateRegionState(HRegionInfo.ROOT_REGIONINFO, State.OFFLINE); + assign(HRegionInfo.ROOT_REGIONINFO); + } /** * Assigns specified regions retaining assignments, if any. @@ -1923,6 +1934,10 @@ public class AssignmentManager { public boolean isCarryingMeta(ServerName serverName) { return isCarryingRegion(serverName, HRegionInfo.FIRST_META_REGIONINFO); } + + public boolean isCarryingRoot(ServerName serverName) { + return isCarryingRegion(serverName, HRegionInfo.ROOT_REGIONINFO); + } /** * Check if the shutdown server carries the specific region. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index 61d1b7a..31a7946 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -557,9 +557,39 @@ public class HMaster extends HRegionServer implements MasterServices, Server { // remove stale recovering regions from previous run this.fileSystemManager.removeStaleRecoveringRegionsFromZK(previouslyFailedServers); + + ServerName preRootServer = metaTableLocator.getRootRegionLocation(zooKeeper); + if (preRootServer !=null && previouslyFailedServers.contains(preRootServer)) { + splitRootLogBeforeAssignment(preRootServer); + } + + Set previouslyFailedRootRSs = getPreviouselyFailedRootServersFromZK(); + previouslyFailedRootRSs.addAll(previouslyFailedServers); + + this.initializationBeforeMetaAssignment = true; + + // Wait for regionserver to finish initialization. + if (BaseLoadBalancer.tablesOnMaster(conf)) { + waitForServerOnline(); + } + //initialize load balancer + this.balancer.setClusterStatus(getClusterStatus()); + this.balancer.setMasterServices(this); + this.balancer.initialize(); + + // Check if master is shutting down because of some issue + // in initializing the regionserver or the balancer. + if(isStopped()) return; + + // Make sure root assigned before proceeding. + status.setStatus("Assigning Root Region"); + assignRoot(status, previouslyFailedRootRSs); + + if(isStopped()) return; + // log splitting for hbase:meta server - ServerName oldMetaServerLocation = metaTableLocator.getMetaRegionLocation(this.getZooKeeper()); + ServerName oldMetaServerLocation = metaTableLocator.getMetaRegionLocation(this.getShortCircuitConnection()); if (oldMetaServerLocation != null && previouslyFailedServers.contains(oldMetaServerLocation)) { splitMetaLogBeforeAssignment(oldMetaServerLocation); // Note: we can't remove oldMetaServerLocation from previousFailedServers list because it @@ -576,22 +606,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { // there is no op for the server. previouslyFailedMetaRSs.addAll(previouslyFailedServers); - this.initializationBeforeMetaAssignment = true; - - // Wait for regionserver to finish initialization. - if (BaseLoadBalancer.tablesOnMaster(conf)) { - waitForServerOnline(); - } - - //initialize load balancer - this.balancer.setClusterStatus(getClusterStatus()); - this.balancer.setMasterServices(this); - this.balancer.initialize(); - - // Check if master is shutting down because of some issue - // in initializing the regionserver or the balancer. - if(isStopped()) return; - + // Make sure meta assigned before proceeding. status.setStatus("Assigning Meta Region"); assignMeta(status, previouslyFailedMetaRSs); @@ -683,18 +698,16 @@ public class HMaster extends HRegionServer implements MasterServices, Server { throws InterruptedException, IOException, KeeperException { // Work on meta region int assigned = 0; - long timeout = this.conf.getLong("hbase.catalog.verification.timeout", 1000); status.setStatus("Assigning hbase:meta region"); // Get current meta state from zk. - RegionState metaState = MetaTableLocator.getMetaRegionState(getZooKeeper()); - + RegionState metaState = metaTableLocator.getMetaRegionState(getShortCircuitConnection()); RegionStates regionStates = assignmentManager.getRegionStates(); - regionStates.createRegionState(HRegionInfo.FIRST_META_REGIONINFO, - metaState.getState(), metaState.getServerName(), null); + regionStates.createRegionState(HRegionInfo.FIRST_META_REGIONINFO, metaState.getState(), + metaState.getServerName(), metaTableLocator.getMetaRegionLocation(getShortCircuitConnection())); if (!metaState.isOpened() || !metaTableLocator.verifyMetaRegionLocation( - this.getShortCircuitConnection(), this.getZooKeeper(), timeout)) { + this.getShortCircuitConnection())) { ServerName currentMetaServer = metaState.getServerName(); if (serverManager.isServerOnline(currentMetaServer)) { LOG.info("Meta was in transition on " + currentMetaServer); @@ -711,7 +724,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { assigned++; } - enableMeta(TableName.META_TABLE_NAME); + enableCatalogTable(TableName.META_TABLE_NAME); if ((RecoveryMode.LOG_REPLAY == this.getMasterFileSystem().getLogRecoveryMode()) && (!previouslyFailedMetaRSs.isEmpty())) { @@ -724,12 +737,69 @@ public class HMaster extends HRegionServer implements MasterServices, Server { // if the meta region server is died at this time, we need it to be re-assigned // by SSH so that system tables can be assigned. // No need to wait for meta is assigned = 0 when meta is just verified. - enableServerShutdownHandler(assigned != 0); + enableServerShutdownHandler(assigned != 0, false); LOG.info("hbase:meta assigned=" + assigned + ", location=" - + metaTableLocator.getMetaRegionLocation(this.getZooKeeper())); + + metaTableLocator.getMetaRegionLocation(this.getShortCircuitConnection())); status.setStatus("META assigned."); } + + + /** + * Check hbase:root is assigned. If not, assign it. + * @param status MonitoredTask + * @throws InterruptedException + * @throws IOException + * @throws KeeperException + */ + void assignRoot(MonitoredTask status, Set previouslyFailedRootRSs) + throws InterruptedException, IOException, KeeperException { + int assigned = 0; + long timeout = this.conf.getLong("hbase.catalog.verification.timeout", 1000); + + status.setStatus("Assigning hbase:root region"); + // Get current meta state from zk. + RegionState rootState = MetaTableLocator.getRootRegionState(getZooKeeper()); + + RegionStates regionStates = assignmentManager.getRegionStates(); + regionStates.createRegionState(HRegionInfo.ROOT_REGIONINFO, rootState.getState(), + rootState.getServerName(), null); + + if (!rootState.isOpened() || !metaTableLocator.verifyRootRegionLocation( + this.getShortCircuitConnection(), this.getZooKeeper(), timeout)) { + ServerName currentRootServer = rootState.getServerName(); + if (serverManager.isServerOnline(currentRootServer)) { + LOG.info("Root was in transition on " + currentRootServer); + assignmentManager.processRegionsInTransition(Arrays.asList(rootState)); + } else { + if (currentRootServer != null) { + splitRootLogBeforeAssignment(currentRootServer); + regionStates.logSplit(HRegionInfo.ROOT_REGIONINFO); + previouslyFailedRootRSs.add(currentRootServer); + } + LOG.info("Re-assigning hbase:root, it was on " + currentRootServer); + assignmentManager.assignRoot(); + } + assigned++; + } + + enableCatalogTable(TableName.ROOT_TABLE_NAME); + + if ((RecoveryMode.LOG_REPLAY == this.getMasterFileSystem().getLogRecoveryMode()) + && (!previouslyFailedRootRSs.isEmpty())) { + status.setStatus("replaying log for hbase:root region"); + this.fileSystemManager.splitRootLog(previouslyFailedRootRSs); + } + // Make sure a hbase:root location is set. We need to enable SSH here since + // if the root region server is died at this time, we need it to be re-assigned + // by SSH so that system tables can be assigned. + enableServerShutdownHandler(false, assigned != 0); + + LOG.info("hbase:root assigned=" + assigned + ", location=" + + metaTableLocator.getRootRegionLocation(this.getZooKeeper())); + status.setStatus("hbase:root assigned."); + } + void initNamespace() throws IOException { //create namespace manager @@ -758,9 +828,21 @@ public class HMaster extends HRegionServer implements MasterServices, Server { this.fileSystemManager.splitMetaLog(currentMetaServer); } } + + private void splitRootLogBeforeAssignment(ServerName currentRootServer) throws IOException { + if (RecoveryMode.LOG_REPLAY == this.getMasterFileSystem().getLogRecoveryMode()) { + // In log replay mode, we mark hbase:root region as recovering in ZK + Set regions = new HashSet(); + regions.add(HRegionInfo.ROOT_REGIONINFO); + this.fileSystemManager.prepareLogReplay(currentRootServer, regions); + } else { + // In recovered.edits mode: create recovered edits file for hbase:root server + this.fileSystemManager.splitRootLog(new HashSet(Arrays.asList(currentRootServer))); + } + } private void enableServerShutdownHandler( - final boolean waitForMeta) throws IOException, InterruptedException { + final boolean waitForMeta, final boolean waitForRoot) throws IOException, InterruptedException { // If ServerShutdownHandler is disabled, we enable it and expire those dead // but not expired servers. This is required so that if meta is assigning to // a server which dies after assignMeta starts assignment, @@ -770,16 +852,26 @@ public class HMaster extends HRegionServer implements MasterServices, Server { serverShutdownHandlerEnabled = true; this.serverManager.processQueuedDeadServers(); } + + if (waitForRoot) { + metaTableLocator.waitRootRegionLocation(this.zooKeeper); + // Above check waits for general root availability but this does not + // guarantee that the transition has completed + this.assignmentManager.waitForAssignment(HRegionInfo.ROOT_REGIONINFO); + } if (waitForMeta) { - metaTableLocator.waitMetaRegionLocation(this.getZooKeeper()); + metaTableLocator.waitMetaRegionLocation(this.shortCircuitConnection); + // Above check waits for general meta availability but this does not + // guarantee that the transition has completed + this.assignmentManager.waitForAssignment(HRegionInfo.FIRST_META_REGIONINFO); } } - private void enableMeta(TableName metaTableName) { - if (!this.tableStateManager.isTableState(metaTableName, + private void enableCatalogTable(TableName tableName) { + if (!this.tableStateManager.isTableState(tableName, TableState.State.ENABLED)) { - this.assignmentManager.setEnabledTable(metaTableName); + this.assignmentManager.setEnabledTable(tableName); } } @@ -801,6 +893,25 @@ public class HMaster extends HRegionServer implements MasterServices, Server { } return result; } + + /** + * This function returns a set of region server names under hbase:root recovering region ZK node + * @return Set of root server names which were recorded in ZK + * @throws KeeperException + */ + private Set getPreviouselyFailedRootServersFromZK() throws KeeperException { + Set result = new HashSet(); + String rootRecoveringZnode = ZKUtil.joinZNode(zooKeeper.recoveringRegionsZNode, + HRegionInfo.ROOT_REGIONINFO.getEncodedName()); + List regionFailedServers = ZKUtil.listChildrenNoWatch(zooKeeper, rootRecoveringZnode); + if (regionFailedServers == null) return result; + + for(String failedServer : regionFailedServers) { + ServerName server = ServerName.parseServerName(failedServer); + result.add(server); + } + return result; + } @Override public TableDescriptors getTableDescriptors() { @@ -837,6 +948,8 @@ public class HMaster extends HRegionServer implements MasterServices, Server { conf.getInt("hbase.master.executor.closeregion.threads", 5)); this.service.startExecutorService(ExecutorType.MASTER_SERVER_OPERATIONS, conf.getInt("hbase.master.executor.serverops.threads", 5)); + this.service.startExecutorService(ExecutorType.MASTER_ROOT_OPERATIONS, + conf.getInt("hbase.master.executor.rootserverops.threads", 5)); this.service.startExecutorService(ExecutorType.MASTER_META_SERVER_OPERATIONS, conf.getInt("hbase.master.executor.serverops.threads", 5)); this.service.startExecutorService(ExecutorType.M_LOG_REPLAY_OPS, @@ -1345,7 +1458,7 @@ public class HMaster extends HRegionServer implements MasterServices, Server { } private static boolean isCatalogTable(final TableName tableName) { - return tableName.equals(TableName.META_TABLE_NAME); + return tableName.equals(TableName.META_TABLE_NAME) || TableName.ROOT_TABLE_NAME.equals(tableName); } @Override diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java index f57fcee..5595377 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterFileSystem.java @@ -46,6 +46,7 @@ import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableDescriptor; import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.backup.HFileArchiver; +import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.TableState; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.fs.HFileSystem; @@ -97,11 +98,18 @@ public class MasterFileSystem { return HLogUtil.isMetaFile(p); } }; + + final static PathFilter ROOT_FILTER = new PathFilter() { + @Override + public boolean accept(Path p) { + return HLogUtil.isRootFile(p); + } + }; final static PathFilter NON_META_FILTER = new PathFilter() { @Override public boolean accept(Path p) { - return !HLogUtil.isMetaFile(p); + return !HLogUtil.isMetaFile(p) && !HLogUtil.isRootFile(p); } }; @@ -301,6 +309,15 @@ public class MasterFileSystem { public void splitMetaLog(final Set serverNames) throws IOException { splitLog(serverNames, META_FILTER); } + + /** + * Specialized method to handle the splitting for root HLog + * @param serverNames + * @throws IOException + */ + public void splitRootLog(final Set serverNames) throws IOException { + splitLog(serverNames, ROOT_FILTER); + } private List getLogDirs(final Set serverNames) throws IOException { List logDirs = new ArrayList(); @@ -385,6 +402,8 @@ public class MasterFileSystem { if (this.metricsMasterFilesystem != null) { if (filter == META_FILTER) { this.metricsMasterFilesystem.addMetaWALSplit(splitTime, splitLogSize); + } else if (filter == ROOT_FILTER) { + this.metricsMasterFilesystem.addRootWALSplit(splitTime, splitLogSize); } else { this.metricsMasterFilesystem.addSplit(splitTime, splitLogSize); } @@ -446,8 +465,8 @@ public class MasterFileSystem { } clusterId = FSUtils.getClusterId(fs, rd); - // Make sure the meta region directory exists! - if (!FSUtils.metaRegionExists(fs, rd)) { + // This should be during clean deployment. Migration from branch-1/0.98 is not handled. + if (!FSUtils.rootRegionExists(fs, rd) && !FSUtils.metaRegionExists(fs, rd)) { bootstrap(rd, c); } else { // Migrate table descriptor files if necessary @@ -494,17 +513,26 @@ public class MasterFileSystem { private static void bootstrap(final Path rd, final Configuration c) throws IOException { - LOG.info("BOOTSTRAP: creating hbase:meta region"); + LOG.info("BOOTSTRAP: creating hbase:root and hbase:meta region"); try { // Bootstrapping, make sure blockcache is off. Else, one will be // created here in bootstrap and it'll need to be cleaned up. Better to // not make it in first place. Turn off block caching for bootstrap. // Enable after. + HRegionInfo rootHRI = new HRegionInfo(HRegionInfo.ROOT_REGIONINFO); + HTableDescriptor rootDescriptor = new FSTableDescriptors(c).get(TableName.ROOT_TABLE_NAME); + setInfoFamilyCaching(rootDescriptor, false); + HRegion root = HRegion.createHRegion(rootHRI, rd, c, rootDescriptor); + setInfoFamilyCaching(rootDescriptor, true); + HRegionInfo metaHRI = new HRegionInfo(HRegionInfo.FIRST_META_REGIONINFO); HTableDescriptor metaDescriptor = new FSTableDescriptors(c).get(TableName.META_TABLE_NAME); - setInfoFamilyCachingForMeta(metaDescriptor, false); + setInfoFamilyCaching(metaDescriptor, false); HRegion meta = HRegion.createHRegion(metaHRI, rd, c, metaDescriptor); - setInfoFamilyCachingForMeta(metaDescriptor, true); + setInfoFamilyCaching(metaDescriptor, true); + // Add first region from the META table to the ROOT region. + HRegion.addRegionToMETA(root, meta); + HRegion.closeHRegion(root); HRegion.closeHRegion(meta); } catch (IOException e) { e = e instanceof RemoteException ? @@ -515,18 +543,17 @@ public class MasterFileSystem { } /** - * Enable in memory caching for hbase:meta + * Enable in memory caching */ - public static void setInfoFamilyCachingForMeta(HTableDescriptor metaDescriptor, final boolean b) { - for (HColumnDescriptor hcd: metaDescriptor.getColumnFamilies()) { + public static void setInfoFamilyCaching(HTableDescriptor descriptor, final boolean b) { + for (HColumnDescriptor hcd: descriptor.getColumnFamilies()) { if (Bytes.equals(hcd.getName(), HConstants.CATALOG_FAMILY)) { hcd.setBlockCacheEnabled(b); hcd.setInMemory(b); } } } - - + public void deleteRegion(HRegionInfo region) throws IOException { HFileArchiver.archiveRegion(conf, fs, region); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java index 00078fd..395cc85 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterRpcServices.java @@ -1271,12 +1271,15 @@ public class MasterRpcServices extends RSRpcServices TableName tableName = ProtobufUtil.toTableName( rt.getRegionInfo(0).getTableName()); RegionStates regionStates = master.assignmentManager.getRegionStates(); - if (!(TableName.META_TABLE_NAME.equals(tableName) + + if (!(TableName.ROOT_TABLE_NAME.equals(tableName) + && regionStates.getRegionState(HRegionInfo.ROOT_REGIONINFO) != null) + && !(TableName.META_TABLE_NAME.equals(tableName) && regionStates.getRegionState(HRegionInfo.FIRST_META_REGIONINFO) != null) - && !master.assignmentManager.isFailoverCleanupDone()) { - // Meta region is assigned before master finishes the - // failover cleanup. So no need this check for it - throw new PleaseHoldException("Master is rebuilding user regions"); + && !master.assignmentManager.isFailoverCleanupDone()) { + // Meta region is assigned before master finishes the + // failover cleanup. So no need this check for it + throw new PleaseHoldException("Master is rebuilding user regions"); } ServerName sn = ProtobufUtil.toServerName(req.getServer()); String error = master.assignmentManager.onRegionTransition(sn, rt); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java index bc9d1db..c5d0b80 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MasterStatusServlet.java @@ -87,7 +87,7 @@ public class MasterStatusServlet extends HttpServlet { private ServerName getMetaLocationOrNull(HMaster master) { MetaTableLocator metaTableLocator = master.getMetaTableLocator(); return metaTableLocator == null ? null : - metaTableLocator.getMetaRegionLocation(master.getZooKeeper()); + metaTableLocator.getRootRegionLocation(master.getZooKeeper()); } private Map getFragmentationInfo( diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystem.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystem.java index 34547ef..8bdad1d 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystem.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/MetricsMasterFileSystem.java @@ -47,4 +47,14 @@ public class MetricsMasterFileSystem { source.updateMetaWALSplitTime(time); source.updateMetaWALSplitSize(size); } + + /** + * Record a single instance of a split + * @param time time that the split took + * @param size length of original HLogs that were split + */ + public synchronized void addRootWALSplit(long time, long size) { + source.updateRootWALSplitTime(time); + source.updateRootWALSplitSize(size); + } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java index ae4af4a..8f831f9 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStateStore.java @@ -33,8 +33,10 @@ import org.apache.hadoop.hbase.RegionLocations; import org.apache.hadoop.hbase.Server; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.TableName; +import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.Table; import org.apache.hadoop.hbase.master.RegionState.State; import org.apache.hadoop.hbase.regionserver.HRegion; import org.apache.hadoop.hbase.regionserver.RegionServerServices; @@ -57,6 +59,8 @@ public class RegionStateStore { protected static final char META_REPLICA_ID_DELIMITER = '_'; private volatile HRegion metaRegion; + private volatile HRegion rootRegion; + private volatile Table rootTable; private volatile boolean initialized; private MultiHConnection multiHConnection; private final Server server; @@ -122,7 +126,7 @@ public class RegionStateStore { */ private boolean shouldPersistStateChange( HRegionInfo hri, RegionState state, RegionState oldState) { - return !hri.isMetaRegion() && !RegionStates.isOneOfStates( + return !hri.isMetaRegion() && !hri.isRootRegion() && !RegionStates.isOneOfStates( state, State.MERGING_NEW, State.SPLITTING_NEW, State.MERGED) && !(RegionStates.isOneOfStates(state, State.OFFLINE) && RegionStates.isOneOfStates(oldState, State.MERGING_NEW, @@ -138,6 +142,12 @@ public class RegionStateStore { if (server instanceof RegionServerServices) { metaRegion = ((RegionServerServices)server).getFromOnlineRegions( HRegionInfo.FIRST_META_REGIONINFO.getEncodedName()); + rootRegion = ((RegionServerServices)server).getFromOnlineRegions( + HRegionInfo.ROOT_REGIONINFO.getEncodedName()); + } + // When root is not colocated on master + if (rootRegion == null) { + rootTable = new HTable(TableName.ROOT_TABLE_NAME, server.getShortCircuitConnection()); } // When meta is not colocated on master if (metaRegion == null) { @@ -154,6 +164,20 @@ public class RegionStateStore { void stop() { initialized = false; + if (rootTable != null) { + synchronized (this) { + if (rootTable != null) { + try { + rootTable.close(); + } catch (Exception e) { + LOG.info("Got exception in closing connection to root table ", e); + } finally { + rootTable = null; + } + + } + } + } if (multiHConnection != null) { multiHConnection.close(); } @@ -164,48 +188,68 @@ public class RegionStateStore { try { HRegionInfo hri = newState.getRegion(); - // update meta before checking for initialization. - // meta state stored in zk. - if (hri.isMetaRegion()) { - // persist meta state in MetaTableLocator (which in turn is zk storage currently) + // update root before checking for initialization. + // root state stored in zk. + if (hri.isRootRegion()) { + // persist root state in MetaTableLocator (which in turn is zk storage currently) try { - MetaTableLocator.setMetaLocation(server.getZooKeeper(), + MetaTableLocator.setRootLocation(server.getZooKeeper(), newState.getServerName(), newState.getState()); return; // Done } catch (KeeperException e) { throw new IOException("Failed to update meta ZNode", e); } } + if (hri.isMetaRegion()) { + Put put = addToPut(openSeqNum, newState, oldState); + // If not initialized, then check whether root is on master or not + if (!initialized && rootRegion == null) { + synchronized (this) { + if (!initialized && rootRegion == null) { + if (server instanceof RegionServerServices) { + rootRegion = + ((RegionServerServices) server) + .getFromOnlineRegions(HRegionInfo.ROOT_REGIONINFO.getEncodedName()); + } + if (rootRegion == null) { + rootTable = + new HTable(TableName.ROOT_TABLE_NAME, server.getShortCircuitConnection()); + } + } + } + } + if (rootRegion != null) { + try { + // Assume root is pinned to master. + // At least, that's what we want. + rootRegion.put(put); + return; // Done here + } catch (Throwable t) { + // In unit tests, root could be moved away by intention + // So, the shortcut is gone. We won't try to establish the + // shortcut any more because we prefer root to be pinned + // to the master + synchronized (this) { + if (rootRegion != null) { + LOG.info("Root region shortcut failed", t); + if (rootTable == null) { + rootTable = + new HTable(TableName.ROOT_TABLE_NAME, server.getShortCircuitConnection()); + } + rootRegion = null; + } + } + } + } + rootTable.put(put); + return; // Done + } if (!initialized || !shouldPersistStateChange(hri, newState, oldState)) { return; } - - ServerName oldServer = oldState != null ? oldState.getServerName() : null; - ServerName serverName = newState.getServerName(); - State state = newState.getState(); - - int replicaId = hri.getReplicaId(); - Put put = new Put(MetaTableAccessor.getMetaKeyForRegion(hri)); - StringBuilder info = new StringBuilder("Updating row "); - info.append(hri.getRegionNameAsString()).append(" with state=").append(state); - if (serverName != null && !serverName.equals(oldServer)) { - put.addImmutable(HConstants.CATALOG_FAMILY, getServerNameColumn(replicaId), - Bytes.toBytes(serverName.getServerName())); - info.append("&sn=").append(serverName); - } - if (openSeqNum >= 0) { - Preconditions.checkArgument(state == State.OPEN - && serverName != null, "Open region should be on a server"); - MetaTableAccessor.addLocation(put, serverName, openSeqNum, replicaId); - info.append("&openSeqNum=").append(openSeqNum); - info.append("&server=").append(serverName); - } - put.addImmutable(HConstants.CATALOG_FAMILY, getStateColumn(replicaId), - Bytes.toBytes(state.name())); - LOG.info(info); - + Put put = addToPut(openSeqNum, newState, oldState); // Persist the state change to meta if (metaRegion != null) { try { @@ -238,6 +282,34 @@ public class RegionStateStore { } } + private Put addToPut(long openSeqNum, RegionState newState, RegionState oldState) throws IOException { + HRegionInfo hri = newState.getRegion(); + ServerName oldServer = oldState != null ? oldState.getServerName() : null; + ServerName serverName = newState.getServerName(); + State state = newState.getState(); + + int replicaId = hri.getReplicaId(); + Put put = new Put(MetaTableAccessor.getMetaKeyForRegion(hri)); + StringBuilder info = new StringBuilder("Updating row "); + info.append(hri.getRegionNameAsString()).append(" with state=").append(state); + if (serverName != null && !serverName.equals(oldServer)) { + put.addImmutable(HConstants.CATALOG_FAMILY, getServerNameColumn(replicaId), + Bytes.toBytes(serverName.getServerName())); + info.append("&sn=").append(serverName); + } + if (openSeqNum >= 0) { + Preconditions.checkArgument(state == State.OPEN + && serverName != null, "Open region should be on a server"); + MetaTableAccessor.addLocation(put, serverName, openSeqNum, replicaId); + info.append("&openSeqNum=").append(openSeqNum); + info.append("&server=").append(serverName); + } + put.addImmutable(HConstants.CATALOG_FAMILY, getStateColumn(replicaId), + Bytes.toBytes(state.name())); + LOG.info(info); + return put; + } + void splitRegion(HRegionInfo p, HRegionInfo a, HRegionInfo b, ServerName sn) throws IOException { MetaTableAccessor.splitRegion(server.getShortCircuitConnection(), p, a, b, sn); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java index 95d41ed..311bc87 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/RegionStates.java @@ -525,7 +525,7 @@ public class RegionStates { ServerName oldServerName = regionAssignments.remove(hri); if (oldServerName != null && serverHoldings.containsKey(oldServerName)) { if (newState == State.MERGED || newState == State.SPLIT - || hri.isMetaRegion() || tableStateManager.isTableState(hri.getTable(), + || hri.isMetaRegion() || hri.isRootRegion() || tableStateManager.isTableState(hri.getTable(), TableState.State.DISABLED, TableState.State.DISABLING)) { // Offline the region only if it's merged/split, or the table is disabled/disabling. // Otherwise, offline it from this server only when it is online on a different server. @@ -799,7 +799,7 @@ public class RegionStates { continue; } TableName tableName = hri.getTable(); - if (!TableName.META_TABLE_NAME.equals(tableName) + if (!TableName.META_TABLE_NAME.equals(tableName) && !TableName.ROOT_TABLE_NAME.equals(tableName) && (noExcludeTables || !excludedTables.contains(tableName))) { toBeClosed.add(hri); } @@ -867,7 +867,7 @@ public class RegionStates { } else { for (Map.Entry> e: serverHoldings.entrySet()) { for (HRegionInfo hri: e.getValue()) { - if (hri.isMetaRegion()) continue; + if (hri.isMetaRegion() || hri.isRootRegion()) continue; TableName tablename = hri.getTable(); Map> svrToRegions = result.get(tablename); if (svrToRegions == null) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java index cca39f5..bfd3052 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/ServerManager.java @@ -51,6 +51,7 @@ import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.RetriesExhaustedException; import org.apache.hadoop.hbase.master.balancer.BaseLoadBalancer; import org.apache.hadoop.hbase.master.handler.MetaServerShutdownHandler; +import org.apache.hadoop.hbase.master.handler.RootServerShutdownHandler; import org.apache.hadoop.hbase.master.handler.ServerShutdownHandler; import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.protobuf.ProtobufUtil; @@ -567,9 +568,12 @@ public class ServerManager { } return; } - + boolean carryingRoot = services.getAssignmentManager().isCarryingRoot(serverName); boolean carryingMeta = services.getAssignmentManager().isCarryingMeta(serverName); - if (carryingMeta) { + if (carryingRoot) { + this.services.getExecutorService().submit( + new RootServerShutdownHandler(this.master, this.services, this.deadservers, serverName)); + } else if (carryingMeta) { this.services.getExecutorService().submit(new MetaServerShutdownHandler(this.master, this.services, this.deadservers, serverName)); } else { @@ -610,6 +614,12 @@ public class ServerManager { new ServerShutdownHandler(this.master, this.services, this.deadservers, serverName, shouldSplitHlog)); } + + public synchronized void processDeadServerHostingMeta(final ServerName serverName) { + this.deadservers.add(serverName); + this.services.getExecutorService().submit( + new MetaServerShutdownHandler(this.master, this.services, this.deadservers, serverName)); + } /** * Process the servers which died during master's initialization. It will be diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitLogManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitLogManager.java index bf28a44..40f13b5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitLogManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/SplitLogManager.java @@ -57,6 +57,7 @@ import org.apache.hadoop.hbase.coordination.SplitLogManagerCoordination; import org.apache.hadoop.hbase.coordination.SplitLogManagerCoordination.SplitLogManagerDetails; import org.apache.hadoop.hbase.monitoring.MonitoredTask; import org.apache.hadoop.hbase.monitoring.TaskMonitor; +import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos; import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode; import org.apache.hadoop.hbase.regionserver.SplitLogWorker; import org.apache.hadoop.hbase.regionserver.wal.HLogUtil; @@ -107,11 +108,16 @@ public class SplitLogManager { public static final int DEFAULT_UNASSIGNED_TIMEOUT = (3 * 60 * 1000); // 3 min + public enum RecoveryMode { + ROOT, + META + } + private long unassignedTimeout; private long lastTaskCreateTime = Long.MAX_VALUE; private long checkRecoveringTimeThreshold = 15000; // 15 seconds - private final List, Boolean>> failedRecoveringRegionDeletions = Collections - .synchronizedList(new ArrayList, Boolean>>()); + private final List, RecoveryMode>> failedRecoveringRegionDeletions = Collections + .synchronizedList(new ArrayList, RecoveryMode>>()); /** * In distributedLogReplay mode, we need touch both splitlog and recovering-regions znodes in one @@ -240,7 +246,6 @@ public class SplitLogManager { long t = EnvironmentEdgeManager.currentTime(); long totalSize = 0; TaskBatch batch = new TaskBatch(); - Boolean isMetaRecovery = (filter == null) ? null : false; for (FileStatus lf : logfiles) { // TODO If the log file is still being written to - which is most likely // the case for the last log file - then its length will show up here @@ -255,12 +260,15 @@ public class SplitLogManager { } waitForSplittingCompletion(batch, status); // remove recovering regions + RecoveryMode recoveryMode = null; if (filter == MasterFileSystem.META_FILTER /* reference comparison */) { // we split meta regions and user regions separately therefore logfiles are either all for // meta or user regions but won't for both( we could have mixed situations in tests) - isMetaRecovery = true; + recoveryMode = RecoveryMode.META; + } else if (filter == MasterFileSystem.ROOT_FILTER) { + recoveryMode = RecoveryMode.ROOT; } - removeRecoveringRegions(serverNames, isMetaRecovery); + removeRecoveringRegions(serverNames, recoveryMode); if (batch.done != batch.installed) { batch.isDead = true; @@ -381,7 +389,7 @@ public class SplitLogManager { * @param isMetaRecovery whether current recovery is for the meta region on * serverNames */ - private void removeRecoveringRegions(final Set serverNames, Boolean isMetaRecovery) { + private void removeRecoveringRegions(final Set serverNames, RecoveryMode recoveryMode) { if (!isLogReplaying()) { // the function is only used in WALEdit direct replay mode return; @@ -398,12 +406,12 @@ public class SplitLogManager { this.recoveringRegionLock.lock(); ((BaseCoordinatedStateManager) server.getCoordinatedStateManager()) .getSplitLogManagerCoordination().removeRecoveringRegions(recoveredServerNameSet, - isMetaRecovery); + recoveryMode); } catch (IOException e) { LOG.warn("removeRecoveringRegions got exception. Will retry", e); if (serverNames != null && !serverNames.isEmpty()) { - this.failedRecoveringRegionDeletions.add(new Pair, Boolean>(serverNames, - isMetaRecovery)); + this.failedRecoveringRegionDeletions.add(new Pair, RecoveryMode>(serverNames, + recoveryMode)); } } finally { this.recoveringRegionLock.unlock(); @@ -587,7 +595,7 @@ public class SplitLogManager { /** * @return the current log recovery mode */ - public RecoveryMode getRecoveryMode() { + public ZooKeeperProtos.SplitLogTask.RecoveryMode getRecoveryMode() { return ((BaseCoordinatedStateManager) server.getCoordinatedStateManager()) .getSplitLogManagerCoordination().getRecoveryMode(); } @@ -779,10 +787,10 @@ public class SplitLogManager { || (tot == 0 && tasks.size() == 0 && (timeInterval > checkRecoveringTimeThreshold))) { // inside the function there have more checks before GC anything if (!failedRecoveringRegionDeletions.isEmpty()) { - List, Boolean>> previouslyFailedDeletions = - new ArrayList, Boolean>>(failedRecoveringRegionDeletions); + List, RecoveryMode>> previouslyFailedDeletions = + new ArrayList, RecoveryMode>>(failedRecoveringRegionDeletions); failedRecoveringRegionDeletions.removeAll(previouslyFailedDeletions); - for (Pair, Boolean> failedDeletion : previouslyFailedDeletions) { + for (Pair, RecoveryMode> failedDeletion : previouslyFailedDeletions) { removeRecoveringRegions(failedDeletion.getFirst(), failedDeletion.getSecond()); } } else { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java index a5e110b..e2518d6 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/BaseLoadBalancer.java @@ -798,7 +798,8 @@ public abstract class BaseLoadBalancer implements LoadBalancer { private static final String[] DEFAULT_TABLES_ON_MASTER = new String[] {AccessControlLists.ACL_TABLE_NAME.getNameAsString(), TableName.NAMESPACE_TABLE_NAME.getNameAsString(), - TableName.META_TABLE_NAME.getNameAsString()}; + TableName.META_TABLE_NAME.getNameAsString(), + TableName.ROOT_TABLE_NAME.getNameAsString()}; public static final String TABLES_ON_MASTER = "hbase.balancer.tablesOnMaster"; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java index 4131f92..5079f5b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/balancer/SimpleLoadBalancer.java @@ -342,7 +342,7 @@ public class SimpleLoadBalancer extends BaseLoadBalancer { balanceInfo == null ? 0 : balanceInfo.getNextRegionForUnload(); if (idx >= server.getValue().size()) break; HRegionInfo region = server.getValue().get(idx); - if (region.isMetaRegion()) continue; // Don't move meta regions. + if (region.isMetaRegion() || region.isRootRegion()) continue; // Don't move meta regions. regionsToMove.add(new RegionPlan(region, server.getKey().getServerName(), null)); totalNumMoved++; if (--neededRegions == 0) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java index ca2478c..d3c9271 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/CreateTableHandler.java @@ -96,7 +96,7 @@ public class CreateTableHandler extends EventHandler { // Need hbase:meta availability to create a table try { if (server.getMetaTableLocator().waitMetaRegionLocation( - server.getZooKeeper(), timeout) == null) { + server.getShortCircuitConnection(), timeout) == null) { throw new NotAllMetaRegionsOnlineException(); } // If we are creating the table in service to an RPC request, record the diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java index 455a6ce..97dd6c9 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/DisableTableHandler.java @@ -69,7 +69,7 @@ public class DisableTableHandler extends EventHandler { public DisableTableHandler prepare() throws TableNotFoundException, TableNotEnabledException, IOException { - if(tableName.equals(TableName.META_TABLE_NAME)) { + if(tableName.equals(TableName.META_TABLE_NAME) || tableName.equals(TableName.ROOT_TABLE_NAME)) { throw new ConstraintException("Cannot disable catalog table"); } //acquire the table write lock, blocking diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java index 3d48124..466a904 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java @@ -172,8 +172,8 @@ public class EnableTableHandler extends EventHandler { // Get the regions of this table. We're done when all listed // tables are onlined. List> tableRegionsAndLocations; - if (TableName.META_TABLE_NAME.equals(tableName)) { - tableRegionsAndLocations = new MetaTableLocator().getMetaRegionsAndLocations( + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + tableRegionsAndLocations = new MetaTableLocator().getRootRegionsAndLocations( server.getZooKeeper()); } else { tableRegionsAndLocations = MetaTableAccessor.getTableRegionsAndLocations( diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/MetaServerShutdownHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/MetaServerShutdownHandler.java index 648c835..74f8e3f 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/MetaServerShutdownHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/MetaServerShutdownHandler.java @@ -57,10 +57,22 @@ public class MetaServerShutdownHandler extends ServerShutdownHandler { super(server, services, deadServers, serverName, EventType.M_META_SERVER_SHUTDOWN, true); } + + public MetaServerShutdownHandler(Server server, MasterServices services, DeadServer deadServers, + ServerName serverName, EventType mRootServerShutdown) { + super(server, services, deadServers, serverName, + mRootServerShutdown, true); + } @Override public void process() throws IOException { boolean gotException = true; + // Dont block RootServerShutdownHandler + if (isCarryingRoot()) { + this.services.getServerManager().processDeadServerHostingMeta(serverName); + this.deadServers.finish(serverName); + return; + } try { AssignmentManager am = this.services.getAssignmentManager(); this.services.getMasterFileSystem().setLogRecoveryMode(); @@ -145,19 +157,16 @@ public class MetaServerShutdownHandler extends ServerShutdownHandler { * @throws KeeperException */ private void verifyAndAssignMeta() - throws InterruptedException, IOException, KeeperException { - long timeout = this.server.getConfiguration(). - getLong("hbase.catalog.verification.timeout", 1000); - if (!server.getMetaTableLocator().verifyMetaRegionLocation(server.getShortCircuitConnection(), - this.server.getZooKeeper(), timeout)) { + throws IOException { + if (!server.getMetaTableLocator().verifyMetaRegionLocation(server.getShortCircuitConnection())) { this.services.getAssignmentManager().assignMeta(); } else if (serverName.equals(server.getMetaTableLocator().getMetaRegionLocation( - this.server.getZooKeeper()))) { + this.server.getShortCircuitConnection()))) { throw new IOException("hbase:meta is onlined on the dead server " + serverName); } else { LOG.info("Skip assigning hbase:meta, because it is online on the " - + server.getMetaTableLocator().getMetaRegionLocation(this.server.getZooKeeper())); + + server.getMetaTableLocator().getMetaRegionLocation(this.server.getShortCircuitConnection())); } } @@ -177,9 +186,6 @@ public class MetaServerShutdownHandler extends ServerShutdownHandler { try { verifyAndAssignMeta(); break; - } catch (KeeperException e) { - this.server.abort("In server shutdown processing, assigning meta", e); - throw new IOException("Aborting", e); } catch (Exception e) { if (iFlag >= iTimes) { this.server.abort("verifyAndAssignMeta failed after" + iTimes diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/RootServerShutdownHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/RootServerShutdownHandler.java new file mode 100644 index 0000000..d612f29 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/RootServerShutdownHandler.java @@ -0,0 +1,184 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.master.handler; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.Server; +import org.apache.hadoop.hbase.ServerName; +import org.apache.hadoop.hbase.executor.EventType; +import org.apache.hadoop.hbase.master.AssignmentManager; +import org.apache.hadoop.hbase.master.DeadServer; +import org.apache.hadoop.hbase.master.MasterServices; +import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos.SplitLogTask.RecoveryMode; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Shutdown handler for the server hosting hbase:meta + */ +@InterfaceAudience.Private +public class RootServerShutdownHandler extends MetaServerShutdownHandler { + private static final Log LOG = LogFactory.getLog(RootServerShutdownHandler.class); + private AtomicInteger eventExceptionCount = new AtomicInteger(0); + + public RootServerShutdownHandler(final Server server, + final MasterServices services, + final DeadServer deadServers, final ServerName serverName) { + super(server, services, deadServers, serverName, + EventType.M_ROOT_SERVER_SHUTDOWN); + } + + @Override + public void process() throws IOException { + boolean gotException = true; + try { + AssignmentManager am = this.services.getAssignmentManager(); + this.services.getMasterFileSystem().setLogRecoveryMode(); + boolean distributedLogReplay = + (this.services.getMasterFileSystem().getLogRecoveryMode() == RecoveryMode.LOG_REPLAY); + try { + if (this.shouldSplitHlog) { + LOG.info("Splitting hbase:root logs for " + serverName); + if (distributedLogReplay) { + Set regions = new HashSet(); + regions.add(HRegionInfo.ROOT_REGIONINFO); + this.services.getMasterFileSystem().prepareLogReplay(serverName, regions); + } else { + this.services.getMasterFileSystem().splitRootLog(new HashSet(Arrays.asList(serverName))); + } + am.getRegionStates().logSplit(HRegionInfo.ROOT_REGIONINFO); + } + } catch (IOException ioe) { + this.services.getExecutorService().submit(this); + this.deadServers.add(serverName); + throw new IOException("failed log splitting for " + serverName + ", will retry", ioe); + } + + // Assign root if we were carrying it. + // Check again: region may be assigned to other where because of RIT + // timeout + if (am.isCarryingRoot(serverName)) { + LOG.info("Server " + serverName + " was carrying Root. Trying to assign."); + verifyAndAssignRootWithRetries(); + } else { + LOG.info("Root has been assigned to otherwhere, skip assigning."); + } + + try { + if (this.shouldSplitHlog && distributedLogReplay) { + if (!am.waitOnRegionToClearRegionsInTransition(HRegionInfo.ROOT_REGIONINFO, + regionAssignmentWaitTimeout)) { + // Wait here is to avoid log replay hits current dead server and incur a RPC timeout + // when replay happens before region assignment completes. + LOG.warn("Region " + HRegionInfo.ROOT_REGIONINFO.getEncodedName() + + " didn't complete assignment in time"); + } + this.services.getMasterFileSystem().splitRootLog(new HashSet(Arrays.asList(serverName))); + } + } catch (Exception ex) { + if (ex instanceof IOException) { + this.services.getExecutorService().submit(this); + this.deadServers.add(serverName); + throw new IOException("failed log splitting for " + serverName + ", will retry", ex); + } else { + throw new IOException(ex); + } + } + + gotException = false; + } finally { + if (gotException){ + // If we had an exception, this.deadServers.finish will be skipped in super.process() + this.deadServers.finish(serverName); + } + } + + super.process(); + // Clear this counter on successful handling. + this.eventExceptionCount.set(0); + } + + @Override + boolean isCarryingRoot() { + return true; + } + + /** + * Before assign the hbase:root region, ensure it haven't + * been assigned by other place + *

+ * Under some scenarios, the hbase:root region can be opened twice, so it seemed online + * in two regionserver at the same time. + * If the hbase:root region has been assigned, so the operation can be canceled. + * @throws InterruptedException + * @throws IOException + */ + private void verifyAndAssignRoot() throws InterruptedException, IOException { + long timeout = + this.server.getConfiguration().getLong("hbase.catalog.verification.timeout", 1000); + if (!this.server.getMetaTableLocator().verifyRootRegionLocation( + server.getShortCircuitConnection(), server.getZooKeeper(), timeout)) { + this.services.getAssignmentManager().assignRoot(); + } else if (serverName.equals(server.getMetaTableLocator().getRootRegionLocation( + server.getZooKeeper()))) { + throw new IOException("hbase:root is onlined on the dead server " + serverName); + } else { + LOG.info("Skip assigning hbase:root, because it is online on the " + + server.getMetaTableLocator().getRootRegionLocation(server.getZooKeeper())); + } + } + + private void verifyAndAssignRootWithRetries() throws IOException { + int iTimes = this.server.getConfiguration().getInt( + "hbase.catalog.verification.retries", 10); + + long waitTime = this.server.getConfiguration().getLong( + "hbase.catalog.verification.timeout", 1000); + + int iFlag = 0; + while (true) { + try { + verifyAndAssignRoot(); + break; + } catch (Exception e) { + if (iFlag >= iTimes) { + this.server.abort("verifyAndAssignRoot failed after" + iTimes + + " times retries, aborting", e); + throw new IOException("Aborting", e); + } + try { + Thread.sleep(waitTime); + } catch (InterruptedException e1) { + LOG.warn("Interrupted when is the thread sleep", e1); + Thread.currentThread().interrupt(); + throw (InterruptedIOException)new InterruptedIOException().initCause(e1); + } + iFlag++; + } + } + } +} \ No newline at end of file diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java index c443968..e94b517 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java @@ -92,6 +92,13 @@ public class ServerShutdownHandler extends EventHandler { } /** + * @return True if the server we are processing was carrying hbase:root + */ + boolean isCarryingRoot() { + return false; + } + + /** * @return True if the server we are processing was carrying hbase:meta */ boolean isCarryingMeta() { @@ -132,7 +139,7 @@ public class ServerShutdownHandler extends EventHandler { // the dead server for further processing too. AssignmentManager am = services.getAssignmentManager(); ServerManager serverManager = services.getServerManager(); - if (isCarryingMeta() /* hbase:meta */ || !am.isFailoverCleanupDone()) { + if (isCarryingMeta() || isCarryingRoot() || !am.isFailoverCleanupDone()) { serverManager.processDeadServer(serverName, this.shouldSplitHlog); return; } @@ -154,7 +161,7 @@ public class ServerShutdownHandler extends EventHandler { // doing the below hbase:meta daughters fixup. Set hris = null; try { - server.getMetaTableLocator().waitMetaRegionLocation(server.getZooKeeper()); + server.getMetaTableLocator().waitMetaRegionLocation(server.getShortCircuitConnection()); if (BaseLoadBalancer.tablesOnMaster(server.getConfiguration())) { while (!this.server.isStopped() && serverManager.countOfRegionServers() < 2) { // Wait till at least another regionserver is up besides the active master diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java index 66c45a4..c90ff00 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java @@ -127,8 +127,8 @@ public abstract class TableEventHandler extends EventHandler { tableName); List hris; - if (TableName.META_TABLE_NAME.equals(tableName)) { - hris = new MetaTableLocator().getMetaRegions(server.getZooKeeper()); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + hris = new MetaTableLocator().getRootRegions(server.getZooKeeper()); } else { hris = MetaTableAccessor.getTableRegions(server.getShortCircuitConnection(), tableName); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java index af4eb09..56cb226 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/MasterSnapshotVerifier.java @@ -152,8 +152,8 @@ public final class MasterSnapshotVerifier { */ private void verifyRegions(final SnapshotManifest manifest) throws IOException { List regions; - if (TableName.META_TABLE_NAME.equals(tableName)) { - regions = new MetaTableLocator().getMetaRegions(services.getZooKeeper()); + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + regions = new MetaTableLocator().getRootRegions(services.getZooKeeper()); } else { regions = MetaTableAccessor.getTableRegions(services.getShortCircuitConnection(), tableName); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java index 94275c8..7cf1f6c 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/TakeSnapshotHandler.java @@ -169,8 +169,8 @@ public abstract class TakeSnapshotHandler extends EventHandler implements Snapsh monitor.rethrowException(); List> regionsAndLocations; - if (TableName.META_TABLE_NAME.equals(snapshotTable)) { - regionsAndLocations = new MetaTableLocator().getMetaRegionsAndLocations( + if (TableName.ROOT_TABLE_NAME.equals(snapshotTable)) { + regionsAndLocations = new MetaTableLocator().getRootRegionsAndLocations( server.getZooKeeper()); } else { regionsAndLocations = MetaTableAccessor.getTableRegionsAndLocations( diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/flush/MasterFlushTableProcedureManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/flush/MasterFlushTableProcedureManager.java index bc248b9..6e20be0 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/flush/MasterFlushTableProcedureManager.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/flush/MasterFlushTableProcedureManager.java @@ -127,8 +127,8 @@ public class MasterFlushTableProcedureManager extends MasterProcedureManager { // We may still miss regions that need to be flushed. List> regionsAndLocations; try { - if (TableName.META_TABLE_NAME.equals(tableName)) { - regionsAndLocations = new MetaTableLocator().getMetaRegionsAndLocations( + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + regionsAndLocations = new MetaTableLocator().getRootRegionsAndLocations( master.getZooKeeper()); } else { regionsAndLocations = MetaTableAccessor.getTableRegionsAndLocations( diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/AnnotationReadingPriorityFunction.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/AnnotationReadingPriorityFunction.java index 3035086..c5338e5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/AnnotationReadingPriorityFunction.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/AnnotationReadingPriorityFunction.java @@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HConstants; +import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.ipc.PriorityFunction; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CloseRegionRequest; import org.apache.hadoop.hbase.protobuf.generated.AdminProtos.CompactRegionRequest; @@ -177,7 +178,8 @@ class AnnotationReadingPriorityFunction implements PriorityFunction { Method getRegion = methodMap.get("getRegion").get(rpcArgClass); regionSpecifier = (RegionSpecifier)getRegion.invoke(param, (Object[])null); HRegion region = rpcServices.getRegion(regionSpecifier); - if (region.getRegionInfo().isMetaTable()) { + HRegionInfo hRegionInfo = region.getRegionInfo(); + if (hRegionInfo.isMetaRegion() || hRegionInfo.isRootRegion()) { if (LOG.isTraceEnabled()) { LOG.trace("High priority because region=" + region.getRegionNameAsString()); } @@ -197,7 +199,7 @@ class AnnotationReadingPriorityFunction implements PriorityFunction { return HConstants.NORMAL_QOS; } RegionScanner scanner = rpcServices.getScanner(request.getScannerId()); - if (scanner != null && scanner.getRegionInfo().isMetaRegion()) { + if (scanner != null && (scanner.getRegionInfo().isMetaRegion() || scanner.getRegionInfo().isRootRegion())) { if (LOG.isTraceEnabled()) { // Scanner requests are small in size so TextFormat version should not overwhelm log. LOG.trace("High priority scanner request " + TextFormat.shortDebugString(request)); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java index 210023d..d165d5e 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegion.java @@ -3109,7 +3109,7 @@ public class HRegion implements HeapSize { // , Writable{ private void checkResources() throws RegionTooBusyException { // If catalog region, do not impose resource constraints or block updates. - if (this.getRegionInfo().isMetaRegion()) return; + if (this.getRegionInfo().isMetaRegion() || this.getRegionInfo().isRootRegion()) return; if (this.memstoreSize.get() > this.blockingMemStoreSize) { requestFlush(); @@ -5908,6 +5908,10 @@ public class HRegion implements HeapSize { // , Writable{ region = HRegion.newHRegion(p, log, fs, c, HRegionInfo.FIRST_META_REGIONINFO, fst.get(TableName.META_TABLE_NAME), null); + } else if (FSUtils.getTableName(p).equals(TableName.ROOT_TABLE_NAME)) { + region = + HRegion.newHRegion(p, log, fs, c, HRegionInfo.ROOT_REGIONINFO, + fst.get(TableName.ROOT_TABLE_NAME), null); } else { throw new IOException("Not a known catalog table: " + p.toString()); } @@ -5974,7 +5978,7 @@ public class HRegion implements HeapSize { // , Writable{ */ public byte[] checkSplit() { // Can't split META - if (this.getRegionInfo().isMetaTable() || + if (this.getRegionInfo().isMetaTable() || this.getRegionInfo().isRootRegion() || TableName.NAMESPACE_TABLE_NAME.equals(this.getRegionInfo().getTable())) { if (shouldForceSplit()) { LOG.warn("Cannot split meta region in HBase 0.20 and above"); @@ -6205,7 +6209,7 @@ public class HRegion implements HeapSize { // , Writable{ * @throws IOException If anything goes wrong with DFS */ private void syncOrDefer(long txid, Durability durability) throws IOException { - if (this.getRegionInfo().isMetaRegion()) { + if (this.getRegionInfo().isMetaRegion() || this.getRegionInfo().isRootRegion()) { this.log.sync(txid); } else { switch(durability) { diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java index 21de028..d6b6cc5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HRegionServer.java @@ -121,6 +121,7 @@ import org.apache.hadoop.hbase.quotas.RegionServerQuotaManager; import org.apache.hadoop.hbase.regionserver.compactions.CompactionProgress; import org.apache.hadoop.hbase.regionserver.handler.CloseMetaHandler; import org.apache.hadoop.hbase.regionserver.handler.CloseRegionHandler; +import org.apache.hadoop.hbase.regionserver.handler.CloseRootHandler; import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.regionserver.wal.HLogFactory; import org.apache.hadoop.hbase.regionserver.wal.HLogUtil; @@ -209,7 +210,7 @@ public class HRegionServer extends HasThread implements protected HConnection shortCircuitConnection; /* - * Long-living meta table locator, which is created when the server is started and stopped + * Long-living root and meta table locator, which is created when the server is started and stopped * when server shuts down. References to this locator shall be used to perform according * operations in EventHandlers. Primary reason for this decision is to make it mockable * for tests. @@ -332,9 +333,14 @@ public class HRegionServer extends HasThread implements // The meta updates are written to a different hlog. If this // regionserver holds meta regions, then this field will be non-null. protected volatile HLog hlogForMeta; + + // The root updates are written to a different hlog. If this + // regionserver holds the root region, then this field will be non-null. + protected volatile HLog hlogForRoot; LogRoller hlogRoller; LogRoller metaHLogRoller; + LogRoller rootHLogRoller; // flag set after we're done setting up server threads final AtomicBoolean online = new AtomicBoolean(false); @@ -1002,14 +1008,15 @@ public class HRegionServer extends HasThread implements } private boolean containsMetaTableRegions() { - return onlineRegions.containsKey(HRegionInfo.FIRST_META_REGIONINFO.getEncodedName()); + return onlineRegions.containsKey(HRegionInfo.FIRST_META_REGIONINFO.getEncodedName()) || + onlineRegions.containsKey(HRegionInfo.ROOT_REGIONINFO.getEncodedName()); } private boolean areAllUserRegionsOffline() { if (getNumberOfOnlineRegions() > 2) return false; boolean allUserRegionsOffline = true; for (Map.Entry e: this.onlineRegions.entrySet()) { - if (!e.getValue().getRegionInfo().isMetaTable()) { + if (!e.getValue().getRegionInfo().isMetaTable() && !e.getValue().getRegionInfo().isRootRegion()) { allUserRegionsOffline = false; break; } @@ -1185,7 +1192,15 @@ public class HRegionServer extends HasThread implements this.hlogForMeta.close(); } catch (Throwable e) { e = e instanceof RemoteException ? ((RemoteException) e).unwrapRemoteException() : e; - LOG.error("Metalog close and delete failed", e); + LOG.error("Metalog close failed", e); + } + } + if (this.hlogForRoot != null) { + try { + this.hlogForRoot.close(); + } catch (Throwable e) { + e = e instanceof RemoteException ? ((RemoteException) e).unwrapRemoteException() : e; + LOG.error("RootLog close failed", e); } } if (this.hlog != null) { @@ -1510,6 +1525,32 @@ public class HRegionServer extends HasThread implements this.conf, getMetaWALActionListeners(), this.serverName.toString()); return this.hlogForMeta; } + + private HLog getRootWAL() throws IOException { + if (this.hlogForRoot != null) return this.hlogForRoot; + final String logName = HLogUtil.getHLogDirectoryName(this.serverName.toString()); + Path logdir = new Path(rootDir, logName); + if (LOG.isDebugEnabled()) LOG.debug("logdir=" + logdir); + this.hlogForRoot = + HLogFactory.createRootHLog(this.fs.getBackingFs(), rootDir, logName, this.conf, + getRootWALActionListeners(), this.serverName.toString()); + return this.hlogForRoot; + } + + protected List getRootWALActionListeners() { + List listeners = new ArrayList(); + // Using a tmp log roller to ensure rootLogroller is alive once it is not + // null + RootLogRoller tmpLogRoller = new RootLogRoller(this, this); + String n = Thread.currentThread().getName(); + Threads.setDaemonThreadRunning(tmpLogRoller.getThread(), + n + "-RootLogRoller", uncaughtExceptionHandler); + this.rootHLogRoller = tmpLogRoller; + tmpLogRoller = null; + listeners.add(this.rootHLogRoller); + return listeners; + } + /** * Called by {@link #setupWALAndReplication()} creating WAL instance. @@ -1589,10 +1630,14 @@ public class HRegionServer extends HasThread implements conf.getInt("hbase.regionserver.executor.openregion.threads", 3)); this.service.startExecutorService(ExecutorType.RS_OPEN_META, conf.getInt("hbase.regionserver.executor.openmeta.threads", 1)); + this.service.startExecutorService(ExecutorType.RS_OPEN_ROOT, + conf.getInt("hbase.regionserver.executor.openroot.threads", 1)); this.service.startExecutorService(ExecutorType.RS_CLOSE_REGION, conf.getInt("hbase.regionserver.executor.closeregion.threads", 3)); this.service.startExecutorService(ExecutorType.RS_CLOSE_META, conf.getInt("hbase.regionserver.executor.closemeta.threads", 1)); + this.service.startExecutorService(ExecutorType.RS_CLOSE_ROOT, + conf.getInt("hbase.regionserver.executor.closeroot.threads", 1)); if (conf.getBoolean(StoreScanner.STORESCANNER_PARALLEL_SEEK_ENABLE, false)) { this.service.startExecutorService(ExecutorType.RS_PARALLEL_SEEK, conf.getInt("hbase.storescanner.parallel.seek.threads", 10)); @@ -1712,6 +1757,10 @@ public class HRegionServer extends HasThread implements stop("Meta HLog roller thread is no longer alive -- stop"); return false; } + if (rootHLogRoller != null && !rootHLogRoller.isAlive()) { + stop("Root HLog roller thread is no longer alive -- stop"); + return false; + } return true; } @@ -1729,9 +1778,13 @@ public class HRegionServer extends HasThread implements //TODO: at some point this should delegate to the HLogFactory //currently, we don't care about the region as much as we care about the //table.. (hence checking the tablename below) - //_ROOT_ and hbase:meta regions have separate WAL. - if (regionInfo != null && regionInfo.isMetaTable()) { - return getMetaWAL(); + //hbase:root and hbase:meta regions have separate WAL. + if (regionInfo != null) { + if (regionInfo.isMetaRegion()) { + return getMetaWAL(); + } else if (regionInfo.isRootRegion()) { + return getRootWAL(); + } } return this.hlog; } @@ -1820,9 +1873,9 @@ public class HRegionServer extends HasThread implements // to handle the region transition report at all. if (code == TransitionCode.OPENED) { Preconditions.checkArgument(hris != null && hris.length == 1); - if (hris[0].isMetaRegion()) { + if (hris[0].isRootRegion()) { try { - MetaTableLocator.setMetaLocation(getZooKeeper(), serverName, State.OPEN); + MetaTableLocator.setRootLocation(getZooKeeper(), serverName, State.OPEN); } catch (KeeperException e) { LOG.info("Failed to update meta location", e); return false; @@ -1984,6 +2037,9 @@ public class HRegionServer extends HasThread implements if (this.metaHLogRoller != null) { Threads.shutdown(this.metaHLogRoller.getThread()); } + if (this.rootHLogRoller != null) { + Threads.shutdown(this.rootHLogRoller.getThread()); + } if (this.compactSplitThread != null) { this.compactSplitThread.join(); } @@ -2180,19 +2236,24 @@ public class HRegionServer extends HasThread implements */ void closeMetaTableRegions(final boolean abort) { HRegion meta = null; + HRegion root = null; this.lock.writeLock().lock(); try { for (Map.Entry e: onlineRegions.entrySet()) { HRegionInfo hri = e.getValue().getRegionInfo(); + if (hri.isRootRegion()) { + root = e.getValue(); + } if (hri.isMetaRegion()) { meta = e.getValue(); } - if (meta != null) break; + if (meta != null && root != null) break; } } finally { this.lock.writeLock().unlock(); } if (meta != null) closeRegionIgnoreErrors(meta.getRegionInfo(), abort); + if (root != null) closeRegionIgnoreErrors(root.getRegionInfo(), abort); } /** @@ -2206,7 +2267,7 @@ public class HRegionServer extends HasThread implements try { for (Map.Entry e: this.onlineRegions.entrySet()) { HRegion r = e.getValue(); - if (!r.getRegionInfo().isMetaTable() && r.isAvailable()) { + if (!(r.getRegionInfo().isRootRegion() || r.getRegionInfo().isMetaRegion()) && r.isAvailable()) { // Don't update zk with this close transition; pass false. closeRegionIgnoreErrors(r.getRegionInfo(), abort); } @@ -2633,7 +2694,9 @@ public class HRegionServer extends HasThread implements CloseRegionHandler crh; final HRegionInfo hri = actualRegion.getRegionInfo(); - if (hri.isMetaRegion()) { + if (hri.isRootRegion()) { + crh = new CloseRootHandler(this, this, hri, abort); + } else if (hri.isMetaRegion()) { crh = new CloseMetaHandler(this, this, hri, abort); } else { crh = new CloseRegionHandler(this, this, hri, abort, sn); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java index 7a331b1..a3f5165 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java @@ -1685,7 +1685,7 @@ public class HStore implements Store { KeyValue kv = new KeyValue(row, HConstants.LATEST_TIMESTAMP); GetClosestRowBeforeTracker state = new GetClosestRowBeforeTracker( - this.comparator, kv, ttlToUse, this.getRegionInfo().isMetaRegion()); + this.comparator, kv, ttlToUse, this.getRegionInfo().isMetaRegion() || this.getRegionInfo().isRootRegion()); this.lock.readLock().lock(); try { // First go to the memstore. Pick up deletes and candidates. @@ -1843,7 +1843,7 @@ public class HStore implements Store { this.lock.readLock().lock(); try { // Should already be enforced by the split policy! - assert !this.getRegionInfo().isMetaRegion(); + assert !this.getRegionInfo().isMetaRegion() && !this.getRegionInfo().isRootRegion(); // Not split-able if we find a reference store file present in the store. if (hasReferences()) { return null; diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java index b6e0d14..10dd2a3 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MemStoreFlusher.java @@ -372,7 +372,7 @@ class MemStoreFlusher implements FlushRequester { */ private boolean flushRegion(final FlushRegionEntry fqe) { HRegion region = fqe.region; - if (!region.getRegionInfo().isMetaRegion() && + if (!region.getRegionInfo().isMetaRegion() && !region.getRegionInfo().isRootRegion() && isTooManyStoreFiles(region)) { if (fqe.isMaximumWait(this.blockingWaitTime)) { LOG.info("Waited " + (EnvironmentEdgeManager.currentTime() - fqe.createTime) + diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetaLogRoller.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetaLogRoller.java index 467cfdf..500a332 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetaLogRoller.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetaLogRoller.java @@ -31,8 +31,6 @@ class MetaLogRoller extends LogRoller { } @Override protected HLog getWAL() throws IOException { - //The argument to getWAL below could either be HRegionInfo.FIRST_META_REGIONINFO or - //HRegionInfo.ROOT_REGIONINFO. Both these share the same WAL. return services.getWAL(HRegionInfo.FIRST_META_REGIONINFO); } } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapperImpl.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapperImpl.java index 327f55c..5b8f2a5 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapperImpl.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/MetricsRegionServerWrapperImpl.java @@ -497,6 +497,10 @@ class MetricsRegionServerWrapperImpl if (regionServer.hlogForMeta != null) { tempNumHLogFiles += regionServer.hlogForMeta.getNumLogFiles(); } + // root logs + if (regionServer.hlogForRoot != null) { + tempNumHLogFiles += regionServer.hlogForRoot.getNumLogFiles(); + } numHLogFiles = tempNumHLogFiles; long tempHlogFileSize = regionServer.hlog.getLogFileSize(); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java index eae6e96..10ea853 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RSRpcServices.java @@ -147,6 +147,7 @@ import org.apache.hadoop.hbase.regionserver.HRegion.Operation; import org.apache.hadoop.hbase.regionserver.Leases.LeaseStillHeldException; import org.apache.hadoop.hbase.regionserver.handler.OpenMetaHandler; import org.apache.hadoop.hbase.regionserver.handler.OpenRegionHandler; +import org.apache.hadoop.hbase.regionserver.handler.OpenRootHandler; import org.apache.hadoop.hbase.regionserver.wal.HLog; import org.apache.hadoop.hbase.regionserver.wal.HLogKey; import org.apache.hadoop.hbase.regionserver.wal.HLogSplitter; @@ -356,7 +357,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler, */ private void mutateRows(final HRegion region, final List actions, final CellScanner cellScanner) throws IOException { - if (!region.getRegionInfo().isMetaTable()) { + if (!region.getRegionInfo().isMetaTable() && !region.getRegionInfo().isRootRegion()) { regionServer.cacheFlusher.reclaimMemStoreMemory(); } RowMutations rm = null; @@ -398,7 +399,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler, private boolean checkAndRowMutate(final HRegion region, final List actions, final CellScanner cellScanner, byte[] row, byte[] family, byte[] qualifier, CompareOp compareOp, ByteArrayComparable comparator) throws IOException { - if (!region.getRegionInfo().isMetaTable()) { + if (!region.getRegionInfo().isMetaTable() && !region.getRegionInfo().isRootRegion()) { regionServer.cacheFlusher.reclaimMemStoreMemory(); } RowMutations rm = null; @@ -634,7 +635,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler, quota.addMutation(mutation); } - if (!region.getRegionInfo().isMetaTable()) { + if (!region.getRegionInfo().isMetaTable() && !region.getRegionInfo().isRootRegion()) { regionServer.cacheFlusher.reclaimMemStoreMemory(); } @@ -718,7 +719,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler, } } requestCount.add(mutations.size()); - if (!region.getRegionInfo().isMetaTable()) { + if (!region.getRegionInfo().isMetaTable() && !region.getRegionInfo().isRootRegion()) { regionServer.cacheFlusher.reclaimMemStoreMemory(); } return region.batchReplay(mutations.toArray( @@ -1259,10 +1260,10 @@ public class RSRpcServices implements HBaseRPCErrorHandler, tableName = ProtobufUtil.toTableName(ri.getTableName()); } } - if (!TableName.META_TABLE_NAME.equals(tableName)) { + if (!TableName.META_TABLE_NAME.equals(tableName) && !TableName.ROOT_TABLE_NAME.equals(tableName)) { throw new ServiceException(ie); } - // We are assigning meta, wait a little for regionserver to finish initialization. + // We are assigning root/meta, wait a little for regionserver to finish initialization. int timeout = regionServer.conf.getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT) >> 2; // Quarter of RPC timeout long endTime = System.currentTimeMillis() + timeout; @@ -1347,7 +1348,10 @@ public class RSRpcServices implements HBaseRPCErrorHandler, } // If there is no action in progress, we can submit a specific handler. // Need to pass the expected version in the constructor. - if (region.isMetaRegion()) { + if (region.isRootRegion()) { + regionServer.service.submit(new OpenRootHandler( + regionServer, regionServer, region, htd)); + } else if (region.isMetaRegion()) { regionServer.service.submit(new OpenMetaHandler( regionServer, regionServer, region, htd)); } else { @@ -1827,7 +1831,7 @@ public class RSRpcServices implements HBaseRPCErrorHandler, HRegion region = getRegion(request.getRegion()); MutateResponse.Builder builder = MutateResponse.newBuilder(); MutationProto mutation = request.getMutation(); - if (!region.getRegionInfo().isMetaTable()) { + if (!region.getRegionInfo().isMetaTable() && !region.getRegionInfo().isRootRegion()) { regionServer.cacheFlusher.reclaimMemStoreMemory(); } long nonceGroup = request.hasNonceGroup() diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RootLogRoller.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RootLogRoller.java new file mode 100644 index 0000000..9eeb54a --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/RootLogRoller.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver; + +import java.io.IOException; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.Server; +import org.apache.hadoop.hbase.regionserver.wal.HLog; + +@InterfaceAudience.Private +class RootLogRoller extends LogRoller { + public RootLogRoller(Server server, RegionServerServices services) { + super(server, services); + } + @Override + protected HLog getWAL() throws IOException { + return services.getWAL(HRegionInfo.ROOT_REGIONINFO); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRootHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRootHandler.java new file mode 100644 index 0000000..e290c72 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/CloseRootHandler.java @@ -0,0 +1,39 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver.handler; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.Server; +import org.apache.hadoop.hbase.executor.EventType; +import org.apache.hadoop.hbase.regionserver.RegionServerServices; + +/** + * Handles closing of the root region on a region server. + */ +@InterfaceAudience.Private +public class CloseRootHandler extends CloseRegionHandler { + + public CloseRootHandler(final Server server, + final RegionServerServices rsServices, + final HRegionInfo regionInfo, + final boolean abort) { + super(server, rsServices, regionInfo, abort, EventType.M_RS_CLOSE_ROOT, null); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRootHandler.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRootHandler.java new file mode 100644 index 0000000..8092197 --- /dev/null +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/handler/OpenRootHandler.java @@ -0,0 +1,40 @@ +/** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.hbase.regionserver.handler; + +import org.apache.hadoop.hbase.classification.InterfaceAudience; +import org.apache.hadoop.hbase.HRegionInfo; +import org.apache.hadoop.hbase.HTableDescriptor; +import org.apache.hadoop.hbase.Server; +import org.apache.hadoop.hbase.executor.EventType; +import org.apache.hadoop.hbase.regionserver.RegionServerServices; + +/** + * Handles opening of a meta region on a region server. + *

+ * This is executed after receiving an OPEN RPC from the master for meta. + */ +@InterfaceAudience.Private +public class OpenRootHandler extends OpenRegionHandler { + public OpenRootHandler(final Server server, + final RegionServerServices rsServices, HRegionInfo regionInfo, + final HTableDescriptor htd) { + super(server, rsServices, regionInfo, htd, EventType.M_RS_OPEN_ROOT); + } +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/FSHLog.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/FSHLog.java index 42e4751..b59258b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/FSHLog.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/FSHLog.java @@ -251,10 +251,15 @@ class FSHLog implements HLog, Syncable { private volatile boolean closed = false; /** - * Set when this WAL is for meta only (we run a WAL for all regions except meta -- it has its + * Set when this WAL is for meta only (we run a WAL for all regions except meta and root -- they have their * own dedicated WAL). */ private final boolean forMeta; + + /** + * Set when this WAL is for root only + */ + private final boolean forRoot; // The timestamp (in ms) when the log file was created. private final AtomicLong filenum = new AtomicLong(-1); @@ -389,7 +394,7 @@ class FSHLog implements HLog, Syncable { public FSHLog(final FileSystem fs, final Path root, final String logDir, final Configuration conf) throws IOException { - this(fs, root, logDir, HConstants.HREGION_OLDLOGDIR_NAME, conf, null, true, null, false); + this(fs, root, logDir, HConstants.HREGION_OLDLOGDIR_NAME, conf, null, true, null, false, false); } /** @@ -417,13 +422,14 @@ class FSHLog implements HLog, Syncable { public FSHLog(final FileSystem fs, final Path rootDir, final String logDir, final String oldLogDir, final Configuration conf, final List listeners, - final boolean failIfLogDirExists, final String prefix, boolean forMeta) + final boolean failIfLogDirExists, final String prefix, boolean forMeta, boolean forRoot) throws IOException { super(); this.fs = fs; this.fullPathLogDir = new Path(rootDir, logDir); this.fullPathOldLogDir = new Path(rootDir, oldLogDir); this.forMeta = forMeta; + this.forRoot = forRoot; this.conf = conf; // Register listeners. TODO: Should this exist anymore? We have CPs? @@ -697,7 +703,7 @@ class FSHLog implements HLog, Syncable { */ protected Writer createWriterInstance(final FileSystem fs, final Path path, final Configuration conf) throws IOException { - if (forMeta) { + if (forMeta || forRoot) { //TODO: set a higher replication for the hlog files (HBASE-6773) } return HLogFactory.createWALWriter(fs, path, conf); @@ -982,6 +988,9 @@ class FSHLog implements HLog, Syncable { if (forMeta) { child += HLog.META_HLOG_FILE_EXTN; } + if (forRoot) { + child += HLog.ROOT_HLOG_FILE_EXTN; + } return new Path(fullPathLogDir, child); } @@ -1002,7 +1011,12 @@ class FSHLog implements HLog, Syncable { " this regionserver " + prefixPathStr); } String chompedPath = fileName.toString().substring(prefixPathStr.length()); - if (forMeta) chompedPath = chompedPath.substring(0, chompedPath.indexOf(META_HLOG_FILE_EXTN)); + if (forMeta) { + chompedPath = chompedPath.substring(0, chompedPath.indexOf(META_HLOG_FILE_EXTN)); + } + if (forRoot) { + chompedPath = chompedPath.substring(0, chompedPath.indexOf(ROOT_HLOG_FILE_EXTN)); + } return Long.parseLong(chompedPath); } @@ -2048,7 +2062,7 @@ class FSHLog implements HLog, Syncable { Path rootDir = FSUtils.getRootDir(conf); FileSystem fs = rootDir.getFileSystem(conf); FSHLog wal = - new FSHLog(fs, rootDir, "perflog", "oldPerflog", conf, null, false, "perf", false); + new FSHLog(fs, rootDir, "perflog", "oldPerflog", conf, null, false, "perf", false, false); long start = System.nanoTime(); WALEdit walEdit = new WALEdit(); walEdit.add(new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("family"), diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java index eb3692e..cae1a1b 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLog.java @@ -60,6 +60,7 @@ public interface HLog { /** The hbase:meta region's HLog filename extension.*/ // TODO: Implementation detail. Does not belong in here. String META_HLOG_FILE_EXTN = ".meta"; + String ROOT_HLOG_FILE_EXTN = ".root"; /** * Configuration name of HLog Trailer's warning size. If a waltrailer's size is greater than the diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogFactory.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogFactory.java index a54091d..8cc1308 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogFactory.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogFactory.java @@ -49,21 +49,28 @@ public class HLogFactory { public static HLog createHLog(final FileSystem fs, final Path root, final String logName, final String oldLogName, final Configuration conf) throws IOException { - return new FSHLog(fs, root, logName, oldLogName, conf, null, true, null, false); + return new FSHLog(fs, root, logName, oldLogName, conf, null, true, null, false, false); } public static HLog createHLog(final FileSystem fs, final Path root, final String logName, final Configuration conf, final List listeners, final String prefix) throws IOException { return new FSHLog(fs, root, logName, HConstants.HREGION_OLDLOGDIR_NAME, conf, listeners, - true, prefix, false); + true, prefix, false, false); } public static HLog createMetaHLog(final FileSystem fs, final Path root, final String logName, final Configuration conf, final List listeners, final String prefix) throws IOException { return new FSHLog(fs, root, logName, HConstants.HREGION_OLDLOGDIR_NAME, conf, listeners, - false, prefix, true); + false, prefix, true, false); + } + + public static HLog createRootHLog(final FileSystem fs, final Path root, final String logName, + final Configuration conf, final List listeners, + final String prefix) throws IOException { + return new FSHLog(fs, root, logName, HConstants.HREGION_OLDLOGDIR_NAME, + conf, listeners, false, prefix, false, true); } /* diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogUtil.java index 29bffd1..3fae227 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogUtil.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/HLogUtil.java @@ -56,7 +56,7 @@ public class HLogUtil { * Pattern used to validate a HLog file name */ private static final Pattern pattern = - Pattern.compile(".*\\.\\d*("+HLog.META_HLOG_FILE_EXTN+")*"); + Pattern.compile(".*\\.\\d*("+HLog.META_HLOG_FILE_EXTN+"|"+HLog.ROOT_HLOG_FILE_EXTN+")*"); /** * @param filename @@ -249,6 +249,10 @@ public class HLogUtil { public static boolean isMetaFile(Path p) { return isMetaFile(p.getName()); } + + public static boolean isRootFile(Path p) { + return isRootFile(p.getName()); + } public static boolean isMetaFile(String p) { if (p != null && p.endsWith(HLog.META_HLOG_FILE_EXTN)) { @@ -256,6 +260,13 @@ public class HLogUtil { } return false; } + + public static boolean isRootFile(String p) { + if (p != null && p.endsWith(HLog.ROOT_HLOG_FILE_EXTN)) { + return true; + } + return false; + } /** * Write the marker that a compaction has succeeded and is about to be committed. diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java index 400e20a..e494a08 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java @@ -277,7 +277,7 @@ public class AccessController extends BaseMasterAndRegionObserver // 1. All users need read access to hbase:meta table. // this is a very common operation, so deal with it quickly. - if (hri.isMetaRegion()) { + if (hri.isMetaRegion() || hri.isRootRegion()) { if (permRequest == Action.READ) { return AuthResult.allow(request, "All users allowed", user, permRequest, tableName, families); @@ -295,7 +295,7 @@ public class AccessController extends BaseMasterAndRegionObserver // e.g. When a table is removed an entry is removed from hbase:meta and _acl_ // and the user need to be allowed to write on both tables. if (permRequest == Action.WRITE && - (hri.isMetaRegion() || + (hri.isMetaRegion() || hri.isRootRegion() || Bytes.equals(tableName.getName(), AccessControlLists.ACL_GLOBAL_NAME)) && (authManager.authorize(user, Action.CREATE) || authManager.authorize(user, Action.ADMIN))) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java index fb9059e..972bf86 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSTableDescriptors.java @@ -95,7 +95,12 @@ public class FSTableDescriptors implements TableDescriptors { /** * Table descriptor for hbase:meta catalog table */ - private final HTableDescriptor metaTableDescritor; + private final HTableDescriptor metaTableDescriptor; + + /** + * Table descriptor for hbase:root catalog table + */ + private final HTableDescriptor rootTableDescriptor; /** * Data structure to hold modification time and table descriptor. @@ -151,7 +156,8 @@ public class FSTableDescriptors implements TableDescriptors { this.rootdir = rootdir; this.fsreadonly = fsreadonly; - this.metaTableDescritor = TableDescriptor.metaTableDescriptor(conf); + this.metaTableDescriptor = TableDescriptor.metaTableDescriptor(conf); + this.rootTableDescriptor = TableDescriptor.rootTableDescriptor(conf); } /** @@ -167,7 +173,11 @@ public class FSTableDescriptors implements TableDescriptors { invocations++; if (TableName.META_TABLE_NAME.equals(tablename)) { cachehits++; - return new TableDescriptor(metaTableDescritor, TableState.State.ENABLED); + return new TableDescriptor(metaTableDescriptor, TableState.State.ENABLED); + } + if (TableName.ROOT_TABLE_NAME.equals(tablename)) { + cachehits++; + return new TableDescriptor(rootTableDescriptor, TableState.State.ENABLED); } // hbase:meta is already handled. If some one tries to get the descriptor for // .logs, .oldlogs or .corrupt throw an exception. @@ -213,7 +223,10 @@ public class FSTableDescriptors implements TableDescriptors { public HTableDescriptor get(TableName tableName) throws IOException { if (TableName.META_TABLE_NAME.equals(tableName)) { cachehits++; - return metaTableDescritor; + return metaTableDescriptor; + } else if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + cachehits++; + return rootTableDescriptor; } TableDescriptor descriptor = getDescriptor(tableName); return descriptor == null ? null : descriptor.getHTableDescriptor(); @@ -289,7 +302,7 @@ public class FSTableDescriptors implements TableDescriptors { throw new NotImplementedException("Cannot add a table descriptor - in read only mode"); } TableName tableName = htd.getHTableDescriptor().getTableName(); - if (TableName.META_TABLE_NAME.equals(tableName)) { + if (TableName.META_TABLE_NAME.equals(tableName) || TableName.ROOT_TABLE_NAME.equals(tableName)) { throw new NotImplementedException(); } if (HConstants.HBASE_NON_USER_TABLE_DIRS.contains(tableName.getNameAsString())) { @@ -312,6 +325,9 @@ public class FSTableDescriptors implements TableDescriptors { TableName tableName = htd.getTableName(); if (TableName.META_TABLE_NAME.equals(tableName)) { throw new NotImplementedException(); + } + if (TableName.ROOT_TABLE_NAME.equals(tableName)) { + throw new NotImplementedException(); } if (HConstants.HBASE_NON_USER_TABLE_DIRS.contains(tableName.getNameAsString())) { throw new NotImplementedException( @@ -569,7 +585,7 @@ public class FSTableDescriptors implements TableDescriptors { private TableDescriptorAndModtime getTableDescriptorAndModtime(TableName tableName) throws IOException { // ignore both -ROOT- and hbase:meta tables - if (tableName.equals(TableName.META_TABLE_NAME)) { + if (tableName.equals(TableName.META_TABLE_NAME) || tableName.equals(TableName.ROOT_TABLE_NAME)) { return null; } return getTableDescriptorAndModtime(getTableDir(tableName)); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java index 284d4ab..cc12e41 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/FSUtils.java @@ -939,6 +939,20 @@ public abstract class FSUtils { HRegion.getRegionDir(rootdir, HRegionInfo.FIRST_META_REGIONINFO); return fs.exists(metaRegionDir); } + + /** + * Checks if root region exists + * + * @param fs file system + * @param rootdir root directory of HBase installation + * @return true if exists + * @throws IOException e + */ + public static boolean rootRegionExists(FileSystem fs, Path rootdir) + throws IOException { + return fs.exists(new Path( + FSUtils.getTableDir(rootdir, HRegionInfo.ROOT_REGIONINFO.getTable()), HRegionInfo.ROOT_REGIONINFO.getEncodedName())); + } /** * Compute HDFS blocks distribution of a given file, or a portion of the file @@ -1916,4 +1930,4 @@ public abstract class FSUtils { return null; } } -} \ No newline at end of file +} diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java index b06e70a..8c71f40 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HBaseFsck.java @@ -80,6 +80,7 @@ import org.apache.hadoop.hbase.TableName; import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.MetaTableAccessor; import org.apache.hadoop.hbase.client.Admin; +import org.apache.hadoop.hbase.client.Connection; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; @@ -1183,9 +1184,9 @@ public class HBaseFsck extends Configured { Configuration c = getConf(); HRegionInfo metaHRI = new HRegionInfo(HRegionInfo.FIRST_META_REGIONINFO); HTableDescriptor metaDescriptor = new FSTableDescriptors(c).get(TableName.META_TABLE_NAME); - MasterFileSystem.setInfoFamilyCachingForMeta(metaDescriptor, false); + MasterFileSystem.setInfoFamilyCaching(metaDescriptor, false); HRegion meta = HRegion.createHRegion(metaHRI, rootdir, c, metaDescriptor); - MasterFileSystem.setInfoFamilyCachingForMeta(metaDescriptor, true); + MasterFileSystem.setInfoFamilyCaching(metaDescriptor, true); return meta; } @@ -1563,7 +1564,7 @@ public class HBaseFsck extends Configured { } ServerName sn; try { - sn = getMetaRegionServerName(); + sn = getMetaRegionServerName(connection); } catch (KeeperException e) { throw new IOException(e); } @@ -1593,12 +1594,12 @@ public class HBaseFsck extends Configured { }); } - private ServerName getMetaRegionServerName() + private ServerName getMetaRegionServerName(Connection conn) throws IOException, KeeperException { ZooKeeperWatcher zkw = createZooKeeperWatcher(); ServerName sn = null; try { - sn = new MetaTableLocator().getMetaRegionLocation(zkw); + sn = new MetaTableLocator().getMetaRegionLocation(conn); } finally { zkw.close(); } diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HMerge.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HMerge.java index 5294b85..167a452 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HMerge.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/HMerge.java @@ -115,7 +115,7 @@ class HMerge { } }); } - if (tableName.equals(TableName.META_TABLE_NAME)) { + if (tableName.equals(TableName.META_TABLE_NAME) || tableName.equals(TableName.ROOT_TABLE_NAME)) { if (masterIsRunning) { throw new IllegalStateException( "Can not compact hbase:meta table if instance is on-line"); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MultiHConnection.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MultiHConnection.java index 1dc9c31..e868494 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MultiHConnection.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MultiHConnection.java @@ -75,8 +75,8 @@ public class MultiHConnection { * Close the open connections and shutdown the batchpool */ public void close() { - synchronized (hConnectionsLock) { - if (hConnections != null) { + if (hConnections != null) { + synchronized (hConnectionsLock) { if (hConnections != null) { for (Connection conn : hConnections) { if (conn != null) { diff --git a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp index 519f883..84022f6 100644 --- a/hbase-server/src/main/resources/hbase-webapps/master/table.jsp +++ b/hbase-server/src/main/resources/hbase-webapps/master/table.jsp @@ -53,12 +53,12 @@ } else { tableHeader = "

Table Regions

"; } - ServerName rl = metaTableLocator.getMetaRegionLocation(master.getZooKeeper()); + ServerName rl = metaTableLocator.getRootRegionLocation(master.getZooKeeper()); boolean showFragmentation = conf.getBoolean("hbase.master.ui.fragmentation.enabled", false); boolean readOnly = conf.getBoolean("hbase.master.ui.readonly", false); Map frags = null; if (showFragmentation) { - frags = FSUtils.getTableFragmentation(master); + frags = FSUtils.getTableFragmentation(master); } %>
NameRegion ServerStart KeyEnd KeyRequests