View Javadoc

1   /**
2    * Copyright 2007 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.regionserver.wal;
21  
22  import java.io.DataInput;
23  import java.io.DataOutput;
24  import java.io.EOFException;
25  import java.io.IOException;
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.util.Bytes;
31  import org.apache.hadoop.io.WritableComparable;
32  
33  /**
34   * A Key for an entry in the change log.
35   *
36   * The log intermingles edits to many tables and rows, so each log entry
37   * identifies the appropriate table and row.  Within a table and row, they're
38   * also sorted.
39   *
40   * <p>Some Transactional edits (START, COMMIT, ABORT) will not have an
41   * associated row.
42   */
43  public class HLogKey implements WritableComparable<HLogKey> {
44    //  The encoded region name.
45    private byte [] encodedRegionName;
46    private byte [] tablename;
47    private long logSeqNum;
48    // Time at which this edit was written.
49    private long writeTime;
50  
51    private byte clusterId;
52  
53    /** Writable Consructor -- Do not use. */
54    public HLogKey() {
55      this(null, null, 0L, HConstants.LATEST_TIMESTAMP);
56    }
57  
58    /**
59     * Create the log key!
60     * We maintain the tablename mainly for debugging purposes.
61     * A regionName is always a sub-table object.
62     *
63     * @param encodedRegionName Encoded name of the region as returned by
64     * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
65     * @param tablename   - name of table
66     * @param logSeqNum   - log sequence number
67     * @param now Time at which this edit was written.
68     */
69    public HLogKey(final byte [] encodedRegionName, final byte [] tablename,
70        long logSeqNum, final long now) {
71      this.encodedRegionName = encodedRegionName;
72      this.tablename = tablename;
73      this.logSeqNum = logSeqNum;
74      this.writeTime = now;
75      this.clusterId = HConstants.DEFAULT_CLUSTER_ID;
76    }
77  
78    /** @return encoded region name */
79    public byte [] getEncodedRegionName() {
80      return encodedRegionName;
81    }
82  
83    /** @return table name */
84    public byte [] getTablename() {
85      return tablename;
86    }
87  
88    /** @return log sequence number */
89    public long getLogSeqNum() {
90      return logSeqNum;
91    }
92  
93    void setLogSeqNum(long logSeqNum) {
94      this.logSeqNum = logSeqNum;
95    }
96  
97    /**
98     * @return the write time
99     */
100   public long getWriteTime() {
101     return this.writeTime;
102   }
103 
104   /**
105    * Get the id of the original cluster
106    * @return Cluster id.
107    */
108   public byte getClusterId() {
109     return clusterId;
110   }
111 
112   /**
113    * Set the cluster id of this key
114    * @param clusterId
115    */
116   public void setClusterId(byte clusterId) {
117     this.clusterId = clusterId;
118   }
119 
120   @Override
121   public String toString() {
122     return Bytes.toString(tablename) + "/" + Bytes.toString(encodedRegionName) + "/" +
123       logSeqNum;
124   }
125 
126   /**
127    * Produces a string map for this key. Useful for programmatic use and
128    * manipulation of the data stored in an HLogKey, for example, printing 
129    * as JSON.
130    * 
131    * @return a Map containing data from this key
132    */
133   public Map<String, Object> toStringMap() {
134     Map<String, Object> stringMap = new HashMap<String, Object>();
135     stringMap.put("table", Bytes.toStringBinary(tablename));
136     stringMap.put("region", Bytes.toStringBinary(encodedRegionName));
137     stringMap.put("sequence", logSeqNum);
138     return stringMap;
139   }
140 
141   @Override
142   public boolean equals(Object obj) {
143     if (this == obj) {
144       return true;
145     }
146     if (obj == null || getClass() != obj.getClass()) {
147       return false;
148     }
149     return compareTo((HLogKey)obj) == 0;
150   }
151 
152   @Override
153   public int hashCode() {
154     int result = Bytes.hashCode(this.encodedRegionName);
155     result ^= this.logSeqNum;
156     result ^= this.writeTime;
157     result ^= this.clusterId;
158     return result;
159   }
160 
161   public int compareTo(HLogKey o) {
162     int result = Bytes.compareTo(this.encodedRegionName, o.encodedRegionName);
163     if (result == 0) {
164       if (this.logSeqNum < o.logSeqNum) {
165         result = -1;
166       } else if (this.logSeqNum > o.logSeqNum) {
167         result = 1;
168       }
169       if (result == 0) {
170         if (this.writeTime < o.writeTime) {
171           result = -1;
172         } else if (this.writeTime > o.writeTime) {
173           return 1;
174         }
175       }
176     }
177     return result;
178   }
179 
180   /**
181    * Drop this instance's tablename byte array and instead
182    * hold a reference to the provided tablename. This is not
183    * meant to be a general purpose setter - it's only used
184    * to collapse references to conserve memory.
185    */
186   void internTableName(byte []tablename) {
187     // We should not use this as a setter - only to swap
188     // in a new reference to the same table name.
189     assert Bytes.equals(tablename, this.tablename);
190     this.tablename = tablename;
191   }
192 
193   /**
194    * Drop this instance's region name byte array and instead
195    * hold a reference to the provided region name. This is not
196    * meant to be a general purpose setter - it's only used
197    * to collapse references to conserve memory.
198    */
199   void internEncodedRegionName(byte []encodedRegionName) {
200     // We should not use this as a setter - only to swap
201     // in a new reference to the same table name.
202     assert Bytes.equals(this.encodedRegionName, encodedRegionName);
203     this.encodedRegionName = encodedRegionName;
204   }
205 
206   public void write(DataOutput out) throws IOException {
207     Bytes.writeByteArray(out, this.encodedRegionName);
208     Bytes.writeByteArray(out, this.tablename);
209     out.writeLong(this.logSeqNum);
210     out.writeLong(this.writeTime);
211     out.writeByte(this.clusterId);
212   }
213 
214   public void readFields(DataInput in) throws IOException {
215     this.encodedRegionName = Bytes.readByteArray(in);
216     this.tablename = Bytes.readByteArray(in);
217     this.logSeqNum = in.readLong();
218     this.writeTime = in.readLong();
219     try {
220       this.clusterId = in.readByte();
221     } catch(EOFException e) {
222       // Means it's an old key, just continue
223     }
224   }
225 }