diff --git a/src/main/java/org/apache/hadoop/hbase/KeyValue.java b/src/main/java/org/apache/hadoop/hbase/KeyValue.java index 94c1209..3422af4 100644 --- a/src/main/java/org/apache/hadoop/hbase/KeyValue.java +++ b/src/main/java/org/apache/hadoop/hbase/KeyValue.java @@ -966,6 +966,7 @@ public class KeyValue implements Writable, HeapSize { * @return True if this KV is a {@link KeyValue.Type#Delete} type. */ public boolean isDeleteType() { + // TODO: Fix this method name vis-a-vis isDelete! return getType() == Type.Delete.getCode(); } diff --git a/src/main/java/org/apache/hadoop/hbase/catalog/CatalogTracker.java b/src/main/java/org/apache/hadoop/hbase/catalog/CatalogTracker.java index ac0bc38..2d37d2b 100644 --- a/src/main/java/org/apache/hadoop/hbase/catalog/CatalogTracker.java +++ b/src/main/java/org/apache/hadoop/hbase/catalog/CatalogTracker.java @@ -33,7 +33,6 @@ import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.Abortable; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException; -import org.apache.hadoop.hbase.NotServingRegionException; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.HConnection; import org.apache.hadoop.hbase.client.HConnectionManager; @@ -61,7 +60,6 @@ import org.apache.hadoop.ipc.RemoteException; */ public class CatalogTracker { private static final Log LOG = LogFactory.getLog(CatalogTracker.class); - private final Configuration conf; private final HConnection connection; private final ZooKeeperWatcher zookeeper; private final RootRegionTracker rootRegionTracker; @@ -76,9 +74,8 @@ public class CatalogTracker { private final int defaultTimeout; private boolean stopped = false; - public static final byte [] ROOT_REGION = - HRegionInfo.ROOT_REGIONINFO.getRegionName(); - public static final byte [] META_REGION = + static final byte [] ROOT_REGION = HRegionInfo.ROOT_REGIONINFO.getRegionName(); + static final byte [] META_REGION = HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); /** @@ -130,7 +127,6 @@ public class CatalogTracker { CatalogTracker(final ZooKeeperWatcher zk, final Configuration conf, HConnection connection, Abortable abortable, final int defaultTimeout) throws IOException { - this.conf = conf; this.connection = connection; this.zookeeper = (zk == null) ? this.connection.getZooKeeperWatcher() : zk; if (abortable == null) { @@ -237,7 +233,7 @@ public class CatalogTracker { * @throws NotAllMetaRegionsOnlineException if timed out waiting * @throws IOException */ - public HRegionInterface waitForRootServerConnection(long timeout) + HRegionInterface waitForRootServerConnection(long timeout) throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { return getCachedConnection(waitForRoot(timeout)); } @@ -260,22 +256,6 @@ public class CatalogTracker { } /** - * Gets a connection to the server hosting root, as reported by ZooKeeper, - * if available. Returns null if no location is immediately available. - * @return connection to server hosting root, null if not available - * @throws IOException - * @throws InterruptedException - */ - private HRegionInterface getRootServerConnection() - throws IOException, InterruptedException { - ServerName sn = this.rootRegionTracker.getRootRegionLocation(); - if (sn == null) { - return null; - } - return getCachedConnection(sn); - } - - /** * Gets a connection to the server currently hosting .META. or * null if location is not currently available. *

@@ -304,11 +284,9 @@ public class CatalogTracker { } resetMetaLocation(); } - HRegionInterface rootConnection = getRootServerConnection(); - if (rootConnection == null) { - return null; - } - ServerName newLocation = MetaReader.readMetaLocation(rootConnection); + // MetaReader.readRegionLocation will create an HTable instance and retry + // getting of cell. + ServerName newLocation = MetaReader.readRegionLocation(this, META_REGION); if (newLocation == null) { return null; } @@ -352,14 +330,16 @@ public class CatalogTracker { throws InterruptedException, IOException, NotAllMetaRegionsOnlineException { long stop = System.currentTimeMillis() + timeout; synchronized (metaAvailable) { - while(!stopped && !metaAvailable.get() && + while (!stopped && !metaAvailable.get() && (timeout == 0 || System.currentTimeMillis() < stop)) { - if (getMetaServerConnection(true) != null) { + // TODO: timeout is not used currently + if (verifyMetaRegionLocation(timeout)) { return metaLocation; } metaAvailable.wait(timeout == 0 ? 50 : timeout); } - if (getMetaServerConnection(true) == null) { + // TODO: timeout is not used currently + if (!verifyMetaRegionLocation(timeout)) { throw new NotAllMetaRegionsOnlineException( "Timed out (" + timeout + "ms)"); } @@ -376,7 +356,7 @@ public class CatalogTracker { * @throws NotAllMetaRegionsOnlineException if timed out waiting * @throws IOException */ - public HRegionInterface waitForMetaServerConnection(long timeout) + HRegionInterface waitForMetaServerConnection(long timeout) throws InterruptedException, NotAllMetaRegionsOnlineException, IOException { return getCachedConnection(waitForMeta(timeout)); } @@ -511,6 +491,7 @@ public class CatalogTracker { */ public boolean verifyMetaRegionLocation(final long timeout) throws InterruptedException, IOException { + // Timeout is not used. return getMetaServerConnection(true) != null; } diff --git a/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java b/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java index dad26b5..61ccb2c 100644 --- a/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java +++ b/src/main/java/org/apache/hadoop/hbase/catalog/MetaEditor.java @@ -28,9 +28,9 @@ import java.net.ConnectException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.hbase.*; +import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Put; -import org.apache.hadoop.hbase.ipc.HRegionInterface; import org.apache.hadoop.hbase.migration.HRegionInfo090x; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Writables; @@ -40,9 +40,6 @@ import org.apache.hadoop.hbase.catalog.MetaReader.Visitor; /** * Writes region and assignment information to .META.. - *

- * Uses the {@link CatalogTracker} to obtain locations and connections to - * catalogs. */ public class MetaEditor { private static final Log LOG = LogFactory.getLog(MetaEditor.class); @@ -62,9 +59,13 @@ public class MetaEditor { public static void addRegionToMeta(CatalogTracker catalogTracker, HRegionInfo regionInfo) throws IOException { - catalogTracker.waitForMetaServerConnectionDefault().put( - CatalogTracker.META_REGION, makePutFromRegionInfo(regionInfo)); - LOG.info("Added region " + regionInfo.getRegionNameAsString() + " to META"); + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.put(makePutFromRegionInfo(regionInfo)); + LOG.info("Added region " + regionInfo.getRegionNameAsString() + " to META"); + } finally { + metaTable.close(); + } } /** @@ -108,23 +109,31 @@ public class MetaEditor { Writables.getBytes(a)); put.add(HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER, Writables.getBytes(b)); - catalogTracker.waitForMetaServerConnectionDefault().put(CatalogTracker.META_REGION, put); - LOG.info("Offlined parent region " + parent.getRegionNameAsString() + + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.put(put); + LOG.info("Offlined parent region " + parent.getRegionNameAsString() + " in META"); + } finally { + metaTable.close(); + } } public static void addDaughter(final CatalogTracker catalogTracker, final HRegionInfo regionInfo, final ServerName sn) throws NotAllMetaRegionsOnlineException, IOException { - HRegionInterface server = catalogTracker.waitForMetaServerConnectionDefault(); - byte [] catalogRegionName = CatalogTracker.META_REGION; Put put = new Put(regionInfo.getRegionName()); addRegionInfo(put, regionInfo); if (sn != null) addLocation(put, sn); - server.put(catalogRegionName, put); - LOG.info("Added daughter " + regionInfo.getRegionNameAsString() + - " in region " + Bytes.toString(catalogRegionName) + + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.put(put); + LOG.info("Added daughter " + regionInfo.getRegionNameAsString() + + " in region " + Bytes.toString(metaTable.getTableName()) + (sn == null? ", serverName=null": ", serverName=" + sn.toString())); + } finally { + metaTable.close(); + } } /** @@ -145,9 +154,7 @@ public class MetaEditor { public static void updateMetaLocation(CatalogTracker catalogTracker, HRegionInfo regionInfo, ServerName sn) throws IOException, ConnectException { - HRegionInterface server = catalogTracker.waitForRootServerConnectionDefault(); - if (server == null) throw new IOException("No server for -ROOT-"); - updateLocation(server, CatalogTracker.ROOT_REGION, regionInfo, sn); + updateLocation(catalogTracker, regionInfo, sn); } /** @@ -165,8 +172,7 @@ public class MetaEditor { public static void updateRegionLocation(CatalogTracker catalogTracker, HRegionInfo regionInfo, ServerName sn) throws IOException { - updateLocation(catalogTracker.waitForMetaServerConnectionDefault(), - CatalogTracker.META_REGION, regionInfo, sn); + updateLocation(catalogTracker, regionInfo, sn); } /** @@ -175,22 +181,28 @@ public class MetaEditor { * Connects to the specified server which should be hosting the specified * catalog region name to perform the edit. * - * @param server connection to server hosting catalog region - * @param catalogRegionName name of catalog region being updated + * @param catalogTracker * @param regionInfo region to update location of * @param sn Server name * @throws IOException In particular could throw {@link java.net.ConnectException} * if the server is down on other end. */ - private static void updateLocation(HRegionInterface server, - byte [] catalogRegionName, HRegionInfo regionInfo, ServerName sn) + private static void updateLocation(final CatalogTracker catalogTracker, + HRegionInfo regionInfo, ServerName sn) throws IOException { + final byte [] regionName = regionInfo.getRegionName(); Put put = new Put(regionInfo.getRegionName()); addLocation(put, sn); - server.put(catalogRegionName, put); - LOG.info("Updated row " + regionInfo.getRegionNameAsString() + - " in region " + Bytes.toStringBinary(catalogRegionName) + " with " + - "serverName=" + sn.toString()); + HTable metaTable = + MetaReader.getCatalogHTable(catalogTracker, regionName); + try { + metaTable.put(put); + LOG.info("Updated row " + regionInfo.getRegionNameAsString() + + " in region " + Bytes.toString(metaTable.getTableName()) + + " with server=" + sn); + } finally { + metaTable.close(); + } } /** @@ -203,9 +215,14 @@ public class MetaEditor { HRegionInfo regionInfo) throws IOException { Delete delete = new Delete(regionInfo.getRegionName()); - catalogTracker.waitForMetaServerConnectionDefault(). - delete(CatalogTracker.META_REGION, delete); - LOG.info("Deleted region " + regionInfo.getRegionNameAsString() + " from META"); + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.delete(delete); + LOG.info("Deleted region " + regionInfo.getRegionNameAsString() + + " from META"); + } finally { + metaTable.close(); + } } /** @@ -223,11 +240,15 @@ public class MetaEditor { throws NotAllMetaRegionsOnlineException, IOException { Delete delete = new Delete(parent.getRegionName()); delete.deleteColumns(HConstants.CATALOG_FAMILY, qualifier); - catalogTracker.waitForMetaServerConnectionDefault(). - delete(CatalogTracker.META_REGION, delete); - LOG.info("Deleted daughter reference " + daughter.getRegionNameAsString() + + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.delete(delete); + LOG.info("Deleted daughter reference " + daughter.getRegionNameAsString() + ", qualifier=" + Bytes.toStringBinary(qualifier) + ", from parent " + parent.getRegionNameAsString()); + } finally { + metaTable.close(); + } } /** @@ -241,9 +262,14 @@ public class MetaEditor { throws IOException { Put put = new Put(regionInfo.getRegionName()); addRegionInfo(put, regionInfo); - catalogTracker.waitForMetaServerConnectionDefault().put( - CatalogTracker.META_REGION, put); - LOG.info("Updated region " + regionInfo.getRegionNameAsString() + " in META"); + HTable metaTable = MetaReader.getMetaHTable(catalogTracker); + try { + metaTable.put(put); + LOG.info("Updated region " + regionInfo.getRegionNameAsString() + + " in META"); + } finally { + metaTable.close(); + } } public static void updateRootWithMetaMigrationStatus(CatalogTracker catalogTracker) throws IOException { @@ -318,13 +344,6 @@ public class MetaEditor { return info; } - private static Put addMetaUpdateStatus(final Put p) { - p.add(HConstants.CATALOG_FAMILY, HConstants.META_MIGRATION_QUALIFIER, - Bytes.toBytes("true")); - return p; - } - - private static Put addMetaUpdateStatus(final Put p, final boolean metaUpdated) { p.add(HConstants.CATALOG_FAMILY, HConstants.META_MIGRATION_QUALIFIER, Bytes.toBytes(metaUpdated)); @@ -335,7 +354,7 @@ public class MetaEditor { private static Put addRegionInfo(final Put p, final HRegionInfo hri) throws IOException { p.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER, - Writables.getBytes(hri)); + Writables.getBytes(hri)); return p; } diff --git a/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java b/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java index 82ce839..62d8d64 100644 --- a/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java +++ b/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java @@ -26,26 +26,24 @@ import java.util.Map; import java.util.NavigableMap; import java.util.Set; 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.*; 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.migration.HRegionInfo090x; +import org.apache.hadoop.hbase.util.Addressing; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.Writables; -import org.apache.hadoop.ipc.RemoteException; /** * Reads region and assignment information from .META.. - *

- * Uses the {@link CatalogTracker} to obtain locations and connections to - * catalogs. */ public class MetaReader { private static final Log LOG = LogFactory.getLog(MetaReader.class); @@ -61,48 +59,6 @@ public class MetaReader { } /** - * @param ct - * @param tableName A user tablename or a .META. table name. - * @return Interface on to server hosting the -ROOT- or - * .META. regions. - * @throws NotAllMetaRegionsOnlineException - * @throws IOException - */ - private static HRegionInterface getCatalogRegionInterface(final CatalogTracker ct, - final byte [] tableName) - throws NotAllMetaRegionsOnlineException, IOException { - return Bytes.equals(HConstants.META_TABLE_NAME, tableName)? - ct.waitForRootServerConnectionDefault(): - ct.waitForMetaServerConnectionDefault(); - } - - /** - * @param tableName - * @return Returns region name to look in for regions for tableName; - * e.g. if we are looking for .META. regions, we need to look - * in the -ROOT- region, else if a user table, we need to look - * in the .META. region. - */ - private static byte [] getCatalogRegionNameForTable(final byte [] tableName) { - return Bytes.equals(HConstants.META_TABLE_NAME, tableName)? - HRegionInfo.ROOT_REGIONINFO.getRegionName(): - HRegionInfo.FIRST_META_REGIONINFO.getRegionName(); - } - - /** - * @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. */ @@ -118,23 +74,6 @@ public class MetaReader { } /** - * Performs a full scan of .META.. - *

- * Returns a map of every region to it's currently assigned server, according - * to META. If the region does not have an assignment it will have a null - * value in the map. - * - * @return map of regions to their currently assigned server where server is - * a String of <host> ':' <port> - * @throws IOException - */ - public static Map fullScan( - CatalogTracker catalogTracker) - throws IOException { - return fullScan(catalogTracker, new TreeSet()); - } - - /** * Performs a full scan of .META., skipping regions from any * tables in the specified set of disabled tables. *

@@ -203,20 +142,16 @@ public class MetaReader { * @return map of regions to their currently assigned server * @throws IOException */ - public static List fullScanOfResults( - CatalogTracker catalogTracker) + public static List fullScan(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(); } /** @@ -245,119 +180,134 @@ public class MetaReader { * @param visitor * @param startrow Where to start the scan. Pass null if want to begin scan * at first row. + * at first row (The visitor will stop the Scan when its done so no need to ++ * pass a stoprow). * @throws IOException */ public static void fullScan(CatalogTracker catalogTracker, final Visitor visitor, final byte [] startrow) throws IOException { - HRegionInterface metaServer = - catalogTracker.waitForMetaServerConnectionDefault(); + fullScan(catalogTracker, visitor, startrow, false); + } + + /** + * Performs a full scan of .META.. + *

+ * Returns a map of every region to it's currently assigned server, according + * to META. If the region does not have an assignment it will have a null + * value in the map. + * @param catalogTracker + * @param visitor + * @param startrow Where to start the scan. Pass null if want to begin scan + * at first row. + * @param scanRoot True if we are to scan -ROOT- rather than .META. + * @throws IOException + */ + static void fullScan(CatalogTracker catalogTracker, final Visitor visitor, + final byte [] startrow, final boolean scanRoot) + throws IOException { 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 = scanRoot? + getRootHTable(catalogTracker): 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 getCatalogHTable(final CatalogTracker catalogTracker, + final byte [] regionName) + throws IOException { + return isMetaRegion(regionName)? getRootHTable(catalogTracker): + getMetaHTable(catalogTracker); + } + + /** + * Callers should call close on the returned {@link HTable} instance. + * @param catalogTracker + * @param tableName + * @return An {@link HTable} for tableName + * @throws IOException + */ + private static HTable getHTable(final CatalogTracker catalogTracker, + final byte [] tableName) + throws IOException { + // Passing the CatalogTracker's connection configuration ensures this + // HTable instance uses the CatalogTracker's connection. + return new HTable(catalogTracker.getConnection().getConfiguration(), tableName); + } + + /** + * Callers should call close on the returned {@link HTable} instance. + * @param ct + * @return An {@link HTable} for .META. + * @throws IOException + */ + static HTable getMetaHTable(final CatalogTracker ct) + throws IOException { + return getHTable(ct, HConstants.META_TABLE_NAME); + } + /** - * Reads the location of META from ROOT. - * @param metaServer connection to server hosting ROOT - * @return location of META in ROOT where location, or null if not available + * Callers should call close on the returned {@link HTable} instance. + * @param ct + * @return An {@link HTable} for -ROOT- * @throws IOException */ - public static ServerName readMetaLocation(HRegionInterface metaServer) + static HTable getRootHTable(final CatalogTracker ct) throws IOException { - return readLocation(metaServer, CatalogTracker.ROOT_REGION, - CatalogTracker.META_REGION); + return getHTable(ct, HConstants.ROOT_TABLE_NAME); } /** * Reads the location of the specified region from META. * @param catalogTracker - * @param regionName region to read location of - * @return location of META in ROOT where location is, or null if not available + * @param regionName region whose location we are after + * @return location of META in ROOT as a {@link ServerName} or null if not found * @throws IOException */ public static ServerName readRegionLocation(CatalogTracker catalogTracker, byte [] regionName) throws IOException { - if (isMetaRegion(regionName)) throw new IllegalArgumentException("See readMetaLocation"); - return readLocation(catalogTracker.waitForMetaServerConnectionDefault(), - CatalogTracker.META_REGION, regionName); - } - - private static ServerName readLocation(HRegionInterface metaServer, - byte [] catalogRegionName, byte [] regionName) - throws IOException { - Result r = null; - try { - r = metaServer.get(catalogRegionName, - new Get(regionName). - addColumn(HConstants.CATALOG_FAMILY, - HConstants.SERVER_QUALIFIER). - addColumn(HConstants.CATALOG_FAMILY, - HConstants.STARTCODE_QUALIFIER)); - } catch (java.net.SocketTimeoutException e) { - // Treat this exception + message as unavailable catalog table. Catch it - // and fall through to return a null - } catch (java.net.SocketException e) { - // Treat this exception + message as unavailable catalog table. Catch it - // and fall through to return a null - } catch (RemoteException re) { - IOException ioe = re.unwrapRemoteException(); - if (ioe instanceof NotServingRegionException) { - // Treat this NSRE as unavailable table. Catch and fall through to - // return null below - } else if (ioe.getMessage().contains("Server not running")) { - // Treat as unavailable table. - } else { - throw re; - } - } catch (IOException e) { - if (e.getCause() != null && e.getCause() instanceof IOException && - e.getCause().getMessage() != null && - e.getCause().getMessage().contains("Connection reset by peer")) { - // Treat this exception + message as unavailable catalog table. Catch it - // and fall through to return a null - } else { - throw e; - } - } - if (r == null || r.isEmpty()) { - return null; - } - return getServerNameFromResult(r); + Pair pair = getRegion(catalogTracker, regionName); + return (pair == null || pair.getSecond() == null)? null: pair.getSecond(); } /** * Gets the region info and assignment for the specified region from META. * @param catalogTracker - * @param regionName - * @return location of META in ROOT where location is - * a String of <host> ':' <port>, or null if not available + * @param regionName Region to lookup. + * @return Location and HRegionInfo for regionName * @throws IOException */ public static Pair getRegion( - CatalogTracker catalogTracker, byte [] regionName) + final CatalogTracker catalogTracker, final byte [] regionName) throws IOException { Get get = new Get(regionName); get.addFamily(HConstants.CATALOG_FAMILY); - byte [] meta = getCatalogRegionNameForRegion(regionName); - Result r = catalogTracker.waitForMetaServerConnectionDefault().get(meta, get); + HTable metaTable = getCatalogHTable(catalogTracker, regionName); + Result r = null; + try { + r = metaTable.get(get); + } finally { + metaTable.close(); + } return (r == null || r.isEmpty())? null: metaRowToRegionPair(r); } /** - * @param data A .META. table row. + * @param data A .META. table row. Cannot be null. * @return A pair of the regioninfo and the ServerName * (or null for server address if no address set in .META.). * @throws IOException @@ -397,28 +347,43 @@ public class MetaReader { * @throws IOException */ public static boolean tableExists(CatalogTracker catalogTracker, - String tableName) + final String tableName) throws IOException { if (tableName.equals(HTableDescriptor.ROOT_TABLEDESC.getNameAsString()) || tableName.equals(HTableDescriptor.META_TABLEDESC.getNameAsString())) { // Catalog tables always exist. return true; } - HRegionInterface metaServer = - catalogTracker.waitForMetaServerConnectionDefault(); - Scan scan = getScanForTableName(Bytes.toBytes(tableName)); - scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); - long scannerid = metaServer.openScanner( - HRegionInfo.FIRST_META_REGIONINFO.getRegionName(), scan); - try { - Result data = metaServer.next(scannerid); - if (data != null && data.size() > 0) { + final byte [] tableNameBytes = Bytes.toBytes(tableName); + // Make a version of ResultCollectingVisitor that only collects the first + // region in a table, if one. + CollectingVisitor visitor = new CollectingVisitor() { + private HRegionInfo current = null; + + @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 (!isInsideTable(this.current, tableNameBytes)) return false; + if (this.current.isSplitParent()) return true; + // Else call super and add this Result to the collection. + super.visit(r); + // Stop collecting regions from table after we get one. + return false; } - return false; - } finally { - metaServer.close(scannerid); - } + + @Override + void add(Result r) { + // Add the current HRI. + this.results.add(this.current); + } + }; + fullScan(catalogTracker, visitor, getTableStartRowForMeta(tableNameBytes)); + // If visitor has results >= 1 then table exists. + return visitor.getResults().size() >= 1; } /** @@ -427,10 +392,11 @@ public class MetaReader { * @param tableName * @return Ordered list of {@link HRegionInfo}. * @throws IOException + * @throws InterruptedException */ public static List getTableRegions(CatalogTracker catalogTracker, byte [] tableName) - throws IOException { + throws IOException, InterruptedException { return getTableRegions(catalogTracker, tableName, false); } @@ -442,46 +408,47 @@ public class MetaReader { * parents in the return. * @return Ordered list of {@link HRegionInfo}. * @throws IOException + * @throws InterruptedException */ public static List getTableRegions(CatalogTracker catalogTracker, - byte [] tableName, final boolean excludeOfflinedSplitParents) - throws IOException { - if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { - // If root, do a bit of special handling. - List list = new ArrayList(); - list.add(HRegionInfo.ROOT_REGIONINFO); - return list; - } else if (Bytes.equals(tableName, HConstants.META_TABLE_NAME)) { - // Same for .META. table - List list = new ArrayList(); - list.add(HRegionInfo.FIRST_META_REGIONINFO); - return list; + final byte [] tableName, final boolean excludeOfflinedSplitParents) + throws IOException, InterruptedException { + List> result = + getTableRegionsAndLocations(catalogTracker, tableName, + excludeOfflinedSplitParents); + return getListOfHRegionInfos(result); + } + + static List getListOfHRegionInfos(final List> pairs) { + if (pairs == null || pairs.isEmpty()) return null; + List result = new ArrayList(pairs.size()); + for (Pair pair: pairs) { + result.add(pair.getFirst()); } + return result; + } - // Its a user table. - HRegionInterface metaServer = - getCatalogRegionInterface(catalogTracker, tableName); - List regions = new ArrayList(); + /** + * @param current + * @param tableName + * @return True if current tablename is equal to + * tableName + */ + static boolean isInsideTable(final HRegionInfo current, final byte [] tableName) { + return Bytes.equals(tableName, current.getTableName()); + } - Scan scan = getScanForTableName(tableName); - 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 (excludeOfflinedSplitParents && info.isSplitParent()) continue; - regions.add(info); - } - } - return regions; - } finally { - metaServer.close(scannerid); - } + /** + * @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; } /** @@ -515,8 +482,22 @@ public class MetaReader { public static List> getTableRegionsAndLocations(CatalogTracker catalogTracker, String tableName) throws IOException, InterruptedException { - byte [] tableNameBytes = Bytes.toBytes(tableName); - if (Bytes.equals(tableNameBytes, HConstants.ROOT_TABLE_NAME)) { + return getTableRegionsAndLocations(catalogTracker, Bytes.toBytes(tableName), + true); + } + + /** + * @param catalogTracker + * @param tableName + * @return Return list of regioninfos and server addresses. + * @throws IOException + * @throws InterruptedException + */ + public static List> + getTableRegionsAndLocations(final CatalogTracker catalogTracker, + final byte [] tableName, final boolean excludeOfflinedSplitParents) + throws IOException, InterruptedException { + if (Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME)) { // If root, do a bit of special handling. ServerName serverName = catalogTracker.getRootLocation(); List> list = @@ -525,27 +506,35 @@ public class MetaReader { serverName)); return list; } - HRegionInterface metaServer = - getCatalogRegionInterface(catalogTracker, tableNameBytes); - List> regions = - new ArrayList>(); - Scan scan = getScanForTableName(tableNameBytes); - scan.addFamily(HConstants.CATALOG_FAMILY); - long scannerid = - metaServer.openScanner(getCatalogRegionNameForTable(tableNameBytes), scan); - try { - Result data; - while((data = metaServer.next(scannerid)) != null) { - if (data != null && data.size() > 0) { - Pair region = metaRowToRegionPair(data); - if (region == null) continue; - regions.add(region); + // Make a version of CollectingVisitor that collects HRegionInfo and ServerAddress + CollectingVisitor> visitor = + new CollectingVisitor>() { + private Pair current = null; + + @Override + public boolean visit(Result r) throws IOException { + HRegionInfo hri = getHRegionInfo(r, HConstants.REGIONINFO_QUALIFIER); + if (hri == null) { + LOG.warn("No serialized HRegionInfo in " + r); + return true; } + if (!isInsideTable(hri, tableName)) return false; + if (excludeOfflinedSplitParents && hri.isSplitParent()) return true; + ServerName sn = getServerNameFromResult(r); + // Populate this.current so available when we call #add + this.current = new Pair(hri, sn); + // 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) { + this.results.add(this.current); + } + }; + fullScan(catalogTracker, visitor, getTableStartRowForMeta(tableName), + Bytes.equals(tableName, HConstants.META_TABLE_NAME)); + return visitor.getResults(); } /** @@ -586,8 +575,6 @@ public class MetaReader { public static void fullScanMetaAndPrint( CatalogTracker catalogTracker) throws IOException { - final List regions = - new ArrayList(); Visitor v = new Visitor() { @Override public boolean visit(Result r) throws IOException { @@ -626,6 +613,38 @@ public class MetaReader { /** + * 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); + } + + /** + * @param r Result to pull from. + * @param qualifier + * @return An {@link HServerAddress} instance made from content of r + * at qualifier. + */ + public static HServerAddress getHServerAddress(final Result r, + byte [] qualifier) { + if (r == null || r.isEmpty()) return null; + byte [] value = r.getValue(HConstants.CATALOG_FAMILY, qualifier); + return value == null || value.length <= 0? null: + new HServerAddress(Addressing. + createInetSocketAddressFromHostAndPortStr(Bytes.toString(value))); + } + + /** * Implementations 'visit' a catalog table row. */ public interface Visitor { @@ -637,4 +656,27 @@ public class MetaReader { */ public boolean visit(final Result r) throws IOException; } + + /** + * A {@link Visitor} that collects content out 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; + } + } } diff --git a/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java b/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java index f151c77..2afc5a9 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -1478,19 +1478,22 @@ public class HBaseAdmin implements Abortable, Closeable { * get the regions of a given table. * * @param tableName the name of the table - * @return Ordered list of {@link HRegionInfo}. * + * @return Ordered list of {@link HRegionInfo}. * @throws IOException */ public List getTableRegions(final byte[] tableName) throws IOException { CatalogTracker ct = getCatalogTracker(); - List Regions; + List Regions = null; try { Regions = MetaReader.getTableRegions(ct, tableName, true); + } catch (InterruptedException e) { + // I can't change this public methods API so convert the IE to a RE. + throw new RuntimeException(e); } finally { cleanupCatalogTracker(ct); } - return Regions; + return Regions; } public void close() throws IOException { diff --git a/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java b/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java index aa09b7d..30ba5e4 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java +++ b/src/main/java/org/apache/hadoop/hbase/client/HConnectionManager.java @@ -895,7 +895,7 @@ public class HConnectionManager { deleteCachedLocation(tableName, row); } - // Query the root or meta region for the location of the meta region + // Query the root or meta region for the location of the meta region regionInfoRow = server.getClosestRowBefore( metaLocation.getRegionInfo().getRegionName(), metaKey, HConstants.CATALOG_FAMILY); @@ -1200,7 +1200,7 @@ public class HConnectionManager { } catch (RemoteException e) { LOG.warn("RemoteException connecting to RS", e); // Throw what the RemoteException was carrying. - throw RemoteExceptionHandler.decodeRemoteException(e); + throw e.unwrapRemoteException(); } } } @@ -1232,19 +1232,22 @@ public class HConnectionManager { public T getRegionServerWithRetries(ServerCallable callable) throws IOException, RuntimeException { - List exceptions = new ArrayList(); + List exceptions = + new ArrayList(); for(int tries = 0; tries < numRetries; tries++) { try { - callable.instantiateServer(tries != 0); callable.beforeCall(); + callable.connect(tries != 0); return callable.call(); } catch (Throwable t) { callable.shouldRetry(t); t = translateException(t); - exceptions.add(t); + RetriesExhaustedException.ThrowableWithExtraContext qt = + new RetriesExhaustedException.ThrowableWithExtraContext(t, + System.currentTimeMillis(), callable.toString()); + exceptions.add(qt); if (tries == numRetries - 1) { - throw new RetriesExhaustedException(callable.getServerName(), - callable.getRegionName(), callable.getRow(), tries, exceptions); + throw new RetriesExhaustedException(tries, exceptions); } } finally { callable.afterCall(); @@ -1253,7 +1256,7 @@ public class HConnectionManager { Thread.sleep(getPauseTime(tries)); } catch (InterruptedException e) { Thread.currentThread().interrupt(); - throw new IOException("Giving up trying to get region server: thread is interrupted."); + throw new IOException("Giving up after tries=" + tries, e); } } return null; @@ -1262,8 +1265,8 @@ public class HConnectionManager { public T getRegionServerWithoutRetries(ServerCallable callable) throws IOException, RuntimeException { try { - callable.instantiateServer(false); callable.beforeCall(); + callable.connect(false); return callable.call(); } catch (Throwable t) { Throwable t2 = translateException(t); @@ -1288,7 +1291,7 @@ public class HConnectionManager { return server.multi(multi); } @Override - public void instantiateServer(boolean reload) throws IOException { + public void connect(boolean reload) throws IOException { server = connection.getHRegionConnection(loc.getHostname(), loc.getPort()); } diff --git a/src/main/java/org/apache/hadoop/hbase/client/HTable.java b/src/main/java/org/apache/hadoop/hbase/client/HTable.java index 5a486f6..45cacdd 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/HTable.java +++ b/src/main/java/org/apache/hadoop/hbase/client/HTable.java @@ -53,7 +53,6 @@ import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.NotServingRegionException; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.UnknownScannerException; -import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.client.HConnectionManager.HConnectable; import org.apache.hadoop.hbase.client.MetaScanner.MetaScannerVisitor; import org.apache.hadoop.hbase.client.coprocessor.Batch; @@ -182,7 +181,8 @@ public class HTable implements HTableInterface, Closeable { } 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.operationTimeout = HTableDescriptor.isMetaTable(tableName) ? HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT : conf.getInt(HConstants.HBASE_CLIENT_OPERATION_TIMEOUT, HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT); @@ -406,8 +406,9 @@ public class HTable implements HTableInterface, Closeable { } }; MetaScanner.metaScan(configuration, visitor, this.tableName); - return new Pair(startKeyList.toArray(new byte[startKeyList.size()][]), - endKeyList.toArray(new byte[endKeyList.size()][])); + return new Pair( + startKeyList.toArray(new byte[startKeyList.size()][]), + endKeyList.toArray(new byte[endKeyList.size()][])); } /** diff --git a/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java b/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java index da5b80d..f56ca17 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java +++ b/src/main/java/org/apache/hadoop/hbase/client/MetaScanner.java @@ -187,7 +187,7 @@ public class MetaScanner { if (LOG.isDebugEnabled()) { LOG.debug("Scanning " + Bytes.toString(metaTableName) + " starting at row=" + Bytes.toStringBinary(startRow) + " for max=" + - rowUpperLimit + " rows"); + rowUpperLimit + " rows using " + connection.toString()); } callable = new ScannerCallable(connection, metaTableName, scan); // Open scanner diff --git a/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java b/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java index 89d2abe..ebc8253 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java +++ b/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedException.java @@ -15,9 +15,8 @@ */ package org.apache.hadoop.hbase.client; -import org.apache.hadoop.hbase.util.Bytes; - import java.io.IOException; +import java.util.Date; import java.util.List; /** @@ -36,28 +35,53 @@ public class RetriesExhaustedException extends IOException { } /** + * Datastructure that allows adding more info around Throwable incident. + */ + public static class ThrowableWithExtraContext { + private final Throwable t; + private final long when; + private final String extras; + + public ThrowableWithExtraContext(final Throwable t, final long when, + final String extras) { + this.t = t; + this.when = when; + this.extras = extras; + } + + @Override + public String toString() { + return new Date(this.when).toString() + ", " + extras + ", " + t.toString(); + } + } + + /** * 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)); + } + + /** + * Create a new RetriesExhaustedException from the list of prior failures. + * @param numTries + * @param exceptions List of exceptions that failed before giving up + */ + public RetriesExhaustedException(final int numTries, + final List exceptions) { + super(getMessage(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) { @@ -66,4 +90,16 @@ public class RetriesExhaustedException extends IOException { } return buffer.toString(); } + + private static String getMessage(final int numTries, + final List exceptions) { + StringBuilder buffer = new StringBuilder("Failed after attempts="); + buffer.append(numTries + 1); + buffer.append(", exceptions:\n"); + for (ThrowableWithExtraContext t : exceptions) { + buffer.append(t.toString()); + buffer.append("\n"); + } + return buffer.toString(); + } } \ No newline at end of file diff --git a/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedWithDetailsException.java b/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedWithDetailsException.java index 9d18889..dbd743f 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedWithDetailsException.java +++ b/src/main/java/org/apache/hadoop/hbase/client/RetriesExhaustedWithDetailsException.java @@ -146,4 +146,4 @@ extends RetriesExhaustedException { return s; } -} +} \ No newline at end of file diff --git a/src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java b/src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java index 5ea38b4..78c00c5 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java +++ b/src/main/java/org/apache/hadoop/hbase/client/ScannerCallable.java @@ -58,9 +58,9 @@ public class ScannerCallable extends ServerCallable { * @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; } } diff --git a/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java b/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java index 2546e35..9850a07 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java +++ b/src/main/java/org/apache/hadoop/hbase/client/ServerCallable.java @@ -34,7 +34,14 @@ import java.net.SocketTimeoutException; 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 { @@ -47,9 +54,9 @@ public abstract class ServerCallable implements Callable { protected long startTime, endTime; /** - * @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, tableName, row, HConstants.DEFAULT_HBASE_CLIENT_OPERATION_TIMEOUT); @@ -62,32 +69,43 @@ public abstract class ServerCallable implements Callable { this.callTimeout = callTimeout; } /** - * - * @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 */ + /** + * @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 server name + * @deprecated Just use {@link #toString()} instead. + */ public String getServerName() { - if (location == null) { - return null; - } + if (location == null) return null; return location.getServerAddress().toString(); } - /** @return the region name */ + /** @return the region name + * @deprecated Just use {@link #toString()} instead. + */ public byte[] getRegionName() { - if (location == null) { - return null; - } + if (location == null) return null; return location.getRegionInfo().getRegionName(); } - /** @return the row */ + /** @return the row + * @deprecated Just use {@link #toString()} instead. + */ public byte [] getRow() { return row; } @@ -115,4 +133,4 @@ public abstract class ServerCallable implements Callable { this.callTimeout = ((int) (this.endTime - this.startTime)); } } -} \ No newline at end of file +} diff --git a/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java b/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java index 49d1e7c..53aa47b 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java +++ b/src/main/java/org/apache/hadoop/hbase/master/AssignmentManager.java @@ -600,7 +600,7 @@ public class AssignmentManager extends ZooKeeperListener { case RS_ZK_REGION_OPENING: // Should see OPENING after we have asked it to OPEN or additional // times after already being in state of OPENING - if(regionState == null || + if (regionState == null || (!regionState.isPendingOpen() && !regionState.isOpening())) { LOG.warn("Received OPENING for region " + prettyPrintedRegionName + @@ -1478,7 +1478,6 @@ public class AssignmentManager extends ZooKeeperListener { // Presume that master has stale data. Presume remote side just split. // Presume that the split message when it comes in will fix up the master's // in memory cluster state. - return; } catch (Throwable t) { if (t instanceof RemoteException) { t = ((RemoteException)t).unwrapRemoteException(); @@ -1793,7 +1792,7 @@ public class AssignmentManager extends ZooKeeperListener { Map>> rebuildUserRegions() throws IOException, KeeperException { // Region assignment from META - List results = MetaReader.fullScanOfResults(this.catalogTracker); + List results = MetaReader.fullScan(this.catalogTracker); // Map of offline servers and their regions to be returned Map>> offlineServers = new TreeMap>>(); diff --git a/src/main/java/org/apache/hadoop/hbase/master/HMaster.java b/src/main/java/org/apache/hadoop/hbase/master/HMaster.java index a00b93d..43798ad 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/HMaster.java +++ b/src/main/java/org/apache/hadoop/hbase/master/HMaster.java @@ -499,8 +499,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server { Result r = catalogTracker.waitForRootServerConnectionDefault().get( HRegionInfo.ROOT_REGIONINFO.getRegionName(), get); - if (r != null && r.getBytes() != null) - { + if (r != null && r.getBytes() != null) { byte[] metaMigrated = r.getValue(HConstants.CATALOG_FAMILY, HConstants.META_MIGRATION_QUALIFIER); String migrated = Bytes.toString(metaMigrated); diff --git a/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java b/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java index 7e3dfc6..9fc4739 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java +++ b/src/main/java/org/apache/hadoop/hbase/master/handler/EnableTableHandler.java @@ -95,8 +95,15 @@ public class EnableTableHandler extends EventHandler { while (true) { // Get the regions of this table. We're done when all listed // tables are onlined. - List regionsInMeta = - MetaReader.getTableRegions(this.ct, tableName, true); + List regionsInMeta; + try { + regionsInMeta = MetaReader.getTableRegions(this.ct, tableName, true); + } catch (InterruptedException e1) { + LOG.warn("getTableRegions was interrupted"); + // Preserve the interrupt. + Thread.currentThread().interrupt(); + break; + } int countOfRegionsInTable = regionsInMeta.size(); List regions = regionsToAssign(regionsInMeta); if (regions.size() == 0) { diff --git a/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java b/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java index dd2d6f6..ba144d1 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java +++ b/src/main/java/org/apache/hadoop/hbase/master/handler/ServerShutdownHandler.java @@ -41,7 +41,6 @@ import org.apache.hadoop.hbase.master.DeadServer; 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; /** @@ -210,13 +209,15 @@ public class ServerShutdownHandler extends EventHandler { if (!rit.isClosing() && !rit.isPendingClose()) { LOG.debug("Removed " + rit.getRegion().getRegionNameAsString() + " from list of regions to assign because in RIT"); - hris.remove(rit.getRegion()); + if (hris != null) hris.remove(rit.getRegion()); } } - LOG.info("Reassigning " + (hris == null? 0: hris.size()) + - " region(s) that " + serverName + - " was carrying (skipping " + regionsInTransition.size() + + assert regionsInTransition != null; + LOG.info("Reassigning " + ((hris == null)? 0: hris.size()) + + " region(s) that " + (serverName == null? "null": serverName) + + " was carrying (skipping " + + regionsInTransition.size() + " regions(s) that are already in transition)"); // Iterate regions that were on this server and assign them @@ -285,7 +286,7 @@ public class ServerShutdownHandler extends EventHandler { 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()); @@ -298,21 +299,6 @@ public class ServerShutdownHandler extends EventHandler { } /** - * 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 in .META. * Daughter could have been split over on regionserver before a run of the * catalogJanitor had chance to clear reference from parent. @@ -354,7 +340,7 @@ public class ServerShutdownHandler extends EventHandler { @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; diff --git a/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java b/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java index 09891aa..eb0d600 100644 --- a/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java +++ b/src/main/java/org/apache/hadoop/hbase/master/handler/TableEventHandler.java @@ -64,6 +64,9 @@ public abstract class TableEventHandler extends EventHandler { MetaReader.getTableRegions(this.server.getCatalogTracker(), tableName); handleTableOperation(hris); + } catch (InterruptedException e) { + LOG.error("Interrupted manipulation of table " + Bytes.toString(tableName), e); + Thread.currentThread().interrupt(); } catch (IOException e) { LOG.error("Error manipulating table " + Bytes.toString(tableName), e); } catch (KeeperException e) { diff --git a/src/main/java/org/apache/hadoop/hbase/regionserver/MemStore.java b/src/main/java/org/apache/hadoop/hbase/regionserver/MemStore.java index 1cf46fc..bdcc538 100644 --- a/src/main/java/org/apache/hadoop/hbase/regionserver/MemStore.java +++ b/src/main/java/org/apache/hadoop/hbase/regionserver/MemStore.java @@ -62,9 +62,6 @@ public class MemStore implements HeapSize { "hbase.hregion.memstore.mslab.enabled"; private static final boolean USEMSLAB_DEFAULT = false; - static final String RESEEKMAX_KEY = - "hbase.hregion.memstore.reseek.maxkeys"; - private static final int RESEEKMAX_DEFAULT = 32; private Configuration conf; @@ -96,11 +93,6 @@ public class MemStore implements HeapSize { MemStoreLAB allocator; - // if a reseek has to scan over more than these number of keys, then - // it morphs into a seek. A seek does a tree map-search while - // reseek does a linear scan. - int reseekNumKeys; - /** * Default constructor. Used for tests. */ @@ -129,7 +121,6 @@ public class MemStore implements HeapSize { } else { this.allocator = null; } - this.reseekNumKeys = conf.getInt(RESEEKMAX_KEY, RESEEKMAX_DEFAULT); } void dump() { @@ -649,9 +640,6 @@ public class MemStore implements HeapSize { Iterator kvsetIt; Iterator snapshotIt; - // number of iterations in this reseek operation - int numIterReseek; - /* Some notes... @@ -687,10 +675,6 @@ public class MemStore implements HeapSize { // keep it. ret = v; } - numIterReseek--; - if (numIterReseek == 0) { - break; - } } return ret; } @@ -700,7 +684,6 @@ public class MemStore implements HeapSize { close(); return false; } - numIterReseek = 0; // kvset and snapshot will never be empty. // if tailSet cant find anything, SS is empty (not null). @@ -729,27 +712,14 @@ public class MemStore implements HeapSize { @Override public boolean reseek(KeyValue key) { - numIterReseek = reseekNumKeys; while (kvsetNextRow != null && comparator.compare(kvsetNextRow, key) < 0) { kvsetNextRow = getNext(kvsetIt); - // if we scanned enough entries but still not able to find the - // kv we are looking for, better cut our costs and do a tree - // scan using seek. - if (kvsetNextRow == null && numIterReseek == 0) { - return seek(key); - } } while (snapshotNextRow != null && comparator.compare(snapshotNextRow, key) < 0) { snapshotNextRow = getNext(snapshotIt); - // if we scanned enough entries but still not able to find the - // kv we are looking for, better cut our costs and do a tree - // scan using seek. - if (snapshotNextRow == null && numIterReseek == 0) { - return seek(key); - } } return (kvsetNextRow != null || snapshotNextRow != null); } diff --git a/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java b/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java index 9023af8..d5f7361 100644 --- a/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java +++ b/src/test/java/org/apache/hadoop/hbase/TestRegionRebalancing.java @@ -20,22 +20,17 @@ package org.apache.hadoop.hbase; import java.io.IOException; -import java.util.List; import java.util.ArrayList; -import java.util.Map; +import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - import org.apache.hadoop.hbase.catalog.CatalogTracker; import org.apache.hadoop.hbase.catalog.MetaReader; -import org.apache.hadoop.hbase.client.HConnection; -import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; - -import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.regionserver.HRegion; +import org.apache.hadoop.hbase.regionserver.HRegionServer; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.FSUtils; import org.apache.hadoop.hbase.util.JVMClusterUtil; @@ -106,10 +101,7 @@ public class TestRegionRebalancing extends HBaseClusterTestCase { public void testRebalancing() throws IOException, InterruptedException { CatalogTracker ct = new CatalogTracker(conf); ct.start(); - Map regions = MetaReader.fullScan(ct); - for (Map.Entry e: regions.entrySet()) { - LOG.info(e); - } + MetaReader.fullScanMetaAndPrint(ct); table = new HTable(conf, "test"); assertEquals("Test table should have 20 regions", 20, table.getStartKeys().length); diff --git a/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java b/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java index 960e781..b98e500 100644 --- a/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java +++ b/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java @@ -19,7 +19,10 @@ */ package org.apache.hadoop.hbase.catalog; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.List; @@ -34,8 +37,6 @@ import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.HRegionInfo; import org.apache.hadoop.hbase.ServerName; import org.apache.hadoop.hbase.client.HBaseAdmin; -import org.apache.hadoop.hbase.client.HConnection; -import org.apache.hadoop.hbase.client.HConnectionManager; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Pair; @@ -64,11 +65,15 @@ public class TestMetaReaderEditor { }; @BeforeClass public static void beforeClass() throws Exception { - UTIL.startMiniCluster(); + UTIL.startMiniCluster(3); } @Before public void setup() throws IOException, InterruptedException { Configuration c = new Configuration(UTIL.getConfiguration()); + // Tests to 4 retries every 5 seconds. Make it try every 1 second so more + // responsive. 1 second is default as is ten retries. + c.setLong("hbase.client.pause", 1000); + c.setInt("hbase.client.retries.number", 10); zkw = new ZooKeeperWatcher(c, "TestMetaReaderEditor", ABORTABLE); ct = new CatalogTracker(zkw, c, ABORTABLE); ct.start(); @@ -78,6 +83,109 @@ public class TestMetaReaderEditor { UTIL.shutdownMiniCluster(); } + /** + * Does {@link MetaReader#getRegion(CatalogTracker, byte[])} and a write + * against .META. while its hosted server is restarted to prove our retrying + * works. + * @throws IOException + * @throws InterruptedException + */ + @Test (timeout = 180000) public void testRetrying() + throws IOException, InterruptedException { + final String name = "testRetrying"; + LOG.info("Started " + name); + final byte [] nameBytes = Bytes.toBytes(name); + HTable t = UTIL.createTable(nameBytes, HConstants.CATALOG_FAMILY); + int regionCount = UTIL.createMultiRegions(t, HConstants.CATALOG_FAMILY); + // Test it works getting a region from just made user table. + final List regions = + testGettingTableRegions(this.ct, nameBytes, regionCount); + MetaTask reader = new MetaTask(this.ct, "reader") { + @Override + void metaTask() throws Throwable { + testGetRegion(this.ct, regions.get(0)); + } + }; + MetaTask writer = new MetaTask(this.ct, "writer") { + @Override + void metaTask() throws Throwable { + MetaEditor.updateRegionInfo(this.ct, regions.get(0)); + } + }; + reader.start(); + writer.start(); + // Make sure reader and writer are working. + assertTrue(reader.isProgressing()); + assertTrue(writer.isProgressing()); + // Kill server hosting meta. See if our reader/writer ride over the + // meta moves. They'll need to retry. + for (int i = 0; i < 1; i++) { + LOG.info("Restart=" + i); + UTIL.ensureSomeRegionServersAvailable(2); + int index = -1; + do { + index = UTIL.getMiniHBaseCluster().getServerWithMeta(); + } while (index == -1); + UTIL.getMiniHBaseCluster().abortRegionServer(index); + UTIL.getMiniHBaseCluster().waitOnRegionServer(index); + } + assertTrue(reader.toString(), reader.isProgressing()); + assertTrue(writer.toString(), writer.isProgressing()); + reader.stop = true; + writer.stop = true; + reader.join(); + writer.join(); + } + + /** + * Thread that runs a MetaReader/MetaEditor task until asked stop. + */ + abstract static class MetaTask extends Thread { + boolean stop = false; + int count = 0; + Throwable t = null; + final CatalogTracker ct; + + MetaTask(final CatalogTracker ct, final String name) { + super(name); + this.ct = ct; + } + + @Override + public void run() { + try { + while(!this.stop) { + LOG.info("Before " + this.getName()+ ", count=" + this.count); + metaTask(); + this.count += 1; + LOG.info("After " + this.getName() + ", count=" + this.count); + Thread.sleep(100); + } + } catch (Throwable t) { + LOG.info(this.getName() + " failed", t); + this.t = t; + } + } + + boolean isProgressing() throws InterruptedException { + int currentCount = this.count; + while(currentCount == this.count) { + if (!isAlive()) return false; + if (this.t != null) return false; + Thread.sleep(10); + } + return true; + } + + @Override + public String toString() { + return "count=" + this.count + ", t=" + + (this.t == null? "null": this.t.toString()); + } + + abstract void metaTask() throws Throwable; + } + @Test public void testGetRegionsCatalogTables() throws IOException, InterruptedException { List regions = @@ -108,19 +216,9 @@ public class TestMetaReaderEditor { @Test public void testGetRegion() throws IOException, InterruptedException { final String name = "testGetRegion"; LOG.info("Started " + name); - final byte [] nameBytes = Bytes.toBytes(name); - HTable t = UTIL.createTable(nameBytes, HConstants.CATALOG_FAMILY); - int regionCount = UTIL.createMultiRegions(t, HConstants.CATALOG_FAMILY); - - // Test it works getting a region from user table. - List regions = MetaReader.getTableRegions(ct, nameBytes); - assertEquals(regionCount, regions.size()); - Pair pair = - MetaReader.getRegion(ct, regions.get(0).getRegionName()); - assertEquals(regions.get(0).getEncodedName(), - pair.getFirst().getEncodedName()); // Test get on non-existent region. - pair = MetaReader.getRegion(ct, Bytes.toBytes("nonexistent-region")); + Pair pair = + MetaReader.getRegion(ct, Bytes.toBytes("nonexistent-region")); assertNull(pair); // Test it works getting a region from meta/root. pair = @@ -131,7 +229,8 @@ public class TestMetaReaderEditor { } // Test for the optimization made in HBASE-3650 - @Test public void testScanMetaForTable() throws IOException { + @Test public void testScanMetaForTable() + throws IOException, InterruptedException { final String name = "testScanMetaForTable"; LOG.info("Started " + name); @@ -159,4 +258,25 @@ public class TestMetaReaderEditor { } assertEquals(1, MetaReader.getTableRegions(ct, greaterName).size()); } -} \ No newline at end of file + + private static List testGettingTableRegions(final CatalogTracker ct, + final byte [] nameBytes, final int regionCount) + throws IOException, InterruptedException { + List regions = MetaReader.getTableRegions(ct, nameBytes); + assertEquals(regionCount, regions.size()); + Pair pair = + MetaReader.getRegion(ct, regions.get(0).getRegionName()); + assertEquals(regions.get(0).getEncodedName(), + pair.getFirst().getEncodedName()); + return regions; + } + + private static void testGetRegion(final CatalogTracker ct, + final HRegionInfo region) + throws IOException, InterruptedException { + Pair pair = + MetaReader.getRegion(ct, region.getRegionName()); + assertEquals(region.getEncodedName(), + pair.getFirst().getEncodedName()); + } +}