View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.catalog;
19  
20  import java.io.IOException;
21  import java.io.InterruptedIOException;
22  import java.net.ConnectException;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.hadoop.hbase.HConstants;
29  import org.apache.hadoop.hbase.HRegionInfo;
30  import org.apache.hadoop.hbase.NotAllMetaRegionsOnlineException;
31  import org.apache.hadoop.hbase.ServerName;
32  import org.apache.hadoop.hbase.client.Delete;
33  import org.apache.hadoop.hbase.client.HTable;
34  import org.apache.hadoop.hbase.client.Mutation;
35  import org.apache.hadoop.hbase.client.Put;
36  import org.apache.hadoop.hbase.client.Result;
37  import org.apache.hadoop.hbase.util.Bytes;
38  import org.apache.hadoop.hbase.util.PairOfSameType;
39  import org.apache.hadoop.hbase.util.Writables;
40  
41  /**
42   * Writes region and assignment information to <code>.META.</code>.
43   * TODO: Put MetaReader and MetaEditor together; doesn't make sense having
44   * them distinct.
45   */
46  public class MetaEditor {
47    // TODO: Strip CatalogTracker from this class.  Its all over and in the end
48    // its only used to get its Configuration so we can get associated
49    // Connection.
50    private static final Log LOG = LogFactory.getLog(MetaEditor.class);
51  
52    private static Put makePutFromRegionInfo(HRegionInfo regionInfo)
53    throws IOException {
54      Put put = new Put(regionInfo.getRegionName());
55      put.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
56          Writables.getBytes(regionInfo));
57      return put;
58    }
59  
60    /**
61     * Put the passed <code>p</code> to the <code>.META.</code> table.
62     * @param ct CatalogTracker on whose back we will ride the edit.
63     * @param p Put to add to .META.
64     * @throws IOException
65     */
66    static void putToMetaTable(final CatalogTracker ct, final Put p)
67    throws IOException {
68      put(MetaReader.getMetaHTable(ct), p);
69    }
70  
71    /**
72     * Put the passed <code>p</code> to the <code>.META.</code> table.
73     * @param ct CatalogTracker on whose back we will ride the edit.
74     * @param p Put to add to .META.
75     * @throws IOException
76     */
77    static void putToRootTable(final CatalogTracker ct, final Put p)
78    throws IOException {
79      put(MetaReader.getRootHTable(ct), p);
80    }
81  
82    /**
83     * Put the passed <code>p</code> to a catalog table.
84     * @param ct CatalogTracker on whose back we will ride the edit.
85     * @param p Put to add
86     * @throws IOException
87     */
88    static void putToCatalogTable(final CatalogTracker ct, final Put p)
89    throws IOException {
90      HTable t = MetaReader.getCatalogHTable(ct, p.getRow());
91      put(t, p);
92    }
93  
94    /**
95     * @param t Table to use (will be closed when done).
96     * @param p
97     * @throws IOException
98     */
99    private static void put(final HTable t, final Put p) throws IOException {
100     try {
101       t.put(p);
102     } finally {
103       t.close();
104     }
105   }
106 
107   /**
108    * Put the passed <code>ps</code> to the <code>.META.</code> table.
109    * @param ct CatalogTracker on whose back we will ride the edit.
110    * @param ps Put to add to .META.
111    * @throws IOException
112    */
113   static void putsToMetaTable(final CatalogTracker ct, final List<Put> ps)
114   throws IOException {
115     HTable t = MetaReader.getMetaHTable(ct);
116     try {
117       t.put(ps);
118     } finally {
119       t.close();
120     }
121   }
122 
123   /**
124    * Delete the passed <code>d</code> from the <code>.META.</code> table.
125    * @param ct CatalogTracker on whose back we will ride the edit.
126    * @param d Delete to add to .META.
127    * @throws IOException
128    */
129   static void deleteFromMetaTable(final CatalogTracker ct, final Delete d)
130       throws IOException {
131     List<Delete> dels = new ArrayList<Delete>(1);
132     dels.add(d);
133     deleteFromMetaTable(ct, dels);
134   }
135 
136   /**
137    * Delete the passed <code>deletes</code> from the <code>.META.</code> table.
138    * @param ct CatalogTracker on whose back we will ride the edit.
139    * @param deletes Deletes to add to .META.  This list should support #remove.
140    * @throws IOException
141    */
142   public static void deleteFromMetaTable(final CatalogTracker ct, final List<Delete> deletes)
143       throws IOException {
144     HTable t = MetaReader.getMetaHTable(ct);
145     try {
146       t.delete(deletes);
147     } finally {
148       t.close();
149     }
150   }
151 
152   /**
153    * Execute the passed <code>mutations</code> against <code>.META.</code> table.
154    * @param ct CatalogTracker on whose back we will ride the edit.
155    * @param mutations Puts and Deletes to execute on .META.
156    * @throws IOException
157    */
158   static void mutateMetaTable(final CatalogTracker ct, final List<Mutation> mutations)
159       throws IOException {
160     HTable t = MetaReader.getMetaHTable(ct);
161     try {
162       t.batch(mutations);
163     } catch (InterruptedException e) {
164       InterruptedIOException ie = new InterruptedIOException(e.getMessage());
165       ie.initCause(e);
166       throw ie;
167     } finally {
168       t.close();
169     }
170   }
171 
172   /**
173    * Adds a META row for the specified new region.
174    * @param regionInfo region information
175    * @throws IOException if problem connecting or updating meta
176    */
177   public static void addRegionToMeta(CatalogTracker catalogTracker,
178       HRegionInfo regionInfo)
179   throws IOException {
180     putToMetaTable(catalogTracker, makePutFromRegionInfo(regionInfo));
181     LOG.info("Added region " + regionInfo.getRegionNameAsString() + " to META");
182   }
183 
184   /**
185    * Adds a META row for each of the specified new regions.
186    * @param catalogTracker CatalogTracker
187    * @param regionInfos region information list
188    * @throws IOException if problem connecting or updating meta
189    */
190   public static void addRegionsToMeta(CatalogTracker catalogTracker,
191       List<HRegionInfo> regionInfos)
192   throws IOException {
193     List<Put> puts = new ArrayList<Put>();
194     for (HRegionInfo regionInfo : regionInfos) {
195       puts.add(makePutFromRegionInfo(regionInfo));
196     }
197     putsToMetaTable(catalogTracker, puts);
198     LOG.info("Added " + puts.size() + " regions in META");
199   }
200 
201   /**
202    * Offline parent in meta.
203    * Used when splitting.
204    * @param catalogTracker
205    * @param parent
206    * @param a Split daughter region A
207    * @param b Split daughter region B
208    * @throws NotAllMetaRegionsOnlineException
209    * @throws IOException
210    */
211   public static void offlineParentInMeta(CatalogTracker catalogTracker,
212       HRegionInfo parent, final HRegionInfo a, final HRegionInfo b)
213   throws NotAllMetaRegionsOnlineException, IOException {
214     HRegionInfo copyOfParent = new HRegionInfo(parent);
215     copyOfParent.setOffline(true);
216     copyOfParent.setSplit(true);
217     Put put = new Put(copyOfParent.getRegionName());
218     addRegionInfo(put, copyOfParent);
219     put.add(HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER,
220       Writables.getBytes(a));
221     put.add(HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER,
222       Writables.getBytes(b));
223     putToMetaTable(catalogTracker, put);
224     LOG.info("Offlined parent region " + parent.getRegionNameAsString() +
225       " in META");
226   }
227 
228   public static void addDaughter(final CatalogTracker catalogTracker,
229       final HRegionInfo regionInfo, final ServerName sn)
230   throws NotAllMetaRegionsOnlineException, IOException {
231     Put put = new Put(regionInfo.getRegionName());
232     addRegionInfo(put, regionInfo);
233     if (sn != null) addLocation(put, sn);
234     putToMetaTable(catalogTracker, put);
235     LOG.info("Added daughter " + regionInfo.getRegionNameAsString() +
236       (sn == null? ", serverName=null": ", serverName=" + sn.toString()));
237   }
238 
239   /**
240    * Updates the location of the specified META region in ROOT to be the
241    * specified server hostname and startcode.
242    * <p>
243    * Uses passed catalog tracker to get a connection to the server hosting
244    * ROOT and makes edits to that region.
245    *
246    * @param catalogTracker catalog tracker
247    * @param regionInfo region to update location of
248    * @param sn Server name
249    * @throws IOException
250    * @throws ConnectException Usually because the regionserver carrying .META.
251    * is down.
252    * @throws NullPointerException Because no -ROOT- server connection
253    */
254   public static void updateMetaLocation(CatalogTracker catalogTracker,
255       HRegionInfo regionInfo, ServerName sn)
256   throws IOException, ConnectException {
257     updateLocation(catalogTracker, regionInfo, sn);
258   }
259 
260   /**
261    * Updates the location of the specified region in META to be the specified
262    * server hostname and startcode.
263    * <p>
264    * Uses passed catalog tracker to get a connection to the server hosting
265    * META and makes edits to that region.
266    *
267    * @param catalogTracker catalog tracker
268    * @param regionInfo region to update location of
269    * @param sn Server name
270    * @throws IOException
271    */
272   public static void updateRegionLocation(CatalogTracker catalogTracker,
273       HRegionInfo regionInfo, ServerName sn)
274   throws IOException {
275     updateLocation(catalogTracker, regionInfo, sn);
276   }
277 
278   /**
279    * Updates the location of the specified region to be the specified server.
280    * <p>
281    * Connects to the specified server which should be hosting the specified
282    * catalog region name to perform the edit.
283    *
284    * @param catalogTracker
285    * @param regionInfo region to update location of
286    * @param sn Server name
287    * @throws IOException In particular could throw {@link java.net.ConnectException}
288    * if the server is down on other end.
289    */
290   private static void updateLocation(final CatalogTracker catalogTracker,
291       HRegionInfo regionInfo, ServerName sn)
292   throws IOException {
293     Put put = new Put(regionInfo.getRegionName());
294     addLocation(put, sn);
295     putToCatalogTable(catalogTracker, put);
296     LOG.info("Updated row " + regionInfo.getRegionNameAsString() +
297       " with server=" + sn);
298   }
299 
300   /**
301    * Deletes the specified region from META.
302    * @param catalogTracker
303    * @param regionInfo region to be deleted from META
304    * @throws IOException
305    */
306   public static void deleteRegion(CatalogTracker catalogTracker,
307       HRegionInfo regionInfo)
308   throws IOException {
309     Delete delete = new Delete(regionInfo.getRegionName());
310     deleteFromMetaTable(catalogTracker, delete);
311     LOG.info("Deleted region " + regionInfo.getRegionNameAsString() + " from META");
312   }
313 
314   /**
315    * Deletes the specified regions from META.
316    * @param catalogTracker
317    * @param regionsInfo list of regions to be deleted from META
318    * @throws IOException
319    */
320   public static void deleteRegions(CatalogTracker catalogTracker,
321       List<HRegionInfo> regionsInfo) throws IOException {
322     List<Delete> deletes = new ArrayList<Delete>(regionsInfo.size());
323     for (HRegionInfo hri: regionsInfo) {
324       deletes.add(new Delete(hri.getRegionName()));
325     }
326     deleteFromMetaTable(catalogTracker, deletes);
327     LOG.info("Deleted from META, regions: " + regionsInfo);
328   }
329 
330   /**
331    * Adds and Removes the specified regions from .META.
332    * @param catalogTracker
333    * @param regionsToRemove list of regions to be deleted from META
334    * @param regionsToAdd list of regions to be added to META
335    * @throws IOException
336    */
337   public static void mutateRegions(CatalogTracker catalogTracker,
338       final List<HRegionInfo> regionsToRemove, final List<HRegionInfo> regionsToAdd)
339       throws IOException {
340     List<Mutation> mutation = new ArrayList<Mutation>();
341     if (regionsToRemove != null) {
342       for (HRegionInfo hri: regionsToRemove) {
343         mutation.add(new Delete(hri.getRegionName()));
344       }
345     }
346     if (regionsToAdd != null) {
347       for (HRegionInfo hri: regionsToAdd) {
348         mutation.add(makePutFromRegionInfo(hri));
349       }
350     }
351     mutateMetaTable(catalogTracker, mutation);
352     if (regionsToRemove != null && regionsToRemove.size() > 0) {
353       LOG.debug("Deleted from META, regions: " + regionsToRemove);
354     }
355     if (regionsToAdd != null && regionsToAdd.size() > 0) {
356       LOG.debug("Add to META, regions: " + regionsToAdd);
357     }
358   }
359 
360   public static HRegionInfo getHRegionInfo(
361       Result data) throws IOException {
362     byte [] bytes =
363       data.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
364     if (bytes == null) return null;
365     HRegionInfo info = Writables.getHRegionInfo(bytes);
366     LOG.info("Current INFO from scan results = " + info);
367     return info;
368   }
369 
370   /**
371    * Returns the daughter regions by reading from the corresponding columns of the .META. table
372    * Result. If the region is not a split parent region, it returns PairOfSameType(null, null).
373    */
374   public static PairOfSameType<HRegionInfo> getDaughterRegions(Result data) throws IOException {
375     HRegionInfo splitA = Writables.getHRegionInfoOrNull(
376         data.getValue(HConstants.CATALOG_FAMILY, HConstants.SPLITA_QUALIFIER));
377     HRegionInfo splitB = Writables.getHRegionInfoOrNull(
378         data.getValue(HConstants.CATALOG_FAMILY, HConstants.SPLITB_QUALIFIER));
379     return new PairOfSameType<HRegionInfo>(splitA, splitB);
380   }
381 
382   private static Put addRegionInfo(final Put p, final HRegionInfo hri)
383   throws IOException {
384     p.add(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER,
385         Writables.getBytes(hri));
386     return p;
387   }
388 
389   private static Put addLocation(final Put p, final ServerName sn) {
390     p.add(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER,
391       Bytes.toBytes(sn.getHostAndPort()));
392     p.add(HConstants.CATALOG_FAMILY, HConstants.STARTCODE_QUALIFIER,
393       Bytes.toBytes(sn.getStartcode()));
394     return p;
395   }
396 }