1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.migration;
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.Arrays;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.HTableDescriptor;
32 import org.apache.hadoop.hbase.KeyValue;
33 import org.apache.hadoop.hbase.KeyValue.KVComparator;
34 import org.apache.hadoop.hbase.util.Bytes;
35 import org.apache.hadoop.hbase.util.JenkinsHash;
36 import org.apache.hadoop.hbase.util.MD5Hash;
37 import org.apache.hadoop.io.VersionedWritable;
38 import org.apache.hadoop.io.WritableComparable;
39
40
41
42
43
44
45 public class HRegionInfo090x extends VersionedWritable implements
46 WritableComparable<HRegionInfo090x>{
47 private static final byte VERSION = 0;
48 private static final Log LOG = LogFactory.getLog(HRegionInfo090x.class);
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 private static final int ENC_SEPARATOR = '.';
77 public static final int MD5_HEX_LENGTH = 32;
78
79
80
81
82
83
84
85 private static boolean hasEncodedName(final byte[] regionName) {
86
87 if ((regionName.length >= 1)
88 && (regionName[regionName.length - 1] == ENC_SEPARATOR)) {
89
90 return true;
91 }
92 return false;
93 }
94
95
96
97
98
99 public static String encodeRegionName(final byte [] regionName) {
100 String encodedName;
101 if (hasEncodedName(regionName)) {
102
103
104 encodedName = Bytes.toString(regionName,
105 regionName.length - MD5_HEX_LENGTH - 1,
106 MD5_HEX_LENGTH);
107 } else {
108
109
110 int hashVal = Math.abs(JenkinsHash.getInstance().hash(regionName,
111 regionName.length, 0));
112 encodedName = String.valueOf(hashVal);
113 }
114 return encodedName;
115 }
116
117
118
119
120
121
122
123
124 public static String prettyPrint(final String encodedRegionName) {
125 if (encodedRegionName.equals("70236052")) {
126 return encodedRegionName + "/-ROOT-";
127 } else if (encodedRegionName.equals("1028785192")) {
128 return encodedRegionName + "/.META.";
129 }
130 return encodedRegionName;
131 }
132
133
134 public static final int DELIMITER = ',';
135
136
137 public static final HRegionInfo090x ROOT_REGIONINFO =
138 new HRegionInfo090x(0L, HTableDescriptor.ROOT_TABLEDESC);
139
140
141 public static final HRegionInfo090x FIRST_META_REGIONINFO =
142 new HRegionInfo090x(1L, HTableDescriptor.META_TABLEDESC);
143
144 private byte [] endKey = HConstants.EMPTY_BYTE_ARRAY;
145
146
147
148 private boolean offLine = false;
149 private long regionId = -1;
150 private transient byte [] regionName = HConstants.EMPTY_BYTE_ARRAY;
151 private String regionNameStr = "";
152 private boolean split = false;
153 private byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
154 protected HTableDescriptor tableDesc = null;
155 private int hashCode = -1;
156
157 public static final String NO_HASH = null;
158 private volatile String encodedName = NO_HASH;
159 private byte [] encodedNameAsBytes = null;
160
161 private void setHashCode() {
162 int result = Arrays.hashCode(this.regionName);
163 result ^= this.regionId;
164 result ^= Arrays.hashCode(this.startKey);
165 result ^= Arrays.hashCode(this.endKey);
166 result ^= Boolean.valueOf(this.offLine).hashCode();
167 result ^= this.tableDesc.hashCode();
168 this.hashCode = result;
169 }
170
171
172
173
174
175 private HRegionInfo090x(long regionId, HTableDescriptor tableDesc) {
176 super();
177 this.regionId = regionId;
178 this.tableDesc = tableDesc;
179
180
181 this.regionName = createRegionName(tableDesc.getName(), null,
182 regionId, false);
183 this.regionNameStr = Bytes.toStringBinary(this.regionName);
184 setHashCode();
185 }
186
187
188 public HRegionInfo090x() {
189 super();
190 this.tableDesc = new HTableDescriptor();
191 }
192
193
194
195
196
197
198
199
200
201 public HRegionInfo090x(final HTableDescriptor tableDesc, final byte[] startKey,
202 final byte[] endKey)
203 throws IllegalArgumentException {
204 this(tableDesc, startKey, endKey, false);
205 }
206
207
208
209
210
211
212
213
214
215
216
217 public HRegionInfo090x(HTableDescriptor tableDesc, final byte[] startKey,
218 final byte[] endKey, final boolean split)
219 throws IllegalArgumentException {
220 this(tableDesc, startKey, endKey, split, System.currentTimeMillis());
221 }
222
223
224
225
226
227
228
229
230
231
232
233
234 public HRegionInfo090x(HTableDescriptor tableDesc, final byte[] startKey,
235 final byte[] endKey, final boolean split, final long regionid)
236 throws IllegalArgumentException {
237 super();
238 if (tableDesc == null) {
239 throw new IllegalArgumentException("tableDesc cannot be null");
240 }
241 this.offLine = false;
242 this.regionId = regionid;
243 this.regionName = createRegionName(tableDesc.getName(), startKey, regionId, true);
244 this.regionNameStr = Bytes.toStringBinary(this.regionName);
245 this.split = split;
246 this.endKey = endKey == null? HConstants.EMPTY_END_ROW: endKey.clone();
247 this.startKey = startKey == null?
248 HConstants.EMPTY_START_ROW: startKey.clone();
249 this.tableDesc = tableDesc;
250 setHashCode();
251 }
252
253
254
255
256
257
258 public HRegionInfo090x(HRegionInfo090x other) {
259 super();
260 this.endKey = other.getEndKey();
261 this.offLine = other.isOffline();
262 this.regionId = other.getRegionId();
263 this.regionName = other.getRegionName();
264 this.regionNameStr = Bytes.toStringBinary(this.regionName);
265 this.split = other.isSplit();
266 this.startKey = other.getStartKey();
267 this.tableDesc = other.getTableDesc();
268 this.hashCode = other.hashCode();
269 this.encodedName = other.getEncodedName();
270 }
271
272
273
274
275
276
277
278
279
280
281 public static byte [] createRegionName(final byte [] tableName,
282 final byte [] startKey, final long regionid, boolean newFormat) {
283 return createRegionName(tableName, startKey, Long.toString(regionid), newFormat);
284 }
285
286
287
288
289
290
291
292
293
294
295 public static byte [] createRegionName(final byte [] tableName,
296 final byte [] startKey, final String id, boolean newFormat) {
297 return createRegionName(tableName, startKey, Bytes.toBytes(id), newFormat);
298 }
299
300
301
302
303
304
305
306
307
308
309 public static byte [] createRegionName(final byte [] tableName,
310 final byte [] startKey, final byte [] id, boolean newFormat) {
311 byte [] b = new byte [tableName.length + 2 + id.length +
312 (startKey == null? 0: startKey.length) +
313 (newFormat ? (MD5_HEX_LENGTH + 2) : 0)];
314
315 int offset = tableName.length;
316 System.arraycopy(tableName, 0, b, 0, offset);
317 b[offset++] = DELIMITER;
318 if (startKey != null && startKey.length > 0) {
319 System.arraycopy(startKey, 0, b, offset, startKey.length);
320 offset += startKey.length;
321 }
322 b[offset++] = DELIMITER;
323 System.arraycopy(id, 0, b, offset, id.length);
324 offset += id.length;
325
326 if (newFormat) {
327
328
329
330
331
332
333
334 String md5Hash = MD5Hash.getMD5AsHex(b, 0, offset);
335 byte [] md5HashBytes = Bytes.toBytes(md5Hash);
336
337 if (md5HashBytes.length != MD5_HEX_LENGTH) {
338 LOG.error("MD5-hash length mismatch: Expected=" + MD5_HEX_LENGTH +
339 "; Got=" + md5HashBytes.length);
340 }
341
342
343 b[offset++] = ENC_SEPARATOR;
344 System.arraycopy(md5HashBytes, 0, b, offset, MD5_HEX_LENGTH);
345 offset += MD5_HEX_LENGTH;
346 b[offset++] = ENC_SEPARATOR;
347 }
348
349 return b;
350 }
351
352
353
354
355
356
357 public static byte [] getTableName(byte [] regionName) {
358 int offset = -1;
359 for (int i = 0; i < regionName.length; i++) {
360 if (regionName[i] == DELIMITER) {
361 offset = i;
362 break;
363 }
364 }
365 byte [] tableName = new byte[offset];
366 System.arraycopy(regionName, 0, tableName, 0, offset);
367 return tableName;
368 }
369
370
371
372
373
374
375
376 public static byte [][] parseRegionName(final byte [] regionName)
377 throws IOException {
378 int offset = -1;
379 for (int i = 0; i < regionName.length; i++) {
380 if (regionName[i] == DELIMITER) {
381 offset = i;
382 break;
383 }
384 }
385 if(offset == -1) throw new IOException("Invalid regionName format");
386 byte [] tableName = new byte[offset];
387 System.arraycopy(regionName, 0, tableName, 0, offset);
388 offset = -1;
389 for (int i = regionName.length - 1; i > 0; i--) {
390 if(regionName[i] == DELIMITER) {
391 offset = i;
392 break;
393 }
394 }
395 if(offset == -1) throw new IOException("Invalid regionName format");
396 byte [] startKey = HConstants.EMPTY_BYTE_ARRAY;
397 if(offset != tableName.length + 1) {
398 startKey = new byte[offset - tableName.length - 1];
399 System.arraycopy(regionName, tableName.length + 1, startKey, 0,
400 offset - tableName.length - 1);
401 }
402 byte [] id = new byte[regionName.length - offset - 1];
403 System.arraycopy(regionName, offset + 1, id, 0,
404 regionName.length - offset - 1);
405 byte [][] elements = new byte[3][];
406 elements[0] = tableName;
407 elements[1] = startKey;
408 elements[2] = id;
409 return elements;
410 }
411
412
413 public long getRegionId(){
414 return regionId;
415 }
416
417
418
419
420
421 public byte [] getRegionName(){
422 return regionName;
423 }
424
425
426
427
428 public String getRegionNameAsString() {
429 if (hasEncodedName(this.regionName)) {
430
431 return this.regionNameStr;
432 }
433
434
435
436
437 return this.regionNameStr + "." + this.getEncodedName();
438 }
439
440
441 public synchronized String getEncodedName() {
442 if (this.encodedName == NO_HASH) {
443 this.encodedName = encodeRegionName(this.regionName);
444 }
445 return this.encodedName;
446 }
447
448 public synchronized byte [] getEncodedNameAsBytes() {
449 if (this.encodedNameAsBytes == null) {
450 this.encodedNameAsBytes = Bytes.toBytes(getEncodedName());
451 }
452 return this.encodedNameAsBytes;
453 }
454
455
456 public byte [] getStartKey(){
457 return startKey;
458 }
459
460
461 public byte [] getEndKey(){
462 return endKey;
463 }
464
465
466
467
468
469
470
471
472 public boolean containsRange(byte[] rangeStartKey, byte[] rangeEndKey) {
473 if (Bytes.compareTo(rangeStartKey, rangeEndKey) > 0) {
474 throw new IllegalArgumentException(
475 "Invalid range: " + Bytes.toStringBinary(rangeStartKey) +
476 " > " + Bytes.toStringBinary(rangeEndKey));
477 }
478
479 boolean firstKeyInRange = Bytes.compareTo(rangeStartKey, startKey) >= 0;
480 boolean lastKeyInRange =
481 Bytes.compareTo(rangeEndKey, endKey) < 0 ||
482 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY);
483 return firstKeyInRange && lastKeyInRange;
484 }
485
486
487
488
489 public boolean containsRow(byte[] row) {
490 return Bytes.compareTo(row, startKey) >= 0 &&
491 (Bytes.compareTo(row, endKey) < 0 ||
492 Bytes.equals(endKey, HConstants.EMPTY_BYTE_ARRAY));
493 }
494
495
496 public HTableDescriptor getTableDesc(){
497 return tableDesc;
498 }
499
500
501
502
503 public void setTableDesc(HTableDescriptor newDesc) {
504 this.tableDesc = newDesc;
505 }
506
507
508 public boolean isRootRegion() {
509 return this.tableDesc.isRootRegion();
510 }
511
512
513
514
515 public boolean isMetaTable() {
516 return this.tableDesc.isMetaTable();
517 }
518
519
520 public boolean isMetaRegion() {
521 return this.tableDesc.isMetaRegion();
522 }
523
524
525
526
527 public boolean isSplit() {
528 return this.split;
529 }
530
531
532
533
534 public void setSplit(boolean split) {
535 this.split = split;
536 }
537
538
539
540
541 public boolean isOffline() {
542 return this.offLine;
543 }
544
545
546
547
548
549
550 public void setOffline(boolean offLine) {
551 this.offLine = offLine;
552 }
553
554
555
556
557
558 public boolean isSplitParent() {
559 if (!isSplit()) return false;
560 if (!isOffline()) {
561 LOG.warn("Region is split but NOT offline: " + getRegionNameAsString());
562 }
563 return true;
564 }
565
566
567
568
569 @Override
570 public String toString() {
571 return "REGION => {" + HConstants.NAME + " => '" +
572 this.regionNameStr +
573 "', STARTKEY => '" +
574 Bytes.toStringBinary(this.startKey) + "', ENDKEY => '" +
575 Bytes.toStringBinary(this.endKey) +
576 "', ENCODED => " + getEncodedName() + "," +
577 (isOffline()? " OFFLINE => true,": "") +
578 (isSplit()? " SPLIT => true,": "") +
579 " TABLE => {" + this.tableDesc.toString() + "}";
580 }
581
582
583
584
585 @Override
586 public boolean equals(Object o) {
587 if (this == o) {
588 return true;
589 }
590 if (o == null) {
591 return false;
592 }
593 if (!(o instanceof HRegionInfo090x)) {
594 return false;
595 }
596 return this.compareTo((HRegionInfo090x)o) == 0;
597 }
598
599
600
601
602 @Override
603 public int hashCode() {
604 return this.hashCode;
605 }
606
607
608 @Override
609 public byte getVersion() {
610 return VERSION;
611 }
612
613
614
615
616
617 @Override
618 public void write(DataOutput out) throws IOException {
619 super.write(out);
620 Bytes.writeByteArray(out, endKey);
621 out.writeBoolean(offLine);
622 out.writeLong(regionId);
623 Bytes.writeByteArray(out, regionName);
624 out.writeBoolean(split);
625 Bytes.writeByteArray(out, startKey);
626 tableDesc.write(out);
627 out.writeInt(hashCode);
628 }
629
630 @Override
631 public void readFields(DataInput in) throws IOException {
632 super.readFields(in);
633 this.endKey = Bytes.readByteArray(in);
634 this.offLine = in.readBoolean();
635 this.regionId = in.readLong();
636 this.regionName = Bytes.readByteArray(in);
637 this.regionNameStr = Bytes.toStringBinary(this.regionName);
638 this.split = in.readBoolean();
639 this.startKey = Bytes.readByteArray(in);
640 try {
641 this.tableDesc.readFields(in);
642 } catch(EOFException eofe) {
643 throw new IOException("HTD not found in input buffer");
644 }
645 this.hashCode = in.readInt();
646 }
647
648
649
650
651
652 public int compareTo(HRegionInfo090x o) {
653 if (o == null) {
654 return 1;
655 }
656
657
658 int result = Bytes.compareTo(this.tableDesc.getName(), o.tableDesc.getName());
659 if (result != 0) {
660 return result;
661 }
662
663
664 result = Bytes.compareTo(this.startKey, o.startKey);
665 if (result != 0) {
666 return result;
667 }
668
669
670 return Bytes.compareTo(this.endKey, o.endKey);
671 }
672
673
674
675
676 public KVComparator getComparator() {
677 return isRootRegion()? KeyValue.ROOT_COMPARATOR: isMetaRegion()?
678 KeyValue.META_COMPARATOR: KeyValue.COMPARATOR;
679 }
680 }