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  
19  package org.apache.hadoop.hbase.catalog;
20  
21  import java.io.IOException;
22  import java.util.List;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.hbase.exceptions.DeserializationException;
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.HRegionInfo;
29  import org.apache.hadoop.hbase.catalog.MetaReader.Visitor;
30  import org.apache.hadoop.hbase.client.Put;
31  import org.apache.hadoop.hbase.client.Result;
32  import org.apache.hadoop.hbase.master.MasterServices;
33  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
34  import org.apache.hadoop.hbase.util.Bytes;
35  
36  /**
37   * A tool to migrate the data stored in hbase:meta table to pbuf serialization.
38   * Supports migrating from 0.92.x and 0.94.x to 0.96.x for the catalog table.
39   * @deprecated will be removed for the major release after 0.96.
40   */
41  @Deprecated
42  public class MetaMigrationConvertingToPB {
43  
44    private static final Log LOG = LogFactory.getLog(MetaMigrationConvertingToPB.class);
45  
46    private static class ConvertToPBMetaVisitor implements Visitor {
47      private final MasterServices services;
48      private long numMigratedRows;
49  
50      public ConvertToPBMetaVisitor(MasterServices services) {
51        this.services = services;
52        numMigratedRows = 0;
53      }
54  
55      @Override
56      public boolean visit(Result r) throws IOException {
57        if (r ==  null || r.isEmpty()) return true;
58        // Check info:regioninfo, info:splitA, and info:splitB.  Make sure all
59        // have migrated HRegionInfos.
60        byte [] hriBytes = getBytes(r, HConstants.REGIONINFO_QUALIFIER);
61        // Presumes that an edit updating all three cells either succeeds or
62        // doesn't -- that we don't have case of info:regioninfo migrated but not
63        // info:splitA.
64        if (isMigrated(hriBytes)) return true;
65        // OK. Need to migrate this row in meta.
66  
67        //This will 'migrate' the HRI from 092.x and 0.94.x to 0.96+ by reading the
68        //writable serialization
69        HRegionInfo hri = parseFrom(hriBytes);
70  
71        // Now make a put to write back to meta.
72        Put p =  MetaEditor.makePutFromRegionInfo(hri);
73  
74        // Now migrate info:splitA and info:splitB if they are not null
75        migrateSplitIfNecessary(r, p, HConstants.SPLITA_QUALIFIER);
76        migrateSplitIfNecessary(r, p, HConstants.SPLITB_QUALIFIER);
77  
78        MetaEditor.putToCatalogTable(this.services.getCatalogTracker(), p);
79        if (LOG.isDebugEnabled()) {
80          LOG.debug("Migrated " + Bytes.toString(p.getRow()));
81        }
82        numMigratedRows++;
83        return true;
84      }
85    }
86  
87    static void migrateSplitIfNecessary(final Result r, final Put p, final byte [] which)
88        throws IOException {
89      byte [] hriSplitBytes = getBytes(r, which);
90      if (!isMigrated(hriSplitBytes)) {
91        //This will 'migrate' the HRI from 092.x and 0.94.x to 0.96+ by reading the
92        //writable serialization
93        HRegionInfo hri = parseFrom(hriSplitBytes);
94        p.addImmutable(HConstants.CATALOG_FAMILY, which, hri.toByteArray());
95      }
96    }
97  
98    static HRegionInfo parseFrom(byte[] hriBytes) throws IOException {
99      try {
100       return HRegionInfo.parseFrom(hriBytes);
101     } catch (DeserializationException ex) {
102       throw new IOException(ex);
103     }
104   }
105 
106   /**
107    * @param r Result to dig in.
108    * @param qualifier Qualifier to look at in the passed <code>r</code>.
109    * @return Bytes for an HRegionInfo or null if no bytes or empty bytes found.
110    */
111   static byte [] getBytes(final Result r, final byte [] qualifier) {
112     byte [] hriBytes = r.getValue(HConstants.CATALOG_FAMILY, qualifier);
113     if (hriBytes == null || hriBytes.length <= 0) return null;
114     return hriBytes;
115   }
116 
117   static boolean isMigrated(final byte [] hriBytes) {
118     if (hriBytes == null || hriBytes.length <= 0) return true;
119 
120     return ProtobufUtil.isPBMagicPrefix(hriBytes);
121   }
122 
123   /**
124    * Converting writable serialization to PB, if it is needed.
125    * @param services MasterServices to get a handle on master
126    * @return num migrated rows
127    * @throws IOException or RuntimeException if something goes wrong
128    */
129   public static long updateMetaIfNecessary(final MasterServices services)
130   throws IOException {
131     if (isMetaTableUpdated(services.getCatalogTracker())) {
132       LOG.info("META already up-to date with PB serialization");
133       return 0;
134     }
135     LOG.info("META has Writable serializations, migrating hbase:meta to PB serialization");
136     try {
137       long rows = updateMeta(services);
138       LOG.info("META updated with PB serialization. Total rows updated: " + rows);
139       return rows;
140     } catch (IOException e) {
141       LOG.warn("Update hbase:meta with PB serialization failed." + "Master startup aborted.");
142       throw e;
143     }
144   }
145 
146   /**
147    * Update hbase:meta rows, converting writable serialization to PB
148    * @return num migrated rows
149    */
150   static long updateMeta(final MasterServices masterServices) throws IOException {
151     LOG.info("Starting update of META");
152     ConvertToPBMetaVisitor v = new ConvertToPBMetaVisitor(masterServices);
153     MetaReader.fullScan(masterServices.getCatalogTracker(), v);
154     LOG.info("Finished update of META. Total rows updated:" + v.numMigratedRows);
155     return v.numMigratedRows;
156   }
157 
158   /**
159    * @param catalogTracker the catalog tracker
160    * @return True if the meta table has been migrated.
161    * @throws IOException
162    */
163   static boolean isMetaTableUpdated(final CatalogTracker catalogTracker) throws IOException {
164     List<Result> results = MetaReader.fullScanOfMeta(catalogTracker);
165     if (results == null || results.isEmpty()) {
166       LOG.info("hbase:meta doesn't have any entries to update.");
167       return true;
168     }
169     for (Result r : results) {
170       byte[] value = r.getValue(HConstants.CATALOG_FAMILY, HConstants.REGIONINFO_QUALIFIER);
171       if (!isMigrated(value)) {
172         return false;
173       }
174     }
175     return true;
176   }
177 }