1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.ArrayList;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.NavigableMap;
31 import java.util.TreeMap;
32 import java.util.UUID;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36 import org.apache.hadoop.classification.InterfaceAudience;
37 import org.apache.hadoop.hbase.HConstants;
38 import org.apache.hadoop.hbase.HRegionInfo;
39 import org.apache.hadoop.hbase.TableName;
40 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
41 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.FamilyScope;
42 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.ScopeType;
43 import org.apache.hadoop.hbase.protobuf.generated.WALProtos.WALKey;
44 import org.apache.hadoop.hbase.util.Bytes;
45 import org.apache.hadoop.io.WritableComparable;
46 import org.apache.hadoop.io.WritableUtils;
47
48 import com.google.protobuf.ByteString;
49 import com.google.protobuf.ZeroCopyLiteralByteString;
50
51
52
53
54
55
56
57
58
59
60
61
62
63 @InterfaceAudience.Private
64 public class HLogKey implements WritableComparable<HLogKey> {
65 public static final Log LOG = LogFactory.getLog(HLogKey.class);
66
67
68
69 enum Version {
70 UNVERSIONED(0),
71
72 INITIAL(-1),
73
74
75 COMPRESSED(-2);
76
77 final int code;
78 static final Version[] byCode;
79 static {
80 byCode = Version.values();
81 for (int i = 0; i < byCode.length; i++) {
82 if (byCode[i].code != -1 * i) {
83 throw new AssertionError("Values in this enum should be descending by one");
84 }
85 }
86 }
87
88 Version(int code) {
89 this.code = code;
90 }
91
92 boolean atLeast(Version other) {
93 return code <= other.code;
94 }
95
96 static Version fromCode(int code) {
97 return byCode[code * -1];
98 }
99 }
100
101
102
103
104
105 private static final String PREFIX_CLUSTER_KEY = ".";
106
107
108 private static final Version VERSION = Version.COMPRESSED;
109
110
111 private byte [] encodedRegionName;
112 private TableName tablename;
113 private long logSeqNum;
114
115 private long writeTime;
116
117
118 private List<UUID> clusterIds;
119
120 private NavigableMap<byte[], Integer> scopes;
121
122 private CompressionContext compressionContext;
123
124 public HLogKey() {
125 init(null, null, 0L, HConstants.LATEST_TIMESTAMP,
126 new ArrayList<UUID>());
127 }
128
129 public HLogKey(final byte[] encodedRegionName, final TableName tablename, long logSeqNum,
130 final long now, UUID clusterId) {
131 List<UUID> clusterIds = new ArrayList<UUID>();
132 clusterIds.add(clusterId);
133 init(encodedRegionName, tablename, logSeqNum, now, clusterIds);
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public HLogKey(final byte [] encodedRegionName, final TableName tablename,
149 long logSeqNum, final long now, List<UUID> clusterIds){
150 init(encodedRegionName, tablename, logSeqNum, now, clusterIds);
151 }
152
153 protected void init(final byte [] encodedRegionName, final TableName tablename,
154 long logSeqNum, final long now, List<UUID> clusterIds) {
155 this.logSeqNum = logSeqNum;
156 this.writeTime = now;
157 this.clusterIds = clusterIds;
158 this.encodedRegionName = encodedRegionName;
159 this.tablename = tablename;
160 }
161
162
163
164
165 public void setCompressionContext(CompressionContext compressionContext) {
166 this.compressionContext = compressionContext;
167 }
168
169
170 public byte [] getEncodedRegionName() {
171 return encodedRegionName;
172 }
173
174
175 public TableName getTablename() {
176 return tablename;
177 }
178
179
180 public long getLogSeqNum() {
181 return this.logSeqNum;
182 }
183
184
185
186
187 public long getWriteTime() {
188 return this.writeTime;
189 }
190
191 public NavigableMap<byte[], Integer> getScopes() {
192 return scopes;
193 }
194
195 public void setScopes(NavigableMap<byte[], Integer> scopes) {
196 this.scopes = scopes;
197 }
198
199 public void readOlderScopes(NavigableMap<byte[], Integer> scopes) {
200 if (scopes != null) {
201 Iterator<Map.Entry<byte[], Integer>> iterator = scopes.entrySet()
202 .iterator();
203 while (iterator.hasNext()) {
204 Map.Entry<byte[], Integer> scope = iterator.next();
205 String key = Bytes.toString(scope.getKey());
206 if (key.startsWith(PREFIX_CLUSTER_KEY)) {
207 addClusterId(UUID.fromString(key.substring(PREFIX_CLUSTER_KEY
208 .length())));
209 iterator.remove();
210 }
211 }
212 if (scopes.size() > 0) {
213 this.scopes = scopes;
214 }
215 }
216 }
217
218
219
220
221 public void addClusterId(UUID clusterId) {
222 if (!clusterIds.contains(clusterId)) {
223 clusterIds.add(clusterId);
224 }
225 }
226
227
228
229
230 public List<UUID> getClusterIds() {
231 return clusterIds;
232 }
233
234
235
236
237
238 public UUID getOriginatingClusterId(){
239 return clusterIds.isEmpty() ? HConstants.DEFAULT_CLUSTER_ID : clusterIds.get(0);
240 }
241
242 @Override
243 public String toString() {
244 return tablename + "/" + Bytes.toString(encodedRegionName) + "/" +
245 logSeqNum;
246 }
247
248
249
250
251
252
253
254
255 public Map<String, Object> toStringMap() {
256 Map<String, Object> stringMap = new HashMap<String, Object>();
257 stringMap.put("table", tablename);
258 stringMap.put("region", Bytes.toStringBinary(encodedRegionName));
259 stringMap.put("sequence", logSeqNum);
260 return stringMap;
261 }
262
263 @Override
264 public boolean equals(Object obj) {
265 if (this == obj) {
266 return true;
267 }
268 if (obj == null || getClass() != obj.getClass()) {
269 return false;
270 }
271 return compareTo((HLogKey)obj) == 0;
272 }
273
274 @Override
275 public int hashCode() {
276 int result = Bytes.hashCode(this.encodedRegionName);
277 result ^= this.logSeqNum;
278 result ^= this.writeTime;
279 return result;
280 }
281
282 public int compareTo(HLogKey o) {
283 int result = Bytes.compareTo(this.encodedRegionName, o.encodedRegionName);
284 if (result == 0) {
285 if (this.logSeqNum < o.logSeqNum) {
286 result = -1;
287 } else if (this.logSeqNum > o.logSeqNum ) {
288 result = 1;
289 }
290 if (result == 0) {
291 if (this.writeTime < o.writeTime) {
292 result = -1;
293 } else if (this.writeTime > o.writeTime) {
294 return 1;
295 }
296 }
297 }
298
299 return result;
300 }
301
302
303
304
305
306
307
308 void internTableName(TableName tablename) {
309
310
311 assert tablename.equals(this.tablename);
312 this.tablename = tablename;
313 }
314
315
316
317
318
319
320
321 void internEncodedRegionName(byte []encodedRegionName) {
322
323
324 assert Bytes.equals(this.encodedRegionName, encodedRegionName);
325 this.encodedRegionName = encodedRegionName;
326 }
327
328 @Override
329 @Deprecated
330 public void write(DataOutput out) throws IOException {
331 LOG.warn("HLogKey is being serialized to writable - only expected in test code");
332 WritableUtils.writeVInt(out, VERSION.code);
333 if (compressionContext == null) {
334 Bytes.writeByteArray(out, this.encodedRegionName);
335 Bytes.writeByteArray(out, this.tablename.getName());
336 } else {
337 Compressor.writeCompressed(this.encodedRegionName, 0,
338 this.encodedRegionName.length, out,
339 compressionContext.regionDict);
340 Compressor.writeCompressed(this.tablename.getName(), 0, this.tablename.getName().length, out,
341 compressionContext.tableDict);
342 }
343 out.writeLong(this.logSeqNum);
344 out.writeLong(this.writeTime);
345
346
347 Iterator<UUID> iterator = clusterIds.iterator();
348 if(iterator.hasNext()){
349 out.writeBoolean(true);
350 UUID clusterId = iterator.next();
351 out.writeLong(clusterId.getMostSignificantBits());
352 out.writeLong(clusterId.getLeastSignificantBits());
353 } else {
354 out.writeBoolean(false);
355 }
356 }
357
358 @Override
359 public void readFields(DataInput in) throws IOException {
360 Version version = Version.UNVERSIONED;
361
362
363
364
365
366
367
368
369 this.scopes = null;
370 int len = WritableUtils.readVInt(in);
371 byte[] tablenameBytes = null;
372 if (len < 0) {
373
374 version = Version.fromCode(len);
375
376
377 if (compressionContext == null || !version.atLeast(Version.COMPRESSED)) {
378 len = WritableUtils.readVInt(in);
379 }
380 }
381 if (compressionContext == null || !version.atLeast(Version.COMPRESSED)) {
382 this.encodedRegionName = new byte[len];
383 in.readFully(this.encodedRegionName);
384 tablenameBytes = Bytes.readByteArray(in);
385 } else {
386 this.encodedRegionName = Compressor.readCompressed(in, compressionContext.regionDict);
387 tablenameBytes = Compressor.readCompressed(in, compressionContext.tableDict);
388 }
389
390 this.logSeqNum = in.readLong();
391 this.writeTime = in.readLong();
392
393 this.clusterIds.clear();
394 if (version.atLeast(Version.INITIAL)) {
395 if (in.readBoolean()) {
396
397
398 clusterIds.add(new UUID(in.readLong(), in.readLong()));
399 }
400 } else {
401 try {
402
403 in.readByte();
404 } catch(EOFException e) {
405
406 }
407 }
408 try {
409 this.tablename = TableName.valueOf(tablenameBytes);
410 } catch (IllegalArgumentException iae) {
411 if (Bytes.toString(tablenameBytes).equals(TableName.OLD_META_STR)) {
412
413 LOG.info("Got an old .META. edit, continuing with new format ");
414 this.tablename = TableName.META_TABLE_NAME;
415 this.encodedRegionName = HRegionInfo.FIRST_META_REGIONINFO.getEncodedNameAsBytes();
416 } else if (Bytes.toString(tablenameBytes).equals(TableName.OLD_ROOT_STR)) {
417 this.tablename = TableName.OLD_ROOT_TABLE_NAME;
418 throw iae;
419 } else throw iae;
420 }
421
422 }
423
424 public WALKey.Builder getBuilder(
425 WALCellCodec.ByteStringCompressor compressor) throws IOException {
426 WALKey.Builder builder = WALKey.newBuilder();
427 if (compressionContext == null) {
428 builder.setEncodedRegionName(ZeroCopyLiteralByteString.wrap(this.encodedRegionName));
429 builder.setTableName(ZeroCopyLiteralByteString.wrap(this.tablename.getName()));
430 } else {
431 builder.setEncodedRegionName(
432 compressor.compress(this.encodedRegionName, compressionContext.regionDict));
433 builder.setTableName(compressor.compress(this.tablename.getName(),
434 compressionContext.tableDict));
435 }
436 builder.setLogSequenceNumber(this.logSeqNum);
437 builder.setWriteTime(writeTime);
438 HBaseProtos.UUID.Builder uuidBuilder = HBaseProtos.UUID.newBuilder();
439 for (UUID clusterId : clusterIds) {
440 uuidBuilder.setLeastSigBits(clusterId.getLeastSignificantBits());
441 uuidBuilder.setMostSigBits(clusterId.getMostSignificantBits());
442 builder.addClusterIds(uuidBuilder.build());
443 }
444 if (scopes != null) {
445 for (Map.Entry<byte[], Integer> e : scopes.entrySet()) {
446 ByteString family = (compressionContext == null) ? ZeroCopyLiteralByteString.wrap(e.getKey())
447 : compressor.compress(e.getKey(), compressionContext.familyDict);
448 builder.addScopes(FamilyScope.newBuilder()
449 .setFamily(family).setScopeType(ScopeType.valueOf(e.getValue())));
450 }
451 }
452 return builder;
453 }
454
455 public void readFieldsFromPb(
456 WALKey walKey, WALCellCodec.ByteStringUncompressor uncompressor) throws IOException {
457 if (this.compressionContext != null) {
458 this.encodedRegionName = uncompressor.uncompress(
459 walKey.getEncodedRegionName(), compressionContext.regionDict);
460 byte[] tablenameBytes = uncompressor.uncompress(
461 walKey.getTableName(), compressionContext.tableDict);
462 this.tablename = TableName.valueOf(tablenameBytes);
463 } else {
464 this.encodedRegionName = walKey.getEncodedRegionName().toByteArray();
465 this.tablename = TableName.valueOf(walKey.getTableName().toByteArray());
466 }
467 clusterIds.clear();
468 if (walKey.hasClusterId()) {
469
470
471 clusterIds.add(new UUID(walKey.getClusterId().getMostSigBits(), walKey.getClusterId()
472 .getLeastSigBits()));
473 }
474 for (HBaseProtos.UUID clusterId : walKey.getClusterIdsList()) {
475 clusterIds.add(new UUID(clusterId.getMostSigBits(), clusterId.getLeastSigBits()));
476 }
477 this.scopes = null;
478 if (walKey.getScopesCount() > 0) {
479 this.scopes = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
480 for (FamilyScope scope : walKey.getScopesList()) {
481 byte[] family = (compressionContext == null) ? scope.getFamily().toByteArray() :
482 uncompressor.uncompress(scope.getFamily(), compressionContext.familyDict);
483 this.scopes.put(family, scope.getScopeType().getNumber());
484 }
485 }
486 this.logSeqNum = walKey.getLogSequenceNumber();
487 this.writeTime = walKey.getWriteTime();
488 }
489 }