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.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.Map;
30 import java.util.Set;
31 import java.util.TreeMap;
32
33 import org.apache.hadoop.fs.Path;
34 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
35 import org.apache.hadoop.hbase.io.hfile.Compression;
36 import org.apache.hadoop.hbase.regionserver.StoreFile;
37 import org.apache.hadoop.hbase.util.Bytes;
38 import org.apache.hadoop.io.WritableComparable;
39
40
41
42
43
44 public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
45
46
47
48
49
50 public static final byte TABLE_DESCRIPTOR_VERSION = 5;
51
52 private byte [] name = HConstants.EMPTY_BYTE_ARRAY;
53 private String nameAsString = "";
54
55
56 protected Map<ImmutableBytesWritable, ImmutableBytesWritable> values =
57 new HashMap<ImmutableBytesWritable, ImmutableBytesWritable>();
58
59 public static final String FAMILIES = "FAMILIES";
60 public static final ImmutableBytesWritable FAMILIES_KEY =
61 new ImmutableBytesWritable(Bytes.toBytes(FAMILIES));
62 public static final String MAX_FILESIZE = "MAX_FILESIZE";
63 public static final ImmutableBytesWritable MAX_FILESIZE_KEY =
64 new ImmutableBytesWritable(Bytes.toBytes(MAX_FILESIZE));
65 public static final String READONLY = "READONLY";
66 public static final ImmutableBytesWritable READONLY_KEY =
67 new ImmutableBytesWritable(Bytes.toBytes(READONLY));
68 public static final String MEMSTORE_FLUSHSIZE = "MEMSTORE_FLUSHSIZE";
69 public static final ImmutableBytesWritable MEMSTORE_FLUSHSIZE_KEY =
70 new ImmutableBytesWritable(Bytes.toBytes(MEMSTORE_FLUSHSIZE));
71 public static final String IS_ROOT = "IS_ROOT";
72 public static final ImmutableBytesWritable IS_ROOT_KEY =
73 new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT));
74 public static final String IS_META = "IS_META";
75
76 public static final ImmutableBytesWritable IS_META_KEY =
77 new ImmutableBytesWritable(Bytes.toBytes(IS_META));
78
79 public static final String DEFERRED_LOG_FLUSH = "DEFERRED_LOG_FLUSH";
80 public static final ImmutableBytesWritable DEFERRED_LOG_FLUSH_KEY =
81 new ImmutableBytesWritable(Bytes.toBytes(DEFERRED_LOG_FLUSH));
82
83
84
85
86
87 private static final ImmutableBytesWritable FALSE =
88 new ImmutableBytesWritable(Bytes.toBytes(Boolean.FALSE.toString()));
89 private static final ImmutableBytesWritable TRUE =
90 new ImmutableBytesWritable(Bytes.toBytes(Boolean.TRUE.toString()));
91
92 public static final boolean DEFAULT_READONLY = false;
93
94 public static final long DEFAULT_MEMSTORE_FLUSH_SIZE = 1024*1024*64L;
95
96 public static final long DEFAULT_MAX_FILESIZE = 1024*1024*256L;
97
98 public static final boolean DEFAULT_DEFERRED_LOG_FLUSH = true;
99
100 private volatile Boolean meta = null;
101 private volatile Boolean root = null;
102 private Boolean isDeferredLog = null;
103
104
105 public final Map<byte [], HColumnDescriptor> families =
106 new TreeMap<byte [], HColumnDescriptor>(Bytes.BYTES_RAWCOMPARATOR);
107
108
109
110
111
112 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families) {
113 this.name = name.clone();
114 this.nameAsString = Bytes.toString(this.name);
115 setMetaFlags(name);
116 for(HColumnDescriptor descriptor : families) {
117 this.families.put(descriptor.getName(), descriptor);
118 }
119 }
120
121
122
123
124
125 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families,
126 Map<ImmutableBytesWritable,ImmutableBytesWritable> values) {
127 this.name = name.clone();
128 this.nameAsString = Bytes.toString(this.name);
129 setMetaFlags(name);
130 for(HColumnDescriptor descriptor : families) {
131 this.families.put(descriptor.getName(), descriptor);
132 }
133 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry:
134 values.entrySet()) {
135 this.values.put(entry.getKey(), entry.getValue());
136 }
137 }
138
139
140
141
142
143
144
145 public HTableDescriptor() {
146 super();
147 }
148
149
150
151
152
153
154
155
156
157 public HTableDescriptor(final String name) {
158 this(Bytes.toBytes(name));
159 }
160
161
162
163
164
165
166
167
168
169 public HTableDescriptor(final byte [] name) {
170 super();
171 setMetaFlags(this.name);
172 this.name = this.isMetaRegion()? name: isLegalTableName(name);
173 this.nameAsString = Bytes.toString(this.name);
174 }
175
176
177
178
179
180
181
182
183 public HTableDescriptor(final HTableDescriptor desc) {
184 super();
185 this.name = desc.name.clone();
186 this.nameAsString = Bytes.toString(this.name);
187 setMetaFlags(this.name);
188 for (HColumnDescriptor c: desc.families.values()) {
189 this.families.put(c.getName(), new HColumnDescriptor(c));
190 }
191 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
192 desc.values.entrySet()) {
193 this.values.put(e.getKey(), e.getValue());
194 }
195 }
196
197
198
199
200
201
202 private void setMetaFlags(final byte [] name) {
203 setRootRegion(Bytes.equals(name, HConstants.ROOT_TABLE_NAME));
204 setMetaRegion(isRootRegion() ||
205 Bytes.equals(name, HConstants.META_TABLE_NAME));
206 }
207
208
209 public boolean isRootRegion() {
210 if (this.root == null) {
211 this.root = isSomething(IS_ROOT_KEY, false)? Boolean.TRUE: Boolean.FALSE;
212 }
213 return this.root.booleanValue();
214 }
215
216
217 protected void setRootRegion(boolean isRoot) {
218
219 values.put(IS_ROOT_KEY, isRoot? TRUE: FALSE);
220 }
221
222
223 public boolean isMetaRegion() {
224 if (this.meta == null) {
225 this.meta = calculateIsMetaRegion();
226 }
227 return this.meta.booleanValue();
228 }
229
230 private synchronized Boolean calculateIsMetaRegion() {
231 byte [] value = getValue(IS_META_KEY);
232 return (value != null)? Boolean.valueOf(Bytes.toString(value)): Boolean.FALSE;
233 }
234
235 private boolean isSomething(final ImmutableBytesWritable key,
236 final boolean valueIfNull) {
237 byte [] value = getValue(key);
238 if (value != null) {
239
240 return Boolean.valueOf(Bytes.toString(value)).booleanValue();
241 }
242 return valueIfNull;
243 }
244
245
246
247
248 protected void setMetaRegion(boolean isMeta) {
249 values.put(IS_META_KEY, isMeta? TRUE: FALSE);
250 }
251
252
253 public boolean isMetaTable() {
254 return isMetaRegion() && !isRootRegion();
255 }
256
257
258
259
260
261
262
263
264
265
266 public static byte [] isLegalTableName(final byte [] b) {
267 if (b == null || b.length <= 0) {
268 throw new IllegalArgumentException("Name is null or empty");
269 }
270 if (b[0] == '.' || b[0] == '-') {
271 throw new IllegalArgumentException("Illegal first character <" + b[0] +
272 "> at 0. User-space table names can only start with 'word " +
273 "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(b));
274 }
275 for (int i = 0; i < b.length; i++) {
276 if (Character.isLetterOrDigit(b[i]) || b[i] == '_' || b[i] == '-' ||
277 b[i] == '.') {
278 continue;
279 }
280 throw new IllegalArgumentException("Illegal character <" + b[i] +
281 "> at " + i + ". User-space table names can only contain " +
282 "'word characters': i.e. [a-zA-Z_0-9-.]: " + Bytes.toString(b));
283 }
284 return b;
285 }
286
287
288
289
290
291 public byte[] getValue(byte[] key) {
292 return getValue(new ImmutableBytesWritable(key));
293 }
294
295 private byte[] getValue(final ImmutableBytesWritable key) {
296 ImmutableBytesWritable ibw = values.get(key);
297 if (ibw == null)
298 return null;
299 return ibw.get();
300 }
301
302
303
304
305
306 public String getValue(String key) {
307 byte[] value = getValue(Bytes.toBytes(key));
308 if (value == null)
309 return null;
310 return Bytes.toString(value);
311 }
312
313
314
315
316 public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
317 return Collections.unmodifiableMap(values);
318 }
319
320
321
322
323
324 public void setValue(byte[] key, byte[] value) {
325 setValue(new ImmutableBytesWritable(key), value);
326 }
327
328
329
330
331
332 private void setValue(final ImmutableBytesWritable key,
333 final byte[] value) {
334 values.put(key, new ImmutableBytesWritable(value));
335 }
336
337
338
339
340
341 private void setValue(final ImmutableBytesWritable key,
342 final ImmutableBytesWritable value) {
343 values.put(key, value);
344 }
345
346
347
348
349
350 public void setValue(String key, String value) {
351 setValue(Bytes.toBytes(key), Bytes.toBytes(value));
352 }
353
354
355
356
357 public void remove(final byte [] key) {
358 values.remove(new ImmutableBytesWritable(key));
359 }
360
361
362
363
364 public boolean isReadOnly() {
365 return isSomething(READONLY_KEY, DEFAULT_READONLY);
366 }
367
368
369
370
371
372 public void setReadOnly(final boolean readOnly) {
373 setValue(READONLY_KEY, readOnly? TRUE: FALSE);
374 }
375
376
377
378
379 public synchronized boolean isDeferredLogFlush() {
380 if(this.isDeferredLog == null) {
381 this.isDeferredLog =
382 isSomething(DEFERRED_LOG_FLUSH_KEY, DEFAULT_DEFERRED_LOG_FLUSH);
383 }
384 return this.isDeferredLog;
385 }
386
387
388
389
390
391 public void setDeferredLogFlush(final boolean isDeferredLogFlush) {
392 setValue(DEFERRED_LOG_FLUSH_KEY, isDeferredLogFlush? TRUE: FALSE);
393 }
394
395
396 public byte [] getName() {
397 return name;
398 }
399
400
401 public String getNameAsString() {
402 return this.nameAsString;
403 }
404
405
406 public long getMaxFileSize() {
407 byte [] value = getValue(MAX_FILESIZE_KEY);
408 if (value != null)
409 return Long.valueOf(Bytes.toString(value)).longValue();
410 return HConstants.DEFAULT_MAX_FILE_SIZE;
411 }
412
413
414 public void setName(byte[] name) {
415 this.name = name;
416 }
417
418
419
420
421
422 public void setMaxFileSize(long maxFileSize) {
423 setValue(MAX_FILESIZE_KEY, Bytes.toBytes(Long.toString(maxFileSize)));
424 }
425
426
427
428
429 public long getMemStoreFlushSize() {
430 byte [] value = getValue(MEMSTORE_FLUSHSIZE_KEY);
431 if (value != null)
432 return Long.valueOf(Bytes.toString(value)).longValue();
433 return DEFAULT_MEMSTORE_FLUSH_SIZE;
434 }
435
436
437
438
439 public void setMemStoreFlushSize(long memstoreFlushSize) {
440 setValue(MEMSTORE_FLUSHSIZE_KEY,
441 Bytes.toBytes(Long.toString(memstoreFlushSize)));
442 }
443
444
445
446
447
448 public void addFamily(final HColumnDescriptor family) {
449 if (family.getName() == null || family.getName().length <= 0) {
450 throw new NullPointerException("Family name cannot be null or empty");
451 }
452 this.families.put(family.getName(), family);
453 }
454
455
456
457
458
459
460 public boolean hasFamily(final byte [] c) {
461 return families.containsKey(c);
462 }
463
464
465
466
467
468
469 @Override
470 public String toString() {
471 StringBuilder s = new StringBuilder();
472 s.append('{');
473 s.append(HConstants.NAME);
474 s.append(" => '");
475 s.append(Bytes.toString(name));
476 s.append("'");
477 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
478 values.entrySet()) {
479 String key = Bytes.toString(e.getKey().get());
480 String value = Bytes.toString(e.getValue().get());
481 if (key == null) {
482 continue;
483 }
484 String upperCase = key.toUpperCase();
485 if (upperCase.equals(IS_ROOT) || upperCase.equals(IS_META)) {
486
487 if (value.toLowerCase().equals(Boolean.FALSE.toString())) {
488 continue;
489 }
490 }
491 s.append(", ");
492 s.append(Bytes.toString(e.getKey().get()));
493 s.append(" => '");
494 s.append(Bytes.toString(e.getValue().get()));
495 s.append("'");
496 }
497 s.append(", ");
498 s.append(FAMILIES);
499 s.append(" => ");
500 s.append(families.values());
501 s.append('}');
502 return s.toString();
503 }
504
505
506
507
508 @Override
509 public boolean equals(Object obj) {
510 if (this == obj) {
511 return true;
512 }
513 if (obj == null) {
514 return false;
515 }
516 if (!(obj instanceof HTableDescriptor)) {
517 return false;
518 }
519 return compareTo((HTableDescriptor)obj) == 0;
520 }
521
522
523
524
525 @Override
526 public int hashCode() {
527 int result = Bytes.hashCode(this.name);
528 result ^= Byte.valueOf(TABLE_DESCRIPTOR_VERSION).hashCode();
529 if (this.families != null && this.families.size() > 0) {
530 for (HColumnDescriptor e: this.families.values()) {
531 result ^= e.hashCode();
532 }
533 }
534 result ^= values.hashCode();
535 return result;
536 }
537
538
539
540 public void readFields(DataInput in) throws IOException {
541 int version = in.readInt();
542 if (version < 3)
543 throw new IOException("versions < 3 are not supported (and never existed!?)");
544
545 name = Bytes.readByteArray(in);
546 nameAsString = Bytes.toString(this.name);
547 setRootRegion(in.readBoolean());
548 setMetaRegion(in.readBoolean());
549 values.clear();
550 int numVals = in.readInt();
551 for (int i = 0; i < numVals; i++) {
552 ImmutableBytesWritable key = new ImmutableBytesWritable();
553 ImmutableBytesWritable value = new ImmutableBytesWritable();
554 key.readFields(in);
555 value.readFields(in);
556 values.put(key, value);
557 }
558 families.clear();
559 int numFamilies = in.readInt();
560 for (int i = 0; i < numFamilies; i++) {
561 HColumnDescriptor c = new HColumnDescriptor();
562 c.readFields(in);
563 families.put(c.getName(), c);
564 }
565 if (version < 4) {
566 return;
567 }
568 }
569
570 public void write(DataOutput out) throws IOException {
571 out.writeInt(TABLE_DESCRIPTOR_VERSION);
572 Bytes.writeByteArray(out, name);
573 out.writeBoolean(isRootRegion());
574 out.writeBoolean(isMetaRegion());
575 out.writeInt(values.size());
576 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
577 values.entrySet()) {
578 e.getKey().write(out);
579 e.getValue().write(out);
580 }
581 out.writeInt(families.size());
582 for(Iterator<HColumnDescriptor> it = families.values().iterator();
583 it.hasNext(); ) {
584 HColumnDescriptor family = it.next();
585 family.write(out);
586 }
587 }
588
589
590
591 public int compareTo(final HTableDescriptor other) {
592 int result = Bytes.compareTo(this.name, other.name);
593 if (result == 0) {
594 result = families.size() - other.families.size();
595 }
596 if (result == 0 && families.size() != other.families.size()) {
597 result = Integer.valueOf(families.size()).compareTo(
598 Integer.valueOf(other.families.size()));
599 }
600 if (result == 0) {
601 for (Iterator<HColumnDescriptor> it = families.values().iterator(),
602 it2 = other.families.values().iterator(); it.hasNext(); ) {
603 result = it.next().compareTo(it2.next());
604 if (result != 0) {
605 break;
606 }
607 }
608 }
609 if (result == 0) {
610
611 result = this.values.hashCode() - other.values.hashCode();
612 if (result < 0)
613 result = -1;
614 else if (result > 0)
615 result = 1;
616 }
617 return result;
618 }
619
620
621
622
623 public Collection<HColumnDescriptor> getFamilies() {
624 return Collections.unmodifiableCollection(this.families.values());
625 }
626
627
628
629
630 public Set<byte[]> getFamiliesKeys() {
631 return Collections.unmodifiableSet(this.families.keySet());
632 }
633
634 public HColumnDescriptor[] getColumnFamilies() {
635 return getFamilies().toArray(new HColumnDescriptor[0]);
636 }
637
638
639
640
641
642
643 public HColumnDescriptor getFamily(final byte [] column) {
644 return this.families.get(column);
645 }
646
647
648
649
650
651
652 public HColumnDescriptor removeFamily(final byte [] column) {
653 return this.families.remove(column);
654 }
655
656
657
658
659
660
661 public static Path getTableDir(Path rootdir, final byte [] tableName) {
662 return new Path(rootdir, Bytes.toString(tableName));
663 }
664
665
666 public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor(
667 HConstants.ROOT_TABLE_NAME,
668 new HColumnDescriptor[] { new HColumnDescriptor(HConstants.CATALOG_FAMILY,
669 10,
670 Compression.Algorithm.NONE.getName(), true, true, 8 * 1024,
671 HConstants.FOREVER, StoreFile.BloomType.NONE.toString(),
672 HConstants.REPLICATION_SCOPE_LOCAL) });
673
674
675 public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor(
676 HConstants.META_TABLE_NAME, new HColumnDescriptor[] {
677 new HColumnDescriptor(HConstants.CATALOG_FAMILY,
678 10,
679 Compression.Algorithm.NONE.getName(), true, true, 8 * 1024,
680 HConstants.FOREVER, StoreFile.BloomType.NONE.toString(),
681 HConstants.REPLICATION_SCOPE_LOCAL),
682 new HColumnDescriptor(HConstants.CATALOG_HISTORIAN_FAMILY,
683 HConstants.ALL_VERSIONS, Compression.Algorithm.NONE.getName(),
684 false, false, 8 * 1024,
685 HConstants.WEEK_IN_SECONDS,StoreFile.BloomType.NONE.toString(),
686 HConstants.REPLICATION_SCOPE_LOCAL)});
687 }