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.ConnectionUtils.isEmptyStopRow; 021 022import java.util.Map; 023import java.util.concurrent.ConcurrentNavigableMap; 024import org.apache.hadoop.hbase.RegionLocations; 025import org.apache.hadoop.hbase.util.Bytes; 026import org.apache.yetus.audience.InterfaceAudience; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030/** 031 * Util class to DRY common logic between AsyncRegionLocationCache and MetaCache 032 */ 033@InterfaceAudience.Private 034final class MetaCacheUtil { 035 036 private static final Logger LOG = LoggerFactory.getLogger(MetaCacheUtil.class); 037 038 private MetaCacheUtil() { 039 } 040 041 /** 042 * When caching a location, the region may have been the result of a merge. Check to see if the 043 * region's boundaries overlap any other cached locations in a problematic way. Those would have 044 * been merge parents which no longer exist. We need to proactively clear them out to avoid a case 045 * where a merged region which receives no requests never gets cleared. This causes requests to 046 * other merged regions after it to see the wrong cached location. 047 * <p> 048 * For example, if we have Start_New < Start_Old < End_Old < End_New, then if we only access 049 * within range [End_Old, End_New], then it will always return the old region but it will then 050 * find out the row is not in the range, and try to get the new region, and then we get 051 * [Start_New, End_New), still fall into the same situation. 052 * <p> 053 * If Start_Old is less than Start_New, even if we have overlap, it is not a problem, as when the 054 * row is greater than Start_New, we will locate to the new region, and if the row is less than 055 * Start_New, it will fall into the old region's range and we will try to access the region and 056 * get a NotServing exception, and then we will clean the cache. 057 * <p> 058 * See HBASE-27650 059 * @param locations the new location that was just cached 060 */ 061 static void cleanProblematicOverlappedRegions(RegionLocations locations, 062 ConcurrentNavigableMap<byte[], RegionLocations> cache) { 063 RegionInfo region = locations.getRegionLocation().getRegion(); 064 065 boolean isLast = isEmptyStopRow(region.getEndKey()); 066 067 while (true) { 068 Map.Entry<byte[], RegionLocations> overlap = 069 isLast ? cache.lastEntry() : cache.lowerEntry(region.getEndKey()); 070 if ( 071 overlap == null || overlap.getValue() == locations 072 || Bytes.equals(overlap.getKey(), region.getStartKey()) 073 ) { 074 break; 075 } 076 077 if (LOG.isDebugEnabled()) { 078 LOG.debug( 079 "Removing cached location {} (endKey={}) because it overlaps with " 080 + "new location {} (endKey={})", 081 overlap.getValue(), 082 Bytes.toStringBinary(overlap.getValue().getRegionLocation().getRegion().getEndKey()), 083 locations, Bytes.toStringBinary(locations.getRegionLocation().getRegion().getEndKey())); 084 } 085 086 cache.remove(overlap.getKey()); 087 } 088 } 089}