View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.master;
21  
22  import org.apache.hadoop.hbase.HConstants;
23  import org.apache.hadoop.hbase.HRegionInfo;
24  import org.apache.hadoop.hbase.HServerInfo;
25  import org.apache.hadoop.hbase.MasterNotRunningException;
26  import org.apache.hadoop.hbase.RemoteExceptionHandler;
27  import org.apache.hadoop.hbase.TableNotFoundException;
28  import org.apache.hadoop.hbase.client.Result;
29  import org.apache.hadoop.hbase.client.Scan;
30  import org.apache.hadoop.hbase.ipc.HRegionInterface;
31  import org.apache.hadoop.hbase.util.Bytes;
32  
33  import java.io.IOException;
34  import java.util.ArrayList;
35  import java.util.List;
36  import java.util.Set;
37  import java.util.TreeSet;
38  
39  /**
40   * Abstract base class for operations that need to examine all HRegionInfo
41   * objects in a table. (For a table, operate on each of its rows
42   * in .META.).
43   */
44  abstract class TableOperation {
45    private final Set<MetaRegion> metaRegions;
46    protected final byte [] tableName;
47    // Do regions in order.
48    protected final Set<HRegionInfo> unservedRegions = new TreeSet<HRegionInfo>();
49    protected HMaster master;
50  
51    protected TableOperation(final HMaster master, final byte [] tableName)
52    throws IOException {
53      this.master = master;
54      if (!this.master.isMasterRunning()) {
55        throw new MasterNotRunningException();
56      }
57      // add the delimiters.
58      // TODO maybe check if this is necessary?
59      this.tableName = tableName;
60  
61      // Don't wait for META table to come on line if we're enabling it
62      if (!Bytes.equals(HConstants.META_TABLE_NAME, this.tableName)) {
63        // We can not access any meta region if they have not already been
64        // assigned and scanned.
65        if (master.getRegionManager().metaScannerThread.waitForMetaRegionsOrClose()) {
66          // We're shutting down. Forget it.
67          throw new MasterNotRunningException();
68        }
69      }
70      this.metaRegions = master.getRegionManager().getMetaRegionsForTable(tableName);
71    }
72  
73    private class ProcessTableOperation extends RetryableMetaOperation<Boolean> {
74      ProcessTableOperation(MetaRegion m, HMaster master) {
75        super(m, master);
76      }
77  
78      public Boolean call() throws IOException {
79        boolean tableExists = false;
80  
81        // Open a scanner on the meta region
82        byte [] tableNameMetaStart =
83          Bytes.toBytes(Bytes.toString(tableName) + ",,");
84        final Scan scan = new Scan(tableNameMetaStart)
85          .addFamily(HConstants.CATALOG_FAMILY);
86        long scannerId = this.server.openScanner(m.getRegionName(), scan);
87        int rows = this.master.getConfiguration().
88          getInt("hbase.meta.scanner.caching", 100);
89        scan.setCaching(rows);
90        List<byte []> emptyRows = new ArrayList<byte []>();
91        try {
92          while (true) {
93            Result values = this.server.next(scannerId);
94            if (values == null || values.isEmpty()) {
95              break;
96            }
97            HRegionInfo info = this.master.getHRegionInfo(values.getRow(), values);
98            if (info == null) {
99              emptyRows.add(values.getRow());
100             LOG.error(Bytes.toString(HConstants.CATALOG_FAMILY) + ":"
101                 + Bytes.toString(HConstants.REGIONINFO_QUALIFIER)
102                 + " not found on "
103                 + Bytes.toStringBinary(values.getRow()));
104             continue;
105           }
106           final String serverAddress = BaseScanner.getServerAddress(values);
107           String serverName = null;
108           if (serverAddress != null && serverAddress.length() > 0) {
109             long startCode = BaseScanner.getStartCode(values);
110             serverName = HServerInfo.getServerName(serverAddress, startCode);
111           }
112           if (Bytes.compareTo(info.getTableDesc().getName(), tableName) > 0) {
113             break; // Beyond any more entries for this table
114           }
115 
116           tableExists = true;
117           if (!isBeingServed(serverName) || !isEnabled(info)) {
118             unservedRegions.add(info);
119           }
120           processScanItem(serverName, info);
121         }
122       } finally {
123         if (scannerId != -1L) {
124           try {
125             this.server.close(scannerId);
126           } catch (IOException e) {
127             e = RemoteExceptionHandler.checkIOException(e);
128             LOG.error("closing scanner", e);
129           }
130         }
131         scannerId = -1L;
132       }
133 
134       // Get rid of any rows that have a null HRegionInfo
135 
136       if (emptyRows.size() > 0) {
137         LOG.warn("Found " + emptyRows.size() +
138             " rows with empty HRegionInfo while scanning meta region " +
139             Bytes.toString(m.getRegionName()));
140         master.deleteEmptyMetaRows(server, m.getRegionName(), emptyRows);
141       }
142 
143       if (!tableExists) {
144         throw new TableNotFoundException(Bytes.toString(tableName));
145       }
146 
147       postProcessMeta(m, server);
148       unservedRegions.clear();
149       return Boolean.TRUE;
150     }
151   }
152 
153   void process() throws IOException {
154     // Prevent meta scanner from running
155     synchronized(master.getRegionManager().metaScannerThread.scannerLock) {
156       for (MetaRegion m: metaRegions) {
157         new ProcessTableOperation(m, master).doWithRetries();
158       }
159     }
160   }
161 
162   protected boolean isBeingServed(String serverName) {
163     boolean result = false;
164     if (serverName != null && serverName.length() > 0) {
165       HServerInfo s = master.getServerManager().getServerInfo(serverName);
166       result = s != null;
167     }
168     return result;
169   }
170 
171   protected boolean isEnabled(HRegionInfo info) {
172     return !info.isOffline();
173   }
174 
175   protected abstract void processScanItem(String serverName, HRegionInfo info)
176   throws IOException;
177 
178   protected abstract void postProcessMeta(MetaRegion m,
179     HRegionInterface server) throws IOException;
180 }