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 3630f0c..515fbd9 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,44 @@ 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; + RegionLocations locations = null; + if (useCache) { + locations = getCachedLocation(tableName, metaCacheKey); + if (locations != null) { + return locations; + } + } else { + // If we are not supposed to be using the cache, delete any existing cached location + // so it won't interfere. + metaCache.clearCache(tableName, metaCacheKey, replicaId); + } + + // 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) { + throw new IOException("Meta cannot be located"); + } + + 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 +1257,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;