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  
27  import org.apache.hadoop.hbase.HConstants;
28  import org.apache.hadoop.hbase.util.Bytes;
29  import org.apache.hadoop.io.WritableComparable;
30  
31  /**
32   * A Key for an entry in the change log.
33   *
34   * The log intermingles edits to many tables and rows, so each log entry
35   * identifies the appropriate table and row.  Within a table and row, they're
36   * also sorted.
37   *
38   * <p>Some Transactional edits (START, COMMIT, ABORT) will not have an
39   * associated row.
40   */
41  public class HLogKey implements WritableComparable<HLogKey> {
42    //  The encoded region name.
43    private byte [] encodedRegionName;
44    private byte [] tablename;
45    private long logSeqNum;
46    // Time at which this edit was written.
47    private long writeTime;
48  
49    private byte clusterId;
50  
51    /** Writable Consructor -- Do not use. */
52    public HLogKey() {
53      this(null, null, 0L, HConstants.LATEST_TIMESTAMP);
54    }
55  
56    /**
57     * Create the log key!
58     * We maintain the tablename mainly for debugging purposes.
59     * A regionName is always a sub-table object.
60     *
61     * @param encodedRegionName Encoded name of the region as returned by
62     * <code>HRegionInfo#getEncodedNameAsBytes()</code>.
63     * @param tablename   - name of table
64     * @param logSeqNum   - log sequence number
65     * @param now Time at which this edit was written.
66     */
67    public HLogKey(final byte [] encodedRegionName, final byte [] tablename,
68        long logSeqNum, final long now) {
69      this.encodedRegionName = encodedRegionName;
70      this.tablename = tablename;
71      this.logSeqNum = logSeqNum;
72      this.writeTime = now;
73      this.clusterId = HConstants.DEFAULT_CLUSTER_ID;
74    }
75  
76    /** @return encoded region name */
77    public byte [] getEncodedRegionName() {
78      return encodedRegionName;
79    }
80  
81    /** @return table name */
82    public byte [] getTablename() {
83      return tablename;
84    }
85  
86    /** @return log sequence number */
87    public long getLogSeqNum() {
88      return logSeqNum;
89    }
90  
91    void setLogSeqNum(long logSeqNum) {
92      this.logSeqNum = logSeqNum;
93    }
94  
95    /**
96     * @return the write time
97     */
98    public long getWriteTime() {
99      return this.writeTime;
100   }
101 
102   /**
103    * Get the id of the original cluster
104    * @return Cluster id.
105    */
106   public byte getClusterId() {
107     return clusterId;
108   }
109 
110   /**
111    * Set the cluster id of this key
112    * @param clusterId
113    */
114   public void setClusterId(byte clusterId) {
115     this.clusterId = clusterId;
116   }
117 
118   @Override
119   public String toString() {
120     return Bytes.toString(tablename) + "/" + Bytes.toString(encodedRegionName) + "/" +
121       logSeqNum;
122   }
123 
124   @Override
125   public boolean equals(Object obj) {
126     if (this == obj) {
127       return true;
128     }
129     if (obj == null || getClass() != obj.getClass()) {
130       return false;
131     }
132     return compareTo((HLogKey)obj) == 0;
133   }
134 
135   @Override
136   public int hashCode() {
137     int result = Bytes.hashCode(this.encodedRegionName);
138     result ^= this.logSeqNum;
139     result ^= this.writeTime;
140     result ^= this.clusterId;
141     return result;
142   }
143 
144   public int compareTo(HLogKey o) {
145     int result = Bytes.compareTo(this.encodedRegionName, o.encodedRegionName);
146     if (result == 0) {
147       if (this.logSeqNum < o.logSeqNum) {
148         result = -1;
149       } else if (this.logSeqNum > o.logSeqNum) {
150         result = 1;
151       }
152       if (result == 0) {
153         if (this.writeTime < o.writeTime) {
154           result = -1;
155         } else if (this.writeTime > o.writeTime) {
156           return 1;
157         }
158       }
159     }
160     return result;
161   }
162 
163   /**
164    * Drop this instance's tablename byte array and instead
165    * hold a reference to the provided tablename. This is not
166    * meant to be a general purpose setter - it's only used
167    * to collapse references to conserve memory.
168    */
169   void internTableName(byte []tablename) {
170     // We should not use this as a setter - only to swap
171     // in a new reference to the same table name.
172     assert Bytes.equals(tablename, this.tablename);
173     this.tablename = tablename;
174   }
175 
176   /**
177    * Drop this instance's region name byte array and instead
178    * hold a reference to the provided region name. This is not
179    * meant to be a general purpose setter - it's only used
180    * to collapse references to conserve memory.
181    */
182   void internEncodedRegionName(byte []encodedRegionName) {
183     // We should not use this as a setter - only to swap
184     // in a new reference to the same table name.
185     assert Bytes.equals(this.encodedRegionName, encodedRegionName);
186     this.encodedRegionName = encodedRegionName;
187   }
188 
189   public void write(DataOutput out) throws IOException {
190     Bytes.writeByteArray(out, this.encodedRegionName);
191     Bytes.writeByteArray(out, this.tablename);
192     out.writeLong(this.logSeqNum);
193     out.writeLong(this.writeTime);
194     out.writeByte(this.clusterId);
195   }
196 
197   public void readFields(DataInput in) throws IOException {
198     this.encodedRegionName = Bytes.readByteArray(in);
199     this.tablename = Bytes.readByteArray(in);
200     this.logSeqNum = in.readLong();
201     this.writeTime = in.readLong();
202     try {
203       this.clusterId = in.readByte();
204     } catch(EOFException e) {
205       // Means it's an old key, just continue
206     }
207   }
208 }