Index: src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java =================================================================== --- src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java (revision 1062080) +++ src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java (working copy) @@ -130,4 +130,6 @@ pair.getFirst().getEncodedName()); LOG.info("Finished " + name); } + + TODO: VERIFY THAT METAREADER getMETAHTABLE USES SAME CONNECTION AS CT } \ No newline at end of file Index: src/main/java/org/apache/hadoop/hbase/HRegionLocation.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/HRegionLocation.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/HRegionLocation.java (working copy) @@ -44,7 +44,7 @@ */ @Override public String toString() { - return "address: " + this.serverAddress.toString() + ", regioninfo: " + + return "address=" + this.serverAddress.toString() + ", regioninfo=" + this.regionInfo.getRegionNameAsString(); } Index: src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java (working copy) @@ -41,7 +41,6 @@ import org.apache.hadoop.hbase.master.MasterServices; import org.apache.hadoop.hbase.master.ServerManager; import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Writables; import org.apache.zookeeper.KeeperException; /** @@ -209,7 +208,7 @@ final AssignmentManager assignmentManager, final CatalogTracker catalogTracker) throws IOException { - HRegionInfo daughter = getHRegionInfo(result, qualifier); + HRegionInfo daughter = MetaReader.getHRegionInfo(result, qualifier); if (daughter == null) return; if (isDaughterMissing(catalogTracker, daughter)) { LOG.info("Fixup; missing daughter " + daughter.getRegionNameAsString()); @@ -222,21 +221,6 @@ } /** - * Interpret the content of the cell at {@link HConstants#CATALOG_FAMILY} and - * qualifier as an HRegionInfo and return it, or null. - * @param r Result instance to pull from. - * @param qualifier Column family qualifier - * @return An HRegionInfo instance or null. - * @throws IOException - */ - private static HRegionInfo getHRegionInfo(final Result r, byte [] qualifier) - throws IOException { - byte [] bytes = r.getValue(HConstants.CATALOG_FAMILY, qualifier); - if (bytes == null || bytes.length <= 0) return null; - return Writables.getHRegionInfoOrNull(bytes); - } - - /** * Look for presence of the daughter OR of a split of the daughter. Daughter * could have been split over on regionserver before a run of the * catalogJanitor had chance to clear reference from parent. @@ -278,7 +262,7 @@ @Override public boolean visit(Result r) throws IOException { - HRegionInfo hri = getHRegionInfo(r, HConstants.REGIONINFO_QUALIFIER); + HRegionInfo hri = MetaReader.getHRegionInfo(r, HConstants.REGIONINFO_QUALIFIER); if (hri == null) { LOG.warn("No serialized HRegionInfo in " + r); return true; Index: src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java (working copy) @@ -28,6 +28,8 @@ import java.util.TreeMap; import java.util.TreeSet; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.HServerAddress; @@ -36,7 +38,9 @@ import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; import org.apache.hadoop.hbase.NotServingRegionException; import org.apache.hadoop.hbase.client.Get; +import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.ipc.HRegionInterface; import org.apache.hadoop.hbase.util.Bytes; @@ -51,6 +55,7 @@ * catalogs. */ public class MetaReader { + private static final Log LOG = LogFactory.getLog(MetaReader.class); public static final byte [] META_REGION_PREFIX; static { // Copy the prefix from FIRST_META_REGIONINFO into META_REGION_PREFIX. @@ -92,19 +97,6 @@ /** * @param regionName - * @return Returns region name to look in for regionName; - * e.g. if we are looking for .META.,,1 region, we need to look - * in -ROOT- region, else if a user region, we need to look - * in the .META.,,1 region. - */ - private static byte [] getCatalogRegionNameForRegion(final byte [] regionName) { - return isMetaRegion(regionName)? - HRegionInfo.ROOT_REGIONINFO.getRegionName(): - HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); - } - - /** - * @param regionName * @return True if regionName is from .META. table. */ private static boolean isMetaRegion(final byte [] regionName) { @@ -208,20 +200,40 @@ public static List fullScanOfResults( CatalogTracker catalogTracker) throws IOException { - final List regions = new ArrayList(); - Visitor v = new Visitor() { + CollectingVisitor v = new CollectingVisitor() { @Override - public boolean visit(Result r) throws IOException { - if (r == null || r.isEmpty()) return true; - regions.add(r); - return true; + void add(Result r) { + this.results.add(r); } }; fullScan(catalogTracker, v); - return regions; + return v.getResults(); } /** + * A {@link Visitor} that collects content of passed {@link Result}. + */ + static abstract class CollectingVisitor implements Visitor { + final List results = new ArrayList(); + @Override + public boolean visit(Result r) throws IOException { + if (r == null || r.isEmpty()) return true; + add(r); + return true; + } + + abstract void add(Result r); + + /** + * @return Collected results; wait till visits complete to collect all + * possible results + */ + List getResults() { + return this.results; + } + } + + /** * Performs a full scan of .META.. *

* Returns a map of every region to it's currently assigned server, according @@ -252,24 +264,33 @@ public static void fullScan(CatalogTracker catalogTracker, final Visitor visitor, final byte [] startrow) throws IOException { - HRegionInterface metaServer = - catalogTracker.waitForMetaServerConnectionDefault(); Scan scan = new Scan(); if (startrow != null) scan.setStartRow(startrow); scan.addFamily(HConstants.CATALOG_FAMILY); - long scannerid = metaServer.openScanner( - HRegionInfo.FIRST_META_REGIONINFO.getRegionName(), scan); + HTable metaTable = getMetaHTable(catalogTracker); + ResultScanner scanner = metaTable.getScanner(scan); try { Result data; - while((data = metaServer.next(scannerid)) != null) { - if (!data.isEmpty()) visitor.visit(data); + while((data = scanner.next()) != null) { + if (data.isEmpty()) continue; + // Break if visit returns false. + if (!visitor.visit(data)) break; } } finally { - metaServer.close(scannerid); + scanner.close(); + metaTable.close(); } return; } + static HTable getMetaHTable(final CatalogTracker ct) + throws IOException { + // Passing the CatalogTracker's connection configuration ensures this + // HTable instance uses the CatalogTracker's connection. + return new HTable(ct.getConnection().getConfiguration(), + HConstants.META_TABLE_NAME); + } + /** * Reads the location of META from ROOT. * @param metaServer connection to server hosting ROOT @@ -356,11 +377,14 @@ throws IOException { Get get = new Get(regionName); get.addFamily(HConstants.CATALOG_FAMILY); - byte [] meta = getCatalogRegionNameForRegion(regionName); - Result r = catalogTracker.waitForMetaServerConnectionDefault().get(meta, get); - if(r == null || r.isEmpty()) { - return null; + HTable metaTable = getMetaHTable(catalogTracker); + Result r = null; + try { + r = metaTable.get(get); + } finally { + metaTable.close(); } + if (r == null || r.isEmpty()) return null; return metaRowToRegionPair(r); } @@ -476,7 +500,7 @@ * @throws IOException */ public static List getTableRegions(CatalogTracker catalogTracker, - byte [] tableName, final boolean excludeOfflinedSplitParents) + final byte [] tableName, final boolean excludeOfflinedSplitParents) throws IOException { if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { // If root, do a bit of special handling. @@ -484,45 +508,61 @@ list.add(HRegionInfo.ROOT_REGIONINFO); return list; } else if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) { - // Same for .META. table + // Same for .META. table. TODO: FIX WHEN .META. can have more than one + // region. List list = new ArrayList(); list.add(HRegionInfo.FIRST_META_REGIONINFO); return list; } + // Make a version of ResultCollectingVisitor that only collects a particular + // tables HRegionInfos. + CollectingVisitor visitor = new CollectingVisitor() { + private HRegionInfo current = null; - // Its a user table. - HRegionInterface metaServer = - getCatalogRegionInterface(catalogTracker, tableName); - List regions = new ArrayList(); - String tableString = Bytes.toString(tableName); - byte[] firstRowInTable = Bytes.toBytes(tableString + ",,"); - Scan scan = new Scan(firstRowInTable); - scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); - long scannerid = - metaServer.openScanner(getCatalogRegionNameForTable(tableName), scan); - try { - Result data; - while((data = metaServer.next(scannerid)) != null) { - if (data != null && data.size() > 0) { - HRegionInfo info = Writables.getHRegionInfo( - data.getValue(HConstants.CATALOG_FAMILY, - HConstants.REGIONINFO_QUALIFIER)); - if (info.getTableDesc().getNameAsString().equals(tableString)) { - // Are we to include split parents in the list? - if (excludeOfflinedSplitParents && info.isSplitParent()) continue; - regions.add(info); - } else { - break; - } + @Override + public boolean visit(Result r) throws IOException { + this.current = getHRegionInfo(r, HConstants.REGIONINFO_QUALIFIER); + if (this.current == null) { + LOG.warn("No serialized HRegionInfo in " + r); + return true; } + // If tablename no longer matches, return + if (!Bytes.equals(tableName, this.current.getTableDesc().getName())) { + return false; + } + // If we are not to include offlined parent regions. + if (excludeOfflinedSplitParents && this.current.isSplitParent()) { + return true; + } + // Else call super and add this Result to the collection. + return super.visit(r); } - return regions; - } finally { - metaServer.close(scannerid); - } + + @Override + void add(Result r) { + // Add the current HRI. + this.results.add(this.current); + } + }; + // Its a user table. + fullScan(catalogTracker, visitor, getTableStartRowForMeta(tableName)); + return visitor.getResults(); } /** + * @param tableName + * @return Place to start Scan in .META. when passed a + * tableName; returns <tableName&rt; <,&rt; <,&rt; + */ + static byte [] getTableStartRowForMeta(final byte [] tableName) { + byte [] startRow = new byte[tableName.length + 2]; + System.arraycopy(tableName, 0, startRow, 0, tableName.length); + startRow[startRow.length - 2] = HRegionInfo.DELIMITER; + startRow[startRow.length - 1] = HRegionInfo.DELIMITER; + return startRow; + } + + /** * @param catalogTracker * @param tableName * @return Return list of regioninfos and server addresses. @@ -607,6 +647,23 @@ } /** + * Interpret the content of the cell at {@link HConstants#CATALOG_FAMILY} and + * qualifier as an HRegionInfo and return it, or null. + * @param r Result instance to pull from. + * @param qualifier Column family qualifier -- either + * {@link HConstants#SPLITA_QUALIFIER}, {@link HConstants#SPLITB_QUALIFIER} or + * {@link HConstants#REGIONINFO_QUALIFIER}. + * @return An HRegionInfo instance or null. + * @throws IOException + */ + public static HRegionInfo getHRegionInfo(final Result r, byte [] qualifier) + throws IOException { + byte [] bytes = r.getValue(HConstants.CATALOG_FAMILY, qualifier); + if (bytes == null || bytes.length <= 0) return null; + return Writables.getHRegionInfoOrNull(bytes); + } + + /** * Implementations 'visit' a catalog table row. */ public interface Visitor { @@ -618,4 +675,4 @@ */ public boolean visit(final Result r) throws IOException; } -} +} \ No newline at end of file Index: src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java (working copy) @@ -989,14 +989,14 @@ List exceptions = new ArrayList(); for(int tries = 0; tries < numRetries; tries++) { try { - callable.instantiateServer(tries != 0); + callable.connect(tries != 0); return callable.call(); } catch (Throwable t) { t = translateException(t); exceptions.add(t); if (tries == numRetries - 1) { - throw new RetriesExhaustedException(callable.getServerName(), - callable.getRegionName(), callable.getRow(), tries, exceptions); + throw new RetriesExhaustedException(callable.toString(), tries, + exceptions); } } try { @@ -1012,7 +1012,7 @@ public T getRegionServerWithoutRetries(ServerCallable callable) throws IOException, RuntimeException { try { - callable.instantiateServer(false); + callable.connect(false); return callable.call(); } catch (Throwable t) { Throwable t2 = translateException(t); @@ -1059,7 +1059,7 @@ return server.multi(multi); } @Override - public void instantiateServer(boolean reload) throws IOException { + public void connect(boolean reload) throws IOException { server = connection.getHRegionConnection(address); } } Index: src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java (working copy) @@ -15,8 +15,6 @@ */ package org.apache.hadoop.hbase.client; -import org.apache.hadoop.hbase.util.Bytes; - import java.io.IOException; import java.util.List; @@ -37,27 +35,21 @@ /** * Create a new RetriesExhaustedException from the list of prior failures. - * @param serverName name of HRegionServer - * @param regionName name of region - * @param row The row we were pursuing when we ran out of retries + * @param callableVitals Details from the {@link ServerCallable} we were using + * when we got this exception. * @param numTries The number of tries we made * @param exceptions List of exceptions that failed before giving up */ - public RetriesExhaustedException(String serverName, final byte [] regionName, - final byte [] row, int numTries, List exceptions) { - super(getMessage(serverName, regionName, row, numTries, exceptions)); + public RetriesExhaustedException(final String callableVitals, int numTries, + List exceptions) { + super(getMessage(callableVitals, numTries, exceptions)); } - private static String getMessage(String serverName, final byte [] regionName, - final byte [] row, - int numTries, List exceptions) { - StringBuilder buffer = new StringBuilder("Trying to contact region server "); - buffer.append(serverName); - buffer.append(" for region "); - buffer.append(regionName == null? "": Bytes.toStringBinary(regionName)); - buffer.append(", row '"); - buffer.append(row == null? "": Bytes.toStringBinary(row)); - buffer.append("', but failed after "); + private static String getMessage(String callableVitals, int numTries, + List exceptions) { + StringBuilder buffer = new StringBuilder("Failed contacting "); + buffer.append(callableVitals); + buffer.append(" after "); buffer.append(numTries + 1); buffer.append(" attempts.\nExceptions:\n"); for (Throwable t : exceptions) { Index: src/main/java/org/apache/hadoop/hbase/client/HTable.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/HTable.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/client/HTable.java (working copy) @@ -170,7 +170,8 @@ } this.connection = HConnectionManager.getConnection(conf); this.scannerTimeout = - (int) conf.getLong(HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, HConstants.DEFAULT_HBASE_REGIONSERVER_LEASE_PERIOD); + (int)conf.getLong(HConstants.HBASE_REGIONSERVER_LEASE_PERIOD_KEY, + HConstants.DEFAULT_HBASE_REGIONSERVER_LEASE_PERIOD); this.configuration = conf; this.connection.locateRegion(tableName, HConstants.EMPTY_START_ROW); this.writeBufferSize = conf.getLong("hbase.client.write.buffer", 2097152); Index: src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java (working copy) @@ -58,9 +58,9 @@ * @throws IOException */ @Override - public void instantiateServer(boolean reload) throws IOException { + public void connect(boolean reload) throws IOException { if (!instantiated || reload) { - super.instantiateServer(reload); + super.connect(reload); instantiated = true; } } Index: src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java =================================================================== --- src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java (revision 1062080) +++ src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java (working copy) @@ -22,12 +22,21 @@ import org.apache.hadoop.hbase.HRegionLocation; import org.apache.hadoop.hbase.ipc.HRegionInterface; +import org.apache.hadoop.hbase.util.Bytes; import java.io.IOException; import java.util.concurrent.Callable; /** - * Abstract class that implements Callable, used by retryable actions. + * Abstract class that implements {@link Callable}. Implementation stipulates + * return type and method we actually invoke on remote Server. Usually + * used inside a try/catch that fields usual connection failures all wrapped + * up in a retry loop. + *

Call {@link #connect(boolean)} to connect to server hosting region + * that contains the passed row in the passed table before invoking + * {@link #call()}. + * @see HConnection#getRegionServerWithoutRetries(ServerCallable) + * * @param the class that the ServerCallable handles */ public abstract class ServerCallable implements Callable { @@ -38,9 +47,9 @@ protected HRegionInterface server; /** - * @param connection connection callable is on - * @param tableName table name callable is on - * @param row row we are querying + * @param connection Connection to use. + * @param tableName Table name to which row belongs. + * @param row The row we want in tableName. */ public ServerCallable(HConnection connection, byte [] tableName, byte [] row) { this.connection = connection; @@ -49,33 +58,21 @@ } /** - * - * @param reload set this to true if connection should re-find the region + * Connect to the server hosting region with row from tablename. + * @param reload Set this to true if connection should re-find the region * @throws IOException e */ - public void instantiateServer(boolean reload) throws IOException { + public void connect(final boolean reload) throws IOException { this.location = connection.getRegionLocation(tableName, row, reload); this.server = connection.getHRegionConnection(location.getServerAddress()); } - /** @return the server name */ - public String getServerName() { - if (location == null) { - return null; - } - return location.getServerAddress().toString(); + /** + * @return String of current state. + */ + public String toString() { + return (location == null? "null": location.toString()) + + ", tableName=" + (tableName == null? "": Bytes.toString(this.tableName)) + + ", row=" + (row == null? "": Bytes.toStringBinary(this.row)); } - - /** @return the region name */ - public byte[] getRegionName() { - if (location == null) { - return null; - } - return location.getRegionInfo().getRegionName(); - } - - /** @return the row */ - public byte [] getRow() { - return row; - } } \ No newline at end of file