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