diff --git a/CHANGES.txt b/CHANGES.txt index 60fc8e6e7ba..33ae4eee9a4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -167,6 +167,7 @@ Release 0.90.2 - Unreleased HBASE-3639 FSUtils.getRootDir should qualify path HBASE-3648 [replication] failover is sloppy with znodes HBASE-3613 NPE in MemStoreFlusher + HBASE-3650 HBA.delete can return too fast IMPROVEMENTS HBASE-3542 MultiGet methods in Thrift 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 efa677bd949..0b416e27dfb 100644 --- a/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java +++ b/src/main/java/org/apache/hadoop/hbase/catalog/MetaReader.java @@ -431,21 +431,14 @@ public class MetaReader { } HRegionInterface metaServer = catalogTracker.waitForMetaServerConnectionDefault(); - byte[] firstRowInTable = Bytes.toBytes(tableName + ",,"); - Scan scan = new Scan(firstRowInTable); + 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) { - HRegionInfo info = Writables.getHRegionInfo( - data.getValue(HConstants.CATALOG_FAMILY, - HConstants.REGIONINFO_QUALIFIER)); - if (info.getTableDesc().getNameAsString().equals(tableName)) { - // A region for this table already exists. Ergo table exists. return true; - } } return false; } finally { @@ -494,9 +487,8 @@ public class MetaReader { 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 scan = getScanForTableName(tableName); scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER); long scannerid = metaServer.openScanner(getCatalogRegionNameForTable(tableName), scan); @@ -507,13 +499,8 @@ public class MetaReader { 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; - } + if (excludeOfflinedSplitParents && info.isSplitParent()) continue; + regions.add(info); } } return regions; @@ -522,6 +509,27 @@ public class MetaReader { } } + /** + * This method creates a Scan object that will only scan catalog rows that + * belong to the specified table. It doesn't specify any columns. + * This is a better alternative to just using a start row and scan until + * it hits a new table since that requires parsing the HRI to get the table + * name. + * @param tableName bytes of table's name + * @return configured Scan object + */ + public static Scan getScanForTableName(byte[] tableName) { + String strName = Bytes.toString(tableName); + // Start key is just the table name with delimiters + byte[] startKey = Bytes.toBytes(strName + ",,"); + // Stop key appends the smallest possible char to the table name + byte[] stopKey = Bytes.toBytes(strName + " ,,"); + + Scan scan = new Scan(startKey); + scan.setStopRow(stopKey); + return scan; + } + /** * @param catalogTracker * @param tableName @@ -545,8 +553,7 @@ public class MetaReader { getCatalogRegionInterface(catalogTracker, tableNameBytes); List> regions = new ArrayList>(); - byte[] firstRowInTable = Bytes.toBytes(tableName + ",,"); - Scan scan = new Scan(firstRowInTable); + Scan scan = getScanForTableName(tableNameBytes); scan.addFamily(HConstants.CATALOG_FAMILY); long scannerid = metaServer.openScanner(getCatalogRegionNameForTable(tableNameBytes), scan); @@ -556,12 +563,7 @@ public class MetaReader { if (data != null && data.size() > 0) { Pair region = metaRowToRegionPair(data); if (region == null) continue; - if (region.getFirst().getTableDesc().getNameAsString().equals( - tableName)) { - regions.add(region); - } else { - break; - } + regions.add(region); } } return regions; 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 69b14a54ed9..6db631a166d 100644 --- a/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java +++ b/src/main/java/org/apache/hadoop/hbase/client/HBaseAdmin.java @@ -22,8 +22,6 @@ package org.apache.hadoop.hbase.client; import java.io.IOException; import java.util.Arrays; import java.util.List; -import java.util.Map; -import java.util.NavigableMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -49,7 +47,6 @@ import org.apache.hadoop.hbase.ipc.HMasterInterface; import org.apache.hadoop.hbase.ipc.HRegionInterface; 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; /** @@ -371,40 +368,21 @@ public class HBaseAdmin implements Abortable { } catch (RemoteException e) { throw RemoteExceptionHandler.decodeRemoteException(e); } - final int batchCount = this.conf.getInt("hbase.admin.scanner.caching", 10); // Wait until all regions deleted HRegionInterface server = connection.getHRegionConnection(firstMetaServer.getServerAddress()); - HRegionInfo info = new HRegionInfo(); for (int tries = 0; tries < (this.numRetries * this.retryLongerMultiplier); tries++) { long scannerId = -1L; try { - Scan scan = new Scan().addColumn(HConstants.CATALOG_FAMILY, - HConstants.REGIONINFO_QUALIFIER); + + Scan scan = MetaReader.getScanForTableName(tableName); + scan.addColumn(HConstants.CATALOG_FAMILY, + HConstants.REGIONINFO_QUALIFIER); scannerId = server.openScanner( firstMetaServer.getRegionInfo().getRegionName(), scan); // Get a batch at a time. - Result [] values = server.next(scannerId, batchCount); - if (values == null || values.length == 0) { - break; - } - boolean found = false; - for (Result r : values) { - NavigableMap infoValues = - r.getFamilyMap(HConstants.CATALOG_FAMILY); - for (Map.Entry e : infoValues.entrySet()) { - if (Bytes.equals(e.getKey(), HConstants.REGIONINFO_QUALIFIER)) { - info = (HRegionInfo) Writables.getWritable(e.getValue(), info); - if (Bytes.equals(info.getTableDesc().getName(), tableName)) { - found = true; - } else { - found = false; - break; - } - } - } - } - if (!found) { + Result values = server.next(scannerId); + if (values == null) { break; } } catch (IOException ex) { 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 43a8171f7f8..60320a39077 100644 --- a/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java +++ b/src/test/java/org/apache/hadoop/hbase/catalog/TestMetaReaderEditor.java @@ -130,4 +130,34 @@ public class TestMetaReaderEditor { pair.getFirst().getEncodedName()); LOG.info("Finished " + name); } + + // Test for the optimization made in HBASE-3650 + @Test public void testScanMetaForTable() throws IOException { + final String name = "testScanMetaForTable"; + LOG.info("Started " + name); + + /** Create 5 tables + - testScanMetaForTable + - testScanMetaForTable0 + - testScanMetaForTable1 + - testScanMetaForTable2 + - testScanMetaForTablf + **/ + + UTIL.createTable(Bytes.toBytes(name), HConstants.CATALOG_FAMILY); + for (int i = 3; i < 3; i ++) { + UTIL.createTable(Bytes.toBytes(name+i), HConstants.CATALOG_FAMILY); + } + // name that is +1 greater than the first one (e+1=f) + byte[] greaterName = Bytes.toBytes("testScanMetaForTablf"); + UTIL.createTable(greaterName, HConstants.CATALOG_FAMILY); + + // Now make sure we only get the regions from 1 of the tables at a time + + assertEquals(1, MetaReader.getTableRegions(ct, Bytes.toBytes(name)).size()); + for (int i = 3; i < 3; i ++) { + assertEquals(1, MetaReader.getTableRegions(ct, Bytes.toBytes(name+i)).size()); + } + assertEquals(1, MetaReader.getTableRegions(ct, greaterName).size()); + } } \ No newline at end of file