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.handler;
21  
22  import java.io.IOException;
23  import java.util.List;
24  import java.util.concurrent.ExecutorService;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.Server;
30  import org.apache.hadoop.hbase.TableNotFoundException;
31  import org.apache.hadoop.hbase.catalog.CatalogTracker;
32  import org.apache.hadoop.hbase.catalog.MetaReader;
33  import org.apache.hadoop.hbase.executor.EventHandler;
34  import org.apache.hadoop.hbase.master.AssignmentManager;
35  import org.apache.hadoop.hbase.master.BulkAssigner;
36  import org.apache.hadoop.hbase.util.Bytes;
37  import org.apache.zookeeper.KeeperException;
38  
39  /**
40   * Handler to run disable of a table.
41   */
42  public class DisableTableHandler extends EventHandler {
43    private static final Log LOG = LogFactory.getLog(DisableTableHandler.class);
44    private final byte [] tableName;
45    private final String tableNameStr;
46    private final AssignmentManager assignmentManager;
47  
48    public DisableTableHandler(Server server, byte [] tableName,
49        CatalogTracker catalogTracker, AssignmentManager assignmentManager)
50    throws TableNotFoundException, IOException {
51      super(server, EventType.C_M_DISABLE_TABLE);
52      this.tableName = tableName;
53      this.tableNameStr = Bytes.toString(this.tableName);
54      this.assignmentManager = assignmentManager;
55      // Check if table exists
56      // TODO: do we want to keep this in-memory as well?  i guess this is
57      //       part of old master rewrite, schema to zk to check for table
58      //       existence and such
59      if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) {
60        throw new TableNotFoundException(Bytes.toString(tableName));
61      }
62    }
63  
64    @Override
65    public void process() {
66      try {
67        LOG.info("Attemping to disable table " + this.tableNameStr);
68        handleDisableTable();
69      } catch (IOException e) {
70        LOG.error("Error trying to disable table " + this.tableNameStr, e);
71      } catch (KeeperException e) {
72        LOG.error("Error trying to disable table " + this.tableNameStr, e);
73      }
74    }
75  
76    private void handleDisableTable() throws IOException, KeeperException {
77      if (this.assignmentManager.getZKTable().isDisabledTable(this.tableNameStr)) {
78        LOG.info("Table " + tableNameStr + " already disabled; skipping disable");
79        return;
80      }
81      // Set table disabling flag up in zk.
82      this.assignmentManager.getZKTable().setDisablingTable(this.tableNameStr);
83      boolean done = false;
84      while (true) {
85        // Get list of online regions that are of this table.  Regions that are
86        // already closed will not be included in this list; i.e. the returned
87        // list is not ALL regions in a table, its all online regions according to
88        // the in-memory state on this master.
89        final List<HRegionInfo> regions =
90          this.assignmentManager.getRegionsOfTable(tableName);
91        if (regions.size() == 0) {
92          done = true;
93          break;
94        }
95        LOG.info("Offlining " + regions.size() + " regions.");
96        BulkDisabler bd = new BulkDisabler(this.server, regions);
97        try {
98          if (bd.bulkAssign()) {
99            done = true;
100           break;
101         }
102       } catch (InterruptedException e) {
103         LOG.warn("Disable was interrupted");
104         // Preserve the interrupt.
105         Thread.currentThread().interrupt();
106         break;
107       }
108     }
109     // Flip the table to disabled if success.
110     if (done) this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr);
111     LOG.info("Disabled table is done=" + done);
112   }
113 
114   /**
115    * Run bulk disable.
116    */
117   class BulkDisabler extends BulkAssigner {
118     private final List<HRegionInfo> regions;
119 
120     BulkDisabler(final Server server, final List<HRegionInfo> regions) {
121       super(server);
122       this.regions = regions;
123     }
124 
125     @Override
126     protected void populatePool(ExecutorService pool) {
127       for (HRegionInfo region: regions) {
128         if (assignmentManager.isRegionInTransition(region) != null) continue;
129         final HRegionInfo hri = region;
130         pool.execute(new Runnable() {
131           public void run() {
132             assignmentManager.unassign(hri);
133           }
134         });
135       }
136     }
137 
138     @Override
139     protected boolean waitUntilDone(long timeout)
140     throws InterruptedException {
141       long startTime = System.currentTimeMillis();
142       long remaining = timeout;
143       List<HRegionInfo> regions = null;
144       while (!server.isStopped() && remaining > 0) {
145         Thread.sleep(waitingTimeForEvents);
146         regions = assignmentManager.getRegionsOfTable(tableName);
147         if (regions.isEmpty()) break;
148         remaining = timeout - (System.currentTimeMillis() - startTime);
149       }
150       return regions != null && regions.isEmpty();
151     }
152   }
153 }