PageRenderTime 33ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/hbase-server/src/main/java/org/apache/hadoop/hbase/util/MetaUtils.java

https://github.com/jmhsieh/hbase
Java | 399 lines | 246 code | 27 blank | 126 comment | 33 complexity | d51a389503636b98f51e31fb1f6d973e MD5 | raw file
  1. /**
  2. *
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. package org.apache.hadoop.hbase.util;
  20. import java.io.IOException;
  21. import java.util.ArrayList;
  22. import java.util.Collections;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.TreeMap;
  26. import org.apache.commons.logging.Log;
  27. import org.apache.commons.logging.LogFactory;
  28. import org.apache.hadoop.classification.InterfaceAudience;
  29. import org.apache.hadoop.conf.Configuration;
  30. import org.apache.hadoop.fs.FileSystem;
  31. import org.apache.hadoop.fs.Path;
  32. import org.apache.hadoop.hbase.HBaseConfiguration;
  33. import org.apache.hadoop.hbase.HConstants;
  34. import org.apache.hadoop.hbase.HRegionInfo;
  35. import org.apache.hadoop.hbase.HTableDescriptor;
  36. import org.apache.hadoop.hbase.KeyValue;
  37. import org.apache.hadoop.hbase.catalog.MetaEditor;
  38. import org.apache.hadoop.hbase.client.Delete;
  39. import org.apache.hadoop.hbase.client.Get;
  40. import org.apache.hadoop.hbase.client.HTable;
  41. import org.apache.hadoop.hbase.client.Put;
  42. import org.apache.hadoop.hbase.client.Result;
  43. import org.apache.hadoop.hbase.client.Scan;
  44. import org.apache.hadoop.hbase.regionserver.HRegion;
  45. import org.apache.hadoop.hbase.regionserver.InternalScanner;
  46. import org.apache.hadoop.hbase.regionserver.wal.HLog;
  47. import org.apache.hadoop.hbase.regionserver.wal.HLogFactory;
  48. /**
  49. * Contains utility methods for manipulating HBase meta tables.
  50. * Be sure to call {@link #shutdown()} when done with this class so it closes
  51. * resources opened during meta processing (ROOT, META, etc.). Be careful
  52. * how you use this class. If used during migrations, be careful when using
  53. * this class to check whether migration is needed.
  54. */
  55. @InterfaceAudience.Private
  56. public class MetaUtils {
  57. private static final Log LOG = LogFactory.getLog(MetaUtils.class);
  58. private final Configuration conf;
  59. private FileSystem fs;
  60. private HLog log;
  61. private HRegion rootRegion;
  62. private Map<byte [], HRegion> metaRegions = Collections.synchronizedSortedMap(
  63. new TreeMap<byte [], HRegion>(Bytes.BYTES_COMPARATOR));
  64. /** Default constructor
  65. * @throws IOException e
  66. */
  67. public MetaUtils() throws IOException {
  68. this(HBaseConfiguration.create());
  69. }
  70. /**
  71. * @param conf Configuration
  72. * @throws IOException e
  73. */
  74. public MetaUtils(Configuration conf) throws IOException {
  75. this.conf = conf;
  76. conf.setInt("hbase.client.retries.number", 1);
  77. this.rootRegion = null;
  78. initialize();
  79. }
  80. /**
  81. * Verifies that DFS is available and that HBase is off-line.
  82. * @throws IOException e
  83. */
  84. private void initialize() throws IOException {
  85. this.fs = FileSystem.get(this.conf);
  86. }
  87. /**
  88. * @return the HLog
  89. * @throws IOException e
  90. */
  91. public synchronized HLog getLog() throws IOException {
  92. if (this.log == null) {
  93. String logName =
  94. HConstants.HREGION_LOGDIR_NAME + "_" + System.currentTimeMillis();
  95. this.log = HLogFactory.createHLog(this.fs, this.fs.getHomeDirectory(),
  96. logName, this.conf);
  97. }
  98. return this.log;
  99. }
  100. /**
  101. * @return HRegion for root region
  102. * @throws IOException e
  103. */
  104. public HRegion getRootRegion() throws IOException {
  105. if (this.rootRegion == null) {
  106. openRootRegion();
  107. }
  108. return this.rootRegion;
  109. }
  110. /**
  111. * Open or return cached opened meta region
  112. *
  113. * @param metaInfo HRegionInfo for meta region
  114. * @return meta HRegion
  115. * @throws IOException e
  116. */
  117. public HRegion getMetaRegion(HRegionInfo metaInfo) throws IOException {
  118. HRegion meta = metaRegions.get(metaInfo.getRegionName());
  119. if (meta == null) {
  120. meta = openMetaRegion(metaInfo);
  121. LOG.info("OPENING META " + meta.toString());
  122. this.metaRegions.put(metaInfo.getRegionName(), meta);
  123. }
  124. return meta;
  125. }
  126. /**
  127. * Closes catalog regions if open. Also closes and deletes the HLog. You
  128. * must call this method if you want to persist changes made during a
  129. * MetaUtils edit session.
  130. */
  131. public void shutdown() {
  132. if (this.rootRegion != null) {
  133. try {
  134. this.rootRegion.close();
  135. } catch (IOException e) {
  136. LOG.error("closing root region", e);
  137. } finally {
  138. this.rootRegion = null;
  139. }
  140. }
  141. try {
  142. for (HRegion r: metaRegions.values()) {
  143. LOG.info("CLOSING META " + r.toString());
  144. r.close();
  145. }
  146. } catch (IOException e) {
  147. LOG.error("closing meta region", e);
  148. } finally {
  149. metaRegions.clear();
  150. }
  151. try {
  152. if (this.log != null) {
  153. this.log.rollWriter();
  154. this.log.closeAndDelete();
  155. }
  156. } catch (IOException e) {
  157. LOG.error("closing HLog", e);
  158. } finally {
  159. this.log = null;
  160. }
  161. }
  162. /**
  163. * Used by scanRootRegion and scanMetaRegion to call back the caller so it
  164. * can process the data for a row.
  165. */
  166. public interface ScannerListener {
  167. /**
  168. * Callback so client of scanner can process row contents
  169. *
  170. * @param info HRegionInfo for row
  171. * @return false to terminate the scan
  172. * @throws IOException e
  173. */
  174. public boolean processRow(HRegionInfo info) throws IOException;
  175. }
  176. /**
  177. * Scans the root region. For every meta region found, calls the listener with
  178. * the HRegionInfo of the meta region.
  179. *
  180. * @param listener method to be called for each meta region found
  181. * @throws IOException e
  182. */
  183. public void scanRootRegion(ScannerListener listener) throws IOException {
  184. // Open root region so we can scan it
  185. if (this.rootRegion == null) {
  186. openRootRegion();
  187. }
  188. scanMetaRegion(this.rootRegion, listener);
  189. }
  190. /**
  191. * Scan the passed in metaregion <code>m</code> invoking the passed
  192. * <code>listener</code> per row found.
  193. * @param r region
  194. * @param listener scanner listener
  195. * @throws IOException e
  196. */
  197. public void scanMetaRegion(final HRegion r, final ScannerListener listener)
  198. throws IOException {
  199. Scan scan = new Scan();
  200. scan.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
  201. InternalScanner s = r.getScanner(scan);
  202. try {
  203. List<KeyValue> results = new ArrayList<KeyValue>();
  204. boolean hasNext = true;
  205. do {
  206. hasNext = s.next(results);
  207. HRegionInfo info = null;
  208. for (KeyValue kv: results) {
  209. info = HRegionInfo.parseFromOrNull(kv.getValue());
  210. if (info == null) {
  211. LOG.warn("Region info is null for row " +
  212. Bytes.toStringBinary(kv.getRow()) + " in table " +
  213. r.getTableDesc().getNameAsString());
  214. }
  215. continue;
  216. }
  217. if (!listener.processRow(info)) {
  218. break;
  219. }
  220. results.clear();
  221. } while (hasNext);
  222. } finally {
  223. s.close();
  224. }
  225. }
  226. /**
  227. * Scans a meta region. For every region found, calls the listener with
  228. * the HRegionInfo of the region.
  229. * TODO: Use Visitor rather than Listener pattern. Allow multiple Visitors.
  230. * Use this everywhere we scan meta regions: e.g. in metascanners, in close
  231. * handling, etc. Have it pass in the whole row, not just HRegionInfo.
  232. * <p>Use for reading meta only. Does not close region when done.
  233. * Use {@link #getMetaRegion(HRegionInfo)} instead if writing. Adds
  234. * meta region to list that will get a close on {@link #shutdown()}.
  235. *
  236. * @param metaRegionInfo HRegionInfo for meta region
  237. * @param listener method to be called for each meta region found
  238. * @throws IOException e
  239. */
  240. public void scanMetaRegion(HRegionInfo metaRegionInfo,
  241. ScannerListener listener)
  242. throws IOException {
  243. // Open meta region so we can scan it
  244. HRegion metaRegion = openMetaRegion(metaRegionInfo);
  245. scanMetaRegion(metaRegion, listener);
  246. }
  247. private synchronized HRegion openRootRegion() throws IOException {
  248. if (this.rootRegion != null) {
  249. return this.rootRegion;
  250. }
  251. this.rootRegion = HRegion.openHRegion(HRegionInfo.ROOT_REGIONINFO,
  252. HTableDescriptor.ROOT_TABLEDESC, getLog(),
  253. this.conf);
  254. this.rootRegion.compactStores();
  255. return this.rootRegion;
  256. }
  257. private HRegion openMetaRegion(HRegionInfo metaInfo) throws IOException {
  258. HRegion meta = HRegion.openHRegion(metaInfo, HTableDescriptor.META_TABLEDESC,
  259. getLog(), this.conf);
  260. meta.compactStores();
  261. return meta;
  262. }
  263. /**
  264. * Set a single region on/offline.
  265. * This is a tool to repair tables that have offlined tables in their midst.
  266. * Can happen on occasion. Use at your own risk. Call from a bit of java
  267. * or jython script. This method is 'expensive' in that it creates a
  268. * {@link HTable} instance per invocation to go against <code>.META.</code>
  269. * @param c A configuration that has its <code>hbase.master</code>
  270. * properly set.
  271. * @param row Row in the catalog .META. table whose HRegionInfo's offline
  272. * status we want to change.
  273. * @param onlineOffline Pass <code>true</code> to OFFLINE the region.
  274. * @throws IOException e
  275. */
  276. public static void changeOnlineStatus (final Configuration c,
  277. final byte [] row, final boolean onlineOffline)
  278. throws IOException {
  279. HTable t = new HTable(c, HConstants.META_TABLE_NAME);
  280. Get get = new Get(row);
  281. get.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
  282. Result res = t.get(get);
  283. KeyValue [] kvs = res.raw();
  284. if(kvs.length <= 0) {
  285. throw new IOException("no information for row " + Bytes.toString(row));
  286. }
  287. HRegionInfo info = HRegionInfo.getHRegionInfo(res);
  288. if (info == null) {
  289. throw new IOException("no information for row " + Bytes.toString(row));
  290. }
  291. info.setOffline(onlineOffline);
  292. MetaEditor.addRegionToMeta(t, info);
  293. Delete delete = new Delete(row);
  294. delete.deleteColumns(HConstants.CATALOG_FAMILY, HConstants.SERVER_QUALIFIER);
  295. delete.deleteColumns(HConstants.CATALOG_FAMILY,
  296. HConstants.STARTCODE_QUALIFIER);
  297. t.delete(delete);
  298. }
  299. /**
  300. * Update COL_REGIONINFO in meta region r with HRegionInfo hri
  301. *
  302. * @param r region
  303. * @param hri region info
  304. * @throws IOException e
  305. */
  306. public void updateMETARegionInfo(HRegion r, final HRegionInfo hri)
  307. throws IOException {
  308. if (LOG.isDebugEnabled()) {
  309. Get get = new Get(hri.getRegionName());
  310. get.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
  311. Result res = r.get(get, null);
  312. KeyValue [] kvs = res.raw();
  313. if(kvs.length <= 0) {
  314. return;
  315. }
  316. HRegionInfo h = HRegionInfo.getHRegionInfo(res);
  317. if (h == null) {
  318. return;
  319. }
  320. LOG.debug("Old " + Bytes.toString(HConstants.CATALOG_FAMILY) + ":" +
  321. Bytes.toString(HConstants.REGIONINFO_QUALIFIER) + " for " +
  322. hri.toString() + " in " + r.toString() + " is: " + h.toString());
  323. }
  324. Put put = MetaEditor.makePutFromRegionInfo(hri);
  325. r.put(put);
  326. if (LOG.isDebugEnabled()) {
  327. Get get = new Get(hri.getRegionName());
  328. get.addColumn(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
  329. Result res = r.get(get, null);
  330. KeyValue [] kvs = res.raw();
  331. if(kvs.length <= 0) {
  332. return;
  333. }
  334. HRegionInfo h = HRegionInfo.getHRegionInfo(res);
  335. if (h == null) {
  336. return;
  337. }
  338. LOG.debug("New " + Bytes.toString(HConstants.CATALOG_FAMILY) + ":" +
  339. Bytes.toString(HConstants.REGIONINFO_QUALIFIER) + " for " +
  340. hri.toString() + " in " + r.toString() + " is: " + h.toString());
  341. }
  342. }
  343. /**
  344. * @return List of {@link HRegionInfo} rows found in the ROOT or META
  345. * catalog table.
  346. * @param tableName Name of table to go looking for.
  347. * @throws IOException e
  348. * @see #getMetaRegion(HRegionInfo)
  349. */
  350. public List<HRegionInfo> getMETARows(final byte [] tableName)
  351. throws IOException {
  352. final List<HRegionInfo> result = new ArrayList<HRegionInfo>();
  353. // If passed table name is META, then return the root region.
  354. if (Bytes.equals(HConstants.META_TABLE_NAME, tableName)) {
  355. result.add(openRootRegion().getRegionInfo());
  356. return result;
  357. }
  358. // Return all meta regions that contain the passed tablename.
  359. scanRootRegion(new ScannerListener() {
  360. private final Log SL_LOG = LogFactory.getLog(this.getClass());
  361. public boolean processRow(HRegionInfo info) throws IOException {
  362. SL_LOG.debug("Testing " + info);
  363. if (Bytes.equals(info.getTableName(),
  364. HConstants.META_TABLE_NAME)) {
  365. result.add(info);
  366. return false;
  367. }
  368. return true;
  369. }});
  370. return result;
  371. }
  372. }