001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.client; 019 020import static org.apache.hadoop.hbase.client.AsyncRegionLocatorHelper.canUpdateOnError; 021import static org.apache.hadoop.hbase.client.AsyncRegionLocatorHelper.createRegionLocations; 022import static org.apache.hadoop.hbase.client.AsyncRegionLocatorHelper.isGood; 023import static org.apache.hadoop.hbase.client.AsyncRegionLocatorHelper.removeRegionLocation; 024import static org.apache.hadoop.hbase.client.AsyncRegionLocatorHelper.replaceRegionLocation; 025 026import java.util.concurrent.CompletableFuture; 027import java.util.concurrent.atomic.AtomicReference; 028import org.apache.hadoop.hbase.HRegionLocation; 029import org.apache.hadoop.hbase.RegionLocations; 030import org.apache.yetus.audience.InterfaceAudience; 031 032/** 033 * The asynchronous locator for meta region. 034 */ 035@InterfaceAudience.Private 036class AsyncMetaRegionLocator { 037 038 private final AsyncRegistry registry; 039 040 private final AtomicReference<RegionLocations> metaRegionLocations = new AtomicReference<>(); 041 042 private final AtomicReference<CompletableFuture<RegionLocations>> metaRelocateFuture = 043 new AtomicReference<>(); 044 045 AsyncMetaRegionLocator(AsyncRegistry registry) { 046 this.registry = registry; 047 } 048 049 /** 050 * Get the region locations for meta region. If the location for the given replica is not 051 * available in the cached locations, then fetch from the HBase cluster. 052 * <p/> 053 * The <code>replicaId</code> parameter is important. If the region replication config for meta 054 * region is changed, then the cached region locations may not have the locations for new 055 * replicas. If we do not check the location for the given replica, we will always return the 056 * cached region locations and cause an infinite loop. 057 */ 058 CompletableFuture<RegionLocations> getRegionLocations(int replicaId, boolean reload) { 059 return ConnectionUtils.getOrFetch(metaRegionLocations, metaRelocateFuture, reload, 060 registry::getMetaRegionLocation, locs -> isGood(locs, replicaId), "meta region location"); 061 } 062 063 private HRegionLocation getCacheLocation(HRegionLocation loc) { 064 RegionLocations locs = metaRegionLocations.get(); 065 return locs != null ? locs.getRegionLocation(loc.getRegion().getReplicaId()) : null; 066 } 067 068 private void addLocationToCache(HRegionLocation loc) { 069 for (;;) { 070 int replicaId = loc.getRegion().getReplicaId(); 071 RegionLocations oldLocs = metaRegionLocations.get(); 072 if (oldLocs == null) { 073 RegionLocations newLocs = createRegionLocations(loc); 074 if (metaRegionLocations.compareAndSet(null, newLocs)) { 075 return; 076 } 077 } 078 HRegionLocation oldLoc = oldLocs.getRegionLocation(replicaId); 079 if (oldLoc != null && (oldLoc.getSeqNum() > loc.getSeqNum() || 080 oldLoc.getServerName().equals(loc.getServerName()))) { 081 return; 082 } 083 RegionLocations newLocs = replaceRegionLocation(oldLocs, loc); 084 if (metaRegionLocations.compareAndSet(oldLocs, newLocs)) { 085 return; 086 } 087 } 088 } 089 090 private void removeLocationFromCache(HRegionLocation loc) { 091 for (;;) { 092 RegionLocations oldLocs = metaRegionLocations.get(); 093 if (oldLocs == null) { 094 return; 095 } 096 HRegionLocation oldLoc = oldLocs.getRegionLocation(loc.getRegion().getReplicaId()); 097 if (!canUpdateOnError(loc, oldLoc)) { 098 return; 099 } 100 RegionLocations newLocs = removeRegionLocation(oldLocs, loc.getRegion().getReplicaId()); 101 if (metaRegionLocations.compareAndSet(oldLocs, newLocs)) { 102 return; 103 } 104 } 105 } 106 107 void updateCachedLocationOnError(HRegionLocation loc, Throwable exception) { 108 AsyncRegionLocatorHelper.updateCachedLocationOnError(loc, exception, this::getCacheLocation, 109 this::addLocationToCache, this::removeLocationFromCache); 110 } 111 112 void clearCache() { 113 metaRegionLocations.set(null); 114 } 115}