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.master.janitor;
019
020import java.util.ArrayList;
021import java.util.List;
022import java.util.Map;
023import java.util.TreeMap;
024import org.apache.hadoop.hbase.ServerName;
025import org.apache.hadoop.hbase.client.RegionInfo;
026import org.apache.hadoop.hbase.client.Result;
027import org.apache.hadoop.hbase.master.janitor.CatalogJanitor.SplitParentFirstComparator;
028import org.apache.hadoop.hbase.util.Bytes;
029import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
030import org.apache.hadoop.hbase.util.Pair;
031import org.apache.yetus.audience.InterfaceAudience;
032
033/**
034 * Report made by ReportMakingVisitor
035 */
036@InterfaceAudience.Private
037public class Report {
038  private final long now = EnvironmentEdgeManager.currentTime();
039
040  // Keep Map of found split parents. These are candidates for cleanup.
041  // Use a comparator that has split parents come before its daughters.
042  final Map<RegionInfo, Result> splitParents = new TreeMap<>(new SplitParentFirstComparator());
043  final Map<RegionInfo, Result> mergedRegions = new TreeMap<>(RegionInfo.COMPARATOR);
044  int count = 0;
045
046  final List<Pair<RegionInfo, RegionInfo>> holes = new ArrayList<>();
047  final List<Pair<RegionInfo, RegionInfo>> overlaps = new ArrayList<>();
048
049  /**
050   * TODO: If CatalogJanitor finds an 'Unknown Server', it should 'fix' it by queuing a
051   * {@link org.apache.hadoop.hbase.master.procedure.HBCKServerCrashProcedure} for found server for
052   * it to clean up meta.
053   */
054  final List<Pair<RegionInfo, ServerName>> unknownServers = new ArrayList<>();
055
056  final List<byte[]> emptyRegionInfo = new ArrayList<>();
057
058  public long getCreateTime() {
059    return this.now;
060  }
061
062  public List<Pair<RegionInfo, RegionInfo>> getHoles() {
063    return this.holes;
064  }
065
066  /**
067   * @return Overlap pairs found as we scanned hbase:meta; ordered by hbase:meta table sort. Pairs
068   *         of overlaps may have overlap with subsequent pairs.
069   * @see MetaFixer#calculateMerges(int, List) where we aggregate overlaps for a single 'merge'
070   *      call.
071   */
072  public List<Pair<RegionInfo, RegionInfo>> getOverlaps() {
073    return this.overlaps;
074  }
075
076  public Map<RegionInfo, Result> getMergedRegions() {
077    return this.mergedRegions;
078  }
079
080  public List<Pair<RegionInfo, ServerName>> getUnknownServers() {
081    return unknownServers;
082  }
083
084  public List<byte[]> getEmptyRegionInfo() {
085    return emptyRegionInfo;
086  }
087
088  /**
089   * @return True if an 'empty' lastReport -- no problems found.
090   */
091  public boolean isEmpty() {
092    return this.holes.isEmpty() && this.overlaps.isEmpty() && this.unknownServers.isEmpty() &&
093      this.emptyRegionInfo.isEmpty();
094  }
095
096  @Override
097  public String toString() {
098    StringBuilder sb = new StringBuilder();
099    for (Pair<RegionInfo, RegionInfo> p : this.holes) {
100      if (sb.length() > 0) {
101        sb.append(", ");
102      }
103      sb.append("hole=").append(p.getFirst().getRegionNameAsString()).append("/")
104        .append(p.getSecond().getRegionNameAsString());
105    }
106    for (Pair<RegionInfo, RegionInfo> p : this.overlaps) {
107      if (sb.length() > 0) {
108        sb.append(", ");
109      }
110      sb.append("overlap=").append(p.getFirst().getRegionNameAsString()).append("/")
111        .append(p.getSecond().getRegionNameAsString());
112    }
113    for (byte[] r : this.emptyRegionInfo) {
114      if (sb.length() > 0) {
115        sb.append(", ");
116      }
117      sb.append("empty=").append(Bytes.toStringBinary(r));
118    }
119    for (Pair<RegionInfo, ServerName> p : this.unknownServers) {
120      if (sb.length() > 0) {
121        sb.append(", ");
122      }
123      sb.append("unknown_server=").append(p.getSecond()).append("/")
124        .append(p.getFirst().getRegionNameAsString());
125    }
126    return sb.toString();
127  }
128}