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.Collections;
26 import java.util.HashMap;
27 import java.util.Map;
28
29 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
30 import org.apache.hadoop.hbase.io.hfile.Compression;
31 import org.apache.hadoop.hbase.io.hfile.HFile;
32 import org.apache.hadoop.hbase.regionserver.StoreFile;
33 import org.apache.hadoop.hbase.regionserver.StoreFile.BloomType;
34 import org.apache.hadoop.hbase.util.Bytes;
35 import org.apache.hadoop.io.Text;
36 import org.apache.hadoop.io.WritableComparable;
37
38
39
40
41
42
43
44
45
46
47 public class HColumnDescriptor implements WritableComparable<HColumnDescriptor> {
48
49
50
51
52
53
54
55
56 private static final byte COLUMN_DESCRIPTOR_VERSION = (byte)8;
57
58
59
60
61
62
63
64 @Deprecated
65 public static enum CompressionType {
66
67 NONE,
68
69 RECORD,
70
71 BLOCK
72 }
73
74 public static final String COMPRESSION = "COMPRESSION";
75 public static final String BLOCKCACHE = "BLOCKCACHE";
76 public static final String BLOCKSIZE = "BLOCKSIZE";
77 public static final String LENGTH = "LENGTH";
78 public static final String TTL = "TTL";
79 public static final String BLOOMFILTER = "BLOOMFILTER";
80 public static final String FOREVER = "FOREVER";
81 public static final String REPLICATION_SCOPE = "REPLICATION_SCOPE";
82
83
84
85
86 public static final String DEFAULT_COMPRESSION =
87 Compression.Algorithm.NONE.getName();
88
89
90
91
92 public static final int DEFAULT_VERSIONS = 3;
93
94
95
96
97
98 private volatile Integer blocksize = null;
99
100
101
102
103 public static final boolean DEFAULT_IN_MEMORY = false;
104
105
106
107
108 public static final boolean DEFAULT_BLOCKCACHE = true;
109
110
111
112
113
114 public static final int DEFAULT_BLOCKSIZE = HFile.DEFAULT_BLOCKSIZE;
115
116
117
118
119 public static final String DEFAULT_BLOOMFILTER = StoreFile.BloomType.NONE.toString();
120
121
122
123
124 public static final int DEFAULT_TTL = HConstants.FOREVER;
125
126
127
128
129 public static final int DEFAULT_REPLICATION_SCOPE = HConstants.REPLICATION_SCOPE_LOCAL;
130
131
132 private byte [] name;
133
134
135 protected Map<ImmutableBytesWritable,ImmutableBytesWritable> values =
136 new HashMap<ImmutableBytesWritable,ImmutableBytesWritable>();
137
138
139
140
141 private int cachedMaxVersions = -1;
142
143
144
145
146 public HColumnDescriptor() {
147 this.name = null;
148 }
149
150
151
152
153
154
155
156
157 public HColumnDescriptor(final String familyName) {
158 this(Bytes.toBytes(familyName));
159 }
160
161
162
163
164
165
166
167
168 public HColumnDescriptor(final byte [] familyName) {
169 this (familyName == null || familyName.length <= 0?
170 HConstants.EMPTY_BYTE_ARRAY: familyName, DEFAULT_VERSIONS,
171 DEFAULT_COMPRESSION, DEFAULT_IN_MEMORY, DEFAULT_BLOCKCACHE,
172 DEFAULT_TTL, DEFAULT_BLOOMFILTER);
173 }
174
175
176
177
178
179
180
181 public HColumnDescriptor(HColumnDescriptor desc) {
182 super();
183 this.name = desc.name.clone();
184 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
185 desc.values.entrySet()) {
186 this.values.put(e.getKey(), e.getValue());
187 }
188 setMaxVersions(desc.getMaxVersions());
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209 public HColumnDescriptor(final byte [] familyName, final int maxVersions,
210 final String compression, final boolean inMemory,
211 final boolean blockCacheEnabled,
212 final int timeToLive, final String bloomFilter) {
213 this(familyName, maxVersions, compression, inMemory, blockCacheEnabled,
214 DEFAULT_BLOCKSIZE, timeToLive, bloomFilter, DEFAULT_REPLICATION_SCOPE);
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237 public HColumnDescriptor(final byte [] familyName, final int maxVersions,
238 final String compression, final boolean inMemory,
239 final boolean blockCacheEnabled, final int blocksize,
240 final int timeToLive, final String bloomFilter, final int scope) {
241 isLegalFamilyName(familyName);
242 this.name = familyName;
243
244 if (maxVersions <= 0) {
245
246
247 throw new IllegalArgumentException("Maximum versions must be positive");
248 }
249 setMaxVersions(maxVersions);
250 setInMemory(inMemory);
251 setBlockCacheEnabled(blockCacheEnabled);
252 setTimeToLive(timeToLive);
253 setCompressionType(Compression.Algorithm.
254 valueOf(compression.toUpperCase()));
255 setBloomFilterType(StoreFile.BloomType.
256 valueOf(bloomFilter.toUpperCase()));
257 setBlocksize(blocksize);
258 setScope(scope);
259 }
260
261
262
263
264
265
266
267
268
269 public static byte [] isLegalFamilyName(final byte [] b) {
270 if (b == null) {
271 return b;
272 }
273 if (b[0] == '.') {
274 throw new IllegalArgumentException("Family names cannot start with a " +
275 "period: " + Bytes.toString(b));
276 }
277 for (int i = 0; i < b.length; i++) {
278 if (Character.isISOControl(b[i]) || b[i] == ':') {
279 throw new IllegalArgumentException("Illegal character <" + b[i] +
280 ">. Family names cannot contain control characters or colons: " +
281 Bytes.toString(b));
282 }
283 }
284 return b;
285 }
286
287
288
289
290 public byte [] getName() {
291 return name;
292 }
293
294
295
296
297 public String getNameAsString() {
298 return Bytes.toString(this.name);
299 }
300
301
302
303
304
305 public byte[] getValue(byte[] key) {
306 ImmutableBytesWritable ibw = values.get(new ImmutableBytesWritable(key));
307 if (ibw == null)
308 return null;
309 return ibw.get();
310 }
311
312
313
314
315
316 public String getValue(String key) {
317 byte[] value = getValue(Bytes.toBytes(key));
318 if (value == null)
319 return null;
320 return Bytes.toString(value);
321 }
322
323
324
325
326 public Map<ImmutableBytesWritable,ImmutableBytesWritable> getValues() {
327 return Collections.unmodifiableMap(values);
328 }
329
330
331
332
333
334 public void setValue(byte[] key, byte[] value) {
335 values.put(new ImmutableBytesWritable(key),
336 new ImmutableBytesWritable(value));
337 }
338
339
340
341
342 public void remove(final byte [] key) {
343 values.remove(new ImmutableBytesWritable(key));
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 public Compression.Algorithm getCompression() {
356 String n = getValue(COMPRESSION);
357 return Compression.Algorithm.valueOf(n.toUpperCase());
358 }
359
360
361 public int getMaxVersions() {
362 return this.cachedMaxVersions;
363 }
364
365
366
367
368 public void setMaxVersions(int maxVersions) {
369 setValue(HConstants.VERSIONS, Integer.toString(maxVersions));
370 cachedMaxVersions = maxVersions;
371 }
372
373
374
375
376 public synchronized int getBlocksize() {
377 if (this.blocksize == null) {
378 String value = getValue(BLOCKSIZE);
379 this.blocksize = (value != null)?
380 Integer.decode(value): Integer.valueOf(DEFAULT_BLOCKSIZE);
381 }
382 return this.blocksize.intValue();
383 }
384
385
386
387
388 public void setBlocksize(int s) {
389 setValue(BLOCKSIZE, Integer.toString(s));
390 this.blocksize = null;
391 }
392
393
394
395
396 public Compression.Algorithm getCompressionType() {
397 return getCompression();
398 }
399
400
401
402
403
404
405
406
407 public void setCompressionType(Compression.Algorithm type) {
408 String compressionType;
409 switch (type) {
410 case LZO: compressionType = "LZO"; break;
411 case GZ: compressionType = "GZ"; break;
412 default: compressionType = "NONE"; break;
413 }
414 setValue(COMPRESSION, compressionType);
415 }
416
417
418
419
420 public boolean isInMemory() {
421 String value = getValue(HConstants.IN_MEMORY);
422 if (value != null)
423 return Boolean.valueOf(value).booleanValue();
424 return DEFAULT_IN_MEMORY;
425 }
426
427
428
429
430
431 public void setInMemory(boolean inMemory) {
432 setValue(HConstants.IN_MEMORY, Boolean.toString(inMemory));
433 }
434
435
436
437
438 public int getTimeToLive() {
439 String value = getValue(TTL);
440 return (value != null)? Integer.valueOf(value).intValue(): DEFAULT_TTL;
441 }
442
443
444
445
446 public void setTimeToLive(int timeToLive) {
447 setValue(TTL, Integer.toString(timeToLive));
448 }
449
450
451
452
453 public boolean isBlockCacheEnabled() {
454 String value = getValue(BLOCKCACHE);
455 if (value != null)
456 return Boolean.valueOf(value).booleanValue();
457 return DEFAULT_BLOCKCACHE;
458 }
459
460
461
462
463 public void setBlockCacheEnabled(boolean blockCacheEnabled) {
464 setValue(BLOCKCACHE, Boolean.toString(blockCacheEnabled));
465 }
466
467
468
469
470 public StoreFile.BloomType getBloomFilterType() {
471 String n = getValue(BLOOMFILTER);
472 if (n == null) {
473 n = DEFAULT_BLOOMFILTER;
474 }
475 return StoreFile.BloomType.valueOf(n.toUpperCase());
476 }
477
478
479
480
481 public void setBloomFilterType(final StoreFile.BloomType bt) {
482 setValue(BLOOMFILTER, bt.toString());
483 }
484
485
486
487
488 public int getScope() {
489 String value = getValue(REPLICATION_SCOPE);
490 if (value != null) {
491 return Integer.valueOf(value).intValue();
492 }
493 return DEFAULT_REPLICATION_SCOPE;
494 }
495
496
497
498
499 public void setScope(int scope) {
500 setValue(REPLICATION_SCOPE, Integer.toString(scope));
501 }
502
503
504
505
506 @Override
507 public String toString() {
508 StringBuilder s = new StringBuilder();
509 s.append('{');
510 s.append(HConstants.NAME);
511 s.append(" => '");
512 s.append(Bytes.toString(name));
513 s.append("'");
514 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
515 values.entrySet()) {
516 String key = Bytes.toString(e.getKey().get());
517 String value = Bytes.toString(e.getValue().get());
518 s.append(", ");
519 s.append(key);
520 s.append(" => '");
521 s.append(value);
522 s.append("'");
523 }
524 s.append('}');
525 return s.toString();
526 }
527
528
529
530
531 @Override
532 public boolean equals(Object obj) {
533 if (this == obj) {
534 return true;
535 }
536 if (obj == null) {
537 return false;
538 }
539 if (!(obj instanceof HColumnDescriptor)) {
540 return false;
541 }
542 return compareTo((HColumnDescriptor)obj) == 0;
543 }
544
545
546
547
548 @Override
549 public int hashCode() {
550 int result = Bytes.hashCode(this.name);
551 result ^= Byte.valueOf(COLUMN_DESCRIPTOR_VERSION).hashCode();
552 result ^= values.hashCode();
553 return result;
554 }
555
556
557
558 public void readFields(DataInput in) throws IOException {
559 int version = in.readByte();
560 if (version < 6) {
561 if (version <= 2) {
562 Text t = new Text();
563 t.readFields(in);
564 this.name = t.getBytes();
565
566
567
568
569 } else {
570 this.name = Bytes.readByteArray(in);
571 }
572 this.values.clear();
573 setMaxVersions(in.readInt());
574 int ordinal = in.readInt();
575 setCompressionType(Compression.Algorithm.values()[ordinal]);
576 setInMemory(in.readBoolean());
577 setBloomFilterType(in.readBoolean() ? BloomType.ROW : BloomType.NONE);
578 if (getBloomFilterType() != BloomType.NONE && version < 5) {
579
580
581
582
583 throw new UnsupportedClassVersionError(this.getClass().getName() +
584 " does not support backward compatibility with versions older " +
585 "than version 5");
586 }
587 if (version > 1) {
588 setBlockCacheEnabled(in.readBoolean());
589 }
590 if (version > 2) {
591 setTimeToLive(in.readInt());
592 }
593 } else {
594
595 this.name = Bytes.readByteArray(in);
596 this.values.clear();
597 int numValues = in.readInt();
598 for (int i = 0; i < numValues; i++) {
599 ImmutableBytesWritable key = new ImmutableBytesWritable();
600 ImmutableBytesWritable value = new ImmutableBytesWritable();
601 key.readFields(in);
602 value.readFields(in);
603
604
605 if (version < 8 && Bytes.toString(key.get()).equals(BLOOMFILTER)) {
606 value.set(Bytes.toBytes(
607 Boolean.getBoolean(Bytes.toString(value.get()))
608 ? BloomType.ROW.toString()
609 : BloomType.NONE.toString()));
610 }
611
612 values.put(key, value);
613 }
614 if (version == 6) {
615
616 setValue(COMPRESSION, Compression.Algorithm.NONE.getName());
617 }
618 String value = getValue(HConstants.VERSIONS);
619 this.cachedMaxVersions = (value != null)?
620 Integer.valueOf(value).intValue(): DEFAULT_VERSIONS;
621 }
622 }
623
624 public void write(DataOutput out) throws IOException {
625 out.writeByte(COLUMN_DESCRIPTOR_VERSION);
626 Bytes.writeByteArray(out, this.name);
627 out.writeInt(values.size());
628 for (Map.Entry<ImmutableBytesWritable, ImmutableBytesWritable> e:
629 values.entrySet()) {
630 e.getKey().write(out);
631 e.getValue().write(out);
632 }
633 }
634
635
636
637 public int compareTo(HColumnDescriptor o) {
638 int result = Bytes.compareTo(this.name, o.getName());
639 if (result == 0) {
640
641 result = this.values.hashCode() - o.values.hashCode();
642 if (result < 0)
643 result = -1;
644 else if (result > 0)
645 result = 1;
646 }
647 return result;
648 }
649 }