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