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.TableNotEnabledException;
31  import org.apache.hadoop.hbase.TableNotFoundException;
32  import org.apache.hadoop.hbase.catalog.CatalogTracker;
33  import org.apache.hadoop.hbase.catalog.MetaReader;
34  import org.apache.hadoop.hbase.executor.EventHandler;
35  import org.apache.hadoop.hbase.master.AssignmentManager;
36  import org.apache.hadoop.hbase.master.BulkAssigner;
37  import org.apache.hadoop.hbase.util.Bytes;
38  import org.apache.zookeeper.KeeperException;
39  
40  /**
41   * Handler to run disable of a table.
42   */
43  public class DisableTableHandler extends EventHandler {
44    private static final Log LOG = LogFactory.getLog(DisableTableHandler.class);
45    private final byte [] tableName;
46    private final String tableNameStr;
47    private final AssignmentManager assignmentManager;
48  
49    public DisableTableHandler(Server server, byte [] tableName,
50        CatalogTracker catalogTracker, AssignmentManager assignmentManager,
51        boolean skipTableStateCheck)
52    throws TableNotFoundException, TableNotEnabledException, IOException {
53      super(server, EventType.C_M_DISABLE_TABLE);
54      this.tableName = tableName;
55      this.tableNameStr = Bytes.toString(this.tableName);
56      this.assignmentManager = assignmentManager;
57      // Check if table exists
58      // TODO: do we want to keep this in-memory as well?  i guess this is
59      //       part of old master rewrite, schema to zk to check for table
60      //       existence and such
61      if (!MetaReader.tableExists(catalogTracker, this.tableNameStr)) {
62        throw new TableNotFoundException(this.tableNameStr);
63      }
64  
65      // There could be multiple client requests trying to disable or enable
66      // the table at the same time. Ensure only the first request is honored
67      // After that, no other requests can be accepted until the table reaches
68      // DISABLED or ENABLED.
69      if (!skipTableStateCheck)
70      {
71        try {
72          if (!this.assignmentManager.getZKTable().checkEnabledAndSetDisablingTable
73            (this.tableNameStr)) {
74            LOG.info("Table " + tableNameStr + " isn't enabled; skipping disable");
75            throw new TableNotEnabledException(this.tableNameStr);
76          }
77        } catch (KeeperException e) {
78          throw new IOException("Unable to ensure that the table will be" +
79            " disabling because of a ZooKeeper issue", e);
80        }
81      }
82    }
83  
84    @Override
85    public String toString() {
86      String name = "UnknownServerName";
87      if(server != null && server.getServerName() != null) {
88        name = server.getServerName().toString();
89      }
90      return getClass().getSimpleName() + "-" + name + "-" + getSeqid() + "-" +
91        tableNameStr;
92    }
93  
94    @Override
95    public void process() {
96      try {
97        LOG.info("Attemping to disable table " + this.tableNameStr);
98        handleDisableTable();
99      } catch (IOException e) {
100       LOG.error("Error trying to disable table " + this.tableNameStr, e);
101     } catch (KeeperException e) {
102       LOG.error("Error trying to disable table " + this.tableNameStr, e);
103     }
104   }
105 
106   private void handleDisableTable() throws IOException, KeeperException {
107     // Set table disabling flag up in zk.
108     this.assignmentManager.getZKTable().setDisablingTable(this.tableNameStr);
109     boolean done = false;
110     while (true) {
111       // Get list of online regions that are of this table.  Regions that are
112       // already closed will not be included in this list; i.e. the returned
113       // list is not ALL regions in a table, its all online regions according
114       // to the in-memory state on this master.
115       final List<HRegionInfo> regions =
116         this.assignmentManager.getRegionsOfTable(tableName);
117       if (regions.size() == 0) {
118         done = true;
119         break;
120       }
121       LOG.info("Offlining " + regions.size() + " regions.");
122       BulkDisabler bd = new BulkDisabler(this.server, regions);
123       try {
124         if (bd.bulkAssign()) {
125           done = true;
126           break;
127         }
128       } catch (InterruptedException e) {
129         LOG.warn("Disable was interrupted");
130         // Preserve the interrupt.
131         Thread.currentThread().interrupt();
132         break;
133       }
134     }
135     // Flip the table to disabled if success.
136     if (done) this.assignmentManager.getZKTable().setDisabledTable(this.tableNameStr);
137     LOG.info("Disabled table is done=" + done);
138   }
139 
140   /**
141    * Run bulk disable.
142    */
143   class BulkDisabler extends BulkAssigner {
144     private final List<HRegionInfo> regions;
145 
146     BulkDisabler(final Server server, final List<HRegionInfo> regions) {
147       super(server);
148       this.regions = regions;
149     }
150 
151     @Override
152     protected void populatePool(ExecutorService pool) {
153       for (HRegionInfo region: regions) {
154         if (assignmentManager.isRegionInTransition(region) != null) continue;
155         final HRegionInfo hri = region;
156         pool.execute(new Runnable() {
157           public void run() {
158             assignmentManager.unassign(hri);
159           }
160         });
161       }
162     }
163 
164     @Override
165     protected boolean waitUntilDone(long timeout)
166     throws InterruptedException {
167       long startTime = System.currentTimeMillis();
168       long remaining = timeout;
169       List<HRegionInfo> regions = null;
170       while (!server.isStopped() && remaining > 0) {
171         Thread.sleep(waitingTimeForEvents);
172         regions = assignmentManager.getRegionsOfTable(tableName);
173         LOG.debug("Disable waiting until done; " + remaining + " ms remaining; " + regions);
174         if (regions.isEmpty()) break;
175         remaining = timeout - (System.currentTimeMillis() - startTime);
176       }
177       return regions != null && regions.isEmpty();
178     }
179   }
180 }