1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Set;
33 import java.util.TreeMap;
34 import java.util.TreeSet;
35 import java.util.regex.Matcher;
36
37 import org.apache.hadoop.classification.InterfaceAudience;
38 import org.apache.hadoop.classification.InterfaceStability;
39 import org.apache.hadoop.fs.Path;
40 import org.apache.hadoop.hbase.exceptions.DeserializationException;
41 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
42 import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
43 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.BytesBytesPair;
44 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ColumnFamilySchema;
45 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
46 import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.TableSchema;
47 import org.apache.hadoop.hbase.regionserver.BloomType;
48 import org.apache.hadoop.hbase.security.User;
49 import org.apache.hadoop.hbase.util.Bytes;
50 import org.apache.hadoop.hbase.util.Writables;
51 import org.apache.hadoop.io.WritableComparable;
52
53 import com.google.protobuf.ByteString;
54 import com.google.protobuf.InvalidProtocolBufferException;
55
56
57
58
59
60
61
62 @InterfaceAudience.Public
63 @InterfaceStability.Evolving
64 public class HTableDescriptor implements WritableComparable<HTableDescriptor> {
65
66
67
68
69
70
71
72
73
74 private static final byte TABLE_DESCRIPTOR_VERSION = 7;
75
76 private byte [] name = HConstants.EMPTY_BYTE_ARRAY;
77
78 private String nameAsString = "";
79
80
81
82
83
84
85 private final Map<ImmutableBytesWritable, ImmutableBytesWritable> values =
86 new HashMap<ImmutableBytesWritable, ImmutableBytesWritable>();
87
88
89
90
91
92
93 private final Map<String, String> configuration = new HashMap<String, String>();
94
95 public static final String SPLIT_POLICY = "SPLIT_POLICY";
96
97
98
99
100
101
102
103
104 public static final String MAX_FILESIZE = "MAX_FILESIZE";
105 private static final ImmutableBytesWritable MAX_FILESIZE_KEY =
106 new ImmutableBytesWritable(Bytes.toBytes(MAX_FILESIZE));
107
108 public static final String OWNER = "OWNER";
109 public static final ImmutableBytesWritable OWNER_KEY =
110 new ImmutableBytesWritable(Bytes.toBytes(OWNER));
111
112
113
114
115
116
117
118 public static final String READONLY = "READONLY";
119 private static final ImmutableBytesWritable READONLY_KEY =
120 new ImmutableBytesWritable(Bytes.toBytes(READONLY));
121
122
123
124
125
126
127
128
129 public static final String MEMSTORE_FLUSHSIZE = "MEMSTORE_FLUSHSIZE";
130 private static final ImmutableBytesWritable MEMSTORE_FLUSHSIZE_KEY =
131 new ImmutableBytesWritable(Bytes.toBytes(MEMSTORE_FLUSHSIZE));
132
133
134
135
136
137
138
139 public static final String IS_ROOT = "IS_ROOT";
140 private static final ImmutableBytesWritable IS_ROOT_KEY =
141 new ImmutableBytesWritable(Bytes.toBytes(IS_ROOT));
142
143
144
145
146
147
148
149
150 public static final String IS_META = "IS_META";
151 private static final ImmutableBytesWritable IS_META_KEY =
152 new ImmutableBytesWritable(Bytes.toBytes(IS_META));
153
154
155
156
157
158 public static final String DEFERRED_LOG_FLUSH = "DEFERRED_LOG_FLUSH";
159 private static final ImmutableBytesWritable DEFERRED_LOG_FLUSH_KEY =
160 new ImmutableBytesWritable(Bytes.toBytes(DEFERRED_LOG_FLUSH));
161
162
163
164
165
166
167 private static final ImmutableBytesWritable FALSE =
168 new ImmutableBytesWritable(Bytes.toBytes(Boolean.FALSE.toString()));
169
170 private static final ImmutableBytesWritable TRUE =
171 new ImmutableBytesWritable(Bytes.toBytes(Boolean.TRUE.toString()));
172
173 private static final boolean DEFAULT_DEFERRED_LOG_FLUSH = false;
174
175
176
177
178 public static final boolean DEFAULT_READONLY = false;
179
180
181
182
183
184 public static final long DEFAULT_MEMSTORE_FLUSH_SIZE = 1024*1024*128L;
185
186 private final static Map<String, String> DEFAULT_VALUES
187 = new HashMap<String, String>();
188 private final static Set<ImmutableBytesWritable> RESERVED_KEYWORDS
189 = new HashSet<ImmutableBytesWritable>();
190 static {
191 DEFAULT_VALUES.put(MAX_FILESIZE,
192 String.valueOf(HConstants.DEFAULT_MAX_FILE_SIZE));
193 DEFAULT_VALUES.put(READONLY, String.valueOf(DEFAULT_READONLY));
194 DEFAULT_VALUES.put(MEMSTORE_FLUSHSIZE,
195 String.valueOf(DEFAULT_MEMSTORE_FLUSH_SIZE));
196 DEFAULT_VALUES.put(DEFERRED_LOG_FLUSH,
197 String.valueOf(DEFAULT_DEFERRED_LOG_FLUSH));
198 for (String s : DEFAULT_VALUES.keySet()) {
199 RESERVED_KEYWORDS.add(new ImmutableBytesWritable(Bytes.toBytes(s)));
200 }
201 RESERVED_KEYWORDS.add(IS_ROOT_KEY);
202 RESERVED_KEYWORDS.add(IS_META_KEY);
203 }
204
205
206
207
208 private volatile Boolean meta = null;
209
210
211
212 private volatile Boolean root = null;
213
214
215
216 private Boolean deferredLog = null;
217
218
219
220
221 private final Map<byte [], HColumnDescriptor> families =
222 new TreeMap<byte [], HColumnDescriptor>(Bytes.BYTES_RAWCOMPARATOR);
223
224
225
226
227
228 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families) {
229 this.name = name.clone();
230 this.nameAsString = Bytes.toString(this.name);
231 setMetaFlags(name);
232 for(HColumnDescriptor descriptor : families) {
233 this.families.put(descriptor.getName(), descriptor);
234 }
235 }
236
237
238
239
240
241 protected HTableDescriptor(final byte [] name, HColumnDescriptor[] families,
242 Map<ImmutableBytesWritable,ImmutableBytesWritable> values) {
243 this.name = name.clone();
244 this.nameAsString = Bytes.toString(this.name);
245 setMetaFlags(name);
246 for(HColumnDescriptor descriptor : families) {
247 this.families.put(descriptor.getName(), descriptor);
248 }
249 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> entry:
250 values.entrySet()) {
251 setValue(entry.getKey(), entry.getValue());
252 }
253 }
254
255
256
257
258
259
260
261 @Deprecated
262 public HTableDescriptor() {
263 super();
264 }
265
266
267
268
269
270
271
272
273
274 public HTableDescriptor(final String name) {
275 this(Bytes.toBytes(name));
276 }
277
278
279
280
281
282
283
284
285
286 public HTableDescriptor(final byte [] name) {
287 super();
288 setMetaFlags(this.name);
289 this.name = this.isMetaRegion()? name: isLegalTableName(name);
290 this.nameAsString = Bytes.toString(this.name);
291 }
292
293
294
295
296
297
298
299
300 public HTableDescriptor(final HTableDescriptor desc) {
301 super();
302 this.name = desc.name.clone();
303 this.nameAsString = Bytes.toString(this.name);
304 setMetaFlags(this.name);
305 for (HColumnDescriptor c: desc.families.values()) {
306 this.families.put(c.getName(), new HColumnDescriptor(c));
307 }
308 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
309 desc.values.entrySet()) {
310 setValue(e.getKey(), e.getValue());
311 }
312 for (Map.Entry<String, String> e : desc.configuration.entrySet()) {
313 this.configuration.put(e.getKey(), e.getValue());
314 }
315 }
316
317
318
319
320
321
322
323
324 private void setMetaFlags(final byte [] name) {
325 setRootRegion(Bytes.equals(name, HConstants.ROOT_TABLE_NAME));
326 setMetaRegion(isRootRegion() ||
327 Bytes.equals(name, HConstants.META_TABLE_NAME));
328 }
329
330
331
332
333
334
335 public boolean isRootRegion() {
336 if (this.root == null) {
337 this.root = isSomething(IS_ROOT_KEY, false)? Boolean.TRUE: Boolean.FALSE;
338 }
339 return this.root.booleanValue();
340 }
341
342
343
344
345
346
347
348
349 protected void setRootRegion(boolean isRoot) {
350
351 setValue(IS_ROOT_KEY, isRoot? TRUE: FALSE);
352 }
353
354
355
356
357
358
359
360
361 public boolean isMetaRegion() {
362 if (this.meta == null) {
363 this.meta = calculateIsMetaRegion();
364 }
365 return this.meta.booleanValue();
366 }
367
368 private synchronized Boolean calculateIsMetaRegion() {
369 byte [] value = getValue(IS_META_KEY);
370 return (value != null)? Boolean.valueOf(Bytes.toString(value)): Boolean.FALSE;
371 }
372
373 private boolean isSomething(final ImmutableBytesWritable key,
374 final boolean valueIfNull) {
375 byte [] value = getValue(key);
376 if (value != null) {
377
378 return Boolean.valueOf(Bytes.toString(value));
379 }
380 return valueIfNull;
381 }
382
383
384
385
386
387
388
389
390
391 protected void setMetaRegion(boolean isMeta) {
392 setValue(IS_META_KEY, isMeta? TRUE: FALSE);
393 }
394
395
396
397
398
399
400 public boolean isMetaTable() {
401 return isMetaRegion() && !isRootRegion();
402 }
403
404
405
406
407
408
409
410
411 public static boolean isMetaTable(final byte [] tableName) {
412 return Bytes.equals(tableName, HConstants.ROOT_TABLE_NAME) ||
413 Bytes.equals(tableName, HConstants.META_TABLE_NAME);
414 }
415
416
417 public static final String VALID_USER_TABLE_REGEX = "(?:[a-zA-Z_0-9][a-zA-Z_0-9.-]*)";
418
419
420
421
422
423
424
425
426
427 public static byte [] isLegalTableName(final byte [] tableName) {
428 if (tableName == null || tableName.length <= 0) {
429 throw new IllegalArgumentException("Name is null or empty");
430 }
431 if (tableName[0] == '.' || tableName[0] == '-') {
432 throw new IllegalArgumentException("Illegal first character <" + tableName[0] +
433 "> at 0. User-space table names can only start with 'word " +
434 "characters': i.e. [a-zA-Z_0-9]: " + Bytes.toString(tableName));
435 }
436 if (HConstants.CLUSTER_ID_FILE_NAME.equalsIgnoreCase(Bytes
437 .toString(tableName))
438 || HConstants.SPLIT_LOGDIR_NAME.equalsIgnoreCase(Bytes
439 .toString(tableName))
440 || HConstants.VERSION_FILE_NAME.equalsIgnoreCase(Bytes
441 .toString(tableName))) {
442 throw new IllegalArgumentException(Bytes.toString(tableName)
443 + " conflicted with system reserved words");
444 }
445 for (int i = 0; i < tableName.length; i++) {
446 if (Character.isLetterOrDigit(tableName[i]) || tableName[i] == '_' ||
447 tableName[i] == '-' || tableName[i] == '.') {
448 continue;
449 }
450 throw new IllegalArgumentException("Illegal character <" + tableName[i] +
451 "> at " + i + ". User-space table names can only contain " +
452 "'word characters': i.e. [a-zA-Z_0-9-.]: " + Bytes.toString(tableName));
453 }
454 return tableName;
455 }
456
457
458
459
460
461
462
463
464 public byte[] getValue(byte[] key) {
465 return getValue(new ImmutableBytesWritable(key));
466 }
467
468 private byte[] getValue(final ImmutableBytesWritable key) {
469 ImmutableBytesWritable ibw = values.get(key);
470 if (ibw == null)
471 return null;
472 return ibw.get();
473 }
474
475
476
477
478
479
480
481
482 public String getValue(String key) {
483 byte[] value = getValue(Bytes.toBytes(key));
484 if (value == null)
485 return null;
486 return Bytes.toString(value);
487 }
488
489
490
491
492
493
494
495 public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
496
497 return Collections.unmodifiableMap(values);
498 }
499
500
501
502
503
504
505
506
507 public void setValue(byte[] key, byte[] value) {
508 setValue(new ImmutableBytesWritable(key), new ImmutableBytesWritable(value));
509 }
510
511
512
513
514
515 private void setValue(final ImmutableBytesWritable key,
516 final String value) {
517 setValue(key, new ImmutableBytesWritable(Bytes.toBytes(value)));
518 }
519
520
521
522
523
524 private void setValue(final ImmutableBytesWritable key,
525 final ImmutableBytesWritable value) {
526 values.put(key, value);
527 }
528
529
530
531
532
533
534
535
536 public void setValue(String key, String value) {
537 if (value == null) {
538 remove(key);
539 } else {
540 setValue(Bytes.toBytes(key), Bytes.toBytes(value));
541 }
542 }
543
544
545
546
547
548
549
550 public void remove(final String key) {
551 remove(new ImmutableBytesWritable(Bytes.toBytes(key)));
552 }
553
554
555
556
557
558
559
560 public void remove(ImmutableBytesWritable key) {
561 values.remove(key);
562 }
563
564
565
566
567
568
569
570 public boolean isReadOnly() {
571 return isSomething(READONLY_KEY, DEFAULT_READONLY);
572 }
573
574
575
576
577
578
579
580
581
582 public void setReadOnly(final boolean readOnly) {
583 setValue(READONLY_KEY, readOnly? TRUE: FALSE);
584 }
585
586
587
588
589
590
591
592
593 public synchronized boolean isDeferredLogFlush() {
594 if(this.deferredLog == null) {
595 this.deferredLog =
596 isSomething(DEFERRED_LOG_FLUSH_KEY, DEFAULT_DEFERRED_LOG_FLUSH);
597 }
598 return this.deferredLog;
599 }
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615 public synchronized void setDeferredLogFlush(final boolean isDeferredLogFlush) {
616 setValue(DEFERRED_LOG_FLUSH_KEY, isDeferredLogFlush? TRUE: FALSE);
617 this.deferredLog = isDeferredLogFlush;
618 }
619
620
621
622
623
624
625 public byte [] getName() {
626 return name;
627 }
628
629
630
631
632
633
634 public String getNameAsString() {
635 return this.nameAsString;
636 }
637
638
639
640
641
642
643
644
645
646 public String getRegionSplitPolicyClassName() {
647 return getValue(SPLIT_POLICY);
648 }
649
650
651
652
653
654
655 public void setName(byte[] name) {
656 this.name = name;
657 this.nameAsString = Bytes.toString(this.name);
658 setMetaFlags(this.name);
659 }
660
661
662
663
664
665
666
667
668
669
670 public long getMaxFileSize() {
671 byte [] value = getValue(MAX_FILESIZE_KEY);
672 if (value != null) {
673 return Long.parseLong(Bytes.toString(value));
674 }
675 return -1;
676 }
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693 public void setMaxFileSize(long maxFileSize) {
694 setValue(MAX_FILESIZE_KEY, Long.toString(maxFileSize));
695 }
696
697
698
699
700
701
702
703
704 public long getMemStoreFlushSize() {
705 byte [] value = getValue(MEMSTORE_FLUSHSIZE_KEY);
706 if (value != null) {
707 return Long.parseLong(Bytes.toString(value));
708 }
709 return -1;
710 }
711
712
713
714
715
716
717
718 public void setMemStoreFlushSize(long memstoreFlushSize) {
719 setValue(MEMSTORE_FLUSHSIZE_KEY, Long.toString(memstoreFlushSize));
720 }
721
722
723
724
725
726 public void addFamily(final HColumnDescriptor family) {
727 if (family.getName() == null || family.getName().length <= 0) {
728 throw new NullPointerException("Family name cannot be null or empty");
729 }
730 this.families.put(family.getName(), family);
731 }
732
733
734
735
736
737
738 public boolean hasFamily(final byte [] familyName) {
739 return families.containsKey(familyName);
740 }
741
742
743
744
745
746
747 @Override
748 public String toString() {
749 StringBuilder s = new StringBuilder();
750 s.append('\'').append(Bytes.toString(name)).append('\'');
751 s.append(getValues(true));
752 for (HColumnDescriptor f : families.values()) {
753 s.append(", ").append(f);
754 }
755 return s.toString();
756 }
757
758
759
760
761
762 public String toStringCustomizedValues() {
763 StringBuilder s = new StringBuilder();
764 s.append('\'').append(Bytes.toString(name)).append('\'');
765 s.append(getValues(false));
766 for(HColumnDescriptor hcd : families.values()) {
767 s.append(", ").append(hcd.toStringCustomizedValues());
768 }
769 return s.toString();
770 }
771
772 private StringBuilder getValues(boolean printDefaults) {
773 StringBuilder s = new StringBuilder();
774
775
776 Set<ImmutableBytesWritable> reservedKeys = new TreeSet<ImmutableBytesWritable>();
777 Set<ImmutableBytesWritable> userKeys = new TreeSet<ImmutableBytesWritable>();
778 for (ImmutableBytesWritable k : values.keySet()) {
779 if (k == null || k.get() == null) continue;
780 String key = Bytes.toString(k.get());
781
782 if (!RESERVED_KEYWORDS.contains(k) && !key.startsWith("coprocessor$")) {
783 userKeys.add(k);
784 continue;
785 }
786
787 String value = Bytes.toString(values.get(k).get());
788 if (key.equalsIgnoreCase(IS_ROOT) || key.equalsIgnoreCase(IS_META)) {
789 if (Boolean.valueOf(value) == false) continue;
790 }
791
792 if (printDefaults
793 || !DEFAULT_VALUES.containsKey(key)
794 || !DEFAULT_VALUES.get(key).equalsIgnoreCase(value)) {
795 reservedKeys.add(k);
796 }
797 }
798
799
800 boolean hasAttributes = !reservedKeys.isEmpty() || !userKeys.isEmpty();
801 if (!hasAttributes && configuration.isEmpty()) return s;
802
803 s.append(", {");
804
805 if (hasAttributes) {
806 s.append("TABLE_ATTRIBUTES => {");
807
808
809 boolean printCommaForAttr = false;
810 for (ImmutableBytesWritable k : reservedKeys) {
811 String key = Bytes.toString(k.get());
812 String value = Bytes.toString(values.get(k).get());
813 if (printCommaForAttr) s.append(", ");
814 printCommaForAttr = true;
815 s.append(key);
816 s.append(" => ");
817 s.append('\'').append(value).append('\'');
818 }
819
820 if (!userKeys.isEmpty()) {
821
822 if (printCommaForAttr) s.append(", ");
823 printCommaForAttr = true;
824 s.append(HConstants.METADATA).append(" => ");
825 s.append("{");
826 boolean printCommaForCfg = false;
827 for (ImmutableBytesWritable k : userKeys) {
828 String key = Bytes.toString(k.get());
829 String value = Bytes.toString(values.get(k).get());
830 if (printCommaForCfg) s.append(", ");
831 printCommaForCfg = true;
832 s.append('\'').append(key).append('\'');
833 s.append(" => ");
834 s.append('\'').append(value).append('\'');
835 }
836 s.append("}");
837 }
838 }
839
840
841 if (!configuration.isEmpty()) {
842 if (hasAttributes) {
843 s.append(", ");
844 }
845 s.append(HConstants.CONFIGURATION).append(" => ");
846 s.append('{');
847 boolean printCommaForConfig = false;
848 for (Map.Entry<String, String> e : configuration.entrySet()) {
849 if (printCommaForConfig) s.append(", ");
850 printCommaForConfig = true;
851 s.append('\'').append(e.getKey()).append('\'');
852 s.append(" => ");
853 s.append('\'').append(e.getValue()).append('\'');
854 }
855 s.append("}");
856 }
857 s.append("}");
858 return s;
859 }
860
861
862
863
864
865
866
867
868
869
870 @Override
871 public boolean equals(Object obj) {
872 if (this == obj) {
873 return true;
874 }
875 if (obj == null) {
876 return false;
877 }
878 if (!(obj instanceof HTableDescriptor)) {
879 return false;
880 }
881 return compareTo((HTableDescriptor)obj) == 0;
882 }
883
884
885
886
887 @Override
888 public int hashCode() {
889 int result = Bytes.hashCode(this.name);
890 result ^= Byte.valueOf(TABLE_DESCRIPTOR_VERSION).hashCode();
891 if (this.families != null && this.families.size() > 0) {
892 for (HColumnDescriptor e: this.families.values()) {
893 result ^= e.hashCode();
894 }
895 }
896 result ^= values.hashCode();
897 result ^= configuration.hashCode();
898 return result;
899 }
900
901
902
903
904
905
906 @Deprecated
907 @Override
908 public void readFields(DataInput in) throws IOException {
909 int version = in.readInt();
910 if (version < 3)
911 throw new IOException("versions < 3 are not supported (and never existed!?)");
912
913 name = Bytes.readByteArray(in);
914 nameAsString = Bytes.toString(this.name);
915 setRootRegion(in.readBoolean());
916 setMetaRegion(in.readBoolean());
917 values.clear();
918 configuration.clear();
919 int numVals = in.readInt();
920 for (int i = 0; i < numVals; i++) {
921 ImmutableBytesWritable key = new ImmutableBytesWritable();
922 ImmutableBytesWritable value = new ImmutableBytesWritable();
923 key.readFields(in);
924 value.readFields(in);
925 setValue(key, value);
926 }
927 families.clear();
928 int numFamilies = in.readInt();
929 for (int i = 0; i < numFamilies; i++) {
930 HColumnDescriptor c = new HColumnDescriptor();
931 c.readFields(in);
932 families.put(c.getName(), c);
933 }
934 if (version >= 7) {
935 int numConfigs = in.readInt();
936 for (int i = 0; i < numConfigs; i++) {
937 ImmutableBytesWritable key = new ImmutableBytesWritable();
938 ImmutableBytesWritable value = new ImmutableBytesWritable();
939 key.readFields(in);
940 value.readFields(in);
941 configuration.put(
942 Bytes.toString(key.get(), key.getOffset(), key.getLength()),
943 Bytes.toString(value.get(), value.getOffset(), value.getLength()));
944 }
945 }
946 }
947
948
949
950
951
952
953
954 @Deprecated
955 @Override
956 public void write(DataOutput out) throws IOException {
957 out.writeInt(TABLE_DESCRIPTOR_VERSION);
958 Bytes.writeByteArray(out, name);
959 out.writeBoolean(isRootRegion());
960 out.writeBoolean(isMetaRegion());
961 out.writeInt(values.size());
962 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
963 values.entrySet()) {
964 e.getKey().write(out);
965 e.getValue().write(out);
966 }
967 out.writeInt(families.size());
968 for(Iterator<HColumnDescriptor> it = families.values().iterator();
969 it.hasNext(); ) {
970 HColumnDescriptor family = it.next();
971 family.write(out);
972 }
973 out.writeInt(configuration.size());
974 for (Map.Entry<String, String> e : configuration.entrySet()) {
975 new ImmutableBytesWritable(Bytes.toBytes(e.getKey())).write(out);
976 new ImmutableBytesWritable(Bytes.toBytes(e.getValue())).write(out);
977 }
978 }
979
980
981
982
983
984
985
986
987
988
989 @Override
990 public int compareTo(final HTableDescriptor other) {
991 int result = Bytes.compareTo(this.name, other.name);
992 if (result == 0) {
993 result = families.size() - other.families.size();
994 }
995 if (result == 0 && families.size() != other.families.size()) {
996 result = Integer.valueOf(families.size()).compareTo(
997 Integer.valueOf(other.families.size()));
998 }
999 if (result == 0) {
1000 for (Iterator<HColumnDescriptor> it = families.values().iterator(),
1001 it2 = other.families.values().iterator(); it.hasNext(); ) {
1002 result = it.next().compareTo(it2.next());
1003 if (result != 0) {
1004 break;
1005 }
1006 }
1007 }
1008 if (result == 0) {
1009
1010 result = this.values.hashCode() - other.values.hashCode();
1011 if (result < 0)
1012 result = -1;
1013 else if (result > 0)
1014 result = 1;
1015 }
1016 if (result == 0) {
1017 result = this.configuration.hashCode() - other.configuration.hashCode();
1018 if (result < 0)
1019 result = -1;
1020 else if (result > 0)
1021 result = 1;
1022 }
1023 return result;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033 public Collection<HColumnDescriptor> getFamilies() {
1034 return Collections.unmodifiableCollection(this.families.values());
1035 }
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 public Set<byte[]> getFamiliesKeys() {
1046 return Collections.unmodifiableSet(this.families.keySet());
1047 }
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057 public HColumnDescriptor[] getColumnFamilies() {
1058 Collection<HColumnDescriptor> hColumnDescriptors = getFamilies();
1059 return hColumnDescriptors.toArray(new HColumnDescriptor[hColumnDescriptors.size()]);
1060 }
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 public HColumnDescriptor getFamily(final byte [] column) {
1072 return this.families.get(column);
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084 public HColumnDescriptor removeFamily(final byte [] column) {
1085 return this.families.remove(column);
1086 }
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099 public void addCoprocessor(String className) throws IOException {
1100 addCoprocessor(className, null, Coprocessor.PRIORITY_USER, null);
1101 }
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118 public void addCoprocessor(String className, Path jarFilePath,
1119 int priority, final Map<String, String> kvs)
1120 throws IOException {
1121 if (hasCoprocessor(className)) {
1122 throw new IOException("Coprocessor " + className + " already exists.");
1123 }
1124
1125 StringBuilder kvString = new StringBuilder();
1126 if (kvs != null) {
1127 for (Map.Entry<String, String> e: kvs.entrySet()) {
1128 if (!e.getKey().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_KEY_PATTERN)) {
1129 throw new IOException("Illegal parameter key = " + e.getKey());
1130 }
1131 if (!e.getValue().matches(HConstants.CP_HTD_ATTR_VALUE_PARAM_VALUE_PATTERN)) {
1132 throw new IOException("Illegal parameter (" + e.getKey() +
1133 ") value = " + e.getValue());
1134 }
1135 if (kvString.length() != 0) {
1136 kvString.append(',');
1137 }
1138 kvString.append(e.getKey());
1139 kvString.append('=');
1140 kvString.append(e.getValue());
1141 }
1142 }
1143
1144
1145 int maxCoprocessorNumber = 0;
1146 Matcher keyMatcher;
1147 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
1148 this.values.entrySet()) {
1149 keyMatcher =
1150 HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(
1151 Bytes.toString(e.getKey().get()));
1152 if (!keyMatcher.matches()) {
1153 continue;
1154 }
1155 maxCoprocessorNumber = Math.max(Integer.parseInt(keyMatcher.group(1)),
1156 maxCoprocessorNumber);
1157 }
1158 maxCoprocessorNumber++;
1159
1160 String key = "coprocessor$" + Integer.toString(maxCoprocessorNumber);
1161 String value = ((jarFilePath == null)? "" : jarFilePath.toString()) +
1162 "|" + className + "|" + Integer.toString(priority) + "|" +
1163 kvString.toString();
1164 setValue(key, value);
1165 }
1166
1167
1168
1169
1170
1171
1172
1173
1174 public boolean hasCoprocessor(String className) {
1175 Matcher keyMatcher;
1176 Matcher valueMatcher;
1177 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
1178 this.values.entrySet()) {
1179 keyMatcher =
1180 HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(
1181 Bytes.toString(e.getKey().get()));
1182 if (!keyMatcher.matches()) {
1183 continue;
1184 }
1185 valueMatcher =
1186 HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(
1187 Bytes.toString(e.getValue().get()));
1188 if (!valueMatcher.matches()) {
1189 continue;
1190 }
1191
1192 String clazz = valueMatcher.group(2).trim();
1193 if (clazz.equals(className.trim())) {
1194 return true;
1195 }
1196 }
1197 return false;
1198 }
1199
1200
1201
1202
1203
1204
1205 public List<String> getCoprocessors() {
1206 List<String> result = new ArrayList<String>();
1207 Matcher keyMatcher;
1208 Matcher valueMatcher;
1209 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e : this.values.entrySet()) {
1210 keyMatcher = HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e.getKey().get()));
1211 if (!keyMatcher.matches()) {
1212 continue;
1213 }
1214 valueMatcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
1215 .toString(e.getValue().get()));
1216 if (!valueMatcher.matches()) {
1217 continue;
1218 }
1219 result.add(valueMatcher.group(2).trim());
1220 }
1221 return result;
1222 }
1223
1224
1225
1226
1227
1228 public void removeCoprocessor(String className) {
1229 ImmutableBytesWritable match = null;
1230 Matcher keyMatcher;
1231 Matcher valueMatcher;
1232 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e : this.values
1233 .entrySet()) {
1234 keyMatcher = HConstants.CP_HTD_ATTR_KEY_PATTERN.matcher(Bytes.toString(e
1235 .getKey().get()));
1236 if (!keyMatcher.matches()) {
1237 continue;
1238 }
1239 valueMatcher = HConstants.CP_HTD_ATTR_VALUE_PATTERN.matcher(Bytes
1240 .toString(e.getValue().get()));
1241 if (!valueMatcher.matches()) {
1242 continue;
1243 }
1244
1245 String clazz = valueMatcher.group(2).trim();
1246
1247 if (clazz.equals(className.trim())) {
1248 match = e.getKey();
1249 break;
1250 }
1251 }
1252
1253 if (match != null)
1254 remove(match);
1255 }
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265 public static Path getTableDir(Path rootdir, final byte [] tableName) {
1266 return new Path(rootdir, Bytes.toString(tableName));
1267 }
1268
1269
1270 public static final HTableDescriptor ROOT_TABLEDESC = new HTableDescriptor(
1271 HConstants.ROOT_TABLE_NAME,
1272 new HColumnDescriptor[] {
1273 new HColumnDescriptor(HConstants.CATALOG_FAMILY)
1274
1275 .setMaxVersions(10)
1276 .setInMemory(true)
1277 .setBlocksize(8 * 1024)
1278 .setTimeToLive(HConstants.FOREVER)
1279 .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
1280 });
1281
1282
1283 public static final HTableDescriptor META_TABLEDESC = new HTableDescriptor(
1284 HConstants.META_TABLE_NAME, new HColumnDescriptor[] {
1285 new HColumnDescriptor(HConstants.CATALOG_FAMILY)
1286
1287 .setMaxVersions(10)
1288 .setInMemory(true)
1289 .setBlocksize(8 * 1024)
1290 .setScope(HConstants.REPLICATION_SCOPE_LOCAL)
1291
1292 .setBloomFilterType(BloomType.NONE)
1293 });
1294
1295 static {
1296 try {
1297 META_TABLEDESC.addCoprocessor(
1298 "org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint",
1299 null, Coprocessor.PRIORITY_SYSTEM, null);
1300 } catch (IOException ex) {
1301
1302 throw new RuntimeException(ex);
1303 }
1304 }
1305
1306
1307 @Deprecated
1308 public void setOwner(User owner) {
1309 setOwnerString(owner != null ? owner.getShortName() : null);
1310 }
1311
1312
1313 @Deprecated
1314 public void setOwnerString(String ownerString) {
1315 if (ownerString != null) {
1316 setValue(OWNER_KEY, ownerString);
1317 } else {
1318 remove(OWNER_KEY);
1319 }
1320 }
1321
1322 @Deprecated
1323 public String getOwnerString() {
1324 if (getValue(OWNER_KEY) != null) {
1325 return Bytes.toString(getValue(OWNER_KEY));
1326 }
1327
1328
1329
1330 return null;
1331 }
1332
1333
1334
1335
1336
1337 public byte [] toByteArray() {
1338 return ProtobufUtil.prependPBMagic(convert().toByteArray());
1339 }
1340
1341
1342
1343
1344
1345
1346
1347
1348 public static HTableDescriptor parseFrom(final byte [] bytes)
1349 throws DeserializationException, IOException {
1350 if (!ProtobufUtil.isPBMagicPrefix(bytes)) {
1351 return (HTableDescriptor)Writables.getWritable(bytes, new HTableDescriptor());
1352 }
1353 int pblen = ProtobufUtil.lengthOfPBMagic();
1354 TableSchema.Builder builder = TableSchema.newBuilder();
1355 TableSchema ts;
1356 try {
1357 ts = builder.mergeFrom(bytes, pblen, bytes.length - pblen).build();
1358 } catch (InvalidProtocolBufferException e) {
1359 throw new DeserializationException(e);
1360 }
1361 return convert(ts);
1362 }
1363
1364
1365
1366
1367 public TableSchema convert() {
1368 TableSchema.Builder builder = TableSchema.newBuilder();
1369 builder.setName(ByteString.copyFrom(getName()));
1370 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e: this.values.entrySet()) {
1371 BytesBytesPair.Builder aBuilder = BytesBytesPair.newBuilder();
1372 aBuilder.setFirst(ByteString.copyFrom(e.getKey().get()));
1373 aBuilder.setSecond(ByteString.copyFrom(e.getValue().get()));
1374 builder.addAttributes(aBuilder.build());
1375 }
1376 for (HColumnDescriptor hcd: getColumnFamilies()) {
1377 builder.addColumnFamilies(hcd.convert());
1378 }
1379 for (Map.Entry<String, String> e : this.configuration.entrySet()) {
1380 NameStringPair.Builder aBuilder = NameStringPair.newBuilder();
1381 aBuilder.setName(e.getKey());
1382 aBuilder.setValue(e.getValue());
1383 builder.addConfiguration(aBuilder.build());
1384 }
1385 return builder.build();
1386 }
1387
1388
1389
1390
1391
1392 public static HTableDescriptor convert(final TableSchema ts) {
1393 List<ColumnFamilySchema> list = ts.getColumnFamiliesList();
1394 HColumnDescriptor [] hcds = new HColumnDescriptor[list.size()];
1395 int index = 0;
1396 for (ColumnFamilySchema cfs: list) {
1397 hcds[index++] = HColumnDescriptor.convert(cfs);
1398 }
1399 HTableDescriptor htd = new HTableDescriptor(ts.getName().toByteArray(), hcds);
1400 for (BytesBytesPair a: ts.getAttributesList()) {
1401 htd.setValue(a.getFirst().toByteArray(), a.getSecond().toByteArray());
1402 }
1403 for (NameStringPair a: ts.getConfigurationList()) {
1404 htd.setConfiguration(a.getName(), a.getValue());
1405 }
1406 return htd;
1407 }
1408
1409
1410
1411
1412 public String getConfigurationValue(String key) {
1413 return configuration.get(key);
1414 }
1415
1416
1417
1418
1419 public Map<String, String> getConfiguration() {
1420
1421 return Collections.unmodifiableMap(configuration);
1422 }
1423
1424
1425
1426
1427
1428
1429 public void setConfiguration(String key, String value) {
1430 if (value == null) {
1431 removeConfiguration(key);
1432 } else {
1433 configuration.put(key, value);
1434 }
1435 }
1436
1437
1438
1439
1440 public void removeConfiguration(final String key) {
1441 configuration.remove(key);
1442 }
1443 }