View Javadoc

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.regionserver.wal;
20  
21  import java.io.DataInput;
22  import java.io.DataOutput;
23  import java.io.EOFException;
24  import java.io.IOException;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.NavigableMap;
28  import java.util.UUID;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.classification.InterfaceAudience;
33  import org.apache.hadoop.hbase.HBaseInterfaceAudience;
34  import org.apache.hadoop.hbase.HRegionInfo;
35  import org.apache.hadoop.hbase.TableName;
36  import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl;
37  import org.apache.hadoop.hbase.util.Bytes;
38  import org.apache.hadoop.hbase.wal.WALKey;
39  import org.apache.hadoop.io.Writable;
40  import org.apache.hadoop.io.WritableUtils;
41  
42  import com.google.common.annotations.VisibleForTesting;
43  
44  /**
45   * A Key for an entry in the change log.
46   *
47   * The log intermingles edits to many tables and rows, so each log entry
48   * identifies the appropriate table and row.  Within a table and row, they're
49   * also sorted.
50   *
51   * <p>Some Transactional edits (START, COMMIT, ABORT) will not have an
52   * associated row.
53   * @deprecated use WALKey. Deprecated as of 1.0 (HBASE-12522). Remove in 2.0
54   */
55  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.REPLICATION)
56  @Deprecated
57  public class HLogKey extends WALKey implements Writable {
58    private static final Log LOG = LogFactory.getLog(HLogKey.class);
59  
60    public HLogKey() {
61      super();
62    }
63  
64    @VisibleForTesting
65    public HLogKey(final byte[] encodedRegionName, final TableName tablename, long logSeqNum,
66        final long now, UUID clusterId) {
67      super(encodedRegionName, tablename, logSeqNum, now, clusterId);
68    }
69  
70    public HLogKey(final byte[] encodedRegionName, final TableName tablename) {
71      super(encodedRegionName, tablename, null);
72    }
73  
74    @VisibleForTesting
75    public HLogKey(final byte[] encodedRegionName, final TableName tablename, final long now) {
76      super(encodedRegionName, tablename, now);
77    }
78  
79    @VisibleForTesting
80    public HLogKey(final byte[] encodedRegionName, final TableName tablename, final long now,
81        final NavigableMap<byte[], Integer> replicationScope) {
82      super(encodedRegionName, tablename, now, replicationScope);
83    }
84  
85    public HLogKey(final byte[] encodedRegionName, final TableName tablename, final long now,
86        final MultiVersionConcurrencyControl mvcc, final NavigableMap<byte[], Integer> scopes) {
87      super(encodedRegionName, tablename, now, mvcc, scopes);
88    }
89  
90    /**
91     * Create the log key for writing to somewhere.
92     * We maintain the tablename mainly for debugging purposes.
93     * A regionName is always a sub-table object.
94     * <p>Used by log splitting and snapshots.
95     *
96     * @param encodedRegionName Encoded name of the region as returned by
97     * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
98     * @param tablename   - name of table
99     * @param logSeqNum   - log sequence number
100    * @param now Time at which this edit was written.
101    * @param clusterIds the clusters that have consumed the change(used in Replication)
102    */
103   public HLogKey(
104       final byte[] encodedRegionName,
105       final TableName tablename,
106       long logSeqNum,
107       final long now,
108       List<UUID> clusterIds,
109       long nonceGroup,
110       long nonce,
111       MultiVersionConcurrencyControl mvcc) {
112     super(encodedRegionName, tablename, logSeqNum, now, clusterIds, nonceGroup, nonce, mvcc);
113   }
114 
115   /**
116    * Create the log key for writing to somewhere.
117    * We maintain the tablename mainly for debugging purposes.
118    * A regionName is always a sub-table object.
119    * <p>Used by log splitting and snapshots.
120    *
121    * @param encodedRegionName Encoded name of the region as returned by
122    * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
123    * @param tablename   - name of table
124    * @param logSeqNum   - log sequence number
125    * @param now Time at which this edit was written.
126    * @param clusterIds the clusters that have consumed the change(used in Replication)
127    * @param nonceGroup the noncegroup
128    * @param nonce      the nonce
129    * @param replicationScope the replicationScope of the non-default column families' of the region
130    */
131   public HLogKey(
132       final byte[] encodedRegionName,
133       final TableName tablename,
134       long logSeqNum,
135       final long now,
136       List<UUID> clusterIds,
137       long nonceGroup,
138       long nonce,
139       MultiVersionConcurrencyControl mvcc, NavigableMap<byte[], Integer> replicationScope) {
140     super(encodedRegionName, tablename, logSeqNum, now, clusterIds, nonceGroup, nonce, mvcc,
141         replicationScope);
142   }
143 
144   /**
145    * Create the log key for writing to somewhere.
146    * We maintain the tablename mainly for debugging purposes.
147    * A regionName is always a sub-table object.
148    *
149    * @param encodedRegionName Encoded name of the region as returned by
150    * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
151    * @param tablename
152    * @param now Time at which this edit was written.
153    * @param clusterIds the clusters that have consumed the change(used in Replication)
154    * @param nonceGroup
155    * @param nonce
156    */
157   public HLogKey(final byte[] encodedRegionName,
158                  final TableName tablename,
159                  final long now,
160                  List<UUID> clusterIds,
161                  long nonceGroup,
162                  long nonce,
163                  final MultiVersionConcurrencyControl mvcc) {
164     super(encodedRegionName, tablename, now, clusterIds, nonceGroup, nonce, mvcc);
165   }
166 
167   /**
168    * Create the log key for writing to somewhere.
169    * We maintain the tablename mainly for debugging purposes.
170    * A regionName is always a sub-table object.
171    *
172    * @param encodedRegionName Encoded name of the region as returned by
173    * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
174    * @param tablename
175    * @param logSeqNum
176    * @param nonceGroup
177    * @param nonce
178    */
179   public HLogKey(final byte [] encodedRegionName, final TableName tablename, long logSeqNum,
180       long nonceGroup, long nonce, MultiVersionConcurrencyControl mvcc) {
181     super(encodedRegionName, tablename, logSeqNum, nonceGroup, nonce, mvcc);
182   }
183 
184   /**
185    * @deprecated Don't use these Writables methods. Use PB instead.
186    */
187   @Override
188   @Deprecated
189   public void write(DataOutput out) throws IOException {
190     LOG.warn("HLogKey is being serialized to writable - only expected in test code");
191     WritableUtils.writeVInt(out, VERSION.code);
192     if (compressionContext == null) {
193       Bytes.writeByteArray(out, this.encodedRegionName);
194       Bytes.writeByteArray(out, this.tablename.getName());
195     } else {
196       Compressor.writeCompressed(this.encodedRegionName, 0,
197           this.encodedRegionName.length, out,
198           compressionContext.regionDict);
199       Compressor.writeCompressed(this.tablename.getName(), 0,
200           this.tablename.getName().length, out,
201           compressionContext.tableDict);
202     }
203     out.writeLong(getSequenceId());
204     out.writeLong(this.writeTime);
205     // Don't need to write the clusters information as we are using protobufs from 0.95
206     // Writing only the first clusterId for testing the legacy read
207     Iterator<UUID> iterator = clusterIds.iterator();
208     if(iterator.hasNext()){
209       out.writeBoolean(true);
210       UUID clusterId = iterator.next();
211       out.writeLong(clusterId.getMostSignificantBits());
212       out.writeLong(clusterId.getLeastSignificantBits());
213     } else {
214       out.writeBoolean(false);
215     }
216   }
217 
218   @Override
219   public void readFields(DataInput in) throws IOException {
220     Version version = Version.UNVERSIONED;
221     // HLogKey was not versioned in the beginning.
222     // In order to introduce it now, we make use of the fact
223     // that encodedRegionName was written with Bytes.writeByteArray,
224     // which encodes the array length as a vint which is >= 0.
225     // Hence if the vint is >= 0 we have an old version and the vint
226     // encodes the length of encodedRegionName.
227     // If < 0 we just read the version and the next vint is the length.
228     // @see Bytes#readByteArray(DataInput)
229     serializeReplicationScope(false); // writable HLogKey does not contain scopes
230     int len = WritableUtils.readVInt(in);
231     byte[] tablenameBytes = null;
232     if (len < 0) {
233       // what we just read was the version
234       version = Version.fromCode(len);
235       // We only compress V2 of WALkey.
236       // If compression is on, the length is handled by the dictionary
237       if (compressionContext == null || !version.atLeast(Version.COMPRESSED)) {
238         len = WritableUtils.readVInt(in);
239       }
240     }
241     if (compressionContext == null || !version.atLeast(Version.COMPRESSED)) {
242       this.encodedRegionName = new byte[len];
243       in.readFully(this.encodedRegionName);
244       tablenameBytes = Bytes.readByteArray(in);
245     } else {
246       this.encodedRegionName = Compressor.readCompressed(in, compressionContext.regionDict);
247       tablenameBytes = Compressor.readCompressed(in, compressionContext.tableDict);
248     }
249 
250     setSequenceId(in.readLong());
251     this.writeTime = in.readLong();
252 
253     this.clusterIds.clear();
254     if (version.atLeast(Version.INITIAL)) {
255       if (in.readBoolean()) {
256         // read the older log
257         // Definitely is the originating cluster
258         clusterIds.add(new UUID(in.readLong(), in.readLong()));
259       }
260     } else {
261       try {
262         // dummy read (former byte cluster id)
263         in.readByte();
264       } catch(EOFException e) {
265         // Means it's a very old key, just continue
266         if (LOG.isTraceEnabled()) LOG.trace(e);
267       }
268     }
269     try {
270       this.tablename = TableName.valueOf(tablenameBytes);
271     } catch (IllegalArgumentException iae) {
272       if (Bytes.toString(tablenameBytes).equals(TableName.OLD_META_STR)) {
273         // It is a pre-namespace meta table edit, continue with new format.
274         LOG.info("Got an old .META. edit, continuing with new format ");
275         this.tablename = TableName.META_TABLE_NAME;
276         this.encodedRegionName = HRegionInfo.FIRST_META_REGIONINFO.getEncodedNameAsBytes();
277       } else if (Bytes.toString(tablenameBytes).equals(TableName.OLD_ROOT_STR)) {
278         this.tablename = TableName.OLD_ROOT_TABLE_NAME;
279          throw iae;
280       } else throw iae;
281     }
282     // Do not need to read the clusters information as we are using protobufs from 0.95
283   }
284 
285 }