diff --git hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java index 286d90d..0800228 100644 --- hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java +++ hbase-client/src/main/java/org/apache/hadoop/hbase/client/ConnectionManager.java @@ -592,6 +592,8 @@ class ConnectionManager { // package protected for the tests ClusterStatusListener clusterStatusListener; + private final Object metaRegionLock = new Object(); + private final Object userRegionLock = new Object(); // We have a single lock for master & zk to prevent deadlocks. Having @@ -1123,7 +1125,7 @@ class ConnectionManager { } if (tableName.equals(TableName.META_TABLE_NAME)) { - return this.registry.getMetaRegionLocation(); + return locateMeta(tableName, useCache, replicaId); } else { // Region not in the cache - have to go to the meta RS return locateRegionInMeta(TableName.META_TABLE_NAME, tableName, row, @@ -1131,6 +1133,37 @@ class ConnectionManager { } } + private RegionLocations locateMeta(final TableName tableName, + boolean useCache, int replicaId) throws IOException { + // HBASE-10785: We cache the location of the META itself, so that we are not overloading + // zookeeper with one request for every region lookup. We cache the META with empty row + // key in MetaCache. + byte[] metaCacheKey = HConstants.EMPTY_START_ROW; // use byte[0] as the row for meta + RegionLocations locations = null; + if (useCache) { + locations = getCachedLocation(tableName, metaCacheKey); + if (locations != null) { + return locations; + } + } + + // only one thread should do the lookup. + synchronized (metaRegionLock) { + // Check the cache again for a hit in case some other thread made the + // same query while we were waiting on the lock. + locations = getCachedLocation(tableName, metaCacheKey); + if (locations != null) { + return locations; + } + // Look up from zookeeper + locations = this.registry.getMetaRegionLocation(); + if (locations != null) { + cacheLocation(tableName, locations); + } + } + return locations; + } + /* * Search hbase:meta for the HRegionLocation info that contains the table and * row we're seeking. It will prefetch certain number of regions info and @@ -1217,7 +1250,7 @@ class ConnectionManager { HRegionLocation metaLocation = null; try { // locate the meta region - RegionLocations metaLocations = locateRegion(parentTable, metaKey, true, false); + RegionLocations metaLocations = locateRegion(parentTable, metaKey, tries == 0, false); metaLocation = metaLocations == null ? null : metaLocations.getDefaultRegionLocation(); // If null still, go around again. if (metaLocation == null) continue;